[{"data":1,"prerenderedAt":17013},["ShallowReactive",2],{"navigation_docs":3,"-client-server-architecture-dns-smtp-application-protocols":5180,"-client-server-architecture-dns-smtp-application-protocols-surround":17008},[4,1707,2084,2556,2737,2863,3070,3192,3242,3299,3333,3459,3536,3550,3689,3983,4060,4793,4968,5061,5114,5176],{"title":5,"icon":6,"path":7,"stem":8,"children":9},"C#","i-devicon-csharp","\u002Fcsharp","01.csharp",[10,13,60,90,120,202,219,253,379,404,457,650,1364,1654,1703],{"title":11,"path":7,"stem":12},"C# та .NET","01.csharp\u002Findex",{"title":14,"icon":15,"path":16,"stem":17,"children":18,"page":59},"Fundamentals","i-lucide-book-open","\u002Fcsharp\u002Ffundamentals","01.csharp\u002F01.fundamentals",[19,23,27,31,35,39,43,47,51,55],{"title":20,"path":21,"stem":22},"Вступ до екосистеми .NET","\u002Fcsharp\u002Ffundamentals\u002Fintroduction-to-ecosystem","01.csharp\u002F01.fundamentals\u002F01.introduction-to-ecosystem",{"title":24,"path":25,"stem":26},"Структура програми на C#","\u002Fcsharp\u002Ffundamentals\u002Fprogram-structure","01.csharp\u002F01.fundamentals\u002F02.program-structure",{"title":28,"path":29,"stem":30},"Змінні та Типи Даних","\u002Fcsharp\u002Ffundamentals\u002Fvariables-data-types","01.csharp\u002F01.fundamentals\u002F03.variables-data-types",{"title":32,"path":33,"stem":34},"Масиви","\u002Fcsharp\u002Ffundamentals\u002Farrays","01.csharp\u002F01.fundamentals\u002F04.arrays",{"title":36,"path":37,"stem":38},"Strings & Text Handling","\u002Fcsharp\u002Ffundamentals\u002Fstrings-text-handling","01.csharp\u002F01.fundamentals\u002F05.strings-text-handling",{"title":40,"path":41,"stem":42},"Дати і Час","\u002Fcsharp\u002Ffundamentals\u002Fdates-time-handling","01.csharp\u002F01.fundamentals\u002F06.dates-time-handling",{"title":44,"path":45,"stem":46},"Потік Керування","\u002Fcsharp\u002Ffundamentals\u002Fcontrol-flow","01.csharp\u002F01.fundamentals\u002F07.control-flow",{"title":48,"path":49,"stem":50},"Методи","\u002Fcsharp\u002Ffundamentals\u002Fmethods","01.csharp\u002F01.fundamentals\u002F08.methods",{"title":52,"path":53,"stem":54},"Основи Відлагодження","\u002Fcsharp\u002Ffundamentals\u002Fdebugging-basics","01.csharp\u002F01.fundamentals\u002F09.debugging-basics",{"title":56,"path":57,"stem":58},"Інтерактивна Консоль (Classic)","\u002Fcsharp\u002Ffundamentals\u002Finteractive-console","01.csharp\u002F01.fundamentals\u002F10.interactive-console",false,{"title":61,"icon":62,"path":63,"stem":64,"children":65,"page":59},"OOP","i-lucide-box","\u002Fcsharp\u002Foop","01.csharp\u002F02.oop",[66,70,74,78,82,86],{"title":67,"path":68,"stem":69},"Package Management (Управління Пакетами)","\u002Fcsharp\u002Foop\u002Fpackage-management","01.csharp\u002F02.oop\u002F01.package-management",{"title":71,"path":72,"stem":73},"Класи та Об'єкти","\u002Fcsharp\u002Foop\u002Fclasses-objects","01.csharp\u002F02.oop\u002F02.classes-objects",{"title":75,"path":76,"stem":77},"Властивості та Поля","\u002Fcsharp\u002Foop\u002Fproperties-fields","01.csharp\u002F02.oop\u002F03.properties-fields",{"title":79,"path":80,"stem":81},"Стовпи ООП","\u002Fcsharp\u002Foop\u002Foop-pillars","01.csharp\u002F02.oop\u002F04.oop-pillars",{"title":83,"path":84,"stem":85},"Advanced Types","\u002Fcsharp\u002Foop\u002Fadvanced-types","01.csharp\u002F02.oop\u002F05.advanced-types",{"title":87,"path":88,"stem":89},"Namespaces (Простори Імен)","\u002Fcsharp\u002Foop\u002Fnamespaces","01.csharp\u002F02.oop\u002F06.namespaces",{"title":91,"icon":92,"path":93,"stem":94,"children":95,"page":59},"Advanced Core","i-lucide-zap","\u002Fcsharp\u002Fadvanced-core","01.csharp\u002F03.advanced-core",[96,100,104,108,112,116],{"title":97,"path":98,"stem":99},"Generics (Узагальнення)","\u002Fcsharp\u002Fadvanced-core\u002Fgenerics","01.csharp\u002F03.advanced-core\u002F01.generics",{"title":101,"path":102,"stem":103},"Делегати, Події та Лямбда-вирази","\u002Fcsharp\u002Fadvanced-core\u002Fdelegates-events-lambdas","01.csharp\u002F03.advanced-core\u002F02.delegates-events-lambdas",{"title":105,"path":106,"stem":107},"Interfaces Deep Dive (Інтерфейси: Поглиблений Розгляд)","\u002Fcsharp\u002Fadvanced-core\u002Finterfaces-deep-dive","01.csharp\u002F03.advanced-core\u002F03.interfaces-deep-dive",{"title":109,"path":110,"stem":111},"Обробка Винятків","\u002Fcsharp\u002Fadvanced-core\u002Fexception-handling","01.csharp\u002F03.advanced-core\u002F04.exception-handling",{"title":113,"path":114,"stem":115},"Pattern Matching","\u002Fcsharp\u002Fadvanced-core\u002Fpattern-matching","01.csharp\u002F03.advanced-core\u002F05.pattern-matching",{"title":117,"path":118,"stem":119},"Додаткові Можливості C#","\u002Fcsharp\u002Fadvanced-core\u002Fadditional-features","01.csharp\u002F03.advanced-core\u002F06.additional-features",{"title":121,"icon":122,"path":123,"stem":124,"children":125,"page":59},"Architecture Best Practices","i-lucide-building-2","\u002Fcsharp\u002Farchitecture-best-practices","01.csharp\u002F04.architecture-best-practices",[126,130,149,153,157,161,165,169],{"title":127,"path":128,"stem":129},"Software Design Principles (Частина 1)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fsoftware-design-principles","01.csharp\u002F04.architecture-best-practices\u002F01.software-design-principles",{"title":131,"icon":132,"path":133,"stem":134,"children":135,"page":59},"Design Patterns","i-lucide-folder","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns",[136],{"title":137,"icon":132,"path":138,"stem":139,"children":140,"page":59},"Creational","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational",[141,145],{"title":142,"path":143,"stem":144},"Singleton (Одинак)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational\u002Fsingleton","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational\u002F01.singleton",{"title":146,"path":147,"stem":148},"Builder (Будівельник)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational\u002Fbuilder","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational\u002F02.builder",{"title":150,"path":151,"stem":152},"Building Professional CLIs","\u002Fcsharp\u002Farchitecture-best-practices\u002Fbuilding-professional-clis","01.csharp\u002F04.architecture-best-practices\u002F03.building-professional-clis",{"title":154,"path":155,"stem":156},"Validation & Flow Control","\u002Fcsharp\u002Farchitecture-best-practices\u002Fvalidation-flow-control","01.csharp\u002F04.architecture-best-practices\u002F04.validation-flow-control",{"title":158,"path":159,"stem":160},"The Modern .NET Host (Microsoft.Extensions)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fmodern-dotnet-host","01.csharp\u002F04.architecture-best-practices\u002F05.modern-dotnet-host",{"title":162,"path":163,"stem":164},"Data Mapper: Repository та DAO патерни (Частина 1)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdata-mapper-part1","01.csharp\u002F04.architecture-best-practices\u002F06.data-mapper-part1",{"title":166,"path":167,"stem":168},"Data Mapper: Repository та DAO патерни (Частина 2)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdata-mapper-part2","01.csharp\u002F04.architecture-best-practices\u002F07.data-mapper-part2",{"title":170,"icon":132,"path":171,"stem":172,"children":173,"page":59},"Di Ioc","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc",[174,178,182,186,190,194,198],{"title":175,"path":176,"stem":177},"Проблема залежностей та Інверсія Контролю","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fthe-dependency-problem","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F01.the-dependency-problem",{"title":179,"path":180,"stem":181},"Будуємо власний Service Container","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fbuild-your-own-container","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F02.build-your-own-container",{"title":183,"path":184,"stem":185},"Service Locator: Паттерн та Анти-паттерн","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fservice-locator-pattern","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F03.service-locator-pattern",{"title":187,"path":188,"stem":189},"Паттерни Dependency Injection","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fdependency-injection-patterns","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F04.dependency-injection-patterns",{"title":191,"path":192,"stem":193},"Microsoft DI: IServiceCollection та IServiceProvider","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fmicrosoft-di-deep-dive","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F05.microsoft-di-deep-dive",{"title":195,"path":196,"stem":197},"Service Lifetimes та Scopes","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fservice-lifetimes-and-scopes","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F06.service-lifetimes-and-scopes",{"title":199,"path":200,"stem":201},"DI Анти-паттерни та Найкращі Практики","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fdi-anti-patterns-and-best-practices","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F07.di-anti-patterns-and-best-practices",{"title":203,"icon":132,"path":204,"stem":205,"children":206,"page":59},"Standard Library","\u002Fcsharp\u002Fstandard-library","01.csharp\u002F05.standard-library",[207,211,215],{"title":208,"path":209,"stem":210},"Collections (Колекції)","\u002Fcsharp\u002Fstandard-library\u002Fcollections","01.csharp\u002F05.standard-library\u002F01.collections",{"title":212,"path":213,"stem":214},"High Performance Types (Високопродуктивні Типи)","\u002Fcsharp\u002Fstandard-library\u002Fhigh-performance-types","01.csharp\u002F05.standard-library\u002F02.high-performance-types",{"title":216,"path":217,"stem":218},"LINQ (Language Integrated Query)","\u002Fcsharp\u002Fstandard-library\u002Flinq","01.csharp\u002F05.standard-library\u002F03.linq",{"title":220,"icon":221,"path":222,"stem":223,"children":224,"page":59},"System Internals Concurrency","i-lucide-server","\u002Fcsharp\u002Fsystem-internals-concurrency","01.csharp\u002F06.system-internals-concurrency",[225,229,233,237,241,245,249],{"title":226,"path":227,"stem":228},"Memory Management","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fmemory-management","01.csharp\u002F06.system-internals-concurrency\u002F01.memory-management",{"title":230,"path":231,"stem":232},"Reflection API: System.Type та Метадані","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Freflection-fundamentals","01.csharp\u002F06.system-internals-concurrency\u002F02.reflection-fundamentals",{"title":234,"path":235,"stem":236},"Attributes та Dynamic Language Runtime","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fattributes-dynamic","01.csharp\u002F06.system-internals-concurrency\u002F03.attributes-dynamic",{"title":238,"path":239,"stem":240},"Expression Trees: Швидка Альтернатива Рефлексії","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fexpression-trees-compiled","01.csharp\u002F06.system-internals-concurrency\u002F04.expression-trees-compiled",{"title":242,"path":243,"stem":244},"Source Generators: Compile-Time Code Generation","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fsource-generators","01.csharp\u002F06.system-internals-concurrency\u002F05.source-generators",{"title":246,"path":247,"stem":248},"Multithreading Fundamentals","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fmultithreading-fundamentals","01.csharp\u002F06.system-internals-concurrency\u002F06.multithreading-fundamentals",{"title":250,"path":251,"stem":252},"Synchronization Primitives","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fsynchronization-primitives","01.csharp\u002F06.system-internals-concurrency\u002F07.synchronization-primitives",{"title":254,"icon":255,"path":256,"stem":257,"children":258,"page":59},"System Programming Windows","i-lucide-cpu","\u002Fcsharp\u002Fsystem-programming-windows","01.csharp\u002F07.system-programming-windows",[259,263,267,271,275,279,283,287,291,295,299,303,307,311,315,319,323,327,331,335,339,343,347,351,355,359,363,367,371,375],{"title":260,"path":261,"stem":262},"Як Працює Операційна Система","\u002Fcsharp\u002Fsystem-programming-windows\u002Fhow-os-works","01.csharp\u002F07.system-programming-windows\u002F01.how-os-works",{"title":264,"path":265,"stem":266},"Процеси в .NET — API та Запуск","\u002Fcsharp\u002Fsystem-programming-windows\u002Fprocesses-in-dotnet","01.csharp\u002F07.system-programming-windows\u002F02.processes-in-dotnet",{"title":268,"path":269,"stem":270},"Процеси в .NET — IPC та Міжпроцесна Комунікація","\u002Fcsharp\u002Fsystem-programming-windows\u002F02a.processes-ipc","01.csharp\u002F07.system-programming-windows\u002F02a.processes-ipc",{"title":272,"path":273,"stem":274},"Application Domains та Збірки — AppDomain і AssemblyLoadContext","\u002Fcsharp\u002Fsystem-programming-windows\u002Fappdomains-assemblies","01.csharp\u002F07.system-programming-windows\u002F03.appdomains-assemblies",{"title":276,"path":277,"stem":278},"Application Domains та Збірки — Plug-in Система з Hot-Reload","\u002Fcsharp\u002Fsystem-programming-windows\u002F03a.appdomains-plugin-system","01.csharp\u002F07.system-programming-windows\u002F03a.appdomains-plugin-system",{"title":280,"path":281,"stem":282},"Потоки — Основи та API Thread","\u002Fcsharp\u002Fsystem-programming-windows\u002Fthread-fundamentals","01.csharp\u002F07.system-programming-windows\u002F04.thread-fundamentals",{"title":284,"path":285,"stem":286},"Потоки — Lifecycle, Пріоритети та Безпечне Завершення","\u002Fcsharp\u002Fsystem-programming-windows\u002F04a.thread-lifecycle-priorities","01.csharp\u002F07.system-programming-windows\u002F04a.thread-lifecycle-priorities",{"title":288,"path":289,"stem":290},"Проблеми Спільного Стану — Race Condition та Data Race","\u002Fcsharp\u002Fsystem-programming-windows\u002Fshared-state-problems","01.csharp\u002F07.system-programming-windows\u002F05.shared-state-problems",{"title":292,"path":293,"stem":294},"Проблеми Спільного Стану — Memory Model та volatile","\u002Fcsharp\u002Fsystem-programming-windows\u002F05a.shared-state-memory-model","01.csharp\u002F07.system-programming-windows\u002F05a.shared-state-memory-model",{"title":296,"path":297,"stem":298},"Синхронізація — Monitor, lock та еволюція примітивів","\u002Fcsharp\u002Fsystem-programming-windows\u002Fsynchronization-fundamentals","01.csharp\u002F07.system-programming-windows\u002F06.synchronization-fundamentals",{"title":300,"path":301,"stem":302},"Синхронізація — Наскрізний Приклад та Deadlock Detection","\u002Fcsharp\u002Fsystem-programming-windows\u002F06a.synchronization-walkthrough","01.csharp\u002F07.system-programming-windows\u002F06a.synchronization-walkthrough",{"title":304,"path":305,"stem":306},"Синхронізація — Mutex, Semaphore та Event-Based Primitives","\u002Fcsharp\u002Fsystem-programming-windows\u002Fsynchronization-advanced","01.csharp\u002F07.system-programming-windows\u002F07.synchronization-advanced",{"title":308,"path":309,"stem":310},"Синхронізація — Interlocked, Volatile та Lock-Free Структури","\u002Fcsharp\u002Fsystem-programming-windows\u002F07a.synchronization-advanced-walkthrough","01.csharp\u002F07.system-programming-windows\u002F07a.synchronization-advanced-walkthrough",{"title":312,"path":313,"stem":314},"Interlocked, CAS та Lock-Free Структури","\u002Fcsharp\u002Fsystem-programming-windows\u002Finterlocked-cas-lockfree","01.csharp\u002F07.system-programming-windows\u002F08.interlocked-cas-lockfree",{"title":316,"path":317,"stem":318},"Volatile, Memory Model та Spinning","\u002Fcsharp\u002Fsystem-programming-windows\u002F08a.volatile-memory-model","01.csharp\u002F07.system-programming-windows\u002F08a.volatile-memory-model",{"title":320,"path":321,"stem":322},"ThreadPool — Пул Потоків для Ефективного Виконання","\u002Fcsharp\u002Fsystem-programming-windows\u002Fthread-pool","01.csharp\u002F07.system-programming-windows\u002F09.thread-pool",{"title":324,"path":325,"stem":326},"ThreadPool — Просунуті Сценарії та Внутрішня Будова","\u002Fcsharp\u002Fsystem-programming-windows\u002F09a.thread-pool-advanced","01.csharp\u002F07.system-programming-windows\u002F09a.thread-pool-advanced",{"title":328,"path":329,"stem":330},"Concurrent та Immutable Collections","\u002Fcsharp\u002Fsystem-programming-windows\u002Fconcurrent-collections","01.csharp\u002F07.system-programming-windows\u002F10.concurrent-collections",{"title":332,"path":333,"stem":334},"TPL, Task та Композиція — Від Thread до Task","\u002Fcsharp\u002Fsystem-programming-windows\u002Ftpl-parallel-plinq","01.csharp\u002F07.system-programming-windows\u002F11.tpl-parallel-plinq",{"title":336,"path":337,"stem":338},"Parallel Class та PLINQ — Data Parallelism","\u002Fcsharp\u002Fsystem-programming-windows\u002F11a.tpl-parallel-plinq-advanced","01.csharp\u002F07.system-programming-windows\u002F11a.tpl-parallel-plinq-advanced",{"title":340,"path":341,"stem":342},"Async\u002FAwait — Фундамент Асинхронного Програмування","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-fundamentals","01.csharp\u002F07.system-programming-windows\u002F12.async-fundamentals",{"title":344,"path":345,"stem":346},"SynchronizationContext та ConfigureAwait — Контекст Виконання","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-context-configureawait","01.csharp\u002F07.system-programming-windows\u002F13.async-context-configureawait",{"title":348,"path":349,"stem":350},"Async — Просунуті Паттерни","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-advanced","01.csharp\u002F07.system-programming-windows\u002F14.async-advanced",{"title":352,"path":353,"stem":354},"System.Threading.Channels — Async Producer-Consumer","\u002Fcsharp\u002Fsystem-programming-windows\u002Fchannels","01.csharp\u002F07.system-programming-windows\u002F15.channels",{"title":356,"path":357,"stem":358},"Асинхронна Синхронізація","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-synchronization","01.csharp\u002F07.system-programming-windows\u002F16.async-synchronization",{"title":360,"path":361,"stem":362},"Unsafe Code та Вказівники","\u002Fcsharp\u002Fsystem-programming-windows\u002Funsafe-code","01.csharp\u002F07.system-programming-windows\u002F17.unsafe-code",{"title":364,"path":365,"stem":366},"P\u002FInvoke та Windows API — Міст між .NET та Native Code","\u002Fcsharp\u002Fsystem-programming-windows\u002Fpinvoke-winapi","01.csharp\u002F07.system-programming-windows\u002F18.pinvoke-winapi",{"title":368,"path":369,"stem":370},"Реєстр Windows — Центральна База Конфігурації Системи","\u002Fcsharp\u002Fsystem-programming-windows\u002Fwindows-registry","01.csharp\u002F07.system-programming-windows\u002F19.windows-registry",{"title":372,"path":373,"stem":374},"Windows Hooks, Hotkeys та Services — Глибока Інтеграція з ОС","\u002Fcsharp\u002Fsystem-programming-windows\u002Fwindows-hooks-services","01.csharp\u002F07.system-programming-windows\u002F20.windows-hooks-services",{"title":376,"path":377,"stem":378},"Системне Програмування C# (Windows) — 07.system-programming-windows","\u002Fcsharp\u002Fsystem-programming-windows\u002Fimplementation_plan","01.csharp\u002F07.system-programming-windows\u002Fimplementation_plan",{"title":380,"icon":132,"path":381,"stem":382,"children":383,"page":59},"Io","\u002Fcsharp\u002Fio","01.csharp\u002F08.io",[384,388,392,396,400],{"title":385,"path":386,"stem":387},"8.1.1. Основи роботи з файловою системою","\u002Fcsharp\u002Fio\u002Ffile-system-basics","01.csharp\u002F08.io\u002F01.file-system-basics",{"title":389,"path":390,"stem":391},"8.1.2. Потоки (Streams) та Серіалізація Даних","\u002Fcsharp\u002Fio\u002Fstreams-serialization","01.csharp\u002F08.io\u002F02.streams-serialization",{"title":393,"path":394,"stem":395},"8.2.1. JSON Serialization з System.Text.Json","\u002Fcsharp\u002Fio\u002Fjson-serialization","01.csharp\u002F08.io\u002F03.json-serialization",{"title":397,"path":398,"stem":399},"8.2.2. XML Serialization та LINQ to XML","\u002Fcsharp\u002Fio\u002Fxml-serialization","01.csharp\u002F08.io\u002F04.xml-serialization",{"title":401,"path":402,"stem":403},"8.2.3. Binary Serialization: MessagePack та Protocol Buffers","\u002Fcsharp\u002Fio\u002Fbinary-serialization","01.csharp\u002F08.io\u002F05.binary-serialization",{"title":405,"icon":132,"path":406,"stem":407,"children":408,"page":59},"Ado Net","\u002Fcsharp\u002Fado-net","01.csharp\u002F09.ado-net",[409,413,417,421,425,429,433,437,441,445,449,453],{"title":410,"path":411,"stem":412},"9.1. Введення в ADO.NET","\u002Fcsharp\u002Fado-net\u002Fintroduction-to-adonet","01.csharp\u002F09.ado-net\u002F01.introduction-to-adonet",{"title":414,"path":415,"stem":416},"9.2. Клас DbConnection — з'єднання з базою даних","\u002Fcsharp\u002Fado-net\u002Fconnection","01.csharp\u002F09.ado-net\u002F02.connection",{"title":418,"path":419,"stem":420},"9.3. Клас DbCommand — виконання SQL-запитів","\u002Fcsharp\u002Fado-net\u002Fcommand-and-queries","01.csharp\u002F09.ado-net\u002F03.command-and-queries",{"title":422,"path":423,"stem":424},"9.4. Клас DbDataReader — ефективне читання даних","\u002Fcsharp\u002Fado-net\u002Fdatareader","01.csharp\u002F09.ado-net\u002F04.datareader",{"title":426,"path":427,"stem":428},"9.5. Параметризовані запити та захист від SQL Injection","\u002Fcsharp\u002Fado-net\u002Fparameters-and-sql-injection","01.csharp\u002F09.ado-net\u002F05.parameters-and-sql-injection",{"title":430,"path":431,"stem":432},"9.6. Транзакції в ADO.NET","\u002Fcsharp\u002Fado-net\u002Ftransactions","01.csharp\u002F09.ado-net\u002F06.transactions",{"title":434,"path":435,"stem":436},"9.7. DbProviderFactory — провайдер-незалежний код","\u002Fcsharp\u002Fado-net\u002Fprovider-factory","01.csharp\u002F09.ado-net\u002F07.provider-factory",{"title":438,"path":439,"stem":440},"9.8. Асинхронний доступ до даних","\u002Fcsharp\u002Fado-net\u002Fasync-data-access","01.csharp\u002F09.ado-net\u002F08.async-data-access",{"title":442,"path":443,"stem":444},"9.9. Від'єднаний режим: DataSet, DataTable, DataRow","\u002Fcsharp\u002Fado-net\u002Fdisconnected-mode-dataset","01.csharp\u002F09.ado-net\u002F09.disconnected-mode-dataset",{"title":446,"path":447,"stem":448},"9.10. DataAdapter — міст між DataSet та базою даних","\u002Fcsharp\u002Fado-net\u002Fdata-adapter","01.csharp\u002F09.ado-net\u002F10.data-adapter",{"title":450,"path":451,"stem":452},"9.11. Data Mapper та Repository: Архітектура доступу до даних","\u002Fcsharp\u002Fado-net\u002Fdata-mapper-repository","01.csharp\u002F09.ado-net\u002F11.data-mapper-repository",{"title":454,"path":455,"stem":456},"9.12. Identity Map, Unit of Work та Specification Pattern","\u002Fcsharp\u002Fado-net\u002Fadvanced-patterns","01.csharp\u002F09.ado-net\u002F12.advanced-patterns",{"title":458,"icon":255,"path":459,"stem":460,"children":461,"page":59},"Ef Core","\u002Fcsharp\u002Fef-core","01.csharp\u002F10.ef-core",[462,466,470,474,478,482,486,490,494,498,502,506,510,514,518,522,526,532,538,542,546,550,554,558,562,566,570,574,578,582,586,590,594,598,602,606,610,614,618,622,626,630,634,638,642,646],{"title":463,"path":464,"stem":465},"Що таке ORM? Від SQL до об'єктів","\u002Fcsharp\u002Fef-core\u002Fwhat-is-orm","01.csharp\u002F10.ef-core\u002F01.what-is-orm",{"title":467,"path":468,"stem":469},"Перший проєкт — від нуля до CRUD","\u002Fcsharp\u002Fef-core\u002Ffirst-project","01.csharp\u002F10.ef-core\u002F02.first-project",{"title":471,"path":472,"stem":473},"DbContext — Серце EF Core","\u002Fcsharp\u002Fef-core\u002Fdbcontext-deep-dive","01.csharp\u002F10.ef-core\u002F03.dbcontext-deep-dive",{"title":475,"path":476,"stem":477},"Провайдери баз даних — Архітектура та Вибір СУБД","\u002Fcsharp\u002Fef-core\u002Fdatabase-providers","01.csharp\u002F10.ef-core\u002F04.database-providers",{"title":479,"path":480,"stem":481},"Конвенції EF Core — Магія без конфігурації","\u002Fcsharp\u002Fef-core\u002Fconventions","01.csharp\u002F10.ef-core\u002F05.conventions",{"title":483,"path":484,"stem":485},"Fluent API та Data Annotations — Явна конфігурація моделі","\u002Fcsharp\u002Fef-core\u002Ffluent-api-vs-annotations","01.csharp\u002F10.ef-core\u002F06.fluent-api-vs-annotations",{"title":487,"path":488,"stem":489},"Зв'язки — One-to-One та One-to-Many","\u002Fcsharp\u002Fef-core\u002Frelationships-basics","01.csharp\u002F10.ef-core\u002F07.relationships-basics",{"title":491,"path":492,"stem":493},"Зв'язки Advanced — Many-to-Many та Складні Сценарії","\u002Fcsharp\u002Fef-core\u002Frelationships-advanced","01.csharp\u002F10.ef-core\u002F08.relationships-advanced",{"title":495,"path":496,"stem":497},"Властивості — Типи, Конвертери, Компаратори (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fproperty-configuration-part1","01.csharp\u002F10.ef-core\u002F09.property-configuration-part1",{"title":499,"path":500,"stem":501},"Властивості — Value Comparers, Generators, Shadow Properties (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fproperty-configuration-part2","01.csharp\u002F10.ef-core\u002F09.property-configuration-part2",{"title":503,"path":504,"stem":505},"Складні типи — Owned Types та Complex Types (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fcomplex-types-owned-part1","01.csharp\u002F10.ef-core\u002F10.complex-types-owned-part1",{"title":507,"path":508,"stem":509},"Складні типи — Complex Types, Keyless Entities, Порівняння (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fcomplex-types-owned-part2","01.csharp\u002F10.ef-core\u002F10.complex-types-owned-part2",{"title":511,"path":512,"stem":513},"JSON Columns — Складні дані у JSON (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fjson-columns-part1","01.csharp\u002F10.ef-core\u002F11.json-columns-part1",{"title":515,"path":516,"stem":517},"JSON Columns — Value Comparers, Індекси, Провайдери (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fjson-columns-part2","01.csharp\u002F10.ef-core\u002F11.json-columns-part2",{"title":519,"path":520,"stem":521},"Успадкування — Абстрактні класи та TPH (Частина 1)","\u002Fcsharp\u002Fef-core\u002Finheritance-part1","01.csharp\u002F10.ef-core\u002F12.inheritance-part1",{"title":523,"path":524,"stem":525},"Успадкування — TPT, TPC та Порівняння Стратегій (Частина 2)","\u002Fcsharp\u002Fef-core\u002Finheritance-part2","01.csharp\u002F10.ef-core\u002F12.inheritance-part2",{"title":527,"path":528,"stem":529,"children":530},"Індекси, Обмеження та Схема (Частина 1)","\u002Fcsharp\u002Fef-core\u002Findexes-constraints-part1","01.csharp\u002F10.ef-core\u002F13.indexes-constraints-part1",[531],{"title":527,"path":528,"stem":529},{"title":533,"path":534,"stem":535,"children":536},"Індекси, Обмеження та Схема (Частина 2)","\u002Fcsharp\u002Fef-core\u002Findexes-constraints-part2","01.csharp\u002F10.ef-core\u002F13.indexes-constraints-part2",[537],{"title":533,"path":534,"stem":535},{"title":539,"path":540,"stem":541},"Seed Data — Початкові Дані (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fseeding-part1","01.csharp\u002F10.ef-core\u002F14.seeding-part1",{"title":543,"path":544,"stem":545},"Seed Data — SQL-скрипти, Bogus та Стратегії (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fseeding-part2","01.csharp\u002F10.ef-core\u002F14.seeding-part2",{"title":547,"path":548,"stem":549},"Global Query Filters — Глобальні Фільтри (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fglobal-query-filters-part1","01.csharp\u002F10.ef-core\u002F15.global-query-filters-part1",{"title":551,"path":552,"stem":553},"Global Query Filters — Підводні камені та Інтеграція (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fglobal-query-filters-part2","01.csharp\u002F10.ef-core\u002F15.global-query-filters-part2",{"title":555,"path":556,"stem":557},"LINQ-запити в EF Core (Частина 1)","\u002Fcsharp\u002Fef-core\u002Flinq-queries-part1","01.csharp\u002F10.ef-core\u002F16.linq-queries-part1",{"title":559,"path":560,"stem":561},"LINQ-запити в EF Core (Частина 2)","\u002Fcsharp\u002Fef-core\u002Flinq-queries-part2","01.csharp\u002F10.ef-core\u002F16.linq-queries-part2",{"title":563,"path":564,"stem":565},"Завантаження Пов'язаних Даних (Частина 1)","\u002Fcsharp\u002Fef-core\u002Floading-related-data-part1","01.csharp\u002F10.ef-core\u002F17.loading-related-data-part1",{"title":567,"path":568,"stem":569},"Завантаження Пов'язаних Даних (Частина 2)","\u002Fcsharp\u002Fef-core\u002Floading-related-data-part2","01.csharp\u002F10.ef-core\u002F17.loading-related-data-part2",{"title":571,"path":572,"stem":573},"Raw SQL, Views та Stored Procedures (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fraw-sql-part1","01.csharp\u002F10.ef-core\u002F18.raw-sql-part1",{"title":575,"path":576,"stem":577},"Raw SQL — Stored Procedures, DbFunction та Bulk Operations (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fraw-sql-part2","01.csharp\u002F10.ef-core\u002F18.raw-sql-part2",{"title":579,"path":580,"stem":581},"Продвинуті Запити — Compiled Queries, Bulk та Оптимізація (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fadvanced-queries-part1","01.csharp\u002F10.ef-core\u002F19.advanced-queries-part1",{"title":583,"path":584,"stem":585},"Продвинуті Запити — Query Tags, Bulk та Interceptors (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fadvanced-queries-part2","01.csharp\u002F10.ef-core\u002F19.advanced-queries-part2",{"title":587,"path":588,"stem":589},"Change Tracker — Відстеження Змін (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fchange-tracking-part1","01.csharp\u002F10.ef-core\u002F20.change-tracking-part1",{"title":591,"path":592,"stem":593},"Change Tracker — Графи Об'єктів та Disconnected (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fchange-tracking-part2","01.csharp\u002F10.ef-core\u002F20.change-tracking-part2",{"title":595,"path":596,"stem":597},"Збереження Даних та Транзакції (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fsaving-data-part1","01.csharp\u002F10.ef-core\u002F21.saving-data-part1",{"title":599,"path":600,"stem":601},"Збереження Даних — Concurrency та Outbox (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fsaving-data-part2","01.csharp\u002F10.ef-core\u002F21.saving-data-part2",{"title":603,"path":604,"stem":605},"Конкурентність та Блокування (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fconcurrency-part1","01.csharp\u002F10.ef-core\u002F22.concurrency-part1",{"title":607,"path":608,"stem":609},"Конкурентність — Дедлоки та Queue Processing (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fconcurrency-part2","01.csharp\u002F10.ef-core\u002F22.concurrency-part2",{"title":611,"path":612,"stem":613},"Міграції в EF Core — Основи (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fmigrations-basics-part1","01.csharp\u002F10.ef-core\u002F23.migrations-basics-part1",{"title":615,"path":616,"stem":617},"Міграції в EF Core — Основи (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fmigrations-basics-part2","01.csharp\u002F10.ef-core\u002F23.migrations-basics-part2",{"title":619,"path":620,"stem":621},"Міграції — Просунуті Сценарії (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fmigrations-advanced-part1","01.csharp\u002F10.ef-core\u002F24.migrations-advanced-part1",{"title":623,"path":624,"stem":625},"Міграції — Просунуті Сценарії (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fmigrations-advanced-part2","01.csharp\u002F10.ef-core\u002F24.migrations-advanced-part2",{"title":627,"path":628,"stem":629},"Управління Схемою та Database-First (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fschema-management-part1","01.csharp\u002F10.ef-core\u002F25.schema-management-part1",{"title":631,"path":632,"stem":633},"Управління Схемою та Database-First (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fschema-management-part2","01.csharp\u002F10.ef-core\u002F25.schema-management-part2",{"title":635,"path":636,"stem":637},"Продуктивність EF Core — Основи (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fperformance-fundamentals-part1","01.csharp\u002F10.ef-core\u002F26.performance-fundamentals-part1",{"title":639,"path":640,"stem":641},"Interceptors в EF Core (Частина 1)","\u002Fcsharp\u002Fef-core\u002Finterceptors-part1","01.csharp\u002F10.ef-core\u002F29.interceptors-part1",{"title":643,"path":644,"stem":645},"Interceptors в EF Core — Connection, Transaction та Materialization (Частина 2)","\u002Fcsharp\u002Fef-core\u002Finterceptors-part2","01.csharp\u002F10.ef-core\u002F29.interceptors-part2",{"title":647,"path":648,"stem":649},"План вивчення Entity Framework Core — Повний курс","\u002Fcsharp\u002Fef-core\u002Fimplementation_plan","01.csharp\u002F10.ef-core\u002Fimplementation_plan",{"title":651,"icon":652,"path":653,"stem":654,"children":655,"page":59},"ASP.NET","i-devicon-dotnetcore","\u002Fcsharp\u002Faspnet","01.csharp\u002F11.aspnet",[656,730,791,869,927,941,967,1057,1111,1182,1212,1289,1346],{"title":657,"icon":658,"path":659,"stem":660,"children":661,"page":59},"Minimal API","i-lucide-network","\u002Fcsharp\u002Faspnet\u002Fminimal-api","01.csharp\u002F11.aspnet\u002F01.minimal-api",[662,666,670,674,678,682,686,690,694,698,702,706,710,714,718,722,726],{"title":663,"path":664,"stem":665},"Вступ до ASP.NET та еволюція фреймворку","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fintroduction","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F01.introduction",{"title":667,"path":668,"stem":669},"Перший додаток на ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Ffirst-application","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F02.first-application",{"title":671,"path":672,"stem":673},"WebApplication, Builder та Dependency Injection","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fwebapplication-builder","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F03.webapplication-builder",{"title":675,"path":676,"stem":677},"Конвеєр запитів та Middleware","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frequest-pipeline-middleware","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F04.request-pipeline-middleware",{"title":679,"path":680,"stem":681},"Маршрутизація в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frouting-basics","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F05.routing-basics",{"title":683,"path":684,"stem":685},"Маршрутизація в ASP.NET Core: Розширені можливості","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frouting-advanced","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F06.routing-advanced",{"title":687,"path":688,"stem":689},"Статичні файли в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstatic-files","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F07.static-files",{"title":691,"path":692,"stem":693},"Статичні Активи: MapStaticAssets (ASP.NET Core 9.0)","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstatic-assets","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F08.static-assets",{"title":695,"path":696,"stem":697},"Конфігурація в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fconfiguration-fundamentals","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F09.configuration-fundamentals",{"title":699,"path":700,"stem":701},"Конфігурація: Паттерн Options","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fconfiguration-options","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F10.configuration-options",{"title":703,"path":704,"stem":705},"Логування в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Flogging-basics","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F11.logging-basics",{"title":707,"path":708,"stem":709},"Логування: Serilog та Middleware","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Flogging-advanced","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F12.logging-advanced",{"title":711,"path":712,"stem":713},"Управління станом: HttpContext.Items та Cookies","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstate-management","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F13.state-management",{"title":715,"path":716,"stem":717},"Стан сесії: Sessions","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fsession-state","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F14.session-state",{"title":719,"path":720,"stem":721},"Структура проєкту: від хаосу до архітектури","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fproject-structure","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F15.project-structure",{"title":723,"path":724,"stem":725},"Scalar у Minimal API: повний проєкт і Fluent OpenAPI","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fscalar-openapi-fluent","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F16.scalar-openapi-fluent",{"title":727,"path":728,"stem":729},"Swagger \u002F Swashbuckle у Minimal API: окремий класичний шлях","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fswagger-swashbuckle","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F17.swagger-swashbuckle",{"title":731,"icon":658,"path":732,"stem":733,"children":734,"page":59},"API","\u002Fcsharp\u002Faspnet\u002Fapi","01.csharp\u002F11.aspnet\u002F02.api",[735,739,743,747,751,755,759,763,767,771,775,779,783,787],{"title":736,"path":737,"stem":738},"Що таке API. Клієнт-серверна архітектура","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fwhat-is-api","01.csharp\u002F11.aspnet\u002F02.api\u002F01.what-is-api",{"title":740,"path":741,"stem":742},"Формати даних: JSON, XML, TOML та бінарні формати","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fdata-formats","01.csharp\u002F11.aspnet\u002F02.api\u002F02.data-formats",{"title":744,"path":745,"stem":746},"Парадигми API та концепція REST","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-paradigms-rest","01.csharp\u002F11.aspnet\u002F02.api\u002F03.api-paradigms-rest",{"title":748,"path":749,"stem":750},"HTTP-методи, статус-коди та заголовки","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fhttp-methods-status-codes","01.csharp\u002F11.aspnet\u002F02.api\u002F04.http-methods-status-codes",{"title":752,"path":753,"stem":754},"Організація HTTP API за принципами REST","\u002Fcsharp\u002Faspnet\u002Fapi\u002Frest-organizing","01.csharp\u002F11.aspnet\u002F02.api\u002F05.rest-organizing",{"title":756,"path":757,"stem":758},"Номенклатура URL та CRUD-операції","\u002Fcsharp\u002Faspnet\u002Fapi\u002Furl-nomenclature-crud","01.csharp\u002F11.aspnet\u002F02.api\u002F06.url-nomenclature-crud",{"title":760,"path":761,"stem":762},"Правила дизайну: іменування та стандарти","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-naming","01.csharp\u002F11.aspnet\u002F02.api\u002F07.api-design-naming",{"title":764,"path":765,"stem":766},"Валідація, ліміти та обробка помилок","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-validation","01.csharp\u002F11.aspnet\u002F02.api\u002F08.api-design-validation",{"title":768,"path":769,"stem":770},"Обробка помилок у Minimal API","\u002Fcsharp\u002Faspnet\u002Fapi\u002Ferror-handling-http","01.csharp\u002F11.aspnet\u002F02.api\u002F09.error-handling-http",{"title":772,"path":773,"stem":774},"Ідемпотентність та синхронізація стану","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fidempotency-sync","01.csharp\u002F11.aspnet\u002F02.api\u002F10.idempotency-sync",{"title":776,"path":777,"stem":778},"Пагінація та організація списків","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fpagination-lists","01.csharp\u002F11.aspnet\u002F02.api\u002F11.pagination-lists",{"title":780,"path":781,"stem":782},"Безпека API, кешування та інтернаціоналізація","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fsecurity-auth","01.csharp\u002F11.aspnet\u002F02.api\u002F12.security-auth",{"title":784,"path":785,"stem":786},"Процес проєктування API та документування","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-process","01.csharp\u002F11.aspnet\u002F02.api\u002F13.api-design-process",{"title":788,"path":789,"stem":790},"OpenAPI: контракт, специфікація та документація API","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fopenapi","01.csharp\u002F11.aspnet\u002F02.api\u002F14.openapi",{"title":792,"icon":793,"path":794,"stem":795,"children":796,"page":59},"Auth","i-lucide-shield-check","\u002Fcsharp\u002Faspnet\u002Fauth","01.csharp\u002F11.aspnet\u002F03.auth",[797,801,805,809,813,817,821,825,829,833,837,841,845,849,853,857,861,865],{"title":798,"path":799,"stem":800},"Основи аутентифікації та авторизації","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fauth-fundamentals","01.csharp\u002F11.aspnet\u002F03.auth\u002F01.auth-fundamentals",{"title":802,"path":803,"stem":804},"JWT-аутентифікація","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fjwt-authentication","01.csharp\u002F11.aspnet\u002F03.auth\u002F02.jwt-authentication",{"title":806,"path":807,"stem":808},"Авторизація: ролі, політики та resource-based доступ","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fauthorization-policies","01.csharp\u002F11.aspnet\u002F03.auth\u002F03.authorization-policies",{"title":810,"path":811,"stem":812},"Cookie-аутентифікація та ASP.NET Core Identity","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fcookie-auth-identity","01.csharp\u002F11.aspnet\u002F03.auth\u002F04.cookie-auth-identity",{"title":814,"path":815,"stem":816},"JWT + Refresh Tokens (HttpOnly Cookie)","\u002Fcsharp\u002Faspnet\u002Fauth\u002F04b.identity-auth-jwt","01.csharp\u002F11.aspnet\u002F03.auth\u002F04b.identity-auth-jwt",{"title":818,"path":819,"stem":820},"Identity: Підтвердження Email та Скидання Пароля","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-email-confirmation","01.csharp\u002F11.aspnet\u002F03.auth\u002F05.identity-email-confirmation",{"title":822,"path":823,"stem":824},"Identity: Двофакторна Аутентифікація (2FA)","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-two-factor","01.csharp\u002F11.aspnet\u002F03.auth\u002F06.identity-two-factor",{"title":826,"path":827,"stem":828},"Identity: Внутрішня Архітектура та Кастомізація","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-internals","01.csharp\u002F11.aspnet\u002F03.auth\u002F07.identity-internals",{"title":830,"path":831,"stem":832},"OAuth 2.0 та зовнішні провайдери","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foauth-external-providers","01.csharp\u002F11.aspnet\u002F03.auth\u002F08.oauth-external-providers",{"title":834,"path":835,"stem":836},"Безпека на практиці: CORS, HTTPS та захист від атак","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fsecurity-hardening","01.csharp\u002F11.aspnet\u002F03.auth\u002F09.security-hardening",{"title":838,"path":839,"stem":840},"Теорія OAuth 2.0: Поняття, Аналогії та Флоу","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foauth-theory","01.csharp\u002F11.aspnet\u002F03.auth\u002F10.oauth-theory",{"title":842,"path":843,"stem":844},"OIDC, OAuth 2.0 та Keycloak в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foidc-keycloak","01.csharp\u002F11.aspnet\u002F03.auth\u002F10.oidc-keycloak",{"title":846,"path":847,"stem":848},"API Keys аутентифікація в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fapi-keys","01.csharp\u002F11.aspnet\u002F03.auth\u002F11.api-keys",{"title":850,"path":851,"stem":852},"Rate Limiting та Throttling в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frate-limiting","01.csharp\u002F11.aspnet\u002F03.auth\u002F12.rate-limiting",{"title":854,"path":855,"stem":856},"Refresh Token Rotation в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frefresh-token-rotation","01.csharp\u002F11.aspnet\u002F03.auth\u002F13.refresh-token-rotation",{"title":858,"path":859,"stem":860},"Certificate Authentication та mTLS в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fcertificate-auth","01.csharp\u002F11.aspnet\u002F03.auth\u002F14.certificate-auth",{"title":862,"path":863,"stem":864},"RBAC, ABAC та ReBAC в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frbac-abac-rebac","01.csharp\u002F11.aspnet\u002F03.auth\u002F15.rbac-abac-rebac",{"title":866,"path":867,"stem":868},"Multi-tenancy та ізоляція даних в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fmulti-tenancy","01.csharp\u002F11.aspnet\u002F03.auth\u002F16.multi-tenancy",{"title":870,"icon":871,"path":872,"stem":873,"children":874,"page":59},"Нотифікації","i-lucide-bell","\u002Fcsharp\u002Faspnet\u002Fnotifications","01.csharp\u002F11.aspnet\u002F04.notifications",[875,879,883,887,891,895,899,903,907,911,915,919,923],{"title":876,"path":877,"stem":878},"In-App нотифікації через базу даних","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fin-app-database-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F01.in-app-database-notifications",{"title":880,"path":881,"stem":882},"Polling: Регулярний запит оновлень","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fpolling","01.csharp\u002F11.aspnet\u002F04.notifications\u002F02.polling",{"title":884,"path":885,"stem":886},"Server-Sent Events: Однострімовий push від сервера","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fserver-sent-events","01.csharp\u002F11.aspnet\u002F04.notifications\u002F03.server-sent-events",{"title":888,"path":889,"stem":890},"WebSockets: Двостороннє з'єднання в реальному часі","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fwebsockets","01.csharp\u002F11.aspnet\u002F04.notifications\u002F04.websockets",{"title":892,"path":893,"stem":894},"SignalR: Абстракція над транспортами реального часу","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fsignalr","01.csharp\u002F11.aspnet\u002F04.notifications\u002F05.signalr",{"title":896,"path":897,"stem":898},"Background Services: Фонові задачі в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fbackground-services","01.csharp\u002F11.aspnet\u002F04.notifications\u002F06.background-services",{"title":900,"path":901,"stem":902},"Web Push нотифікації","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fweb-push","01.csharp\u002F11.aspnet\u002F04.notifications\u002F07.web-push",{"title":904,"path":905,"stem":906},"Email нотифікації","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Femail-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F08.email-notifications",{"title":908,"path":909,"stem":910},"Порівняння підходів: Як вибрати правильну технологію нотифікацій","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fchoosing-the-right-approach","01.csharp\u002F11.aspnet\u002F04.notifications\u002F09.choosing-the-right-approach",{"title":912,"path":913,"stem":914},"Hangfire: Надійне планування фонових задач","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire","01.csharp\u002F11.aspnet\u002F04.notifications\u002F10.hangfire",{"title":916,"path":917,"stem":918},"Практика: Конвертація зображень у WebP через Hangfire","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire-image-webp","01.csharp\u002F11.aspnet\u002F04.notifications\u002F11.hangfire-image-webp",{"title":920,"path":921,"stem":922},"Практика: Підготовка відео до HLS-стрімінгу через Hangfire","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire-video-hls","01.csharp\u002F11.aspnet\u002F04.notifications\u002F12.hangfire-video-hls",{"title":924,"path":925,"stem":926},"Telegram-нотифікації: від одного повідомлення до масових розсилок і мульти-канального підходу","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Ftelegram-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F13.telegram-notifications",{"title":928,"icon":929,"path":930,"stem":931,"children":932,"page":59},"Інтернаціоналізація","i-lucide-languages","\u002Fcsharp\u002Faspnet\u002Fi18n","01.csharp\u002F11.aspnet\u002F05.i18n",[933,937],{"title":934,"path":935,"stem":936},"Інтернаціоналізація (i18n) у Minimal API: від A до Я","\u002Fcsharp\u002Faspnet\u002Fi18n\u002Finternationalization","01.csharp\u002F11.aspnet\u002F05.i18n\u002F01.internationalization",{"title":938,"path":939,"stem":940},"Humanizer: людиномовні рядки у .NET","\u002Fcsharp\u002Faspnet\u002Fi18n\u002Fhumanizer","01.csharp\u002F11.aspnet\u002F05.i18n\u002F02.humanizer",{"title":942,"icon":943,"path":944,"stem":945,"children":946,"page":59},"Кешування","i-lucide-layers","\u002Fcsharp\u002Faspnet\u002Fcaching","01.csharp\u002F11.aspnet\u002F06.caching",[947,951,955,959,963],{"title":948,"path":949,"stem":950},"Огляд кешування: чотири рівні і коли що обирати","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fcaching","01.csharp\u002F11.aspnet\u002F06.caching\u002F01.caching",{"title":952,"path":953,"stem":954},"IMemoryCache: кеш в оперативній пам'яті","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fmemory-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F02.memory-cache",{"title":956,"path":957,"stem":958},"IDistributedCache і Redis: розподілений кеш","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fdistributed-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F03.distributed-cache",{"title":960,"path":961,"stem":962},"Response Cache: HTTP-кешування через Cache-Control","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fresponse-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F04.response-cache",{"title":964,"path":965,"stem":966},"Output Cache: серверний кеш HTTP-відповідей (.NET 7+)","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Foutput-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F05.output-cache",{"title":968,"icon":969,"path":970,"stem":971,"children":972,"page":59},"Тестування","i-lucide-test-tube","\u002Fcsharp\u002Faspnet\u002Ftesting","01.csharp\u002F11.aspnet\u002F07.testing",[973,977,981,985,989,993,997,1001,1005,1009,1013,1017,1021,1025,1029,1033,1037,1041,1045,1049,1053],{"title":974,"path":975,"stem":976},"Що таке тестування? Від інтуїції до науки","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwhat-is-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F01.what-is-testing",{"title":978,"path":979,"stem":980},"Піраміда тестування — Стратегія, а не Догма","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-pyramid","01.csharp\u002F11.aspnet\u002F07.testing\u002F02.testing-pyramid",{"title":982,"path":983,"stem":984},"Дві Школи Тестування — Лондон проти Детройту","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-schools","01.csharp\u002F11.aspnet\u002F07.testing\u002F03.testing-schools",{"title":986,"path":987,"stem":988},"TDD та BDD — Тести як Дизайн-інструмент","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftdd-and-bdd","01.csharp\u002F11.aspnet\u002F07.testing\u002F04.tdd-and-bdd",{"title":990,"path":991,"stem":992},"Що саме тестувати — Техніки аналізу та Циклomatична складність","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwhat-to-test","01.csharp\u002F11.aspnet\u002F07.testing\u002F05.what-to-test",{"title":994,"path":995,"stem":996},"Тестові Фреймворки — Навіщо вони і що всередині","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftest-frameworks","01.csharp\u002F11.aspnet\u002F07.testing\u002F06.test-frameworks",{"title":998,"path":999,"stem":1000},"xUnit — Факти, Теорії та Lifecycle тестів","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fxunit-basics","01.csharp\u002F11.aspnet\u002F07.testing\u002F07.xunit-basics",{"title":1002,"path":1003,"stem":1004},"xUnit Advanced — Fixtures, Кастомізація та Розширення","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fxunit-advanced","01.csharp\u002F11.aspnet\u002F07.testing\u002F08.xunit-advanced",{"title":1006,"path":1007,"stem":1008},"Moq — Глибоке занурення в мокування","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fmocking-with-moq","01.csharp\u002F11.aspnet\u002F07.testing\u002F09.mocking-with-moq",{"title":1010,"path":1011,"stem":1012},"Тестування Баз Даних — EF Core, SQLite та Testcontainers","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fdatabase-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F10.database-testing",{"title":1014,"path":1015,"stem":1016},"Integration Testing — Частина 1 [Теорія та WebApplicationFactory]","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fintegration-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F11.integration-testing",{"title":1018,"path":1019,"stem":1020},"Інтеграційне тестування — Практика","\u002Fcsharp\u002Faspnet\u002Ftesting\u002F11a.integration-testing-practice","01.csharp\u002F11.aspnet\u002F07.testing\u002F11a.integration-testing-practice",{"title":1022,"path":1023,"stem":1024},"Integration Testing — Частина 2 [Просунуті Сценарії та Testcontainers]","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fintegration-testing-advanced","01.csharp\u002F11.aspnet\u002F07.testing\u002F12.integration-testing-advanced",{"title":1026,"path":1027,"stem":1028},"Професійний Postman: Колекції, Змінні та GitHub Інтеграція","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fpostman-professional","01.csharp\u002F11.aspnet\u002F07.testing\u002F13.postman-professional",{"title":1030,"path":1031,"stem":1032},"HttpClient у Тестах Частина 1: Архітектура та MockHttpMessageHandler","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fhttpclient-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F14.httpclient-testing",{"title":1034,"path":1035,"stem":1036},"HttpClient у Тестах Частина 2: WireMock.Net та Resilience","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwiremock-net","01.csharp\u002F11.aspnet\u002F07.testing\u002F15.wiremock-net",{"title":1038,"path":1039,"stem":1040},"Патерни та Анти-патерни Тестування: Test Smells","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-patterns","01.csharp\u002F11.aspnet\u002F07.testing\u002F16.testing-patterns",{"title":1042,"path":1043,"stem":1044},"Просунуті інструменти: Time, Snapshots та Властивості","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fadvanced-testing-tools","01.csharp\u002F11.aspnet\u002F07.testing\u002F17.advanced-testing-tools",{"title":1046,"path":1047,"stem":1048},"Тестування Архітектури з NetArchTest","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Farchitecture-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F18.architecture-testing",{"title":1050,"path":1051,"stem":1052},"Тестування Продуктивності: BenchmarkDotNet, NBomber та k6","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fperformance-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F19.performance-testing",{"title":1054,"path":1055,"stem":1056},"Залишок плану для курсу \"Тестування ASP.NET Minimal API\"","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fremaining_plan","01.csharp\u002F11.aspnet\u002F07.testing\u002Fremaining_plan",{"title":1058,"icon":1059,"path":1060,"stem":1061,"children":1062,"page":59},"Платежі","i-lucide-credit-card","\u002Fcsharp\u002Faspnet\u002Fpayments","01.csharp\u002F11.aspnet\u002F08.payments",[1063,1067,1071,1075,1079,1083,1087,1091,1095,1099,1103,1107],{"title":1064,"path":1065,"stem":1066},"Основи платіжної інфраструктури","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-fundamentals","01.csharp\u002F11.aspnet\u002F08.payments\u002F01.payment-fundamentals",{"title":1068,"path":1069,"stem":1070},"Методи оплати в Україні","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-methods-ukraine","01.csharp\u002F11.aspnet\u002F08.payments\u002F02.payment-methods-ukraine",{"title":1072,"path":1073,"stem":1074},"PCI DSS та безпека платежів","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpci-dss-security","01.csharp\u002F11.aspnet\u002F08.payments\u002F03.pci-dss-security",{"title":1076,"path":1077,"stem":1078},"Архітектура платіжної підсистеми","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-architecture","01.csharp\u002F11.aspnet\u002F08.payments\u002F04.payment-architecture",{"title":1080,"path":1081,"stem":1082},"Інтеграція LiqPay (ПриватБанк)","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fliqpay-integration","01.csharp\u002F11.aspnet\u002F08.payments\u002F05.liqpay-integration",{"title":1084,"path":1085,"stem":1086},"Інтеграція Monobank Acquiring API","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fmonobank-acquiring","01.csharp\u002F11.aspnet\u002F08.payments\u002F06.monobank-acquiring",{"title":1088,"path":1089,"stem":1090},"Інтеграція Stripe","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fstripe-integration","01.csharp\u002F11.aspnet\u002F08.payments\u002F07.stripe-integration",{"title":1092,"path":1093,"stem":1094},"Webhooks — глибоке занурення","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fwebhooks-deep-dive","01.csharp\u002F11.aspnet\u002F08.payments\u002F08.webhooks-deep-dive",{"title":1096,"path":1097,"stem":1098},"Підписки та рекурентні платежі","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fsubscriptions-recurring","01.csharp\u002F11.aspnet\u002F08.payments\u002F09.subscriptions-recurring",{"title":1100,"path":1101,"stem":1102},"Повернення коштів та диспути","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Frefunds-disputes","01.csharp\u002F11.aspnet\u002F08.payments\u002F10.refunds-disputes",{"title":1104,"path":1105,"stem":1106},"Тестування платіжних інтеграцій","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Ftesting-payments","01.csharp\u002F11.aspnet\u002F08.payments\u002F11.testing-payments",{"title":1108,"path":1109,"stem":1110},"Чекліст виходу в Production","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fproduction-checklist","01.csharp\u002F11.aspnet\u002F08.payments\u002F12.production-checklist",{"title":1112,"icon":1113,"items":1114,"path":1127,"stem":1128,"children":1129,"page":59},"Популярні бібліотеки","lucide:box",[1115,1116,1117,1118,1119,1120,1121,1122,1123,1124,1125,1126],"01.fluent-validation","02.mapster","03.erroror-result-pattern","04.serilog","05.mediatr","06.polly","07.health-checks","08.feature-management","09.fluent-email","10.quest-pdf","11.bogus","12.humanizer-guard","\u002Fcsharp\u002Faspnet\u002Flibraries","01.csharp\u002F11.aspnet\u002F09.libraries",[1130,1134,1138,1142,1146,1150,1154,1158,1162,1166,1170,1174,1178],{"title":1131,"path":1132,"stem":1133},"Валідація з FluentValidation в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffluent-validation","01.csharp\u002F11.aspnet\u002F09.libraries\u002F01.fluent-validation",{"title":1135,"path":1136,"stem":1137},"Маппінг об","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fmapster","01.csharp\u002F11.aspnet\u002F09.libraries\u002F02.mapster",{"title":1139,"path":1140,"stem":1141},"Обробка помилок з ErrorOr та Result Pattern в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ferroror-result-pattern","01.csharp\u002F11.aspnet\u002F09.libraries\u002F03.erroror-result-pattern",{"title":1143,"path":1144,"stem":1145},"Структуроване логування з Serilog в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fserilog","01.csharp\u002F11.aspnet\u002F09.libraries\u002F04.serilog",{"title":1147,"path":1148,"stem":1149},"CQRS та Mediator з MediatR в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fmediatr","01.csharp\u002F11.aspnet\u002F09.libraries\u002F05.mediatr",{"title":1151,"path":1152,"stem":1153},"Відмовостійкість з Polly в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fpolly","01.csharp\u002F11.aspnet\u002F09.libraries\u002F06.polly",{"title":1155,"path":1156,"stem":1157},"Health Checks в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fhealth-checks","01.csharp\u002F11.aspnet\u002F09.libraries\u002F07.health-checks",{"title":1159,"path":1160,"stem":1161},"Feature Management та Feature Flags в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffeature-management","01.csharp\u002F11.aspnet\u002F09.libraries\u002F08.feature-management",{"title":1163,"path":1164,"stem":1165},"Відправка Email з FluentEmail в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffluent-email","01.csharp\u002F11.aspnet\u002F09.libraries\u002F09.fluent-email",{"title":1167,"path":1168,"stem":1169},"Генерація PDF з QuestPDF в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fquest-pdf","01.csharp\u002F11.aspnet\u002F09.libraries\u002F10.quest-pdf",{"title":1171,"path":1172,"stem":1173},"Генерація тестових даних з Bogus в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fbogus","01.csharp\u002F11.aspnet\u002F09.libraries\u002F11.bogus",{"title":1175,"path":1176,"stem":1177},"Humanizer та Guard Clauses в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fhumanizer-guard","01.csharp\u002F11.aspnet\u002F09.libraries\u002F12.humanizer-guard",{"title":1179,"path":1180,"stem":1181},"План модуля 10.libraries — Популярні бібліотеки ASP.NET","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fplan","01.csharp\u002F11.aspnet\u002F09.libraries\u002Fplan",{"title":1183,"icon":1184,"path":1185,"stem":1186,"children":1187,"page":59},"Razor Pages","i-lucide-layout-template","\u002Fcsharp\u002Faspnet\u002Frazor-pages","01.csharp\u002F11.aspnet\u002F10.razor-pages",[1188,1192,1196,1200,1204,1208],{"title":1189,"path":1190,"stem":1191},"Від Minimal API до Razor Pages: концептуальний перехід","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Ffrom-minimal-api","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F01.from-minimal-api",{"title":1193,"path":1194,"stem":1195},"PageModel: логіка сторінки Razor Pages","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fpage-model","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F02.page-model",{"title":1197,"path":1198,"stem":1199},"Razor синтаксис: шаблонізатор у .cshtml","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Frazor-syntax","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F03.razor-syntax",{"title":1201,"path":1202,"stem":1203},"Tag Helpers: типізований HTML","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Ftag-helpers","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F04.tag-helpers",{"title":1205,"path":1206,"stem":1207},"Форми і валідація: повний цикл обробки даних","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fforms-validation","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F05.forms-validation",{"title":1209,"path":1210,"stem":1211},"Практичний проєкт: TaskManager на Razor Pages","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fproject-task-manager","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F06.project-task-manager",{"title":1213,"path":1214,"stem":1215,"children":1216,"page":59},"ASP.NET Core MVC","\u002Fcsharp\u002Faspnet\u002Fmvc","01.csharp\u002F11.aspnet\u002F11.mvc",[1217,1221,1225,1229,1233,1237,1241,1245,1249,1253,1257,1261,1265,1269,1273,1277,1281,1285],{"title":1218,"path":1219,"stem":1220},"Патерн MVC: архітектура, що змінила веб","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmvc-pattern","01.csharp\u002F11.aspnet\u002F11.mvc\u002F01.mvc-pattern",{"title":1222,"path":1223,"stem":1224},"Від Razor Pages до MVC: концептуальний перехід","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffrom-razor-pages","01.csharp\u002F11.aspnet\u002F11.mvc\u002F02.from-razor-pages",{"title":1226,"path":1227,"stem":1228},"Controllers та Actions: серце MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fcontrollers-actions","01.csharp\u002F11.aspnet\u002F11.mvc\u002F03.controllers-actions",{"title":1230,"path":1231,"stem":1232},"Маршрутизація в MVC: Convention vs Attribute Routing","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Frouting-mvc","01.csharp\u002F11.aspnet\u002F11.mvc\u002F04.routing-mvc",{"title":1234,"path":1235,"stem":1236},"Model Binding: від HTTP до C#","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmodel-binding","01.csharp\u002F11.aspnet\u002F11.mvc\u002F05.model-binding",{"title":1238,"path":1239,"stem":1240},"Views, ViewData, ViewBag, TempData і ViewModel","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fviews-viewdata-tempdata","01.csharp\u002F11.aspnet\u002F11.mvc\u002F06.views-viewdata-tempdata",{"title":1242,"path":1243,"stem":1244},"Filters: аспектно-орієнтоване програмування в MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffilters","01.csharp\u002F11.aspnet\u002F11.mvc\u002F07.filters",{"title":1246,"path":1247,"stem":1248},"Areas: структурування великих застосунків","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fareas","01.csharp\u002F11.aspnet\u002F11.mvc\u002F08.areas",{"title":1250,"path":1251,"stem":1252},"View Components: повторювані незалежні блоки UI","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fview-components","01.csharp\u002F11.aspnet\u002F11.mvc\u002F09.view-components",{"title":1254,"path":1255,"stem":1256},"Display та Editor Templates","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fdisplay-editor-templates","01.csharp\u002F11.aspnet\u002F11.mvc\u002F10.display-editor-templates",{"title":1258,"path":1259,"stem":1260},"Валідація: IValidatableObject та FluentValidation","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fvalidation-advanced","01.csharp\u002F11.aspnet\u002F11.mvc\u002F11.validation-advanced",{"title":1262,"path":1263,"stem":1264},"HTMX: інтерактивність через HTML-атрибути","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fhtmx","01.csharp\u002F11.aspnet\u002F11.mvc\u002F12.htmx",{"title":1266,"path":1267,"stem":1268},"HTMX у ASP.NET Core MVC: серверна інтеграція","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fajax-htmx-mvc","01.csharp\u002F11.aspnet\u002F11.mvc\u002F13.ajax-htmx-mvc",{"title":1270,"path":1271,"stem":1272},"Практичний проєкт: Каталог товарів з HTMX","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fhtmx-project","01.csharp\u002F11.aspnet\u002F11.mvc\u002F14.htmx-project",{"title":1274,"path":1275,"stem":1276},"Завантаження та обробка файлів","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffile-upload","01.csharp\u002F11.aspnet\u002F11.mvc\u002F15.file-upload",{"title":1278,"path":1279,"stem":1280},"Глобалізація та Локалізація MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fglobalization-localization","01.csharp\u002F11.aspnet\u002F11.mvc\u002F16.globalization-localization",{"title":1282,"path":1283,"stem":1284},"Підсумковий проєкт: Блог-платформа","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmvc-project","01.csharp\u002F11.aspnet\u002F11.mvc\u002F17.mvc-project",{"title":1286,"path":1287,"stem":1288},"План курсу: ASP.NET Core MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fplan","01.csharp\u002F11.aspnet\u002F11.mvc\u002Fplan",{"title":1290,"path":1291,"stem":1292,"children":1293,"page":59},"Web Api","\u002Fcsharp\u002Faspnet\u002Fweb-api","01.csharp\u002F11.aspnet\u002F12.web-api",[1294,1298,1302,1306,1310,1314,1318,1322,1326,1330,1334,1338,1342],{"title":1295,"path":1296,"stem":1297},"Від Minimal API до Controller-based API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Ffrom-minimal-api-to-controllers","01.csharp\u002F11.aspnet\u002F12.web-api\u002F01.from-minimal-api-to-controllers",{"title":1299,"path":1300,"stem":1301},"ControllerBase, ActionResult\u003CT> та Response Types","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fcontroller-base-actionresult","01.csharp\u002F11.aspnet\u002F12.web-api\u002F02.controller-base-actionresult",{"title":1303,"path":1304,"stem":1305},"Content Negotiation - JSON, XML та власні форматери","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fcontent-negotiation","01.csharp\u002F11.aspnet\u002F12.web-api\u002F03.content-negotiation",{"title":1307,"path":1308,"stem":1309},"Версіонування API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fapi-versioning","01.csharp\u002F11.aspnet\u002F12.web-api\u002F04.api-versioning",{"title":1311,"path":1312,"stem":1313},"ProblemDetails та структурована обробка помилок","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fproblemdetails-error-handling","01.csharp\u002F11.aspnet\u002F12.web-api\u002F05.problemdetails-error-handling",{"title":1315,"path":1316,"stem":1317},"Фільтри у Web API контексті","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Ffilters-for-api","01.csharp\u002F11.aspnet\u002F12.web-api\u002F06.filters-for-api",{"title":1319,"path":1320,"stem":1321},"Пагінація, фільтрація та сортування","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fpagination-filtering-sorting","01.csharp\u002F11.aspnet\u002F12.web-api\u002F07.pagination-filtering-sorting",{"title":1323,"path":1324,"stem":1325},"HATEOAS та Resource Expansion","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fhateoas-resource-expansion","01.csharp\u002F11.aspnet\u002F12.web-api\u002F08.hateoas-resource-expansion",{"title":1327,"path":1328,"stem":1329},"Гібридна архітектура - Minimal API + Controllers","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fminimal-api-vs-controllers-hybrid","01.csharp\u002F11.aspnet\u002F12.web-api\u002F09.minimal-api-vs-controllers-hybrid",{"title":1331,"path":1332,"stem":1333},"Документація API - Swashbuckle, NSwag та генерація клієнтів","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fapi-documentation-generation","01.csharp\u002F11.aspnet\u002F12.web-api\u002F10.api-documentation-generation",{"title":1335,"path":1336,"stem":1337},"Health Checks та моніторинг API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fhealth-checks-monitoring","01.csharp\u002F11.aspnet\u002F12.web-api\u002F11.health-checks-monitoring",{"title":1339,"path":1340,"stem":1341},"Підсумковий проєкт - Production-Ready REST API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fweb-api-project","01.csharp\u002F11.aspnet\u002F12.web-api\u002F12.web-api-project",{"title":1343,"path":1344,"stem":1345},"План курсу: ASP.NET Core Web API (Controllers)","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fplan","01.csharp\u002F11.aspnet\u002F12.web-api\u002Fplan",{"title":1347,"icon":1348,"path":1349,"stem":1350,"children":1351,"page":59},"Моніторинг","i-lucide-activity","\u002Fcsharp\u002Faspnet\u002Fmonitoring","01.csharp\u002F11.aspnet\u002F13.monitoring",[1352,1356,1360],{"title":1353,"path":1354,"stem":1355},"Спостережуваність: від console.log до production-систем","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fobservability-intro","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F01.observability-intro",{"title":1357,"path":1358,"stem":1359},"Health Checks: перший рівень observability","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fhealth-checks","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F02.health-checks",{"title":1361,"path":1362,"stem":1363},"Вбудовані метрики .NET 10 та System.Diagnostics.Metrics","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fdotnet-metrics","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F03.dotnet-metrics",{"title":1365,"icon":1366,"path":1367,"stem":1368,"children":1369,"page":59},"Desktop UI","i-lucide-app-window","\u002Fcsharp\u002Fdesktop-ui","01.csharp\u002F12.desktop-ui",[1370,1374,1378,1382,1386,1390,1394,1398,1402,1406,1410,1414,1418,1422,1426,1430,1434,1438,1442,1446,1450,1454,1458,1462,1466,1470,1474,1478,1482,1486,1490,1494,1498,1502,1506,1510,1514,1518,1522,1526,1530,1534,1538,1542,1546,1550,1554,1558,1562,1566,1570,1574,1578,1582,1586,1590,1594,1598,1602,1606,1610,1614,1618,1622,1626,1630,1634,1638,1642,1646,1650],{"title":1371,"path":1372,"stem":1373},"Що таке десктопна розробка?","\u002Fcsharp\u002Fdesktop-ui\u002Fwhat-is-desktop-dev","01.csharp\u002F12.desktop-ui\u002F01.what-is-desktop-dev",{"title":1375,"path":1376,"stem":1377},"Архітектура WPF — як влаштований графічний інтерфейс","\u002Fcsharp\u002Fdesktop-ui\u002Fwpf-architecture","01.csharp\u002F12.desktop-ui\u002F02.wpf-architecture",{"title":1379,"path":1380,"stem":1381},"Перший WPF-проєкт — від нуля до вікна","\u002Fcsharp\u002Fdesktop-ui\u002Ffirst-wpf-app","01.csharp\u002F12.desktop-ui\u002F03.first-wpf-app",{"title":1383,"path":1384,"stem":1385},"Перший Avalonia-проєкт: WPF для всіх платформ","\u002Fcsharp\u002Fdesktop-ui\u002F03a.first-avalonia-app","01.csharp\u002F12.desktop-ui\u002F03a.first-avalonia-app",{"title":1387,"path":1388,"stem":1389},"XAML: декларативний інтерфейс","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-basics","01.csharp\u002F12.desktop-ui\u002F04.xaml-basics",{"title":1391,"path":1392,"stem":1393},"Fluent UI у WPF — сучасний дизайн Windows 11","\u002Fcsharp\u002Fdesktop-ui\u002F04a.wpf-fluent-ui","01.csharp\u002F12.desktop-ui\u002F04a.wpf-fluent-ui",{"title":1395,"path":1396,"stem":1397},"WPF UI — сучасна бібліотека Fluent контролів","\u002Fcsharp\u002Fdesktop-ui\u002F04b.wpf-ui-library","01.csharp\u002F12.desktop-ui\u002F04b.wpf-ui-library",{"title":1399,"path":1400,"stem":1401},"HandyControl — велика бібліотека UI контролів для WPF","\u002Fcsharp\u002Fdesktop-ui\u002F04c.handycontrol-library","01.csharp\u002F12.desktop-ui\u002F04c.handycontrol-library",{"title":1403,"path":1404,"stem":1405},"Простори імен та ресурси XAML","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-namespaces-resources","01.csharp\u002F12.desktop-ui\u002F05.xaml-namespaces-resources",{"title":1407,"path":1408,"stem":1409},"XAML в Avalonia: ключові відмінності від WPF","\u002Fcsharp\u002Fdesktop-ui\u002F05a.avalonia-xaml-differences","01.csharp\u002F12.desktop-ui\u002F05a.avalonia-xaml-differences",{"title":1411,"path":1412,"stem":1413},"Розширення розмітки XAML (Markup Extensions)","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-markup-extensions","01.csharp\u002F12.desktop-ui\u002F06.xaml-markup-extensions",{"title":1415,"path":1416,"stem":1417},"Панелі Layout: StackPanel, WrapPanel, DockPanel","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-panels-part1","01.csharp\u002F12.desktop-ui\u002F07.layout-panels-part1",{"title":1419,"path":1420,"stem":1421},"Grid, Canvas, UniformGrid","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-panels-part2","01.csharp\u002F12.desktop-ui\u002F07.layout-panels-part2",{"title":1423,"path":1424,"stem":1425},"Просунуті техніки Layout","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-advanced","01.csharp\u002F12.desktop-ui\u002F08.layout-advanced",{"title":1427,"path":1428,"stem":1429},"Адаптивний Layout та найкращі практики","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-responsive","01.csharp\u002F12.desktop-ui\u002F09.layout-responsive",{"title":1431,"path":1432,"stem":1433},"Layout в Avalonia: відмінності та нові можливості","\u002Fcsharp\u002Fdesktop-ui\u002F09a.layout-avalonia","01.csharp\u002F12.desktop-ui\u002F09a.layout-avalonia",{"title":1435,"path":1436,"stem":1437},"Button, Image, ProgressBar та інші базові контроли","\u002Fcsharp\u002Fdesktop-ui\u002Fbasic-controls","01.csharp\u002F12.desktop-ui\u002F10.basic-controls",{"title":1439,"path":1440,"stem":1441},"Контроли в Avalonia: відмінності від WPF","\u002Fcsharp\u002Fdesktop-ui\u002F10a.controls-avalonia","01.csharp\u002F12.desktop-ui\u002F10a.controls-avalonia",{"title":1443,"path":1444,"stem":1445},"Текстові контроли — TextBlock, TextBox, RichTextBox","\u002Fcsharp\u002Fdesktop-ui\u002Ftext-controls","01.csharp\u002F12.desktop-ui\u002F11.text-controls",{"title":1447,"path":1448,"stem":1449},"Контроли вибору — CheckBox, RadioButton, ComboBox, ListBox, DatePicker","\u002Fcsharp\u002Fdesktop-ui\u002Fselection-controls","01.csharp\u002F12.desktop-ui\u002F12.selection-controls",{"title":1451,"path":1452,"stem":1453},"Content Model — GroupBox, Expander, TabControl, StatusBar","\u002Fcsharp\u002Fdesktop-ui\u002Fcontent-controls","01.csharp\u002F12.desktop-ui\u002F13.content-controls",{"title":1455,"path":1456,"stem":1457},"UI\u002FUX принципи десктопних застосунків","\u002Fcsharp\u002Fdesktop-ui\u002F13a.ui-ux-principles","01.csharp\u002F12.desktop-ui\u002F13a.ui-ux-principles",{"title":1459,"path":1460,"stem":1461},"Dependency Properties — Концепція та Value Resolution","\u002Fcsharp\u002Fdesktop-ui\u002Fdependency-properties-part1","01.csharp\u002F12.desktop-ui\u002F14.dependency-properties-part1",{"title":1463,"path":1464,"stem":1465},"Avalonia Property System — StyledProperty та DirectProperty","\u002Fcsharp\u002Fdesktop-ui\u002F14a.avalonia-property-system","01.csharp\u002F12.desktop-ui\u002F14a.avalonia-property-system",{"title":1467,"path":1468,"stem":1469},"Attached Properties — Властивості без меж","\u002Fcsharp\u002Fdesktop-ui\u002Fattached-properties","01.csharp\u002F12.desktop-ui\u002F15.attached-properties",{"title":1471,"path":1472,"stem":1473},"Routed Events — Маршрутизація подій у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Frouted-events","01.csharp\u002F12.desktop-ui\u002F16.routed-events",{"title":1475,"path":1476,"stem":1477},"Data Binding — Від Code-Behind до Декларативності","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-basics-part1","01.csharp\u002F12.desktop-ui\u002F17.data-binding-basics-part1",{"title":1479,"path":1480,"stem":1481},"INotifyPropertyChanged — Живе оновлення UI","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-basics-part2","01.csharp\u002F12.desktop-ui\u002F17.data-binding-basics-part2",{"title":1483,"path":1484,"stem":1485},"Compiled Bindings в Avalonia — Безпека на етапі компіляції","\u002Fcsharp\u002Fdesktop-ui\u002F17a.avalonia-compiled-bindings","01.csharp\u002F12.desktop-ui\u002F17a.avalonia-compiled-bindings",{"title":1487,"path":1488,"stem":1489},"Просунутий Data Binding — ElementName, RelativeSource, MultiBinding","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-advanced","01.csharp\u002F12.desktop-ui\u002F18.data-binding-advanced",{"title":1491,"path":1492,"stem":1493},"Value Converters — Перетворення типів даних у Data Binding","\u002Fcsharp\u002Fdesktop-ui\u002Fvalue-converters","01.csharp\u002F12.desktop-ui\u002F19.value-converters",{"title":1495,"path":1496,"stem":1497},"Data Templates — Візуалізація об'єктів у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-templates","01.csharp\u002F12.desktop-ui\u002F20.data-templates",{"title":1499,"path":1500,"stem":1501},"Collections Binding Part 1 — ObservableCollection та ItemsControl","\u002Fcsharp\u002Fdesktop-ui\u002Fcollections-binding-part1","01.csharp\u002F12.desktop-ui\u002F21.collections-binding-part1",{"title":1503,"path":1504,"stem":1505},"Collections Binding Part 2 — ICollectionView, Filtering, Sorting та Virtualization","\u002Fcsharp\u002Fdesktop-ui\u002Fcollections-binding-part2","01.csharp\u002F12.desktop-ui\u002F21.collections-binding-part2",{"title":1507,"path":1508,"stem":1509},"MVVM Pattern — Від Spaghetti Code до архітектури","\u002Fcsharp\u002Fdesktop-ui\u002Fmvvm-pattern","01.csharp\u002F12.desktop-ui\u002F22.mvvm-pattern",{"title":1511,"path":1512,"stem":1513},"ViewModel Implementation — Від BaseViewModel до валідації","\u002Fcsharp\u002Fdesktop-ui\u002Fviewmodel-implementation","01.csharp\u002F12.desktop-ui\u002F23.viewmodel-implementation",{"title":1515,"path":1516,"stem":1517},"Commands — Від event handlers до декларативних команд","\u002Fcsharp\u002Fdesktop-ui\u002Fcommands","01.csharp\u002F12.desktop-ui\u002F24.commands",{"title":1519,"path":1520,"stem":1521},"MVVM Toolkit — MVVM без boilerplate через Source Generators","\u002Fcsharp\u002Fdesktop-ui\u002Fmvvm-toolkit","01.csharp\u002F12.desktop-ui\u002F25.mvvm-toolkit",{"title":1523,"path":1524,"stem":1525},"Messenger Pattern — Комунікація між ViewModel без прямих посилань","\u002Fcsharp\u002Fdesktop-ui\u002Fmessenger-pattern","01.csharp\u002F12.desktop-ui\u002F26.messenger-pattern",{"title":1527,"path":1528,"stem":1529},"Стилі WPF — CSS для десктопу","\u002Fcsharp\u002Fdesktop-ui\u002Fstyles-basics","01.csharp\u002F12.desktop-ui\u002F27.styles-basics",{"title":1531,"path":1532,"stem":1533},"CSS-like стилі Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002F27a.avalonia-css-styling","01.csharp\u002F12.desktop-ui\u002F27a.avalonia-css-styling",{"title":1535,"path":1536,"stem":1537},"Control Templates — Частина 1. Концепція та TemplateBinding","\u002Fcsharp\u002Fdesktop-ui\u002Fcontrol-templates-part1","01.csharp\u002F12.desktop-ui\u002F28.control-templates-part1",{"title":1539,"path":1540,"stem":1541},"Control Templates — Частина 2. Named Parts та ContentPresenter","\u002Fcsharp\u002Fdesktop-ui\u002Fcontrol-templates-part2","01.csharp\u002F12.desktop-ui\u002F28.control-templates-part2",{"title":1543,"path":1544,"stem":1545},"Control Themes в Avalonia — нова ера стилізації","\u002Fcsharp\u002Fdesktop-ui\u002F28a.avalonia-control-themes","01.csharp\u002F12.desktop-ui\u002F28a.avalonia-control-themes",{"title":1547,"path":1548,"stem":1549},"Triggers та Visual State Manager у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Ftriggers-visual-states","01.csharp\u002F12.desktop-ui\u002F29.triggers-visual-states",{"title":1551,"path":1552,"stem":1553},"Pseudo-classes в Avalonia — замість WPF Triggers","\u002Fcsharp\u002Fdesktop-ui\u002F29a.avalonia-pseudo-classes","01.csharp\u002F12.desktop-ui\u002F29a.avalonia-pseudo-classes",{"title":1555,"path":1556,"stem":1557},"Теми та ресурсні словники у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fresources-themes","01.csharp\u002F12.desktop-ui\u002F30.resources-themes",{"title":1559,"path":1560,"stem":1561},"Avalonia Themes — Fluent Design та система тематизації","\u002Fcsharp\u002Fdesktop-ui\u002F30a.avalonia-themes-fluent","01.csharp\u002F12.desktop-ui\u002F30a.avalonia-themes-fluent",{"title":1563,"path":1564,"stem":1565},"Контроли колекцій — глибоке занурення","\u002Fcsharp\u002Fdesktop-ui\u002Fcollection-controls","01.csharp\u002F12.desktop-ui\u002F31.collection-controls",{"title":1567,"path":1568,"stem":1569},"DataGrid — колонки та базове відображення","\u002Fcsharp\u002Fdesktop-ui\u002Fdatagrid-part1","01.csharp\u002F12.desktop-ui\u002F32.datagrid-part1",{"title":1571,"path":1572,"stem":1573},"DataGrid — сортування, фільтрація, редагування","\u002Fcsharp\u002Fdesktop-ui\u002Fdatagrid-part2","01.csharp\u002F12.desktop-ui\u002F32.datagrid-part2",{"title":1575,"path":1576,"stem":1577},"TreeView та GridView","\u002Fcsharp\u002Fdesktop-ui\u002Ftreeview-listview","01.csharp\u002F12.desktop-ui\u002F33.treeview-listview",{"title":1579,"path":1580,"stem":1581},"Меню, Toolbar, ContextMenu, StatusBar","\u002Fcsharp\u002Fdesktop-ui\u002Fmenus-toolbars","01.csharp\u002F12.desktop-ui\u002F34.menus-toolbars",{"title":1583,"path":1584,"stem":1585},"Навігація та керування вікнами. Частина 1: вікна та сторінки","\u002Fcsharp\u002Fdesktop-ui\u002Fnavigation-windows-part1","01.csharp\u002F12.desktop-ui\u002F35.navigation-windows-part1",{"title":1587,"path":1588,"stem":1589},"Навігація та керування вікнами. Частина 2: MVVM-навігація","\u002Fcsharp\u002Fdesktop-ui\u002Fnavigation-windows-part2","01.csharp\u002F12.desktop-ui\u002F35.navigation-windows-part2",{"title":1591,"path":1592,"stem":1593},"Avalonia — Навігація та діалоги","\u002Fcsharp\u002Fdesktop-ui\u002F35a.avalonia-navigation-dialogs","01.csharp\u002F12.desktop-ui\u002F35a.avalonia-navigation-dialogs",{"title":1595,"path":1596,"stem":1597},"Діалоги та File Pickers у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fdialogs-file-pickers","01.csharp\u002F12.desktop-ui\u002F36.dialogs-file-pickers",{"title":1599,"path":1600,"stem":1601},"UserControl: компонентний підхід у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fuser-controls","01.csharp\u002F12.desktop-ui\u002F37.user-controls",{"title":1603,"path":1604,"stem":1605},"Custom Controls: Lookless Controls у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fcustom-controls","01.csharp\u002F12.desktop-ui\u002F38.custom-controls",{"title":1607,"path":1608,"stem":1609},"Avalonia TemplatedControl — Lookless Controls","\u002Fcsharp\u002Fdesktop-ui\u002F38a.avalonia-templated-controls","01.csharp\u002F12.desktop-ui\u002F38a.avalonia-templated-controls",{"title":1611,"path":1612,"stem":1613},"Анімації у WPF: Storyboard та Easing Functions","\u002Fcsharp\u002Fdesktop-ui\u002Fanimations-transitions","01.csharp\u002F12.desktop-ui\u002F39.animations-transitions",{"title":1615,"path":1616,"stem":1617},"Анімації в Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002F39a.avalonia-animations","01.csharp\u002F12.desktop-ui\u002F39a.avalonia-animations",{"title":1619,"path":1620,"stem":1621},"2D Графіка та Мультимедіа у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fmedia-graphics","01.csharp\u002F12.desktop-ui\u002F40.media-graphics",{"title":1623,"path":1624,"stem":1625},"Dependency Injection у WPF та Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002Fdi-integration","01.csharp\u002F12.desktop-ui\u002F41.di-integration",{"title":1627,"path":1628,"stem":1629},"SQLite та EF Core у десктопних додатках","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-persistence-part1","01.csharp\u002F12.desktop-ui\u002F42.data-persistence-part1",{"title":1631,"path":1632,"stem":1633},"Repository Pattern та Unit of Work","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-persistence-part2","01.csharp\u002F12.desktop-ui\u002F43.data-persistence-part2",{"title":1635,"path":1636,"stem":1637},"Тестування ViewModels","\u002Fcsharp\u002Fdesktop-ui\u002Fviewmodel-testing","01.csharp\u002F12.desktop-ui\u002F44.viewmodel-testing",{"title":1639,"path":1640,"stem":1641},"Avalonia Headless Testing — тестування UI без вікон","\u002Fcsharp\u002Fdesktop-ui\u002F44a.avalonia-headless-testing","01.csharp\u002F12.desktop-ui\u002F44a.avalonia-headless-testing",{"title":1643,"path":1644,"stem":1645},"Кросплатформна розробка з Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002Favalonia-cross-platform","01.csharp\u002F12.desktop-ui\u002F45.avalonia-cross-platform",{"title":1647,"path":1648,"stem":1649},"Пакування та розгортання Avalonia додатків","\u002Fcsharp\u002Fdesktop-ui\u002Favalonia-packaging-deployment","01.csharp\u002F12.desktop-ui\u002F46.avalonia-packaging-deployment",{"title":1651,"path":1652,"stem":1653},"Розгортання WPF застосунків","\u002Fcsharp\u002Fdesktop-ui\u002Fwpf-packaging-deployment","01.csharp\u002F12.desktop-ui\u002F47.wpf-packaging-deployment",{"title":1655,"icon":658,"path":1656,"stem":1657,"children":1658,"page":59},"Network Programming","\u002Fcsharp\u002Fnetwork-programming","01.csharp\u002F13.network-programming",[1659,1663,1667,1671,1675,1679,1683,1687,1691,1695,1699],{"title":1660,"path":1661,"stem":1662},"Основи комп'ютерних мереж","\u002Fcsharp\u002Fnetwork-programming\u002Ffoundations","01.csharp\u002F13.network-programming\u002F01.foundations",{"title":1664,"path":1665,"stem":1666},"Модель OSI та стек TCP\u002FIP","\u002Fcsharp\u002Fnetwork-programming\u002Fosi-model","01.csharp\u002F13.network-programming\u002F02.osi-model",{"title":1668,"path":1669,"stem":1670},"IP-протокол та адресація","\u002Fcsharp\u002Fnetwork-programming\u002Fip-addressing","01.csharp\u002F13.network-programming\u002F03.ip-addressing",{"title":1672,"path":1673,"stem":1674},"UDP — протокол без з'єднання","\u002Fcsharp\u002Fnetwork-programming\u002Fudp","01.csharp\u002F13.network-programming\u002F05.udp",{"title":1676,"path":1677,"stem":1678},"UDP Broadcast та Multicast","\u002Fcsharp\u002Fnetwork-programming\u002Fudp-broadcast-multicast","01.csharp\u002F13.network-programming\u002F06.udp-broadcast-multicast",{"title":1680,"path":1681,"stem":1682},"HTTP — протокол вебу","\u002Fcsharp\u002Fnetwork-programming\u002Fhttp-fundamentals","01.csharp\u002F13.network-programming\u002F07.http-fundamentals",{"title":1684,"path":1685,"stem":1686},"HttpListener — вбудований HTTP-сервер .NET","\u002Fcsharp\u002Fnetwork-programming\u002F07a.http-listener","01.csharp\u002F13.network-programming\u002F07a.http-listener",{"title":1688,"path":1689,"stem":1690},"HTTP Advanced — cookies, аутентифікація та HTTPS","\u002Fcsharp\u002Fnetwork-programming\u002Fhttp-advanced","01.csharp\u002F13.network-programming\u002F08.http-advanced",{"title":1692,"path":1693,"stem":1694},"SMTP та протоколи електронної пошти","\u002Fcsharp\u002Fnetwork-programming\u002Fsmtp","01.csharp\u002F13.network-programming\u002F09.smtp",{"title":1696,"path":1697,"stem":1698},"WebSocket — повнодуплексний протокол реального часу","\u002Fcsharp\u002Fnetwork-programming\u002Fwebsockets","01.csharp\u002F13.network-programming\u002F10.websockets",{"title":1700,"path":1701,"stem":1702},"TLS\u002FSSL — криптографічний захист мережевих з'єднань","\u002Fcsharp\u002Fnetwork-programming\u002Ftls-ssl","01.csharp\u002F13.network-programming\u002F11.tls-ssl",{"title":1704,"path":1705,"stem":1706},"C# & .NET: The Ultimate Roadmap","\u002Fcsharp\u002Froadmap","01.csharp\u002Froadmap",{"title":1708,"icon":1709,"path":1710,"stem":1711,"children":1712,"page":59},"C++","i-devicon-cplusplus","\u002Fcpp","02.cpp",[1713,1717,1721,1725,1729,1733,1737,1741,1745,1748,1752,1756,1760,1764,1768,1772,1776,1780,1784,1788,1792,1796,1800,1804,1808,1812,1816,1820,1824,1828,1832,1836,1840,1844,1848,1852,1856,1860,1864,1868,1872,1876,1880,1884,1888,1892,1896,1900,1904,1908,1912,1916,1920,1924,1928,1932,1936,1940,1944,1948,1952,1956,1960,1964,1968,1972,1976,1980,1984,1988,1992,1996,2000,2004,2008,2012,2016,2020,2024,2028,2032,2036,2040,2044,2048,2052,2056,2060,2064,2068,2072,2076,2080],{"title":1714,"path":1715,"stem":1716},"Вступ у програмування та алгоритми","\u002Fcpp\u002Fintro-algorithms","02.cpp\u002F01.intro-algorithms",{"title":1718,"path":1719,"stem":1720},"Code Style: угоди про оформлення коду","\u002Fcpp\u002Fcode-style","02.cpp\u002F02.code-style",{"title":1722,"path":1723,"stem":1724},"Середовище розробки та перший проєкт","\u002Fcpp\u002Fide-setup","02.cpp\u002F03.ide-setup",{"title":1726,"path":1727,"stem":1728},"Вивід даних на екран","\u002Fcpp\u002Fdata-output","02.cpp\u002F04.data-output",{"title":1730,"path":1731,"stem":1732},"Типи даних, змінні та константи","\u002Fcpp\u002Fdata-types-variables","02.cpp\u002F05.data-types-variables",{"title":1734,"path":1735,"stem":1736},"Ввід даних з клавіатури","\u002Fcpp\u002Fdata-input","02.cpp\u002F06.data-input",{"title":1738,"path":1739,"stem":1740},"Оператори, перетворення типів та логічні операції","\u002Fcpp\u002Foperators-type-conversion","02.cpp\u002F07.operators-type-conversion",{"title":1742,"path":1743,"stem":1744},"Цикли","\u002Fcpp\u002Floops","02.cpp\u002F08.loops",{"title":32,"path":1746,"stem":1747},"\u002Fcpp\u002Farrays","02.cpp\u002F09.arrays",{"title":1749,"path":1750,"stem":1751},"Алгоритми сортування та аналіз складності","\u002Fcpp\u002Fsorting","02.cpp\u002F10.sorting",{"title":1753,"path":1754,"stem":1755},"Алгоритми пошуку","\u002Fcpp\u002Fsearching","02.cpp\u002F11.searching",{"title":1757,"path":1758,"stem":1759},"Функції: основи","\u002Fcpp\u002Ffunctions-basics","02.cpp\u002F12.functions-basics",{"title":1761,"path":1762,"stem":1763},"Функції: прототипи, область видимості та додаткові можливості","\u002Fcpp\u002Ffunctions-scope","02.cpp\u002F13.functions-scope",{"title":1765,"path":1766,"stem":1767},"Функції: перевантаження та шаблони","\u002Fcpp\u002Ffunctions-overloading-templates","02.cpp\u002F14.functions-overloading-templates",{"title":1769,"path":1770,"stem":1771},"Вказівники: основи","\u002Fcpp\u002Fpointers-basics","02.cpp\u002F15.pointers-basics",{"title":1773,"path":1774,"stem":1775},"Посилання (References)","\u002Fcpp\u002Freferences","02.cpp\u002F16.references",{"title":1777,"path":1778,"stem":1779},"Вказівники, const і масиви","\u002Fcpp\u002Fpointers-const-arrays","02.cpp\u002F17.pointers-const-arrays",{"title":1781,"path":1782,"stem":1783},"Адресна арифметика","\u002Fcpp\u002Fpointer-arithmetic","02.cpp\u002F18.pointer-arithmetic",{"title":1785,"path":1786,"stem":1787},"Динамічна пам'ять","\u002Fcpp\u002Fdynamic-memory","02.cpp\u002F19.dynamic-memory",{"title":1789,"path":1790,"stem":1791},"Вказівники типу void","\u002Fcpp\u002Fvoid-pointers","02.cpp\u002F20.void-pointers",{"title":1793,"path":1794,"stem":1795},"Вказівники на вказівники","\u002Fcpp\u002Fpointers-to-pointers","02.cpp\u002F21.pointers-to-pointers",{"title":1797,"path":1798,"stem":1799},"Оператор доступу до членів через вказівник (->)","\u002Fcpp\u002Fmember-access-operator","02.cpp\u002F22.member-access-operator",{"title":1801,"path":1802,"stem":1803},"Цикл for-each (Range-based for)","\u002Fcpp\u002Fforeach-loop","02.cpp\u002F23.foreach-loop",{"title":1805,"path":1806,"stem":1807},"Вказівники на функції","\u002Fcpp\u002Ffunction-pointers","02.cpp\u002F24.function-pointers",{"title":1809,"path":1810,"stem":1811},"Лямбда-вирази","\u002Fcpp\u002Flambdas","02.cpp\u002F25.lambdas",{"title":1813,"path":1814,"stem":1815},"Лямбда-захоплення","\u002Fcpp\u002Flambda-captures","02.cpp\u002F26.lambda-captures",{"title":1817,"path":1818,"stem":1819},"Еліпсис","\u002Fcpp\u002Fellipsis","02.cpp\u002F27.ellipsis",{"title":1821,"path":1822,"stem":1823},"Безпечні альтернативи еліпсису","\u002Fcpp\u002F27a.ellipsis","02.cpp\u002F27a.ellipsis",{"title":1825,"path":1826,"stem":1827},"Аргументи командного рядка","\u002Fcpp\u002Fcommand-line-arguments","02.cpp\u002F28.command-line-arguments",{"title":1829,"path":1830,"stem":1831},"Перерахування (enum)","\u002Fcpp\u002Fenum","02.cpp\u002F29.enum",{"title":1833,"path":1834,"stem":1835},"Класи-перерахування (enum class)","\u002Fcpp\u002Fenum-class","02.cpp\u002F30.enum-class",{"title":1837,"path":1838,"stem":1839},"Псевдоніми типів (typedef і using)","\u002Fcpp\u002Ftype-aliases","02.cpp\u002F31.type-aliases",{"title":1841,"path":1842,"stem":1843},"Системи числення та двійкова арифметика","\u002Fcpp\u002Fnumber-systems","02.cpp\u002F32.number-systems",{"title":1845,"path":1846,"stem":1847},"Структури (struct): агрегування даних","\u002Fcpp\u002Fstruct","02.cpp\u002F33.struct",{"title":1849,"path":1850,"stem":1851},"Структури у функціях","\u002Fcpp\u002Fstruct-functions","02.cpp\u002F34.struct-functions",{"title":1853,"path":1854,"stem":1855},"Масиви структур і вкладені структури","\u002Fcpp\u002Fstruct-arrays","02.cpp\u002F35.struct-arrays",{"title":1857,"path":1858,"stem":1859},"Патерни struct та межі застосування","\u002Fcpp\u002Fstruct-patterns","02.cpp\u002F36.struct-patterns",{"title":1861,"path":1862,"stem":1863},"Символи та таблиця ASCII","\u002Fcpp\u002Fascii-characters","02.cpp\u002F37.ascii-characters",{"title":1865,"path":1866,"stem":1867},"Unicode та кодування UTF","\u002Fcpp\u002Funicode-utf","02.cpp\u002F38.unicode-utf",{"title":1869,"path":1870,"stem":1871},"C-style рядки","\u002Fcpp\u002Fc-strings","02.cpp\u002F39.c-strings",{"title":1873,"path":1874,"stem":1875},"Вступ до std::string","\u002Fcpp\u002Fstd-string-intro","02.cpp\u002F40.std-string-intro",{"title":1877,"path":1878,"stem":1879},"Довжина, ємність та доступ до символів std::string","\u002Fcpp\u002Fstd-string-capacity-access","02.cpp\u002F41.std-string-capacity-access",{"title":1881,"path":1882,"stem":1883},"Модифікація std::string: присвоювання, додавання, вставка, видалення та заміна","\u002Fcpp\u002Fstd-string-modification","02.cpp\u002F42.std-string-modification",{"title":1885,"path":1886,"stem":1887},"Пошук у std::string: find, npos та практичні патерни","\u002Fcpp\u002Fstd-string-search","02.cpp\u002F43.std-string-search",{"title":1889,"path":1890,"stem":1891},"std::string_view: невласницький погляд на рядок без копіювання","\u002Fcpp\u002Fstd-string-view","02.cpp\u002F44.std-string-view",{"title":1893,"path":1894,"stem":1895},"Об'єднання (union): один блок пам'яті, кілька інтерпретацій","\u002Fcpp\u002Funion","02.cpp\u002F45.union",{"title":1897,"path":1898,"stem":1899},"Організація коду: файли, препроцесор, простори імен","\u002Fcpp\u002Fmultifile-programs","02.cpp\u002F46.multifile-programs",{"title":1901,"path":1902,"stem":1903},"Робота з файлами: C-стиль (stdio.h)","\u002Fcpp\u002Fc-style-files","02.cpp\u002F47.c-style-files",{"title":1905,"path":1906,"stem":1907},"Робота з файлами: C++-стиль (fstream)","\u002Fcpp\u002Fcpp-style-files","02.cpp\u002F48.cpp-style-files",{"title":1909,"path":1910,"stem":1911},"Введення в ООП: від процедур до об'єктів","\u002Fcpp\u002Foop-intro","02.cpp\u002F49.oop-intro",{"title":1913,"path":1914,"stem":1915},"Класи, об'єкти та методи","\u002Fcpp\u002Fclasses-objects-methods","02.cpp\u002F50.classes-objects-methods",{"title":1917,"path":1918,"stem":1919},"Специфікатори доступу та інкапсуляція","\u002Fcpp\u002Faccess-specifiers-encapsulation","02.cpp\u002F51.access-specifiers-encapsulation",{"title":1921,"path":1922,"stem":1923},"Конструктори: гарантована ініціалізація об'єктів","\u002Fcpp\u002Fconstructors","02.cpp\u002F52.constructors",{"title":1925,"path":1926,"stem":1927},"Списки ініціалізації та делегуючі конструктори","\u002Fcpp\u002Finit-lists-delegating","02.cpp\u002F53.init-lists-delegating",{"title":1929,"path":1930,"stem":1931},"Деструктори та ідіома RAII","\u002Fcpp\u002Fdestructors-raii","02.cpp\u002F54.destructors-raii",{"title":1933,"path":1934,"stem":1935},"Прихований покажчик this","\u002Fcpp\u002Fthis-pointer","02.cpp\u002F55.this-pointer",{"title":1937,"path":1938,"stem":1939},"Розподіл класу на заголовковий файл та файл реалізації","\u002Fcpp\u002Fclass-header-source","02.cpp\u002F56.class-header-source",{"title":1941,"path":1942,"stem":1943},"Класи та const","\u002Fcpp\u002Fconst-classes","02.cpp\u002F57.const-classes",{"title":1945,"path":1946,"stem":1947},"Статичні члени класу","\u002Fcpp\u002Fstatic-members","02.cpp\u002F58.static-members",{"title":1949,"path":1950,"stem":1951},"Конструктор копіювання та запобігання копіюванню","\u002Fcpp\u002Fcopy-constructor","02.cpp\u002F59.copy-constructor",{"title":1953,"path":1954,"stem":1955},"Дружні функції та класи","\u002Fcpp\u002Ffriend-functions-classes","02.cpp\u002F60.friend-functions-classes",{"title":1957,"path":1958,"stem":1959},"Анонімні об'єкти та вкладені типи","\u002Fcpp\u002Fanonymous-objects-nested-types","02.cpp\u002F61.anonymous-objects-nested-types",{"title":1961,"path":1962,"stem":1963},"Вимірювання часу виконання: RAII-таймер","\u002Fcpp\u002Ftiming-raii-timer","02.cpp\u002F62.timing-raii-timer",{"title":1965,"path":1966,"stem":1967},"Перевантаження операторів: основи та арифметика","\u002Fcpp\u002Foperator-overloading-basics","02.cpp\u002F63.operator-overloading-basics",{"title":1969,"path":1970,"stem":1971},"Перевантаження операторів: методи класу та спеціальні оператори","\u002Fcpp\u002Foperator-overloading-methods","02.cpp\u002F64.operator-overloading-methods",{"title":1973,"path":1974,"stem":1975},"Приведення типів, explicit та delete","\u002Fcpp\u002Ftypecast-explicit-delete","02.cpp\u002F65.typecast-explicit-delete",{"title":1977,"path":1978,"stem":1979},"Глибоке копіювання та оператор присвоювання","\u002Fcpp\u002Fdeep-copy-assignment","02.cpp\u002F66.deep-copy-assignment",{"title":1981,"path":1982,"stem":1983},"Зв'язки між об'єктами: композиція та агрегація","\u002Fcpp\u002Fcomposition-aggregation","02.cpp\u002F67.composition-aggregation",{"title":1985,"path":1986,"stem":1987},"Асоціація та залежність між об","\u002Fcpp\u002Fassociation-dependency","02.cpp\u002F68.association-dependency",{"title":1989,"path":1990,"stem":1991},"Контейнерні класи та `std::initializer_list`","\u002Fcpp\u002Fcontainer-classes-initializer-list","02.cpp\u002F69.container-classes-initializer-list",{"title":1993,"path":1994,"stem":1995},"Вступ до наслідування: базові поняття та відношення «is-a»","\u002Fcpp\u002Finheritance-intro","02.cpp\u002F70.inheritance-intro",{"title":1997,"path":1998,"stem":1999},"Конструктори, деструктори та порядок ініціалізації в ієрархіях","\u002Fcpp\u002Finheritance-constructors-destructors","02.cpp\u002F71.inheritance-constructors-destructors",{"title":2001,"path":2002,"stem":2003},"Специфікатор `protected` та види наслідування","\u002Fcpp\u002Finheritance-access-specifiers","02.cpp\u002F72.inheritance-access-specifiers",{"title":2005,"path":2006,"stem":2007},"Перевизначення методів та приховування імен","\u002Fcpp\u002Fmethod-overriding-hiding","02.cpp\u002F73.method-overriding-hiding",{"title":2009,"path":2010,"stem":2011},"Множинне наслідування та проблема ромба","\u002Fcpp\u002Fmultiple-inheritance-diamond","02.cpp\u002F74.multiple-inheritance-diamond",{"title":2013,"path":2014,"stem":2015},"Вказівники на базовий клас та віртуальні функції","\u002Fcpp\u002Fvirtual-functions-polymorphism","02.cpp\u002F75.virtual-functions-polymorphism",{"title":2017,"path":2018,"stem":2019},"Специфікатори override, final та віртуальні деструктори","\u002Fcpp\u002Foverride-final-virtual-destructors","02.cpp\u002F76.override-final-virtual-destructors",{"title":2021,"path":2022,"stem":2023},"Внутрішні механізми поліморфізму: vtable, vptr та зв'язування","\u002Fcpp\u002Fvirtual-table-binding","02.cpp\u002F77.virtual-table-binding",{"title":2025,"path":2026,"stem":2027},"Абстрактні класи та чисті віртуальні функції","\u002Fcpp\u002Fabstract-classes-interfaces","02.cpp\u002F78.abstract-classes-interfaces",{"title":2029,"path":2030,"stem":2031},"Зрізка об'єктів, віртуальне наслідування та поліморфний вивід","\u002Fcpp\u002Fslicing-virtual-base-io","02.cpp\u002F79.slicing-virtual-base-io",{"title":2033,"path":2034,"stem":2035},"Динамічне приведення типів (`dynamic_cast`) та RTTI","\u002Fcpp\u002Fdynamic-cast-rtti","02.cpp\u002F80.dynamic-cast-rtti",{"title":2037,"path":2038,"stem":2039},"Шаблони функцій: узагальнене програмування","\u002Fcpp\u002Ffunction-templates","02.cpp\u002F81.function-templates",{"title":2041,"path":2042,"stem":2043},"Шаблони класів та NTTP-параметри","\u002Fcpp\u002Fclass-templates-nttp","02.cpp\u002F82.class-templates-nttp",{"title":2045,"path":2046,"stem":2047},"Повна (явна) спеціалізація шаблонів","\u002Fcpp\u002Ffull-template-specialization","02.cpp\u002F83.full-template-specialization",{"title":2049,"path":2050,"stem":2051},"Часткова спеціалізація шаблонів класів","\u002Fcpp\u002Fpartial-template-specialization","02.cpp\u002F84.partial-template-specialization",{"title":2053,"path":2054,"stem":2055},"Механізм винятків: try, catch, throw та розкручування стеку","\u002Fcpp\u002Fexceptions-basics","02.cpp\u002F85.exceptions-basics",{"title":2057,"path":2058,"stem":2059},"Ієрархія std::exception та власні класи винятків","\u002Fcpp\u002Fexception-hierarchy-custom","02.cpp\u002F86.exception-hierarchy-custom",{"title":2061,"path":2062,"stem":2063},"Повторне генерування винятків та функціональний try-блок","\u002Fcpp\u002Frethrow-function-try","02.cpp\u002F87.rethrow-function-try",{"title":2065,"path":2066,"stem":2067},"Безпека винятків, noexcept та деструктори","\u002Fcpp\u002Fsafety-noexcept","02.cpp\u002F88.safety-noexcept",{"title":2069,"path":2070,"stem":2071},"Стаття 89 — Власні структури даних: стек та черга","\u002Fcpp\u002Fcustom-stack-queue","02.cpp\u002F89.custom-stack-queue",{"title":2073,"path":2074,"stem":2075},"Стаття 90 — Власні структури даних: однозв'язаний список","\u002Fcpp\u002Flinked-list","02.cpp\u002F90.linked-list",{"title":2077,"path":2078,"stem":2079},"Стаття 91 — Власні структури даних: бінарне дерево пошуку","\u002Fcpp\u002Fbinary-search-tree","02.cpp\u002F91.binary-search-tree",{"title":2081,"path":2082,"stem":2083},"Стаття 92 — Власні структури даних: хеш-таблиця","\u002Fcpp\u002Fhash-table","02.cpp\u002F92.hash-table",{"title":2085,"icon":2086,"path":2087,"stem":2088,"children":2089,"page":59},"JavaScript","i-devicon-javascript","\u002Fjavascript","03.javascript",[2090,2116,2170,2192,2496,2534,2552],{"title":2091,"icon":2092,"path":2093,"stem":2094,"children":2095,"page":59},"Events","i-lucide-mouse-pointer-click","\u002Fjavascript\u002Fevents","03.javascript\u002F01.events",[2096,2100,2104,2108,2112],{"title":2097,"path":2098,"stem":2099},"Вступ до подій браузера","\u002Fjavascript\u002Fevents\u002Fintro","03.javascript\u002F01.events\u002F01.intro",{"title":2101,"path":2102,"stem":2103},"Бульбашковий механізм (Bubbling) та занурення (Capturing)","\u002Fjavascript\u002Fevents\u002Fbubbling-capturing","03.javascript\u002F01.events\u002F02.bubbling-capturing",{"title":2105,"path":2106,"stem":2107},"Делегування подій (Event Delegation)","\u002Fjavascript\u002Fevents\u002Fdelegate-events","03.javascript\u002F01.events\u002F03.delegate-events",{"title":2109,"path":2110,"stem":2111},"Типові дії браузера та preventDefault()","\u002Fjavascript\u002Fevents\u002Fprevent-default","03.javascript\u002F01.events\u002F04.prevent-default",{"title":2113,"path":2114,"stem":2115},"Запуск користувацьких подій (Custom Events)","\u002Fjavascript\u002Fevents\u002Fcustom-events","03.javascript\u002F01.events\u002F05.custom-events",{"title":2117,"icon":2118,"path":2119,"stem":2120,"children":2121,"page":59},"Network","i-lucide-globe","\u002Fjavascript\u002Fnetwork","03.javascript\u002F02.network",[2122,2126,2130,2134,2138,2142,2146,2150,2154,2158,2162,2166],{"title":2123,"path":2124,"stem":2125},"Fetch API - Сучасний підхід до HTTP-запитів","\u002Fjavascript\u002Fnetwork\u002F01-fetch-api","03.javascript\u002F02.network\u002F01-fetch-api",{"title":2127,"path":2128,"stem":2129},"FormData - Робота з формами та файлами","\u002Fjavascript\u002Fnetwork\u002F02-formdata","03.javascript\u002F02.network\u002F02-formdata",{"title":2131,"path":2132,"stem":2133},"Відстеження прогресу завантаження","\u002Fjavascript\u002Fnetwork\u002F03-download-progress","03.javascript\u002F02.network\u002F03-download-progress",{"title":2135,"path":2136,"stem":2137},"Переривання fetch-запитів","\u002Fjavascript\u002Fnetwork\u002F04-abort-requests","03.javascript\u002F02.network\u002F04-abort-requests",{"title":2139,"path":2140,"stem":2141},"CORS - Запити між різними джерелами","\u002Fjavascript\u002Fnetwork\u002F05-cors","03.javascript\u002F02.network\u002F05-cors",{"title":2143,"path":2144,"stem":2145},"Fetch API - Повний довідник опцій","\u002Fjavascript\u002Fnetwork\u002F06-fetch-options","03.javascript\u002F02.network\u002F06-fetch-options",{"title":2147,"path":2148,"stem":2149},"URL Objects - Робота з посиланнями","\u002Fjavascript\u002Fnetwork\u002F07-url-objects","03.javascript\u002F02.network\u002F07-url-objects",{"title":2151,"path":2152,"stem":2153},"XMLHttpRequest - AJAX та низькорівневі запити","\u002Fjavascript\u002Fnetwork\u002F08-xmlhttprequest","03.javascript\u002F02.network\u002F08-xmlhttprequest",{"title":2155,"path":2156,"stem":2157},"Відновлюване завантаження файлів","\u002Fjavascript\u002Fnetwork\u002F09-resumable-upload","03.javascript\u002F02.network\u002F09-resumable-upload",{"title":2159,"path":2160,"stem":2161},"Cookies, document.cookie та світ після \"Cookiepocalypse\"","\u002Fjavascript\u002Fnetwork\u002F10-cookies","03.javascript\u002F02.network\u002F10-cookies",{"title":2163,"path":2164,"stem":2165},"js-cookie: Керування Cookies без Болю","\u002Fjavascript\u002Fnetwork\u002F11-js-cookie","03.javascript\u002F02.network\u002F11-js-cookie",{"title":2167,"path":2168,"stem":2169},"Axios: Потужний HTTP-клієнт для JavaScript","\u002Fjavascript\u002Fnetwork\u002F12-axios","03.javascript\u002F02.network\u002F12-axios",{"title":2171,"icon":2172,"path":2173,"stem":2174,"children":2175,"page":59},"Bom","i-lucide-monitor","\u002Fjavascript\u002Fbom","03.javascript\u002F03.bom",[2176,2180,2184,2188],{"title":2177,"path":2178,"stem":2179},"LocalStorage, SessionStorage та patterns збереження даних","\u002Fjavascript\u002Fbom\u002F01-localstorage","03.javascript\u002F03.bom\u002F01-localstorage",{"title":2181,"path":2182,"stem":2183},"Location Object - Керування адресою сторінки","\u002Fjavascript\u002Fbom\u002F02-location-object","03.javascript\u002F03.bom\u002F02-location-object",{"title":2185,"path":2186,"stem":2187},"History API - Керування історією браузера","\u002Fjavascript\u002Fbom\u002F03-history-api","03.javascript\u002F03.bom\u002F03-history-api",{"title":2189,"path":2190,"stem":2191},"Navigator Object - Ідентифікація та Можливості Пристрою","\u002Fjavascript\u002Fbom\u002F04-navigator-object","03.javascript\u002F03.bom\u002F04-navigator-object",{"title":2193,"icon":2194,"path":2195,"stem":2196,"children":2197},"React","i-devicon-react","\u002Fjavascript\u002Freact","03.javascript\u002F04.react\u002Findex",[2198,2199,2203,2207,2211,2215,2278,2313,2465],{"title":2193,"path":2195,"stem":2196},{"title":2200,"path":2201,"stem":2202},"Робота з Формами в React","\u002Fjavascript\u002Freact\u002Freact-forms","03.javascript\u002F04.react\u002F01.react-forms",{"title":2204,"path":2205,"stem":2206},"React Hook Form: Професійна Робота з Формами","\u002Fjavascript\u002Freact\u002Freact-hook-form","03.javascript\u002F04.react\u002F02.react-hook-form",{"title":2208,"path":2209,"stem":2210},"React Hook Form: Глибоке Розуміння Архітектури та Оптимізації","\u002Fjavascript\u002Freact\u002Freact-hook-form-new","03.javascript\u002F04.react\u002F02.react-hook-form-new",{"title":2212,"path":2213,"stem":2214},"Axios та React: Професійна Архітектура Запитів","\u002Fjavascript\u002Freact\u002Fdata-fetching-axios","03.javascript\u002F04.react\u002F03.data-fetching-axios",{"title":2216,"icon":132,"path":2217,"stem":2218,"children":2219},"Tanstack Query","\u002Fjavascript\u002Freact\u002Ftanstack-query","03.javascript\u002F04.react\u002F04.tanstack-query\u002Findex",[2220,2222,2226,2230,2234,2238,2242,2246,2250,2254,2258,2262,2266,2270,2274],{"title":2221,"path":2217,"stem":2218},"TanStack Query: Майстерність Керування Станом Сервера",{"title":2223,"path":2224,"stem":2225},"Парадигма Server State: Чому useEffect недостатньо","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fserver-state-paradigm","03.javascript\u002F04.react\u002F04.tanstack-query\u002F01.server-state-paradigm",{"title":2227,"path":2228,"stem":2229},"Встановлення та Налаштування: Фундамент","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Finstallation-and-devtools","03.javascript\u002F04.react\u002F04.tanstack-query\u002F02.installation-and-devtools",{"title":2231,"path":2232,"stem":2233},"Основи Запитів та Магія Ключів","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fquery-basics-and-keys","03.javascript\u002F04.react\u002F04.tanstack-query\u002F03.query-basics-and-keys",{"title":2235,"path":2236,"stem":2237},"Синхронізація Даних: Життєвий Цикл Запиту","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fdata-synchronization","03.javascript\u002F04.react\u002F04.tanstack-query\u002F04.data-synchronization",{"title":2239,"path":2240,"stem":2241},"Мутації та Інвалідація: Зміна Даних","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fmutations-and-invalidation","03.javascript\u002F04.react\u002F04.tanstack-query\u002F05.mutations-and-invalidation",{"title":2243,"path":2244,"stem":2245},"Оптимістичні Оновлення: Швидше за Світло","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Foptimistic-updates","03.javascript\u002F04.react\u002F04.tanstack-query\u002F06.optimistic-updates",{"title":2247,"path":2248,"stem":2249},"Пагінація та Infinite Scroll","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fpagination-and-load-more","03.javascript\u002F04.react\u002F04.tanstack-query\u002F07.pagination-and-load-more",{"title":2251,"path":2252,"stem":2253},"Просунуті Патерни та Оптимізація","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fadvanced-patterns","03.javascript\u002F04.react\u002F04.tanstack-query\u002F08.advanced-patterns",{"title":2255,"path":2256,"stem":2257},"Архітектура та Best Practices","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Farchitecture-and-best-practices","03.javascript\u002F04.react\u002F04.tanstack-query\u002F09.architecture-and-best-practices",{"title":2259,"path":2260,"stem":2261},"Server-Side Rendering (SSR) та Гідратація","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fserver-side-rendering","03.javascript\u002F04.react\u002F04.tanstack-query\u002F10.server-side-rendering",{"title":2263,"path":2264,"stem":2265},"Стратегії Тестування","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Ftesting-strategies","03.javascript\u002F04.react\u002F04.tanstack-query\u002F11.testing-strategies",{"title":2267,"path":2268,"stem":2269},"Аутентифікація та Обробка Помилок","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fauthentication-and-errors","03.javascript\u002F04.react\u002F04.tanstack-query\u002F12.authentication-and-errors",{"title":2271,"path":2272,"stem":2273},"React Suspense та Майбутнє","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Freact-suspense","03.javascript\u002F04.react\u002F04.tanstack-query\u002F13.react-suspense",{"title":2275,"path":2276,"stem":2277},"Глибоке Занурення в Продуктивність","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fperformance-deep-dive","03.javascript\u002F04.react\u002F04.tanstack-query\u002F14.performance-deep-dive",{"title":2279,"icon":2194,"path":2280,"stem":2281,"children":2282},"React Router","\u002Fjavascript\u002Freact\u002Freact-router","03.javascript\u002F04.react\u002F05.react-router\u002Findex",[2283,2285,2289,2293,2297,2301,2305,2309],{"title":2284,"path":2280,"stem":2281},"React Router: Навігаційна система сучасного вебу",{"title":2286,"path":2287,"stem":2288},"Налаштування та Базовий Роутинг","\u002Fjavascript\u002Freact\u002Freact-router\u002Fsetup-and-basic-routing","03.javascript\u002F04.react\u002F05.react-router\u002F01.setup-and-basic-routing",{"title":2290,"path":2291,"stem":2292},"Динамічна Навігація","\u002Fjavascript\u002Freact\u002Freact-router\u002Fnavigation-and-links","03.javascript\u002F04.react\u002F05.react-router\u002F02.navigation-and-links",{"title":2294,"path":2295,"stem":2296},"Вкладені Маршрути та Макети","\u002Fjavascript\u002Freact\u002Freact-router\u002Fnested-routes-and-layouts","03.javascript\u002F04.react\u002F05.react-router\u002F03.nested-routes-and-layouts",{"title":2298,"path":2299,"stem":2300},"Динамічні Маршрути та Параметри","\u002Fjavascript\u002Freact\u002Freact-router\u002Fdynamic-routing","03.javascript\u002F04.react\u002F05.react-router\u002F04.dynamic-routing",{"title":2302,"path":2303,"stem":2304},"Data APIs: Loaders та Actions","\u002Fjavascript\u002Freact\u002Freact-router\u002Fdata-loading","03.javascript\u002F04.react\u002F05.react-router\u002F05.data-loading",{"title":2306,"path":2307,"stem":2308},"Просунуті Патерни","\u002Fjavascript\u002Freact\u002Freact-router\u002Fadvanced-patterns","03.javascript\u002F04.react\u002F05.react-router\u002F06.advanced-patterns",{"title":2310,"path":2311,"stem":2312},"Legacy Routing: Компонентний підхід","\u002Fjavascript\u002Freact\u002Freact-router\u002Flegacy-routing","03.javascript\u002F04.react\u002F05.react-router\u002F07.legacy-routing",{"title":2314,"icon":132,"path":2315,"stem":2316,"children":2317},"Redux","\u002Fjavascript\u002Freact\u002Fredux","03.javascript\u002F04.react\u002F06.redux\u002Findex",[2318,2320,2336,2365,2374,2395,2411,2440],{"title":2319,"path":2315,"stem":2316},"Redux: Еволюція управління станом",{"title":14,"icon":15,"path":2321,"stem":2322,"children":2323,"page":59},"\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals",[2324,2328,2332],{"title":2325,"path":2326,"stem":2327},"Вступ до State Management","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fintro-state-management","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F01.intro-state-management",{"title":2329,"path":2330,"stem":2331},"Філософія Redux та Три Принципи","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fredux-philosophy","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F02.redux-philosophy",{"title":2333,"path":2334,"stem":2335},"Чисті функції та Іммутабельність","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fpure-functions-immutability","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F03.pure-functions-immutability",{"title":2337,"icon":132,"path":2338,"stem":2339,"children":2340,"page":59},"Classic Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux",[2341,2345,2349,2353,2357,2361],{"title":2342,"path":2343,"stem":2344},"Створення Store (Classic Redux)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fstore-setup","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F01.store-setup",{"title":2346,"path":2347,"stem":2348},"Actions, Constants та Action Creators","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Factions-constants","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F02.actions-constants",{"title":2350,"path":2351,"stem":2352},"Логіка Reducers","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Freducers","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F03.reducers",{"title":2354,"path":2355,"stem":2356},"Комбінування Reducers (Root Reducer)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fdata-flow","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F04.data-flow",{"title":2358,"path":2359,"stem":2360},"Підключення до React (React-Redux)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Freact-redux-connection","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F05.react-redux-connection",{"title":2362,"path":2363,"stem":2364},"Middleware та Асинхронність (Redux Thunk)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fmiddleware-thunk","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F06.middleware-thunk",{"title":2366,"icon":132,"path":2367,"stem":2368,"children":2369,"page":59},"Transition To Rtk","\u002Fjavascript\u002Freact\u002Fredux\u002Ftransition-to-rtk","03.javascript\u002F04.react\u002F06.redux\u002F03.transition-to-rtk",[2370],{"title":2371,"path":2372,"stem":2373},"Проблеми класичного Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Ftransition-to-rtk\u002Fproblems-with-classic","03.javascript\u002F04.react\u002F06.redux\u002F03.transition-to-rtk\u002F01.problems-with-classic",{"title":2375,"icon":132,"path":2376,"stem":2377,"children":2378,"page":59},"Redux Toolkit","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit",[2379,2383,2387,2391],{"title":2380,"path":2381,"stem":2382},"Налаштування Store з configureStore","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fconfigure-store","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F01.configure-store",{"title":2384,"path":2385,"stem":2386},"createSlice: Революція в Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fcreate-slice","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F02.create-slice",{"title":2388,"path":2389,"stem":2390},"Асинхронність з createAsyncThunk","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fasync-thunks","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F03.async-thunks",{"title":2392,"path":2393,"stem":2394},"04. Entity Adapter: Керування нормалізованим станом","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fentity-adapter","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F04.entity-adapter",{"title":2396,"icon":92,"path":2397,"stem":2398,"children":2399,"page":59},"Advanced","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced",[2400,2404,2408],{"title":2401,"path":2402,"stem":2403},"Мемоізація та Селектори: Повний Гайд по Reselect","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Fselectors-reselect","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F01.selectors-reselect",{"title":2405,"path":2406,"stem":2407},"RTK Query: Архітектура Серверного Кешу","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Frtk-query-intro","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F02.rtk-query-intro",{"title":2255,"path":2409,"stem":2410},"\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Farchitecture-best-practices","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F03.architecture-best-practices",{"title":2412,"icon":132,"path":2413,"stem":2414,"children":2415,"page":59},"Project Kanban","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban",[2416,2420,2424,2428,2432,2436],{"title":2417,"path":2418,"stem":2419},"Проєкт: Kanban Board (Trello Clone)","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fproject-overview","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F01.project-overview",{"title":2421,"path":2422,"stem":2423},"Налаштування та Типізація","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fsetup-and-types","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F02.setup-and-types",{"title":2425,"path":2426,"stem":2427},"Board Slice: Серце Дошки","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fboard-slice","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F03.board-slice",{"title":2429,"path":2430,"stem":2431},"Логіка Drag & Drop","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fdrag-and-drop-logic","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F04.drag-and-drop-logic",{"title":2433,"path":2434,"stem":2435},"Інтеграція з RTK Query","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Frtk-query-integration","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F05.rtk-query-integration",{"title":2437,"path":2438,"stem":2439},"Optimistic Updates","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Foptimistic-updates","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F06.optimistic-updates",{"title":2441,"icon":132,"path":2442,"stem":2443,"children":2444,"page":59},"Testing","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting","03.javascript\u002F04.react\u002F06.redux\u002F07.testing",[2445,2449,2453,2457,2461],{"title":2446,"path":2447,"stem":2448},"Тестування Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Fintro-testing","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F01.intro-testing",{"title":2450,"path":2451,"stem":2452},"Тестування Reducers","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-reducers","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F02.testing-reducers",{"title":2454,"path":2455,"stem":2456},"Тестування Селекторів","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-selectors","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F03.testing-selectors",{"title":2458,"path":2459,"stem":2460},"Тестування Компонентів (Integration)","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-components","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F04.testing-components",{"title":2462,"path":2463,"stem":2464},"Тестування Async Thunks","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-thunks","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F05.testing-thunks",{"title":2466,"icon":132,"path":2467,"stem":2468,"children":2469},"Ui Libraries","\u002Fjavascript\u002Freact\u002Fui-libraries","03.javascript\u002F04.react\u002F07.ui-libraries\u002Findex",[2470,2472,2476,2480,2484,2488,2492],{"title":2471,"path":2467,"stem":2468},"UI Бібліотеки в React",{"title":2473,"path":2474,"stem":2475},"Вступ до UI Бібліотек: Навіщо Винаходити Велосипед Двічі?","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fintroduction-to-ui-libraries","03.javascript\u002F04.react\u002F07.ui-libraries\u002F01.introduction-to-ui-libraries",{"title":2477,"path":2478,"stem":2479},"Філософія shadcn\u002Fui: \"Not a Component Library\"","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-philosophy","03.javascript\u002F04.react\u002F07.ui-libraries\u002F02.shadcn-philosophy",{"title":2481,"path":2482,"stem":2483},"Установка та Налаштування shadcn\u002Fui","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-installation","03.javascript\u002F04.react\u002F07.ui-libraries\u002F03.shadcn-installation",{"title":2485,"path":2486,"stem":2487},"Базові Компоненти shadcn\u002Fui: Фундамент Інтерфейсу","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-basics","03.javascript\u002F04.react\u002F07.ui-libraries\u002F04.shadcn-components-basics",{"title":2489,"path":2490,"stem":2491},"Компоненти Форм: Побудова Інтерактивних Form","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-forms","03.javascript\u002F04.react\u002F07.ui-libraries\u002F05.shadcn-components-forms",{"title":2493,"path":2494,"stem":2495},"Складні Компоненти: Dialog, Dropdown, Table та Command","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-advanced","03.javascript\u002F04.react\u002F07.ui-libraries\u002F06.shadcn-components-advanced",{"title":2497,"icon":2498,"path":2499,"stem":2500,"children":2501,"page":59},"TypeScript","i-devicon-typescript","\u002Fjavascript\u002Ftypescript","03.javascript\u002F05.typescript",[2502,2506,2510,2514,2518,2522,2526,2530],{"title":2503,"path":2504,"stem":2505},"TypeScript: Броня для вашого коду","\u002Fjavascript\u002Ftypescript\u002Fintro-and-basic-types","03.javascript\u002F05.typescript\u002F01.intro-and-basic-types",{"title":2507,"path":2508,"stem":2509},"Майстерність Моделювання Даних: Інтерфейси та Просунуті Типи","\u002Fjavascript\u002Ftypescript\u002Finterfaces-and-advanced-types","03.javascript\u002F05.typescript\u002F02.interfaces-and-advanced-types",{"title":2511,"path":2512,"stem":2513},"Алхімія Типів: Generics та Utility Types","\u002Fjavascript\u002Ftypescript\u002Fgenerics-and-utilities","03.javascript\u002F05.typescript\u002F03.generics-and-utilities",{"title":2515,"path":2516,"stem":2517},"Архітектура та Шаблони: Класи в TypeScript","\u002Fjavascript\u002Ftypescript\u002Fclasses-and-oop","03.javascript\u002F05.typescript\u002F04.classes-and-oop",{"title":2519,"path":2520,"stem":2521},"Продакшн та Екосистема: Advanced Config & Workflow","\u002Fjavascript\u002Ftypescript\u002Fadvanced-patterns-and-config","03.javascript\u002F05.typescript\u002F05.advanced-patterns-and-config",{"title":2523,"path":2524,"stem":2525},"TypeScript у світі React","\u002Fjavascript\u002Ftypescript\u002Freact-basics","03.javascript\u002F05.typescript\u002F06.react-basics",{"title":2527,"path":2528,"stem":2529},"React + TypeScript: Продвинуті патерни","\u002Fjavascript\u002Ftypescript\u002Freact-advanced","03.javascript\u002F05.typescript\u002F07.react-advanced",{"title":2531,"path":2532,"stem":2533},"React + TypeScript: Екосистема та бібліотеки","\u002Fjavascript\u002Ftypescript\u002Freact-ecosystem","03.javascript\u002F05.typescript\u002F08.react-ecosystem",{"title":2535,"icon":2536,"path":2537,"stem":2538,"children":2539,"page":59},"Асинхронність","i-lucide-refresh-cw","\u002Fjavascript\u002Fasync-programming","03.javascript\u002F06.async-programming",[2540,2544,2548],{"title":2541,"path":2542,"stem":2543},"Event Loop: серце асинхронності в JavaScript","\u002Fjavascript\u002Fasync-programming\u002Fevent-loop-fundamentals","03.javascript\u002F06.async-programming\u002F01.event-loop-fundamentals",{"title":2545,"path":2546,"stem":2547},"Task Queue та Microtask Queue: пріоритети виконання","\u002Fjavascript\u002Fasync-programming\u002Ftask-queues","03.javascript\u002F06.async-programming\u002F02.task-queues",{"title":2549,"path":2550,"stem":2551},"Асинхронні патерни: від Callbacks до Async\u002FAwait","\u002Fjavascript\u002Fasync-programming\u002Fasync-patterns","03.javascript\u002F06.async-programming\u002F03.async-patterns",{"title":2553,"path":2554,"stem":2555},"Atomic Design","\u002Fjavascript\u002Fatomic-design","03.javascript\u002F2.atomic-design",{"title":2557,"icon":2558,"path":2559,"stem":2560,"children":2561,"page":59},"Java","i-devicon-java","\u002Fjava","04.java",[2562,2565,2568,2572,2576,2580,2584],{"title":162,"path":2563,"stem":2564},"\u002Fjava\u002Fdata-mapper-part1","04.java\u002F01.data-mapper-part1",{"title":166,"path":2566,"stem":2567},"\u002Fjava\u002Fdata-mapper-part2","04.java\u002F02.data-mapper-part2",{"title":2569,"path":2570,"stem":2571},"Service Layer: Організація бізнес-логіки","\u002Fjava\u002Fservice-layer","04.java\u002F03.service-layer",{"title":2573,"path":2574,"stem":2575},"Rich Domain Model та State Pattern","\u002Fjava\u002Frich-domain-model","04.java\u002F04.rich-domain-model",{"title":2577,"path":2578,"stem":2579},"Патерни для складної бізнес-логіки","\u002Fjava\u002Fbusiness-logic-patterns","04.java\u002F05.business-logic-patterns",{"title":2581,"path":2582,"stem":2583},"Обробка помилок та валідація","\u002Fjava\u002Ferror-handling-validation","04.java\u002F06.error-handling-validation",{"title":2585,"path":2586,"stem":2587,"children":2588,"page":59},"Проектування баз даних","\u002Fjava\u002Fpr2","04.java\u002Fpr2",[2589,2593,2597,2601,2605,2609,2613,2617,2621,2625,2629,2633,2637,2641,2645,2649,2653,2657,2661,2665,2669,2673,2677,2681,2685,2689,2693,2697,2701,2705,2709,2713,2717,2721,2725,2729,2733],{"title":2590,"path":2591,"stem":2592},"Концептуальне моделювання: Мистецтво розуміння предметної області","\u002Fjava\u002Fpr2\u002Fconceptual-modeling","04.java\u002Fpr2\u002F01.conceptual-modeling",{"title":2594,"path":2595,"stem":2596},"Логічне моделювання: Від бізнес-ідей до структур даних","\u002Fjava\u002Fpr2\u002Flogical-modeling","04.java\u002Fpr2\u002F02.logical-modeling",{"title":2598,"path":2599,"stem":2600},"Нормалізація: Гігієна даних та боротьба з аномаліями","\u002Fjava\u002Fpr2\u002Fnormalization","04.java\u002Fpr2\u002F03.normalization",{"title":2602,"path":2603,"stem":2604},"Фізична схема: Від абстракції до DDL","\u002Fjava\u002Fpr2\u002Fphysical-schema","04.java\u002Fpr2\u002F04.physical-schema",{"title":2606,"path":2607,"stem":2608},"Архітектурна класифікація таблиць","\u002Fjava\u002Fpr2\u002Ftable-classification","04.java\u002Fpr2\u002F05.table-classification",{"title":2610,"path":2611,"stem":2612},"Database Migrations: Версіонування схеми з Flyway","\u002Fjava\u002Fpr2\u002Fdatabase-migrations","04.java\u002Fpr2\u002F06.database-migrations",{"title":2614,"path":2615,"stem":2616},"А що, якби це була не реляційна БД?","\u002Fjava\u002Fpr2\u002Fbeyond-relational","04.java\u002Fpr2\u002F07.beyond-relational",{"title":2618,"path":2619,"stem":2620},"Object-Relational Impedance Mismatch: Два світи, що не хочуть дружити","\u002Fjava\u002Fpr2\u002Fimpedance-mismatch","04.java\u002Fpr2\u002F09.impedance-mismatch",{"title":2622,"path":2623,"stem":2624},"JDBC: Перший контакт із базою даних","\u002Fjava\u002Fpr2\u002Fjdbc-fundamentals","04.java\u002Fpr2\u002F10.jdbc-fundamentals",{"title":2626,"path":2627,"stem":2628},"Якість коду: Spotless, SpotBugs та SonarQube","\u002Fjava\u002Fpr2\u002F10a.code-quality","04.java\u002Fpr2\u002F10a.code-quality",{"title":2630,"path":2631,"stem":2632},"Connection Pool: Патерн Object Pool для JDBC-з'єднань","\u002Fjava\u002Fpr2\u002Fconnection-pool","04.java\u002Fpr2\u002F11.connection-pool",{"title":2634,"path":2635,"stem":2636},"Row Data Gateway: Об'єкт як обгортка рядка таблиці","\u002Fjava\u002Fpr2\u002Frow-data-gateway","04.java\u002Fpr2\u002F12.row-data-gateway",{"title":2638,"path":2639,"stem":2640},"Table Data Gateway: Фасад таблиці як архітектурний відступ","\u002Fjava\u002Fpr2\u002Ftable-data-gateway","04.java\u002Fpr2\u002F13.table-data-gateway",{"title":2642,"path":2643,"stem":2644},"Repository + Data Mapper: Правильна шарова архітектура з JDBC","\u002Fjava\u002Fpr2\u002Frepository-data-mapper","04.java\u002Fpr2\u002F14.repository-data-mapper",{"title":2646,"path":2647,"stem":2648},"Identity Map: Кешування сутностей у рамках сесії","\u002Fjava\u002Fpr2\u002Fidentity-map","04.java\u002Fpr2\u002F15.identity-map",{"title":2650,"path":2651,"stem":2652},"Unit of Work: Відстеження змін і координація JDBC-транзакцій","\u002Fjava\u002Fpr2\u002Funit-of-work","04.java\u002Fpr2\u002F16.unit-of-work",{"title":2654,"path":2655,"stem":2656},"Strategy: Замінювані SQL-стратегії для підтримки різних СУБД","\u002Fjava\u002Fpr2\u002Fstrategy-sql","04.java\u002Fpr2\u002F17.strategy-sql",{"title":2658,"path":2659,"stem":2660},"Proxy: Lazy Loading для One-To-Many колекцій","\u002Fjava\u002Fpr2\u002Fproxy-lazy-loading","04.java\u002Fpr2\u002F18.proxy-lazy-loading",{"title":2662,"path":2663,"stem":2664},"Generic Repository через Java Reflection: анотації та динамічний SQL","\u002Fjava\u002Fpr2\u002Fgeneric-repository-reflection","04.java\u002Fpr2\u002F19.generic-repository-reflection",{"title":2666,"path":2667,"stem":2668},"Specification Pattern: Композиція бізнес-правил для складних запитів","\u002Fjava\u002Fpr2\u002Fspecification-pattern","04.java\u002Fpr2\u002F20.specification-pattern",{"title":2670,"path":2671,"stem":2672},"Розширені можливості Specification Pattern: підзапити, агрегації та гібридний підхід","\u002Fjava\u002Fpr2\u002F20a.advanced-specifications","04.java\u002Fpr2\u002F20a.advanced-specifications",{"title":2674,"path":2675,"stem":2676},"Асинхронність у JDBC: Від блокуючих викликів до CompletableFuture","\u002Fjava\u002Fpr2\u002Fasynchronous-jdbc","04.java\u002Fpr2\u002F21.asynchronous-jdbc",{"title":2678,"path":2679,"stem":2680},"Інтеграційне тестування JDBC-репозиторіїв: Embedded H2 та патерн AAA","\u002Fjava\u002Fpr2\u002Fintegration-testing-h2","04.java\u002Fpr2\u002F22.integration-testing-h2",{"title":2682,"path":2683,"stem":2684},"Testcontainers: Тестування з реальною PostgreSQL у Docker-контейнерах","\u002Fjava\u002Fpr2\u002Fintegration-testing-testcontainers","04.java\u002Fpr2\u002F23.integration-testing-testcontainers",{"title":2686,"path":2687,"stem":2688},"Google Guice: Впровадження залежностей у JavaFX-проєкті","\u002Fjava\u002Fpr2\u002Fdependency-injection-guice","04.java\u002Fpr2\u002F24.dependency-injection-guice",{"title":2690,"path":2691,"stem":2692},"JavaFX: Основи побудови графічних інтерфейсів","\u002Fjava\u002Fpr2\u002Fjavafx-fundamentals","04.java\u002Fpr2\u002F25.javafx-fundamentals",{"title":2694,"path":2695,"stem":2696},"Properties та Bindings: Реактивність у JavaFX","\u002Fjava\u002Fpr2\u002Fjavafx-properties-bindings","04.java\u002Fpr2\u002F26.javafx-properties-bindings",{"title":2698,"path":2699,"stem":2700},"MVC vs MVP vs MVVM: Еволюція архітектурних патернів UI","\u002Fjava\u002Fpr2\u002Fui-architecture-patterns","04.java\u002Fpr2\u002F27.ui-architecture-patterns",{"title":2702,"path":2703,"stem":2704},"MVVM на практиці: Побудова ViewModel","\u002Fjava\u002Fpr2\u002Fmvvm-viewmodel-implementation","04.java\u002Fpr2\u002F28.mvvm-viewmodel-implementation",{"title":2706,"path":2707,"stem":2708},"View та Controller: Зв'язування з ViewModel через FXML","\u002Fjava\u002Fpr2\u002Fmvvm-view-controller","04.java\u002Fpr2\u002F29.mvvm-view-controller",{"title":2710,"path":2711,"stem":2712},"Інтеграція MVVM з Guice: Автоматична ін'єкція залежностей","\u002Fjava\u002Fpr2\u002Fmvvm-guice-integration","04.java\u002Fpr2\u002F30.mvvm-guice-integration",{"title":2714,"path":2715,"stem":2716},"Валідація та обробка помилок у MVVM","\u002Fjava\u002Fpr2\u002Fmvvm-validation-error-handling","04.java\u002Fpr2\u002F31.mvvm-validation-error-handling",{"title":2718,"path":2719,"stem":2720},"Навігація та управління екранами у JavaFX MVVM","\u002Fjava\u002Fpr2\u002Fmvvm-navigation-screen-management","04.java\u002Fpr2\u002F32.mvvm-navigation-screen-management",{"title":2722,"path":2723,"stem":2724},"Тестування JavaFX MVVM-додатків","\u002Fjava\u002Fpr2\u002Fmvvm-testing","04.java\u002Fpr2\u002F33.mvvm-testing",{"title":2726,"path":2727,"stem":2728},"Стилізація та теми у JavaFX: CSS та User Experience","\u002Fjava\u002Fpr2\u002Fjavafx-styling-themes","04.java\u002Fpr2\u002F34.javafx-styling-themes",{"title":2730,"path":2731,"stem":2732},"AtlantaFX: Сучасні теми для JavaFX додатків","\u002Fjava\u002Fpr2\u002Fatlantafx-modern-themes","04.java\u002Fpr2\u002F35.atlantafx-modern-themes",{"title":2734,"path":2735,"stem":2736},"Пакування та розповсюдження JavaFX-додатків","\u002Fjava\u002Fpr2\u002Fjar-packaging-distribution","04.java\u002Fpr2\u002F36.jar-packaging-distribution",{"title":2738,"icon":2739,"path":2740,"stem":2741,"children":2742,"page":59},"Python","i-devicon-python","\u002Fpython","05.python",[2743,2747,2750,2754,2758,2762,2766,2770,2774,2778,2782,2786,2790,2794,2798,2859],{"title":2744,"path":2745,"stem":2746},"Модулі, Пакети та Віртуальні Середовища","\u002Fpython\u002Fmodules-packages-venv","05.python\u002F00.modules-packages-venv",{"title":71,"path":2748,"stem":2749},"\u002Fpython\u002Fclasses-objects","05.python\u002F01.classes-objects",{"title":2751,"path":2752,"stem":2753},"Інкапсуляція, Керування Доступом та Властивості","\u002Fpython\u002Fencapsulation","05.python\u002F02.encapsulation",{"title":2755,"path":2756,"stem":2757},"Наслідування, MRO та суперсила super()","\u002Fpython\u002Finheritance-mro","05.python\u002F03.inheritance-mro",{"title":2759,"path":2760,"stem":2761},"Абстракція — ABC проти Статичних Протоколів (PEP 544)","\u002Fpython\u002Fabstraction-protocols","05.python\u002F04.abstraction-protocols",{"title":2763,"path":2764,"stem":2765},"Магічні методи (Dunder) та Емуляція протоколів","\u002Fpython\u002Fdunder-methods","05.python\u002F05.dunder-methods",{"title":2767,"path":2768,"stem":2769},"Декоратори та Керування життєвим циклом методів","\u002Fpython\u002Fdecorators-static-class","05.python\u002F06.decorators-static-class",{"title":2771,"path":2772,"stem":2773},"Дескриптори — Магія доступу до атрибутів","\u002Fpython\u002Fdescriptors","05.python\u002F07.descriptors",{"title":2775,"path":2776,"stem":2777},"Метакласи — Динамічне створення класів під капотом CPython","\u002Fpython\u002Fmetaclasses","05.python\u002F08.metaclasses",{"title":2779,"path":2780,"stem":2781},"Dataclasses, NamedTuple та сучасні контейнери Python","\u002Fpython\u002Fmodern-containers","05.python\u002F09.modern-containers",{"title":2783,"path":2784,"stem":2785},"GIL та модель конкурентності CPython — фундамент перед потоками і процесами","\u002Fpython\u002Fgil-concurrency-intro","05.python\u002F11.gil-concurrency-intro",{"title":2787,"path":2788,"stem":2789},"Threading — конкурентність для I\u002FO-bound задач","\u002Fpython\u002Fthreading","05.python\u002F12.threading",{"title":2791,"path":2792,"stem":2793},"Multiprocessing — справжній паралелізм для CPU-bound задач","\u002Fpython\u002Fmultiprocessing","05.python\u002F13.multiprocessing",{"title":2795,"path":2796,"stem":2797},"asyncio — кооперативна конкурентність та event loop","\u002Fpython\u002Fasyncio","05.python\u002F14.asyncio",{"title":2799,"icon":92,"path":2800,"stem":2801,"children":2802,"page":59},"FastAPI","\u002Fpython\u002Ffastapi","05.python\u002Ffastapi",[2803,2807,2811,2815,2819,2823,2827,2831,2835,2839,2843,2847,2851,2855],{"title":2804,"path":2805,"stem":2806},"Глибокий Typing та Pydantic v2 — від анотацій до валідації","\u002Fpython\u002Ffastapi\u002Ftyping-pydantic","05.python\u002Ffastapi\u002F15.typing-pydantic",{"title":2808,"path":2809,"stem":2810},"WSGI, ASGI та Python Web-екосистема","\u002Fpython\u002Ffastapi\u002Fwsgi-asgi-ecosystem","05.python\u002Ffastapi\u002F16.wsgi-asgi-ecosystem",{"title":2812,"path":2813,"stem":2814},"FastAPI: Перший додаток, Uvicorn та OpenAPI","\u002Fpython\u002Ffastapi\u002Ffastapi-intro","05.python\u002Ffastapi\u002F17.fastapi-intro",{"title":2816,"path":2817,"stem":2818},"Маршрутизація, параметри запитів та APIRouter","\u002Fpython\u002Ffastapi\u002Ffastapi-routing-params","05.python\u002Ffastapi\u002F18.fastapi-routing-params",{"title":2820,"path":2821,"stem":2822},"Pydantic v2 у FastAPI — схеми, валідація та серіалізація","\u002Fpython\u002Ffastapi\u002Ffastapi-pydantic-schemas","05.python\u002Ffastapi\u002F19.fastapi-pydantic-schemas",{"title":2824,"path":2825,"stem":2826},"Dependency Injection — серце архітектури FastAPI","\u002Fpython\u002Ffastapi\u002Ffastapi-dependency-injection","05.python\u002Ffastapi\u002F20.fastapi-dependency-injection",{"title":2828,"path":2829,"stem":2830},"Обробка помилок, Middleware та CORS у FastAPI","\u002Fpython\u002Ffastapi\u002Ffastapi-errors-middleware","05.python\u002Ffastapi\u002F21.fastapi-errors-middleware",{"title":2832,"path":2833,"stem":2834},"SQLAlchemy 2.0 — ORM, Core та Async Engine","\u002Fpython\u002Ffastapi\u002Fsqlalchemy-orm","05.python\u002Ffastapi\u002F22.sqlalchemy-orm",{"title":2836,"path":2837,"stem":2838},"Alembic — міграції бази даних","\u002Fpython\u002Ffastapi\u002Falembic-migrations","05.python\u002Ffastapi\u002F23.alembic-migrations",{"title":2840,"path":2841,"stem":2842},"Repository Pattern та Clean Architecture у FastAPI","\u002Fpython\u002Ffastapi\u002Ffastapi-repository-clean-arch","05.python\u002Ffastapi\u002F24.fastapi-repository-clean-arch",{"title":2844,"path":2845,"stem":2846},"Автентифікація та авторизація — JWT, OAuth2, RBAC","\u002Fpython\u002Ffastapi\u002Ffastapi-auth-security","05.python\u002Ffastapi\u002F25.fastapi-auth-security",{"title":2848,"path":2849,"stem":2850},"Тестування FastAPI — pytest, httpx, fixtures","\u002Fpython\u002Ffastapi\u002Ffastapi-testing","05.python\u002Ffastapi\u002F26.fastapi-testing",{"title":2852,"path":2853,"stem":2854},"Async на повну — Background Tasks, WebSockets, SSE та Celery","\u002Fpython\u002Ffastapi\u002Ffastapi-async-advanced","05.python\u002Ffastapi\u002F27.fastapi-async-advanced",{"title":2856,"path":2857,"stem":2858},"Deployment — Docker, CI\u002FCD, Monitoring","\u002Fpython\u002Ffastapi\u002Ffastapi-deployment","05.python\u002Ffastapi\u002F28.fastapi-deployment",{"title":2860,"path":2861,"stem":2862},"[object Object]","\u002Fpython\u002Foop-plan","05.python\u002Foop-plan",{"title":2864,"icon":2865,"path":2866,"stem":2867,"children":2868,"page":59},"Бази даних","i-lucide-database","\u002Fdatabases","06.databases",[2869,2899,2922,2959,2988,3006,3040,3052,3061],{"title":2870,"icon":2871,"path":2872,"stem":2873,"children":2874,"page":59},"Intro","i-lucide-play","\u002Fdatabases\u002Fintro","06.databases\u002F01.intro",[2875,2879,2883,2887,2891,2895],{"title":2876,"path":2877,"stem":2878},"Введення в теорію баз даних","\u002Fdatabases\u002Fintro\u002Fintroduction-to-databases","06.databases\u002F01.intro\u002F01.introduction-to-databases",{"title":2880,"path":2881,"stem":2882},"Реляційна модель даних","\u002Fdatabases\u002Fintro\u002Frelational-model-theory","06.databases\u002F01.intro\u002F02.relational-model-theory",{"title":2884,"path":2885,"stem":2886},"ER-моделювання","\u002Fdatabases\u002Fintro\u002Fer-modeling","06.databases\u002F01.intro\u002F03.er-modeling",{"title":2888,"path":2889,"stem":2890},"Логічне проектування БД","\u002Fdatabases\u002Fintro\u002Flogical-schema","06.databases\u002F01.intro\u002F04.logical-schema",{"title":2892,"path":2893,"stem":2894},"Класифікація таблиць","\u002Fdatabases\u002Fintro\u002Ftable-classification","06.databases\u002F01.intro\u002F05.table-classification",{"title":2896,"path":2897,"stem":2898},"PlantUML для баз даних","\u002Fdatabases\u002Fintro\u002Fplantuml-diagrams","06.databases\u002F01.intro\u002F06.plantuml-diagrams",{"title":2900,"icon":2865,"path":2901,"stem":2902,"children":2903,"page":59},"MS SQL Server Start","\u002Fdatabases\u002Fms-sql-server-start","06.databases\u002F02.ms-sql-server-start",[2904,2908,2914,2918],{"title":2905,"path":2906,"stem":2907},"Типи даних у MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fdata-types","06.databases\u002F02.ms-sql-server-start\u002F01.data-types",{"title":2909,"path":2910,"stem":2911,"children":2912},"Індекси у MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fsql-indexes","06.databases\u002F02.ms-sql-server-start\u002F02.sql-indexes",[2913],{"title":2909,"path":2910,"stem":2911},{"title":2915,"path":2916,"stem":2917},"Системні бази даних MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fsystem-databases","06.databases\u002F02.ms-sql-server-start\u002F03.system-databases",{"title":2919,"path":2920,"stem":2921},"Огляд мови SQL та запитів","\u002Fdatabases\u002Fms-sql-server-start\u002Fsql-queries-overview","06.databases\u002F02.ms-sql-server-start\u002F04.sql-queries-overview",{"title":2923,"icon":2865,"path":2924,"stem":2925,"children":2926,"page":59},"SQL","\u002Fdatabases\u002Fsql","06.databases\u002F03.sql",[2927,2931,2935,2939,2943,2947,2951,2955],{"title":2928,"path":2929,"stem":2930},"Налаштування демонстраційної бази даних","\u002Fdatabases\u002Fsql\u002Fsample-database-setup","06.databases\u002F03.sql\u002F00.sample-database-setup",{"title":2932,"path":2933,"stem":2934},"DDL - Створення таблиць (CREATE TABLE)","\u002Fdatabases\u002Fsql\u002Fddl-create-table","06.databases\u002F03.sql\u002F01.ddl-create-table",{"title":2936,"path":2937,"stem":2938},"DDL - Зміна та видалення таблиць (ALTER, DROP)","\u002Fdatabases\u002Fsql\u002Fddl-alter-drop-table","06.databases\u002F03.sql\u002F02.ddl-alter-drop-table",{"title":2940,"path":2941,"stem":2942},"SELECT запити - Основи","\u002Fdatabases\u002Fsql\u002Fselect-queries-fundamentals","06.databases\u002F03.sql\u002F03.select-queries-fundamentals",{"title":2944,"path":2945,"stem":2946},"SELECT запити - Розширені можливості","\u002Fdatabases\u002Fsql\u002Fselect-queries-advanced","06.databases\u002F03.sql\u002F04.select-queries-advanced",{"title":2948,"path":2949,"stem":2950},"INSERT запити - Додавання даних","\u002Fdatabases\u002Fsql\u002Finsert-queries","06.databases\u002F03.sql\u002F05.insert-queries",{"title":2952,"path":2953,"stem":2954},"UPDATE та DELETE запити","\u002Fdatabases\u002Fsql\u002Fupdate-delete-queries","06.databases\u002F03.sql\u002F06.update-delete-queries",{"title":2956,"path":2957,"stem":2958},"Транзакції в SQL","\u002Fdatabases\u002Fsql\u002Ftransactions","06.databases\u002F03.sql\u002F07.transactions",{"title":2960,"icon":2865,"path":2961,"stem":2962,"children":2963,"page":59},"Multi Table Databases","\u002Fdatabases\u002Fmulti-table-databases","06.databases\u002F04.multi-table-databases",[2964,2968,2972,2976,2980,2984],{"title":2965,"path":2966,"stem":2967},"Зв'язки та нормалізація БД","\u002Fdatabases\u002Fmulti-table-databases\u002Frelationships-and-normalization","06.databases\u002F04.multi-table-databases\u002F00.relationships-and-normalization",{"title":2969,"path":2970,"stem":2971},"INNER JOIN - З'єднання таблиць","\u002Fdatabases\u002Fmulti-table-databases\u002Finner-join","06.databases\u002F04.multi-table-databases\u002F01.inner-join",{"title":2973,"path":2974,"stem":2975},"OUTER JOINs - LEFT, RIGHT, FULL","\u002Fdatabases\u002Fmulti-table-databases\u002Fouter-joins","06.databases\u002F04.multi-table-databases\u002F02.outer-joins",{"title":2977,"path":2978,"stem":2979},"CROSS та SELF JOINs","\u002Fdatabases\u002Fmulti-table-databases\u002Fcross-self-joins","06.databases\u002F04.multi-table-databases\u002F03.cross-self-joins",{"title":2981,"path":2982,"stem":2983},"Підзапити (Subqueries)","\u002Fdatabases\u002Fmulti-table-databases\u002Fsubqueries","06.databases\u002F04.multi-table-databases\u002F04.subqueries",{"title":2985,"path":2986,"stem":2987},"Агрегації з JOIN","\u002Fdatabases\u002Fmulti-table-databases\u002Faggregations-with-joins","06.databases\u002F04.multi-table-databases\u002F05.aggregations-with-joins",{"title":2989,"icon":2990,"path":2991,"stem":2992,"children":2993,"page":59},"Aggregate Functions","i-lucide-calculator","\u002Fdatabases\u002Faggregate-functions","06.databases\u002F05.aggregate-functions",[2994,2998,3002],{"title":2995,"path":2996,"stem":2997},"Функції агрегування в MS SQL Server","\u002Fdatabases\u002Faggregate-functions\u002Fintroduction-aggregate-functions","06.databases\u002F05.aggregate-functions\u002F01.introduction-aggregate-functions",{"title":2999,"path":3000,"stem":3001},"Групування даних в MS SQL Server","\u002Fdatabases\u002Faggregate-functions\u002Fgrouping-data","06.databases\u002F05.aggregate-functions\u002F02.grouping-data",{"title":3003,"path":3004,"stem":3005},"Підзапити з агрегатними функціями","\u002Fdatabases\u002Faggregate-functions\u002Fsubqueries-aggregates","06.databases\u002F05.aggregate-functions\u002F03.subqueries-aggregates",{"title":3007,"icon":3008,"path":3009,"stem":3010,"children":3011,"page":59},"Тригери та зберігаємі процедури","i-lucide-database-zap","\u002Fdatabases\u002Ftriggers-stored-procedures","06.databases\u002F07.triggers-stored-procedures",[3012,3016,3020,3024,3028,3032,3036],{"title":3013,"path":3014,"stem":3015},"DML-тригери","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fdml-triggers","06.databases\u002F07.triggers-stored-procedures\u002F01.dml-triggers",{"title":3017,"path":3018,"stem":3019},"DDL-тригери","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fddl-triggers","06.databases\u002F07.triggers-stored-procedures\u002F02.ddl-triggers",{"title":3021,"path":3022,"stem":3023},"Transact-SQL розширення","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Ftransact-sql-extensions","06.databases\u002F07.triggers-stored-procedures\u002F03.transact-sql-extensions",{"title":3025,"path":3026,"stem":3027},"Транзакції","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Ftransactions","06.databases\u002F07.triggers-stored-procedures\u002F04.transactions",{"title":3029,"path":3030,"stem":3031},"Зберігаємі процедури","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fstored-procedures","06.databases\u002F07.triggers-stored-procedures\u002F05.stored-procedures",{"title":3033,"path":3034,"stem":3035},"Користувацькі функції","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fuser-defined-functions","06.databases\u002F07.triggers-stored-procedures\u002F06.user-defined-functions",{"title":3037,"path":3038,"stem":3039},"Безпека баз даних","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fsecurity","06.databases\u002F07.triggers-stored-procedures\u002F08.security",{"title":3037,"icon":793,"path":3041,"stem":3042,"children":3043,"page":59},"\u002Fdatabases\u002Fsecurity","06.databases\u002F08.security",[3044,3048],{"title":3045,"path":3046,"stem":3047},"Вступ до безпеки баз даних","\u002Fdatabases\u002Fsecurity\u002Fintroduction","06.databases\u002F08.security\u002F01.introduction",{"title":3049,"path":3050,"stem":3051},"Системні представлення та метадані","\u002Fdatabases\u002Fsecurity\u002Fsystem-views","06.databases\u002F08.security\u002F02.system-views",{"title":3053,"icon":3054,"path":3055,"stem":3056,"children":3057,"page":59},"Резервне копіювання та відновлення","i-lucide-database-backup","\u002Fdatabases\u002Fbackup-recovery","06.databases\u002F09.backup-recovery",[3058],{"title":3053,"path":3059,"stem":3060},"\u002Fdatabases\u002Fbackup-recovery\u002Fbackup-restore","06.databases\u002F09.backup-recovery\u002F01.backup-restore",{"title":3062,"icon":3063,"path":3064,"stem":3065,"children":3066,"page":59},"Повнотекстовий пошук","i-lucide-search","\u002Fdatabases\u002Ffull-text-search","06.databases\u002F10.full-text-search",[3067],{"title":3062,"path":3068,"stem":3069},"\u002Fdatabases\u002Ffull-text-search\u002Ffull-text-search","06.databases\u002F10.full-text-search\u002F01.full-text-search",{"title":3071,"icon":3072,"path":3073,"stem":3074,"children":3075,"page":59},"Tools","i-lucide-wrench","\u002Ftools","07.tools",[3076,3152],{"title":3077,"icon":3078,"path":3079,"stem":3080,"children":3081},"Docker","i-simple-icons-docker","\u002Ftools\u002Fdocker","07.tools\u002F01.docker\u002Findex",[3082,3084,3088,3092,3096,3100,3104,3108,3112,3116,3120,3124,3128,3132,3136,3140,3144,3148],{"title":3083,"path":3079,"stem":3080},"Docker: від нуля до production",{"title":3085,"path":3086,"stem":3087},"Контейнеризація — від проблеми до рішення","\u002Ftools\u002Fdocker\u002Fcontainerization-concept","07.tools\u002F01.docker\u002F01.containerization-concept",{"title":3089,"path":3090,"stem":3091},"Docker — що це і навіщо?","\u002Ftools\u002Fdocker\u002Fdocker-what-and-why","07.tools\u002F01.docker\u002F02.docker-what-and-why",{"title":3093,"path":3094,"stem":3095},"Архітектура Docker Engine","\u002Ftools\u002Fdocker\u002Fdocker-architecture","07.tools\u002F01.docker\u002F03.docker-architecture",{"title":3097,"path":3098,"stem":3099},"Встановлення Docker","\u002Ftools\u002Fdocker\u002Finstallation","07.tools\u002F01.docker\u002F04.installation",{"title":3101,"path":3102,"stem":3103},"Перший контейнер — docker run","\u002Ftools\u002Fdocker\u002Ffirst-container","07.tools\u002F01.docker\u002F05.first-container",{"title":3105,"path":3106,"stem":3107},"Життєвий цикл контейнера","\u002Ftools\u002Fdocker\u002Fcontainer-lifecycle","07.tools\u002F01.docker\u002F06.container-lifecycle",{"title":3109,"path":3110,"stem":3111},"Docker Images — фундаментальні концепції","\u002Ftools\u002Fdocker\u002Fdocker-images-fundamentals","07.tools\u002F01.docker\u002F07.docker-images-fundamentals",{"title":3113,"path":3114,"stem":3115},"Dockerfile — основи","\u002Ftools\u002Fdocker\u002Fdockerfile-basics","07.tools\u002F01.docker\u002F08.dockerfile-basics",{"title":3117,"path":3118,"stem":3119},"Dockerfile — просунуті техніки","\u002Ftools\u002Fdocker\u002Fdockerfile-advanced","07.tools\u002F01.docker\u002F09.dockerfile-advanced",{"title":3121,"path":3122,"stem":3123},"Build Context та кешування шарів","\u002Ftools\u002Fdocker\u002Fbuild-context-and-cache","07.tools\u002F01.docker\u002F10.build-context-and-cache",{"title":3125,"path":3126,"stem":3127},"Реєстри Docker-образів","\u002Ftools\u002Fdocker\u002Fimage-registries","07.tools\u002F01.docker\u002F11.image-registries",{"title":3129,"path":3130,"stem":3131},"Контейнеризація .NET додатків","\u002Ftools\u002Fdocker\u002Fdotnet-containerization","07.tools\u002F01.docker\u002F12.dotnet-containerization",{"title":3133,"path":3134,"stem":3135},"Томи та збереження даних","\u002Ftools\u002Fdocker\u002Fvolumes-and-data","07.tools\u002F01.docker\u002F13.volumes-and-data",{"title":3137,"path":3138,"stem":3139},"Основи мережі в Docker","\u002Ftools\u002Fdocker\u002Fnetworking-basics","07.tools\u002F01.docker\u002F14.networking-basics",{"title":3141,"path":3142,"stem":3143},"Змінні оточення та конфігурація","\u002Ftools\u002Fdocker\u002Fenvironment-and-configuration","07.tools\u002F01.docker\u002F15.environment-and-configuration",{"title":3145,"path":3146,"stem":3147},"Docker Compose — оркестрація контейнерів","\u002Ftools\u002Fdocker\u002Fdocker-compose-basics","07.tools\u002F01.docker\u002F16.docker-compose-basics",{"title":3149,"path":3150,"stem":3151},"Docker Compose — Multi-Service застосунки","\u002Ftools\u002Fdocker\u002Fcompose-multi-service","07.tools\u002F01.docker\u002F17.compose-multi-service",{"title":3153,"icon":3154,"path":3155,"stem":3156,"children":3157},"Kubernetes","simple-icons:kubernetes","\u002Ftools\u002Fkubernetes","07.tools\u002F02.kubernetes\u002Findex",[3158,3160,3164,3168,3172,3176,3180,3184,3188],{"title":3159,"path":3155,"stem":3156},"Kubernetes: від розробки до production",{"title":3161,"path":3162,"stem":3163},"Kubernetes — коли Docker Compose більше не вистачає","\u002Ftools\u002Fkubernetes\u002Fwhy-kubernetes","07.tools\u002F02.kubernetes\u002F01.why-kubernetes",{"title":3165,"path":3166,"stem":3167},"Архітектура Kubernetes — анатомія кластера","\u002Ftools\u002Fkubernetes\u002Fkubernetes-architecture","07.tools\u002F02.kubernetes\u002F02.kubernetes-architecture",{"title":3169,"path":3170,"stem":3171},"Локальне середовище — minikube, kind та k3s","\u002Ftools\u002Fkubernetes\u002Flocal-environment","07.tools\u002F02.kubernetes\u002F03.local-environment",{"title":3173,"path":3174,"stem":3175},"Pod — атомарна одиниця Kubernetes","\u002Ftools\u002Fkubernetes\u002Fpods-and-containers","07.tools\u002F02.kubernetes\u002F04.pods-and-containers",{"title":3177,"path":3178,"stem":3179},"Патерни використання Pod","\u002Ftools\u002Fkubernetes\u002Fpod-patterns","07.tools\u002F02.kubernetes\u002F05.pod-patterns",{"title":3181,"path":3182,"stem":3183},"Deployment — декларативне управління Pod","\u002Ftools\u002Fkubernetes\u002Fdeployment-basics","07.tools\u002F02.kubernetes\u002F06.deployment-basics",{"title":3185,"path":3186,"stem":3187},"Rolling Updates та управління життєвим циклом Deployment","\u002Ftools\u002Fkubernetes\u002Fdeployment-rolling-updates","07.tools\u002F02.kubernetes\u002F07.deployment-rolling-updates",{"title":3189,"path":3190,"stem":3191},"Service — мережева абстракція для Pod","\u002Ftools\u002Fkubernetes\u002Fservices-networking","07.tools\u002F02.kubernetes\u002F08.services-networking",{"title":3193,"icon":3194,"path":3195,"stem":3196,"children":3197,"page":59},"Software Engineering","i-lucide-code-2","\u002Fsoftware-engineering","09.software-engineering",[3198,3202,3206,3210,3214,3218,3222,3226,3230,3234,3238],{"title":3199,"path":3200,"stem":3201},"1. Аналіз предметної області. Експертні знання та складність","\u002Fsoftware-engineering\u002Fintro-subdomains","09.software-engineering\u002F01.intro-subdomains",{"title":3203,"path":3204,"stem":3205},"2. Обмежені контексти. Інтеграція обмежених контекстів","\u002Fsoftware-engineering\u002Fintegrating-limited-contexts","09.software-engineering\u002F02.integrating-limited-contexts",{"title":3207,"path":3208,"stem":3209},"3. Реалізація простої бізнес-логіки","\u002Fsoftware-engineering\u002Fsimple","09.software-engineering\u002F03.simple",{"title":3211,"path":3212,"stem":3213},"4. Опрацювання складної бізнес-логіки","\u002Fsoftware-engineering\u002Fcomplex-business-logic","09.software-engineering\u002F04.complex-business-logic",{"title":3215,"path":3216,"stem":3217},"5. Моделювання фактора часу. Подієво-орієнтована архітектура.","\u002Fsoftware-engineering\u002Fmodelling-the-time-factor","09.software-engineering\u002F05.modelling-the-time-factor",{"title":3219,"path":3220,"stem":3221},"6. Архітектурні патерни","\u002Fsoftware-engineering\u002Farchitectural-patterns","09.software-engineering\u002F06.architectural-patterns",{"title":3223,"path":3224,"stem":3225},"Паттерни взаємодії","\u002Fsoftware-engineering\u002Fpatterns-of-interaction","09.software-engineering\u002F07.patterns-of-interaction",{"title":3227,"path":3228,"stem":3229},"Евристика проєктування","\u002Fsoftware-engineering\u002Fdesign-heuristics","09.software-engineering\u002F08.design-heuristics",{"title":3231,"path":3232,"stem":3233},"Еволюція проєктних рішень","\u002Fsoftware-engineering\u002Fevolution-of-design-solutions","09.software-engineering\u002F09.evolution-of-design-solutions",{"title":3235,"path":3236,"stem":3237},"EventStorming","\u002Fsoftware-engineering\u002Feventstorming","09.software-engineering\u002F10.eventstorming",{"title":3239,"path":3240,"stem":3241},"DDD на практиці","\u002Fsoftware-engineering\u002Fddd-in-practice","09.software-engineering\u002F11.ddd-in-practice",{"title":3243,"icon":943,"path":3244,"stem":3245,"children":3246,"page":59},"DDD","\u002Fddd","10.ddd",[3247,3251,3255,3259,3263,3267,3271,3275,3279,3283,3287,3291,3295],{"title":3248,"path":3249,"stem":3250},"Аналіз предметної області","\u002Fddd\u002Fdomain-analysis","10.ddd\u002F01.domain-analysis",{"title":3252,"path":3253,"stem":3254},"Експертні знання про предметну область","\u002Fddd\u002Fdomain-expert-knowledge","10.ddd\u002F02.domain-expert-knowledge",{"title":3256,"path":3257,"stem":3258},"Як осмислити складність предметної області","\u002Fddd\u002Fmanaging-domain-complexity","10.ddd\u002F03.managing-domain-complexity",{"title":3260,"path":3261,"stem":3262},"Інтеграція обмежених контекстів","\u002Fddd\u002Fbounded-context-integration","10.ddd\u002F04.bounded-context-integration",{"title":3264,"path":3265,"stem":3266},"Реалізація простої бізнес-логіки","\u002Fddd\u002Fsimple-business-logic","10.ddd\u002F05.simple-business-logic",{"title":3268,"path":3269,"stem":3270},"Обробка складної бізнес-логіки","\u002Fddd\u002Fcomplex-business-logic","10.ddd\u002F06.complex-business-logic",{"title":3272,"path":3273,"stem":3274},"Моделювання фактора часу","\u002Fddd\u002Ftime-modeling","10.ddd\u002F07.time-modeling",{"title":3276,"path":3277,"stem":3278},"Глава 8. Архітектурні Патерни","\u002Fddd\u002Farchitectural-patterns","10.ddd\u002F08.architectural-patterns",{"title":3280,"path":3281,"stem":3282},"Глава 9. Патерни Взаємодії","\u002Fddd\u002Finteraction-patterns","10.ddd\u002F09.interaction-patterns",{"title":3284,"path":3285,"stem":3286},"Глава 10. Проектні Евристики","\u002Fddd\u002Fdesign-heuristics","10.ddd\u002F10.design-heuristics",{"title":3288,"path":3289,"stem":3290},"Глава 11. Еволюція Проектних Рішень","\u002Fddd\u002Fevolution-of-design-decisions","10.ddd\u002F11.evolution-of-design-decisions",{"title":3292,"path":3293,"stem":3294},"Глава 12. EventStorming","\u002Fddd\u002Fevent-storming","10.ddd\u002F12.event-storming",{"title":3296,"path":3297,"stem":3298},"Глава 13. DDD на Практиці","\u002Fddd\u002Fddd-in-practice","10.ddd\u002F13.ddd-in-practice",{"title":3300,"icon":3301,"path":3302,"stem":3303,"children":3304,"page":59},"Media Streaming","i-lucide-video","\u002Fmedia-streaming","11.media-streaming",[3305,3309,3313,3317,3321,3325,3329],{"title":3306,"path":3307,"stem":3308},"01. Магія Стрімінгу: Що відбувається, коли ви натискаєте \"Play\"","\u002Fmedia-streaming\u002Fintroduction","11.media-streaming\u002F01.introduction",{"title":3310,"path":3311,"stem":3312},"02. Анатомія Медіа: Кодеки, Контейнери та Стиснення","\u002Fmedia-streaming\u002Faudio-video-anatomy","11.media-streaming\u002F02.audio-video-anatomy",{"title":3314,"path":3315,"stem":3316},"03. The Gym: FFmpeg Deep Dive","\u002Fmedia-streaming\u002Fffmpeg-gym","11.media-streaming\u002F03.ffmpeg-gym",{"title":3318,"path":3319,"stem":3320},"04. HLS Protocol: HTTP Live Streaming у Деталях","\u002Fmedia-streaming\u002Fhls-protocol","11.media-streaming\u002F04.hls-protocol",{"title":3322,"path":3323,"stem":3324},"05. DASH Protocol: Відкритий Стандарт","\u002Fmedia-streaming\u002Fdash-protocol","11.media-streaming\u002F05.dash-protocol",{"title":3326,"path":3327,"stem":3328},"06. Масштабування: CDN та Adaptive Bitrate","\u002Fmedia-streaming\u002Fcdn-and-adaptive-bitrate","11.media-streaming\u002F06.cdn-and-adaptive-bitrate",{"title":3330,"path":3331,"stem":3332},"07. Війна із Затримкою (Latency)","\u002Fmedia-streaming\u002Frealtime-latency","11.media-streaming\u002F07.realtime-latency",{"title":3334,"icon":3335,"path":3336,"stem":3337,"children":3338,"page":59},"HTML & CSS","i-devicon-html5","\u002Fhtml-css","12.html-css",[3339,3343,3347,3351,3355,3359,3363,3367,3371,3375,3379,3383,3387,3391,3395,3399,3403,3407,3411,3415,3419,3423,3427,3431,3435,3439,3443,3447,3451,3455],{"title":3340,"path":3341,"stem":3342},"Вступ до HTML. Структура документа","\u002Fhtml-css\u002Fintro-html-structure","12.html-css\u002F01.intro-html-structure",{"title":3344,"path":3345,"stem":3346},"Форматування тексту в HTML","\u002Fhtml-css\u002Fhtml-text-formatting","12.html-css\u002F02.html-text-formatting",{"title":3348,"path":3349,"stem":3350},"Посилання та зображення в HTML","\u002Fhtml-css\u002Fhtml-links-images","12.html-css\u002F03.html-links-images",{"title":3352,"path":3353,"stem":3354},"Списки та таблиці в HTML","\u002Fhtml-css\u002Fhtml-lists-tables","12.html-css\u002F04.html-lists-tables",{"title":3356,"path":3357,"stem":3358},"Форми в HTML","\u002Fhtml-css\u002Fhtml-forms","12.html-css\u002F05.html-forms",{"title":3360,"path":3361,"stem":3362},"Семантичні елементи HTML5","\u002Fhtml-css\u002Fhtml-semantic-elements","12.html-css\u002F06.html-semantic-elements",{"title":3364,"path":3365,"stem":3366},"Мультимедіа та розширені елементи HTML","\u002Fhtml-css\u002Fhtml-multimedia-advanced","12.html-css\u002F07.html-multimedia-advanced",{"title":3368,"path":3369,"stem":3370},"Мікророзмітка та SEO в HTML","\u002Fhtml-css\u002Fhtml-microdata-seo","12.html-css\u002F08.html-microdata-seo",{"title":3372,"path":3373,"stem":3374},"Вступ до CSS. Селектори та специфічність","\u002Fhtml-css\u002Fcss-intro-selectors","12.html-css\u002F09.css-intro-selectors",{"title":3376,"path":3377,"stem":3378},"Блокова модель CSS. Відступи. Box Sizing","\u002Fhtml-css\u002Fcss-box-model","12.html-css\u002F10.css-box-model",{"title":3380,"path":3381,"stem":3382},"Розміри у CSS: повний довідник одиниць і ключових слів","\u002Fhtml-css\u002F10a.css-sizing","12.html-css\u002F10a.css-sizing",{"title":3384,"path":3385,"stem":3386},"Типографіка в CSS. Шрифти та текст","\u002Fhtml-css\u002Fcss-typography","12.html-css\u002F11.css-typography",{"title":3388,"path":3389,"stem":3390},"Кольори та фони в CSS","\u002Fhtml-css\u002Fcss-colors-backgrounds","12.html-css\u002F12.css-colors-backgrounds",{"title":3392,"path":3393,"stem":3394},"Тіні та фільтри в CSS","\u002Fhtml-css\u002F12b.css-shadows-filters","12.html-css\u002F12b.css-shadows-filters",{"title":3396,"path":3397,"stem":3398},"CSS Flexbox: Фундамент гнучких макетів","\u002Fhtml-css\u002Fcss-flexbox-fundamentals","12.html-css\u002F13.css-flexbox-fundamentals",{"title":3400,"path":3401,"stem":3402},"CSS Flexbox: Вирівнювання та Позиціонування","\u002Fhtml-css\u002Fcss-flexbox-alignment-sizing-and-patterns","12.html-css\u002F14.css-flexbox-alignment-sizing-and-patterns",{"title":3404,"path":3405,"stem":3406},"CSS Grid. Двовимірний макет. Частина 1","\u002Fhtml-css\u002Fcss-layout-grid","12.html-css\u002F15.css-layout-grid",{"title":3408,"path":3409,"stem":3410},"CSS Grid. Двовимірний макет. Частина 2","\u002Fhtml-css\u002Fcss-layout-grid-advanced","12.html-css\u002F16.css-layout-grid-advanced",{"title":3412,"path":3413,"stem":3414},"Позиціонування в CSS. Z-index. Stacking Context","\u002Fhtml-css\u002Fcss-positioning","12.html-css\u002F17.css-positioning",{"title":3416,"path":3417,"stem":3418},"CSS Анімації та Переходи","\u002Fhtml-css\u002Fcss-animations-transitions","12.html-css\u002F18.css-animations-transitions",{"title":3420,"path":3421,"stem":3422},"Адаптивний дизайн. Media Queries. Частина 1","\u002Fhtml-css\u002Fcss-responsive-media-queries","12.html-css\u002F19.css-responsive-media-queries",{"title":3424,"path":3425,"stem":3426},"Адаптивний дизайн. Частина 2: clamp(), Container Queries, @layer","\u002Fhtml-css\u002Fcss-responsive-advanced","12.html-css\u002F20.css-responsive-advanced",{"title":3428,"path":3429,"stem":3430},"CSS Custom Properties. Методології. Сучасний CSS","\u002Fhtml-css\u002Fcss-variables-methodologies","12.html-css\u002F21.css-variables-methodologies",{"title":3432,"path":3433,"stem":3434},"Сучасний CSS 2023–2025: Нові можливості","\u002Fhtml-css\u002Fcss-modern-features","12.html-css\u002F22.css-modern-features",{"title":3436,"path":3437,"stem":3438},"CSS Nesting, @layer, @scope та @property: нативний препроцесор","\u002Fhtml-css\u002F22a.css-nesting-modern-syntax","12.html-css\u002F22a.css-nesting-modern-syntax",{"title":3440,"path":3441,"stem":3442},"CSS для форм та інтерактивних станів","\u002Fhtml-css\u002Fcss-forms-interactive-states","12.html-css\u002F23.css-forms-interactive-states",{"title":3444,"path":3445,"stem":3446},"Доступність у CSS (CSS Accessibility)","\u002Fhtml-css\u002Fcss-accessibility","12.html-css\u002F24.css-accessibility",{"title":3448,"path":3449,"stem":3450},"CSS-функції та сучасні sizing primitives","\u002Fhtml-css\u002Fcss-functions-sizing","12.html-css\u002F25.css-functions-sizing",{"title":3452,"path":3453,"stem":3454},"Rendering Pipeline і CSS Performance","\u002Fhtml-css\u002Fcss-rendering-performance","12.html-css\u002F26.css-rendering-performance",{"title":3456,"path":3457,"stem":3458},"CSS Best Practices: типові ситуації та правильні рішення","\u002Fhtml-css\u002Fcss-best-practices","12.html-css\u002F27.css-best-practices",{"title":3460,"path":3461,"stem":3462,"children":3463,"page":59},"AWS","\u002Faws","13.aws",[3464,3468,3472,3476,3480,3484,3488,3492,3496,3500,3504,3508,3512,3516,3520,3524,3528,3532],{"title":3465,"path":3466,"stem":3467},"Реєстрація AWS акаунту та студентські програми","\u002Faws\u002Faccount-registration","13.aws\u002F00.account-registration",{"title":3469,"path":3470,"stem":3471},"Вступ до хмарних обчислень та AWS","\u002Faws\u002Fintroduction-to-cloud","13.aws\u002F01.introduction-to-cloud",{"title":3473,"path":3474,"stem":3475},"AWS IAM — Identity and Access Management","\u002Faws\u002Fiam","13.aws\u002F02.iam",{"title":3477,"path":3478,"stem":3479},"AWS IAM CLI — Довідник команд","\u002Faws\u002F02a.iam-doc","13.aws\u002F02a.iam-doc",{"title":3481,"path":3482,"stem":3483},"Docker та контейнеризація в AWS — ECR, ECS та Fargate","\u002Faws\u002Fdocker-ecs","13.aws\u002F03.docker-ecs",{"title":3485,"path":3486,"stem":3487},"AWS ECR \u002F ECS CLI — Довідник команд","\u002Faws\u002F03a.docker-ecs-doc","13.aws\u002F03a.docker-ecs-doc",{"title":3489,"path":3490,"stem":3491},"Amazon EC2 — Elastic Compute Cloud","\u002Faws\u002Fec2","13.aws\u002F04.ec2",{"title":3493,"path":3494,"stem":3495},"AWS EC2 CLI — Довідник команд","\u002Faws\u002F04a.ec2-doc","13.aws\u002F04a.ec2-doc",{"title":3497,"path":3498,"stem":3499},"Elastic Load Balancing та Auto Scaling","\u002Faws\u002Falb-asg","13.aws\u002F05.alb-asg",{"title":3501,"path":3502,"stem":3503},"Amazon S3 — Simple Storage Service","\u002Faws\u002Fs3","13.aws\u002F06.s3",{"title":3505,"path":3506,"stem":3507},"Amazon CloudFront — Content Delivery Network","\u002Faws\u002Fcloudfront","13.aws\u002F07.cloudfront",{"title":3509,"path":3510,"stem":3511},"Amazon RDS — Relational Database Service","\u002Faws\u002Frds","13.aws\u002F08.rds",{"title":3513,"path":3514,"stem":3515},"Amazon DynamoDB — NoSQL Database","\u002Faws\u002Fdynamodb","13.aws\u002F09.dynamodb",{"title":3517,"path":3518,"stem":3519},"AWS Lambda та Serverless Compute","\u002Faws\u002Flambda","13.aws\u002F10.lambda",{"title":3521,"path":3522,"stem":3523},"Amazon Bedrock - Foundation Models, RAG та Agents","\u002Faws\u002Fbedrock","13.aws\u002F22.bedrock",{"title":3525,"path":3526,"stem":3527},"Amazon Rekognition - Комп'ютерний зір","\u002Faws\u002Frekognition","13.aws\u002F23.rekognition",{"title":3529,"path":3530,"stem":3531},"Amazon Textract - Інтелектуальний аналіз документів","\u002Faws\u002Ftextract","13.aws\u002F24.textract",{"title":3533,"path":3534,"stem":3535},"Amazon Polly, Transcribe, Comprehend та Translate","\u002Faws\u002Faudio-nlp-services","13.aws\u002F25.audio-nlp-services",{"title":3537,"path":3538,"stem":3539,"children":3540,"page":59},"Ai Development","\u002Fai-development","14.ai-development",[3541],{"title":3542,"path":3543,"stem":3544,"children":3545,"page":59},"Foundations","\u002Fai-development\u002Ffoundations","14.ai-development\u002F00.foundations",[3546],{"title":3547,"path":3548,"stem":3549},"Модуль 0.1. Що таке Large Language Model (LLM)","\u002Fai-development\u002Ffoundations\u002Fwhat-is-llm","14.ai-development\u002F00.foundations\u002F01.what-is-llm",{"title":3551,"path":3552,"stem":3553,"children":3554,"page":59},"React Native","\u002Freact-native","15.react-native",[3555,3576],{"title":3556,"path":3557,"stem":3558,"children":3559,"page":59},"Version1","\u002Freact-native\u002Fversion1","15.react-native\u002Fversion1",[3560,3564,3568,3572],{"title":3561,"path":3562,"stem":3563},"Що таке React Native","\u002Freact-native\u002Fversion1\u002Fwhat-is-react-native","15.react-native\u002Fversion1\u002F01.what-is-react-native",{"title":3565,"path":3566,"stem":3567},"Як влаштований React Native «під капотом»","\u002Freact-native\u002Fversion1\u002Freact-native-architecture","15.react-native\u002Fversion1\u002F02.react-native-architecture",{"title":3569,"path":3570,"stem":3571},"Від React до React Native: ключові відмінності","\u002Freact-native\u002Fversion1\u002Freact-native-vs-react","15.react-native\u002Fversion1\u002F03.react-native-vs-react",{"title":3573,"path":3574,"stem":3575},"View та Text — фундаментальні будівельні блоки","\u002Freact-native\u002Fversion1\u002Fview-and-text","15.react-native\u002Fversion1\u002F04.view-and-text",{"title":3577,"path":3578,"stem":3579,"children":3580,"page":59},"Version2","\u002Freact-native\u002Fversion2","15.react-native\u002Fversion2",[3581,3585,3589,3593,3597,3601,3605,3609,3613,3617,3621,3625,3629,3633,3637,3641,3645,3649,3653,3657,3661,3665,3669,3673,3677,3681,3685],{"title":3582,"path":3583,"stem":3584},"React Native — навіщо він потрібен","\u002Freact-native\u002Fversion2\u002Fwhy-react-native","15.react-native\u002Fversion2\u002F01.why-react-native",{"title":3586,"path":3587,"stem":3588},"Налаштування середовища розробки","\u002Freact-native\u002Fversion2\u002Fenvironment-setup","15.react-native\u002Fversion2\u002F02.environment-setup",{"title":3590,"path":3591,"stem":3592},"Expo і класичний React Native — два шляхи одного фреймворку","\u002Freact-native\u002Fversion2\u002Fexpo-vs-cli-landscape","15.react-native\u002Fversion2\u002F03.expo-vs-cli-landscape",{"title":3594,"path":3595,"stem":3596},"Середовище Expo — перший запуск","\u002Freact-native\u002Fversion2\u002Fexpo-setup-and-tooling","15.react-native\u002Fversion2\u002F04.expo-setup-and-tooling",{"title":3598,"path":3599,"stem":3600},"Структура проєкту та перші UI-примітиви","\u002Freact-native\u002Fversion2\u002Fproject-structure-and-conventions","15.react-native\u002Fversion2\u002F05.project-structure-and-conventions",{"title":3602,"path":3603,"stem":3604},"Базові компоненти React Native","\u002Freact-native\u002Fversion2\u002Fcore-components","15.react-native\u002Fversion2\u002F06.core-components",{"title":3606,"path":3607,"stem":3608},"Flexbox і layout у React Native","\u002Freact-native\u002Fversion2\u002Fflexbox-and-layout","15.react-native\u002Fversion2\u002F07.flexbox-and-layout",{"title":3610,"path":3611,"stem":3612},"StyleSheet і теми (light \u002F dark)","\u002Freact-native\u002Fversion2\u002Fstylesheet-and-theming","15.react-native\u002Fversion2\u002F08.stylesheet-and-theming",{"title":3614,"path":3615,"stem":3616},"Списки та віртуалізація","\u002Freact-native\u002Fversion2\u002Flists-and-virtualization","15.react-native\u002Fversion2\u002F09.lists-and-virtualization",{"title":3618,"path":3619,"stem":3620},"Форми, ввід і валідація","\u002Freact-native\u002Fversion2\u002Fforms-input-validation","15.react-native\u002Fversion2\u002F10.forms-input-validation",{"title":3622,"path":3623,"stem":3624},"Основи Expo Router","\u002Freact-native\u002Fversion2\u002Fexpo-router-basics","15.react-native\u002Fversion2\u002F11.expo-router-basics",{"title":3626,"path":3627,"stem":3628},"Вкладені навігатори та модалки","\u002Freact-native\u002Fversion2\u002Fnested-navigators-and-modals","15.react-native\u002Fversion2\u002F12.nested-navigators-and-modals",{"title":3630,"path":3631,"stem":3632},"Deep linking і параметри маршрутів","\u002Freact-native\u002Fversion2\u002Fdeep-linking-and-params","15.react-native\u002Fversion2\u002F13.deep-linking-and-params",{"title":3634,"path":3635,"stem":3636},"Робота з мережею та життєвий цикл застосунку","\u002Freact-native\u002Fversion2\u002Fnetworking-and-app-lifecycle","15.react-native\u002Fversion2\u002F14.networking-and-app-lifecycle",{"title":3638,"path":3639,"stem":3640},"Redux Toolkit на мобільних платформах","\u002Freact-native\u002Fversion2\u002Fredux-toolkit-on-mobile","15.react-native\u002Fversion2\u002F15.redux-toolkit-on-mobile",{"title":3642,"path":3643,"stem":3644},"RTK Query на мобільних платформах","\u002Freact-native\u002Fversion2\u002Frtk-query-mobile","15.react-native\u002Fversion2\u002F16.rtk-query-mobile",{"title":3646,"path":3647,"stem":3648},"Автентифікація та Безпечне Зберігання","\u002Freact-native\u002Fversion2\u002Fauth-secure-storage","15.react-native\u002Fversion2\u002F18.auth-secure-storage",{"title":3650,"path":3651,"stem":3652},"Локальне сховище — AsyncStorage, MMKV, SQLite","\u002Freact-native\u002Fversion2\u002Flocal-storage-mmkv-sqlite","15.react-native\u002Fversion2\u002F19.local-storage-mmkv-sqlite",{"title":3654,"path":3655,"stem":3656},"Офлайн-First і синхронізація","\u002Freact-native\u002Fversion2\u002Foffline-first-sync","15.react-native\u002Fversion2\u002F20.offline-first-sync",{"title":3658,"path":3659,"stem":3660},"Камера, медіа та файлова система","\u002Freact-native\u002Fversion2\u002Fcamera-media-filesystem","15.react-native\u002Fversion2\u002F21.camera-media-filesystem",{"title":3662,"path":3663,"stem":3664},"Карти та геолокація","\u002Freact-native\u002Fversion2\u002Fmaps-and-location","15.react-native\u002Fversion2\u002F22.maps-and-location",{"title":3666,"path":3667,"stem":3668},"Жести та дотики","\u002Freact-native\u002Fversion2\u002Fgestures-and-touch","15.react-native\u002Fversion2\u002F23.gestures-and-touch",{"title":3670,"path":3671,"stem":3672},"Анімації з Reanimated","\u002Freact-native\u002Fversion2\u002Freanimated-animations","15.react-native\u002Fversion2\u002F24.reanimated-animations",{"title":3674,"path":3675,"stem":3676},"Push і локальні сповіщення","\u002Freact-native\u002Fversion2\u002Fpush-and-local-notifications","15.react-native\u002Fversion2\u002F25.push-and-local-notifications",{"title":3678,"path":3679,"stem":3680},"Інтернаціоналізація та доступність","\u002Freact-native\u002Fversion2\u002Faccessibility-and-i18n","15.react-native\u002Fversion2\u002F26.accessibility-and-i18n",{"title":3682,"path":3683,"stem":3684},"EAS Build та профілі збірки","\u002Freact-native\u002Fversion2\u002Feas-build-and-profiles","15.react-native\u002Fversion2\u002F29.eas-build-and-profiles",{"title":3686,"path":3687,"stem":3688},"Публікація в App Store та Google Play","\u002Freact-native\u002Fversion2\u002Fapp-store-play-release","15.react-native\u002Fversion2\u002F30.app-store-play-release",{"title":3690,"path":3691,"stem":3692,"children":3693,"page":59},"Ai Python","\u002Fai-python","16.ai-python",[3694,3703,3712,3721,3750,3776,3801,3834,3851,3864,3873,3886,3895,3916,3929,3950],{"title":3695,"path":3696,"stem":3697,"children":3698,"page":59},"Intro To Ai","\u002Fai-python\u002Fintro-to-ai","16.ai-python\u002F01.intro-to-ai",[3699],{"title":3700,"path":3701,"stem":3702},"Вступ до штучного інтелекту та машинного навчання","\u002Fai-python\u002Fintro-to-ai\u002Fintro-to-ai","16.ai-python\u002F01.intro-to-ai\u002F01.intro-to-ai",{"title":3704,"path":3705,"stem":3706,"children":3707,"page":59},"Jupyter Notebook","\u002Fai-python\u002Fjupyter-notebook","16.ai-python\u002F02.jupyter-notebook",[3708],{"title":3709,"path":3710,"stem":3711},"Знайомство з Jupyter Notebook та JupyterLab","\u002Fai-python\u002Fjupyter-notebook\u002Fjupyter-notebook","16.ai-python\u002F02.jupyter-notebook\u002F02.jupyter-notebook",{"title":3713,"path":3714,"stem":3715,"children":3716,"page":59},"Numpy Pandas","\u002Fai-python\u002Fnumpy-pandas","16.ai-python\u002F03.numpy-pandas",[3717],{"title":3718,"path":3719,"stem":3720},"Робота з даними з використанням NumPy і pandas","\u002Fai-python\u002Fnumpy-pandas\u002Fnumpy-pandas","16.ai-python\u002F03.numpy-pandas\u002F03.numpy-pandas",{"title":3722,"path":3723,"stem":3724,"children":3725,"page":59},"Statistics Basics","\u002Fai-python\u002Fstatistics-basics","16.ai-python\u002F04.statistics-basics",[3726,3730,3734,3738,3742,3746],{"title":3727,"path":3728,"stem":3729},"Випадкові величини та їх типи","\u002Fai-python\u002Fstatistics-basics\u002Frandom-variables","16.ai-python\u002F04.statistics-basics\u002F01.random-variables",{"title":3731,"path":3732,"stem":3733},"Міри центральної тенденції","\u002Fai-python\u002Fstatistics-basics\u002Fcentral-tendency","16.ai-python\u002F04.statistics-basics\u002F02.central-tendency",{"title":3735,"path":3736,"stem":3737},"Міри варіації (розсіювання)","\u002Fai-python\u002Fstatistics-basics\u002Fvariability","16.ai-python\u002F04.statistics-basics\u002F03.variability",{"title":3739,"path":3740,"stem":3741},"Розподіли випадкових величин","\u002Fai-python\u002Fstatistics-basics\u002Fdistributions","16.ai-python\u002F04.statistics-basics\u002F04.distributions",{"title":3743,"path":3744,"stem":3745},"Кореляція та взаємозв'язки","\u002Fai-python\u002Fstatistics-basics\u002Fcorrelation","16.ai-python\u002F04.statistics-basics\u002F05.correlation",{"title":3747,"path":3748,"stem":3749},"Викиди та аномалії","\u002Fai-python\u002Fstatistics-basics\u002Foutliers","16.ai-python\u002F04.statistics-basics\u002F06.outliers",{"title":3751,"path":3752,"stem":3753,"children":3754},"Візуалізація даних за допомогою matplotlib","\u002Fai-python\u002Fdata-visualization","16.ai-python\u002F05.data-visualization\u002Findex",[3755,3756,3760,3764,3768,3772],{"title":3751,"path":3752,"stem":3753},{"title":3757,"path":3758,"stem":3759},"Основи matplotlib — Figure, Axes та перший графік","\u002Fai-python\u002Fdata-visualization\u002Fmatplotlib-basics","16.ai-python\u002F05.data-visualization\u002F01.matplotlib-basics",{"title":3761,"path":3762,"stem":3763},"Візуалізація розподілів — гістограми та box plots","\u002Fai-python\u002Fdata-visualization\u002Fdistributions","16.ai-python\u002F05.data-visualization\u002F02.distributions",{"title":3765,"path":3766,"stem":3767},"Візуалізація залежностей — scatter plots та кореляція","\u002Fai-python\u002Fdata-visualization\u002Frelationships","16.ai-python\u002F05.data-visualization\u002F03.relationships",{"title":3769,"path":3770,"stem":3771},"Візуалізація категоріальних даних — bar charts та pie charts","\u002Fai-python\u002Fdata-visualization\u002Fcategorical","16.ai-python\u002F05.data-visualization\u002F04.categorical",{"title":3773,"path":3774,"stem":3775},"Композиції та стилізація — subplots та багатопанельні дашборди","\u002Fai-python\u002Fdata-visualization\u002Fsubplots-styling","16.ai-python\u002F05.data-visualization\u002F05.subplots-styling",{"title":3777,"path":3778,"stem":3779,"children":3780,"page":59},"Linear Regression","\u002Fai-python\u002Flinear-regression","16.ai-python\u002F06.linear-regression",[3781,3785,3789,3793,3797],{"title":3782,"path":3783,"stem":3784},"Регресійна задача та лінійна регресія з однією змінною","\u002Fai-python\u002Flinear-regression\u002Fregression-task","16.ai-python\u002F06.linear-regression\u002F01.regression-task",{"title":3786,"path":3787,"stem":3788},"Метрики якості регресії — як оцінити модель","\u002Fai-python\u002Flinear-regression\u002Fquality-metrics","16.ai-python\u002F06.linear-regression\u002F02.quality-metrics",{"title":3790,"path":3791,"stem":3792},"Градієнтний спуск — як модель навчається","\u002Fai-python\u002Flinear-regression\u002Fgradient-descent","16.ai-python\u002F06.linear-regression\u002F03.gradient-descent",{"title":3794,"path":3795,"stem":3796},"Множинна лінійна регресія — модель з багатьма ознаками","\u002Fai-python\u002Flinear-regression\u002Fmultiple-regression","16.ai-python\u002F06.linear-regression\u002F04.multiple-regression",{"title":3798,"path":3799,"stem":3800},"Практичні завдання та резюме модуля","\u002Fai-python\u002Flinear-regression\u002Fpractice","16.ai-python\u002F06.linear-regression\u002F05.practice",{"title":3802,"path":3803,"stem":3804,"children":3805,"page":59},"Practical Regression","\u002Fai-python\u002Fpractical-regression","16.ai-python\u002F07.practical-regression",[3806,3810,3814,3818,3822,3826,3830],{"title":3807,"path":3808,"stem":3809},"Знайомство з scikit-learn","\u002Fai-python\u002Fpractical-regression\u002Fintro-scikit-learn","16.ai-python\u002F07.practical-regression\u002F01.intro-scikit-learn",{"title":3811,"path":3812,"stem":3813},"Exploratory Data Analysis датасету Housing Prices","\u002Fai-python\u002Fpractical-regression\u002Fhousing-dataset-eda","16.ai-python\u002F07.practical-regression\u002F02.housing-dataset-eda",{"title":3815,"path":3816,"stem":3817},"Попередня обробка даних (Data Preprocessing)","\u002Fai-python\u002Fpractical-regression\u002Fdata-preprocessing","16.ai-python\u002F07.practical-regression\u002F03.data-preprocessing",{"title":3819,"path":3820,"stem":3821},"Train\u002FTest Split та перша повноцінна модель","\u002Fai-python\u002Fpractical-regression\u002Ftrain-test-split","16.ai-python\u002F07.practical-regression\u002F04.train-test-split",{"title":3823,"path":3824,"stem":3825},"Перенавчання та недонавчання","\u002Fai-python\u002Fpractical-regression\u002Foverfitting-underfitting","16.ai-python\u002F07.practical-regression\u002F05.overfitting-underfitting",{"title":3827,"path":3828,"stem":3829},"Крос-валідація (Cross-Validation)","\u002Fai-python\u002Fpractical-regression\u002Fcross-validation","16.ai-python\u002F07.practical-regression\u002F06.cross-validation",{"title":3831,"path":3832,"stem":3833},"Гіперпараметри та їх оптимізація","\u002Fai-python\u002Fpractical-regression\u002Fhyperparameter-tuning","16.ai-python\u002F07.practical-regression\u002F07.hyperparameter-tuning",{"title":3835,"path":3836,"stem":3837,"children":3838,"page":59},"Polynomial Regression","\u002Fai-python\u002Fpolynomial-regression","16.ai-python\u002F08.polynomial-regression",[3839,3843,3847],{"title":3840,"path":3841,"stem":3842},"Нелінійні залежності та поліноміальна регресія","\u002Fai-python\u002Fpolynomial-regression\u002Fnonlinear-patterns","16.ai-python\u002F08.polynomial-regression\u002F01.nonlinear-patterns",{"title":3844,"path":3845,"stem":3846},"Регуляризація в регресії — Ridge та Lasso","\u002Fai-python\u002Fpolynomial-regression\u002Fregularization-methods","16.ai-python\u002F08.polynomial-regression\u002F02.regularization-methods",{"title":3848,"path":3849,"stem":3850},"Практика — поліноміальна регресія та регуляризація на Housing Prices","\u002Fai-python\u002Fpolynomial-regression\u002Fhousing-prices-practice","16.ai-python\u002F08.polynomial-regression\u002F03.housing-prices-practice",{"title":3852,"path":3853,"stem":3854,"children":3855,"page":59},"Decision Trees Random Forest","\u002Fai-python\u002Fdecision-trees-random-forest","16.ai-python\u002F09.decision-trees-random-forest",[3856,3860],{"title":3857,"path":3858,"stem":3859},"Дерева рішень — моделі з прозорою та зрозумілою логікою","\u002Fai-python\u002Fdecision-trees-random-forest\u002Fdecision-trees","16.ai-python\u002F09.decision-trees-random-forest\u002F01.decision-trees",{"title":3861,"path":3862,"stem":3863},"Random Forest — ансамблі дерев рішень","\u002Fai-python\u002Fdecision-trees-random-forest\u002Frandom-forest","16.ai-python\u002F09.decision-trees-random-forest\u002F02.random-forest",{"title":3865,"path":3866,"stem":3867,"children":3868,"page":59},"Gradient Boosting","\u002Fai-python\u002Fgradient-boosting","16.ai-python\u002F10.gradient-boosting",[3869],{"title":3870,"path":3871,"stem":3872},"Градієнтний бустинг та XGBoost — послідовне виправлення помилок","\u002Fai-python\u002Fgradient-boosting\u002Fgradient-boosting-xgboost","16.ai-python\u002F10.gradient-boosting\u002F01.gradient-boosting-xgboost",{"title":3874,"path":3875,"stem":3876,"children":3877,"page":59},"Logistic Regression Classification","\u002Fai-python\u002Flogistic-regression-classification","16.ai-python\u002F11.logistic-regression-classification",[3878,3882],{"title":3879,"path":3880,"stem":3881},"Основи класифікації та логістична регресія","\u002Fai-python\u002Flogistic-regression-classification\u002Fclassification-basics","16.ai-python\u002F11.logistic-regression-classification\u002F01.classification-basics",{"title":3883,"path":3884,"stem":3885},"Метрики якості класифікації","\u002Fai-python\u002Flogistic-regression-classification\u002Fclassification-metrics","16.ai-python\u002F11.logistic-regression-classification\u002F02.classification-metrics",{"title":3887,"path":3888,"stem":3889,"children":3890,"page":59},"Neural Networks Basics","\u002Fai-python\u002Fneural-networks-basics","16.ai-python\u002F12.neural-networks-basics",[3891],{"title":3892,"path":3893,"stem":3894},"Вступ до нейронних мереж — від персептрона до багатошарових мереж","\u002Fai-python\u002Fneural-networks-basics\u002Fperceptron-to-mlp","16.ai-python\u002F12.neural-networks-basics\u002F01.perceptron-to-mlp",{"title":3896,"path":3897,"stem":3898,"children":3899,"page":59},"Pytorch Intro","\u002Fai-python\u002Fpytorch-intro","16.ai-python\u002F13.pytorch-intro",[3900,3904,3908,3912],{"title":3901,"path":3902,"stem":3903},"Тензори та автоматичне диференціювання в PyTorch","\u002Fai-python\u002Fpytorch-intro\u002Ftensors-and-autograd","16.ai-python\u002F13.pytorch-intro\u002F01.tensors-and-autograd",{"title":3905,"path":3906,"stem":3907},"Побудова та тренування нейронних мереж у PyTorch","\u002Fai-python\u002Fpytorch-intro\u002Fbuilding-and-training","16.ai-python\u002F13.pytorch-intro\u002F02.building-and-training",{"title":3909,"path":3910,"stem":3911},"Робота з даними та регуляризація в PyTorch","\u002Fai-python\u002Fpytorch-intro\u002Fdata-and-regularization","16.ai-python\u002F13.pytorch-intro\u002F03.data-and-regularization",{"title":3913,"path":3914,"stem":3915},"Просунуті теми PyTorch — GPU, оптимізація та deployment","\u002Fai-python\u002Fpytorch-intro\u002Fadvanced-topics","16.ai-python\u002F13.pytorch-intro\u002F04.advanced-topics",{"title":3917,"path":3918,"stem":3919,"children":3920,"page":59},"Activation Functions Heart Disease","\u002Fai-python\u002Factivation-functions-heart-disease","16.ai-python\u002F14.activation-functions-heart-disease",[3921,3925],{"title":3922,"path":3923,"stem":3924},"Функції активації та побудова нейронної мережі для передбачення вад серця","\u002Fai-python\u002Factivation-functions-heart-disease\u002Fheart-disease-prediction","16.ai-python\u002F14.activation-functions-heart-disease\u002F01.heart-disease-prediction",{"title":3926,"path":3927,"stem":3928},"Бонус — Повний приклад Student Performance Prediction","\u002Fai-python\u002Factivation-functions-heart-disease\u002Fstudent-performance-bonus","16.ai-python\u002F14.activation-functions-heart-disease\u002F02.student-performance-bonus",{"title":3930,"path":3931,"stem":3932,"children":3933,"page":59},"Cnn Image Classification","\u002Fai-python\u002Fcnn-image-classification","16.ai-python\u002F15.cnn-image-classification",[3934,3938,3942,3946],{"title":3935,"path":3936,"stem":3937},"Основи згорткових нейронних мереж — чому не MLP?","\u002Fai-python\u002Fcnn-image-classification\u002Fcnn-fundamentals","16.ai-python\u002F15.cnn-image-classification\u002F01.cnn-fundamentals",{"title":3939,"path":3940,"stem":3941},"Практична імплементація CNN для класифікації MNIST","\u002Fai-python\u002Fcnn-image-classification\u002Fmnist-classification","16.ai-python\u002F15.cnn-image-classification\u002F02.mnist-classification",{"title":3943,"path":3944,"stem":3945},"Глибші CNN та аугментація даних для CIFAR-10","\u002Fai-python\u002Fcnn-image-classification\u002Fcifar10-and-data-augmentation","16.ai-python\u002F15.cnn-image-classification\u002F03.cifar10-and-data-augmentation",{"title":3947,"path":3948,"stem":3949},"Transfer Learning та візуалізація внутрішніх представлень CNN","\u002Fai-python\u002Fcnn-image-classification\u002Ftransfer-learning-and-visualization","16.ai-python\u002F15.cnn-image-classification\u002F04.transfer-learning-and-visualization",{"title":3951,"path":3952,"stem":3953,"children":3954,"page":59},"Batching Normalization Deep Networks","\u002Fai-python\u002Fbatching-normalization-deep-networks","16.ai-python\u002F16.batching-normalization-deep-networks",[3955,3959,3963,3967,3971,3975,3979],{"title":3956,"path":3957,"stem":3958},"Mini-batch Gradient Descent та ефективна обробка даних","\u002Fai-python\u002Fbatching-normalization-deep-networks\u002Fmini-batch-gradient-descent","16.ai-python\u002F16.batching-normalization-deep-networks\u002F01.mini-batch-gradient-descent",{"title":3960,"path":3961,"stem":3962},"Ініціалізація ваг — фундамент стабільного навчання","\u002Fai-python\u002Fbatching-normalization-deep-networks\u002Fweight-initialization","16.ai-python\u002F16.batching-normalization-deep-networks\u002F02.weight-initialization",{"title":3964,"path":3965,"stem":3966},"Batch Normalization — прорив у глибокому навчанні","\u002Fai-python\u002Fbatching-normalization-deep-networks\u002Fbatch-normalization","16.ai-python\u002F16.batching-normalization-deep-networks\u002F03.batch-normalization",{"title":3968,"path":3969,"stem":3970},"Dropout та комбіновані стратегії регуляризації","\u002Fai-python\u002Fbatching-normalization-deep-networks\u002Fdropout-and-regularization","16.ai-python\u002F16.batching-normalization-deep-networks\u002F04.dropout-and-regularization",{"title":3972,"path":3973,"stem":3974},"Проєктування глибоких мереж — від теорії до практики","\u002Fai-python\u002Fbatching-normalization-deep-networks\u002Fdeep-networks-architectures","16.ai-python\u002F16.batching-normalization-deep-networks\u002F05.deep-networks-architectures",{"title":3976,"path":3977,"stem":3978},"Планування learning rate — коли та як зменшувати крок навчання","\u002Fai-python\u002Fbatching-normalization-deep-networks\u002Flearning-rate-scheduling","16.ai-python\u002F16.batching-normalization-deep-networks\u002F06.learning-rate-scheduling",{"title":3980,"path":3981,"stem":3982},"Підсумковий проєкт — побудова сучасного класифікатора зображень","\u002Fai-python\u002Fbatching-normalization-deep-networks\u002Ffinal-project-deep-classifier","16.ai-python\u002F16.batching-normalization-deep-networks\u002F07.final-project-deep-classifier",{"title":3984,"icon":658,"path":3985,"stem":3986,"children":3987,"page":59},"Клієнт-серверна архітектура","\u002Fclient-server-architecture","17.client-server-architecture",[3988,3992,3996,4000,4004,4008,4012,4016,4020,4024,4028,4032,4036,4040,4044,4048,4052,4056],{"title":3989,"path":3990,"stem":3991},"Архітектура клієнт-серверних систем та основи Go","\u002Fclient-server-architecture\u002Fclient-server-architecture-and-go","17.client-server-architecture\u002F01.client-server-architecture-and-go",{"title":3993,"path":3994,"stem":3995},"Система типів та модель пам’яті мови Go","\u002Fclient-server-architecture\u002Ftype-system-and-memory-model","17.client-server-architecture\u002F02.type-system-and-memory-model",{"title":3997,"path":3998,"stem":3999},"Інтерфейси та модель конкурентності мови Go","\u002Fclient-server-architecture\u002Finterfaces-and-concurrency-model","17.client-server-architecture\u002F03.interfaces-and-concurrency-model",{"title":4001,"path":4002,"stem":4003},"Сокетне програмування та протокол TCP у Go","\u002Fclient-server-architecture\u002Ftcp-socket-programming","17.client-server-architecture\u002F04.tcp-socket-programming",{"title":4005,"path":4006,"stem":4007},"Протокол UDP та датаграмна передача даних","\u002Fclient-server-architecture\u002Fudp-datagram-transmission","17.client-server-architecture\u002F05.udp-datagram-transmission",{"title":4009,"path":4010,"stem":4011},"Криптографічний захист каналів зв","\u002Fclient-server-architecture\u002Ftls-cryptographic-channel-protection","17.client-server-architecture\u002F06.tls-cryptographic-channel-protection",{"title":4013,"path":4014,"stem":4015},"Прикладні мережеві протоколи DNS та SMTP","\u002Fclient-server-architecture\u002Fdns-smtp-application-protocols","17.client-server-architecture\u002F07.dns-smtp-application-protocols",{"title":4017,"path":4018,"stem":4019},"Протокол HTTP та стандартний вебсервер Go","\u002Fclient-server-architecture\u002Fhttp-protocol-and-web-server","17.client-server-architecture\u002F08.http-protocol-and-web-server",{"title":4021,"path":4022,"stem":4023},"Проєктування REST API та маршрутизація засобами Chi","\u002Fclient-server-architecture\u002Frest-api-design-and-chi-routing","17.client-server-architecture\u002F09.rest-api-design-and-chi-routing",{"title":4025,"path":4026,"stem":4027},"Лекція 10. Шарувата архітектура та конвеєри обробки запитів","\u002Fclient-server-architecture\u002Flayered-architecture-and-middleware-pipelines","17.client-server-architecture\u002F10.layered-architecture-and-middleware-pipelines",{"title":4029,"path":4030,"stem":4031},"Лекція 11. Архітектура та маршрутизація фреймворку Gin","\u002Fclient-server-architecture\u002Fgin-framework-architecture-and-routing","17.client-server-architecture\u002F11.gin-framework-architecture-and-routing",{"title":4033,"path":4034,"stem":4035},"Лекція 12. Валідація даних, безпека та документування у Gin","\u002Fclient-server-architecture\u002Fdata-validation-security-and-documentation-in-gin","17.client-server-architecture\u002F12.data-validation-security-and-documentation-in-gin",{"title":4037,"path":4038,"stem":4039},"Лекція 13. Взаємодія з реляційними СУБД та технології ORM","\u002Fclient-server-architecture\u002Frelational-databases-and-orm","17.client-server-architecture\u002F13.relational-databases-and-orm",{"title":4041,"path":4042,"stem":4043},"Потокова передача даних та протокол WebSocket","\u002Fclient-server-architecture\u002Fstreaming-data-and-websockets","17.client-server-architecture\u002F14.streaming-data-and-websockets",{"title":4045,"path":4046,"stem":4047},"Міжсервісна взаємодія на основі протоколу gRPC","\u002Fclient-server-architecture\u002Fgrpc-inter-service-communication","17.client-server-architecture\u002F15.grpc-inter-service-communication",{"title":4049,"path":4050,"stem":4051},"Асинхронний обмін повідомленнями та протоколи черг","\u002Fclient-server-architecture\u002Fasynchronous-message-exchange-and-queue-protocols","17.client-server-architecture\u002F16.asynchronous-message-exchange-and-queue-protocols",{"title":4053,"path":4054,"stem":4055},"Протоколи потокового медіа та технологія WebRTC","\u002Fclient-server-architecture\u002Fstreaming-media-protocols-and-webrtc","17.client-server-architecture\u002F17.streaming-media-protocols-and-webrtc",{"title":4057,"path":4058,"stem":4059},"Моніторинг, безпека та контейнеризація застосунків","\u002Fclient-server-architecture\u002Fmonitoring-security-and-containerization","17.client-server-architecture\u002F18.monitoring-security-and-containerization",{"title":4061,"icon":2118,"path":4062,"stem":4063,"children":4064,"page":59},"Розробка WEB-застосувань","\u002Fweb-development","18.web-development",[4065,4110,4148,4177,4206,4263,4313,4407,4473,4555,4588,4616,4658,4704,4747],{"title":4066,"icon":658,"path":4067,"stem":4068,"children":4069,"page":59},"Архітектура комп'ютерних мереж та мережеві протоколи","\u002Fweb-development\u002Fnetwork-architecture-and-protocols","18.web-development\u002F01.network-architecture-and-protocols",[4070,4074,4078,4082,4086,4090,4094,4098,4102,4106],{"title":4071,"path":4072,"stem":4073},"Еволюція веброзробки та модель клієнт-сервер","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fweb-evolution-client-server","18.web-development\u002F01.network-architecture-and-protocols\u002F01.web-evolution-client-server",{"title":4075,"path":4076,"stem":4077},"Еталонна модель OSI","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fosi-model","18.web-development\u002F01.network-architecture-and-protocols\u002F02.osi-model",{"title":4079,"path":4080,"stem":4081},"Стек протоколів TCP\u002FIP","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Ftcp-ip-stack","18.web-development\u002F01.network-architecture-and-protocols\u002F03.tcp-ip-stack",{"title":4083,"path":4084,"stem":4085},"IP-адресація, порти та сокети","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fip-addressing-ports-sockets","18.web-development\u002F01.network-architecture-and-protocols\u002F04.ip-addressing-ports-sockets",{"title":4087,"path":4088,"stem":4089},"Протоколи TCP та UDP","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Ftcp-udp-protocols","18.web-development\u002F01.network-architecture-and-protocols\u002F05.tcp-udp-protocols",{"title":4091,"path":4092,"stem":4093},"Система доменних імен DNS","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fdns-system","18.web-development\u002F01.network-architecture-and-protocols\u002F06.dns-system",{"title":4095,"path":4096,"stem":4097},"Протокол SMTP та поштові протоколи","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fsmtp-email-protocols","18.web-development\u002F01.network-architecture-and-protocols\u002F07.smtp-email-protocols",{"title":4099,"path":4100,"stem":4101},"Протокол WebSocket","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fwebsocket-protocol","18.web-development\u002F01.network-architecture-and-protocols\u002F08.websocket-protocol",{"title":4103,"path":4104,"stem":4105},"Протокол SSH","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fssh-protocol","18.web-development\u002F01.network-architecture-and-protocols\u002F09.ssh-protocol",{"title":4107,"path":4108,"stem":4109},"Огляд сучасних серверних технологій","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fmodern-backend-technologies","18.web-development\u002F01.network-architecture-and-protocols\u002F10.modern-backend-technologies",{"title":4111,"icon":4112,"path":4113,"stem":4114,"children":4115,"page":59},"Протокол HTTP та захищена передача даних HTTPS","i-lucide-lock","\u002Fweb-development\u002Fhttp-and-https","18.web-development\u002F02.http-and-https",[4116,4120,4124,4128,4132,4136,4140,4144],{"title":4117,"path":4118,"stem":4119},"Вступ до протоколу HTTP та еволюція веб-технологій","\u002Fweb-development\u002Fhttp-and-https\u002Fintroduction-and-evolution","18.web-development\u002F02.http-and-https\u002F01.introduction-and-evolution",{"title":4121,"path":4122,"stem":4123},"Анатомія HTTP-запиту","\u002Fweb-development\u002Fhttp-and-https\u002Fhttp-request-structure","18.web-development\u002F02.http-and-https\u002F02.http-request-structure",{"title":4125,"path":4126,"stem":4127},"Анатомія HTTP-відповіді","\u002Fweb-development\u002Fhttp-and-https\u002Fhttp-response-structure","18.web-development\u002F02.http-and-https\u002F03.http-response-structure",{"title":4129,"path":4130,"stem":4131},"Методи HTTP та їхня семантика","\u002Fweb-development\u002Fhttp-and-https\u002Fhttp-methods","18.web-development\u002F02.http-and-https\u002F04.http-methods",{"title":4133,"path":4134,"stem":4135},"Коди статусу HTTP та їхнє призначення","\u002Fweb-development\u002Fhttp-and-https\u002Fhttp-status-codes","18.web-development\u002F02.http-and-https\u002F05.http-status-codes",{"title":4137,"path":4138,"stem":4139},"HTTP-заголовки та їхнє призначення","\u002Fweb-development\u002Fhttp-and-https\u002Fhttp-headers","18.web-development\u002F02.http-and-https\u002F06.http-headers",{"title":4141,"path":4142,"stem":4143},"CORS та механізми безпеки HTTP","\u002Fweb-development\u002Fhttp-and-https\u002Fcors-and-security","18.web-development\u002F02.http-and-https\u002F07.cors-and-security",{"title":4145,"path":4146,"stem":4147},"HTTPS та криптографічні основи TLS","\u002Fweb-development\u002Fhttp-and-https\u002Fhttps-and-tls","18.web-development\u002F02.http-and-https\u002F08.https-and-tls",{"title":4149,"icon":2498,"path":4150,"stem":4151,"children":4152,"page":59},"Система типів мови TypeScript","\u002Fweb-development\u002Ftypescript-type-system","18.web-development\u002F03.typescript-type-system",[4153,4157,4161,4165,4169,4173],{"title":4154,"path":4155,"stem":4156},"Знайомство з TypeScript Compiler","\u002Fweb-development\u002Ftypescript-type-system\u002Fintroduction-compiler-config","18.web-development\u002F03.typescript-type-system\u002F01.introduction-compiler-config",{"title":4158,"path":4159,"stem":4160},"Примітивні типи даних: string, number, boolean","\u002Fweb-development\u002Ftypescript-type-system\u002Fprimitive-special-types","18.web-development\u002F03.typescript-type-system\u002F02.primitive-special-types",{"title":4162,"path":4163,"stem":4164},"Масиви, кортежі та об","\u002Fweb-development\u002Ftypescript-type-system\u002Farrays-tuples-objects","18.web-development\u002F03.typescript-type-system\u002F03.arrays-tuples-objects",{"title":4166,"path":4167,"stem":4168},"Псевдоніми типів, Union типи, Intersection типи та літеральні типи","\u002Fweb-development\u002Ftypescript-type-system\u002Funion-intersection-literals","18.web-development\u002F03.typescript-type-system\u002F04.union-intersection-literals",{"title":4170,"path":4171,"stem":4172},"Type Narrowing (звуження типів)","\u002Fweb-development\u002Ftypescript-type-system\u002Ftype-narrowing","18.web-development\u002F03.typescript-type-system\u002F05.type-narrowing",{"title":4174,"path":4175,"stem":4176},"Типізація функцій","\u002Fweb-development\u002Ftypescript-type-system\u002Ffunctions-typing","18.web-development\u002F03.typescript-type-system\u002F06.functions-typing",{"title":4178,"icon":2498,"path":4179,"stem":4180,"children":4181,"page":59},"Розширені засоби мови TypeScript","\u002Fweb-development\u002Ftypescript-advanced","18.web-development\u002F04.typescript-advanced",[4182,4186,4190,4194,4198,4202],{"title":4183,"path":4184,"stem":4185},"Interfaces та Classes","\u002Fweb-development\u002Ftypescript-advanced\u002Finterfaces-classes","18.web-development\u002F04.typescript-advanced\u002F01.interfaces-classes",{"title":4187,"path":4188,"stem":4189},"Основи Generic типів","\u002Fweb-development\u002Ftypescript-advanced\u002Fgenerics-fundamentals","18.web-development\u002F04.typescript-advanced\u002F02.generics-fundamentals",{"title":4191,"path":4192,"stem":4193},"Enums та Decorators","\u002Fweb-development\u002Ftypescript-advanced\u002Fenums-decorators","18.web-development\u002F04.typescript-advanced\u002F03.enums-decorators",{"title":4195,"path":4196,"stem":4197},"Utility Types","\u002Fweb-development\u002Ftypescript-advanced\u002Futility-types","18.web-development\u002F04.typescript-advanced\u002F04.utility-types",{"title":4199,"path":4200,"stem":4201},"Mapped та Conditional Types","\u002Fweb-development\u002Ftypescript-advanced\u002Fmapped-conditional-types","18.web-development\u002F04.typescript-advanced\u002F05.mapped-conditional-types",{"title":4203,"path":4204,"stem":4205},"Модулі та Strict Mode","\u002Fweb-development\u002Ftypescript-advanced\u002Fmodules-strict-mode","18.web-development\u002F04.typescript-advanced\u002F06.modules-strict-mode",{"title":4207,"icon":4208,"path":4209,"stem":4210,"children":4211,"page":59},"Платформа Node.js як середовище виконання","i-devicon-nodejs","\u002Fweb-development\u002Fnodejs-platform","18.web-development\u002F05.nodejs-platform",[4212,4216,4220,4224,4228,4232,4236,4240,4244,4248,4252,4255,4259],{"title":4213,"path":4214,"stem":4215},"Що таке Node.js та його архітектура","\u002Fweb-development\u002Fnodejs-platform\u002Fwhat-is-nodejs","18.web-development\u002F05.nodejs-platform\u002F01.what-is-nodejs",{"title":4217,"path":4218,"stem":4219},"Event Loop — серце Node.js","\u002Fweb-development\u002Fnodejs-platform\u002Fevent-loop","18.web-development\u002F05.nodejs-platform\u002F02.event-loop",{"title":4221,"path":4222,"stem":4223},"Модульні системи: CommonJS vs ES Modules","\u002Fweb-development\u002Fnodejs-platform\u002Fmodule-systems","18.web-development\u002F05.nodejs-platform\u002F03.module-systems",{"title":4225,"path":4226,"stem":4227},"npm та package.json","\u002Fweb-development\u002Fnodejs-platform\u002Fnpm-package-json","18.web-development\u002F05.nodejs-platform\u002F04.npm-package-json",{"title":4229,"path":4230,"stem":4231},"Глобальні об\\","\u002Fweb-development\u002Fnodejs-platform\u002Fglobal-objects","18.web-development\u002F05.nodejs-platform\u002F05.global-objects",{"title":4233,"path":4234,"stem":4235},"Вбудований модуль fs (File System)","\u002Fweb-development\u002Fnodejs-platform\u002Fbuilt-in-modules-fs","18.web-development\u002F05.nodejs-platform\u002F06.built-in-modules-fs",{"title":4237,"path":4238,"stem":4239},"Вбудований модуль path","\u002Fweb-development\u002Fnodejs-platform\u002Fbuilt-in-modules-path","18.web-development\u002F05.nodejs-platform\u002F07.built-in-modules-path",{"title":4241,"path":4242,"stem":4243},"Вбудований модуль http","\u002Fweb-development\u002Fnodejs-platform\u002Fbuilt-in-modules-http","18.web-development\u002F05.nodejs-platform\u002F08.built-in-modules-http",{"title":4245,"path":4246,"stem":4247},"Streams — потоки даних у Node.js","\u002Fweb-development\u002Fnodejs-platform\u002Fstreams","18.web-development\u002F05.nodejs-platform\u002F09.streams",{"title":4249,"path":4250,"stem":4251},"Вбудований модуль util (Utilities)","\u002Fweb-development\u002Fnodejs-platform\u002Fbuilt-in-modules-util","18.web-development\u002F05.nodejs-platform\u002F10.built-in-modules-util",{"title":3141,"path":4253,"stem":4254},"\u002Fweb-development\u002Fnodejs-platform\u002Fenvironment-variables","18.web-development\u002F05.nodejs-platform\u002F11.environment-variables",{"title":4256,"path":4257,"stem":4258},"Інструменти налагодження та розробки","\u002Fweb-development\u002Fnodejs-platform\u002Fdebugging-tools","18.web-development\u002F05.nodejs-platform\u002F12.debugging-tools",{"title":4260,"path":4261,"stem":4262},"Продуктивність та Best Practices","\u002Fweb-development\u002Fnodejs-platform\u002Fperformance-best-practices","18.web-development\u002F05.nodejs-platform\u002F13.performance-best-practices",{"title":4264,"icon":4265,"path":4266,"stem":4267,"children":4268,"page":59},"Асинхронне програмування у Node.js","i-lucide-clock","\u002Fweb-development\u002Fasync-programming-nodejs","18.web-development\u002F06.async-programming-nodejs",[4269,4273,4277,4281,4285,4289,4293,4297,4301,4305,4309],{"title":4270,"path":4271,"stem":4272},"Синхронний vs асинхронний код","\u002Fweb-development\u002Fasync-programming-nodejs\u002Fsync-vs-async","18.web-development\u002F06.async-programming-nodejs\u002F01.sync-vs-async",{"title":4274,"path":4275,"stem":4276},"Callbacks — перша парадигма асинхронності","\u002Fweb-development\u002Fasync-programming-nodejs\u002Fcallbacks","18.web-development\u002F06.async-programming-nodejs\u002F02.callbacks",{"title":4278,"path":4279,"stem":4280},"Promises — стандарт асинхронності","\u002Fweb-development\u002Fasync-programming-nodejs\u002Fpromises","18.web-development\u002F06.async-programming-nodejs\u002F03.promises",{"title":4282,"path":4283,"stem":4284},"Promise комбінатори","\u002Fweb-development\u002Fasync-programming-nodejs\u002Fpromise-combinators","18.web-development\u002F06.async-programming-nodejs\u002F04.promise-combinators",{"title":4286,"path":4287,"stem":4288},"Async\u002FAwait — синтаксичний цукор над Promises","\u002Fweb-development\u002Fasync-programming-nodejs\u002Fasync-await","18.web-development\u002F06.async-programming-nodejs\u002F05.async-await",{"title":4290,"path":4291,"stem":4292},"Паралельне vs послідовне виконання","\u002Fweb-development\u002Fasync-programming-nodejs\u002Fparallel-vs-sequential","18.web-development\u002F06.async-programming-nodejs\u002F06.parallel-vs-sequential",{"title":4294,"path":4295,"stem":4296},"EventEmitter — подієва модель Node.js","\u002Fweb-development\u002Fasync-programming-nodejs\u002Fevent-emitter","18.web-development\u002F06.async-programming-nodejs\u002F07.event-emitter",{"title":4298,"path":4299,"stem":4300},"Worker Threads — багатопотоковість у Node.js","\u002Fweb-development\u002Fasync-programming-nodejs\u002Fworker-threads","18.web-development\u002F06.async-programming-nodejs\u002F08.worker-threads",{"title":4302,"path":4303,"stem":4304},"Child Processes — запуск зовнішніх процесів","\u002Fweb-development\u002Fasync-programming-nodejs\u002Fchild-processes","18.web-development\u002F06.async-programming-nodejs\u002F09.child-processes",{"title":4306,"path":4307,"stem":4308},"Обробка помилок у асинхронному коді","\u002Fweb-development\u002Fasync-programming-nodejs\u002Ferror-handling","18.web-development\u002F06.async-programming-nodejs\u002F10.error-handling",{"title":4310,"path":4311,"stem":4312},"Порівняння Node.js фреймворків","\u002Fweb-development\u002Fasync-programming-nodejs\u002Fnodejs-frameworks","18.web-development\u002F06.async-programming-nodejs\u002F11.nodejs-frameworks",{"title":4314,"icon":4315,"path":4316,"stem":4317,"children":4318,"page":59},"Тема 7. Фреймворк NestJS. Контролери та маршрутизація","i-lucide-route","\u002Fweb-development\u002Fnestjs-controllers-routing","18.web-development\u002F07.nestjs-controllers-routing",[4319,4323,4327,4331,4335,4339,4343,4347,4351,4355,4359,4363,4367,4371,4375,4379,4383,4387,4391,4395,4399,4403],{"title":4320,"path":4321,"stem":4322},"Філософія та архітектура NestJS","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fnestjs-philosophy","18.web-development\u002F07.nestjs-controllers-routing\u002F01.nestjs-philosophy",{"title":4324,"path":4325,"stem":4326},"Три стовпи архітектури: модулі, контролери, провайдери","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fthree-pillars","18.web-development\u002F07.nestjs-controllers-routing\u002F02.three-pillars",{"title":4328,"path":4329,"stem":4330},"Інверсія керування (IoC) та ін","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fioc-and-di","18.web-development\u002F07.nestjs-controllers-routing\u002F03.ioc-and-di",{"title":4332,"path":4333,"stem":4334},"Встановлення NestJS CLI та створення проєкту","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fnestjs-cli-setup","18.web-development\u002F07.nestjs-controllers-routing\u002F04.nestjs-cli-setup",{"title":4336,"path":4337,"stem":4338},"Структура проєкту NestJS та конвенції","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fproject-structure","18.web-development\u002F07.nestjs-controllers-routing\u002F05.project-structure",{"title":4340,"path":4341,"stem":4342},"Контролери: основи маршрутизації","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fcontrollers-basics","18.web-development\u002F07.nestjs-controllers-routing\u002F06.controllers-basics",{"title":4344,"path":4345,"stem":4346},"Декоратори маршрутизації HTTP-методів","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Froute-decorators","18.web-development\u002F07.nestjs-controllers-routing\u002F07.route-decorators",{"title":4348,"path":4349,"stem":4350},"Параметри маршруту та декоратор @Param","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Froute-parameters","18.web-development\u002F07.nestjs-controllers-routing\u002F08.route-parameters",{"title":4352,"path":4353,"stem":4354},"Query-параметри та декоратор @Query","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fquery-parameters","18.web-development\u002F07.nestjs-controllers-routing\u002F09.query-parameters",{"title":4356,"path":4357,"stem":4358},"Тіло запиту та декоратор @Body","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Frequest-body","18.web-development\u002F07.nestjs-controllers-routing\u002F10.request-body",{"title":4360,"path":4361,"stem":4362},"Робота з заголовками запиту та відповіді","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fheaders-decorators","18.web-development\u002F07.nestjs-controllers-routing\u002F11.headers-decorators",{"title":4364,"path":4365,"stem":4366},"Data Transfer Objects (DTO): визначення та призначення","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fdto-introduction","18.web-development\u002F07.nestjs-controllers-routing\u002F12.dto-introduction",{"title":4368,"path":4369,"stem":4370},"Об'єкти Request та Response","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Frequest-response-objects","18.web-development\u002F07.nestjs-controllers-routing\u002F13.request-response-objects",{"title":4372,"path":4373,"stem":4374},"HTTP-статус коди та декоратор @HttpCode","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fhttp-status-codes","18.web-development\u002F07.nestjs-controllers-routing\u002F14.http-status-codes",{"title":4376,"path":4377,"stem":4378},"Перенаправлення (Redirects) та декоратор @Redirect","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fredirects","18.web-development\u002F07.nestjs-controllers-routing\u002F15.redirects",{"title":4380,"path":4381,"stem":4382},"Асинхронні обробники та Observables","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fasync-handlers","18.web-development\u002F07.nestjs-controllers-routing\u002F16.async-handlers",{"title":4384,"path":4385,"stem":4386},"Маршрутизація за піддоменами та версіонування API","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fsub-domain-routing","18.web-development\u002F07.nestjs-controllers-routing\u002F17.sub-domain-routing",{"title":4388,"path":4389,"stem":4390},"Області видимості контролерів (Scopes)","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fcontroller-scopes","18.web-development\u002F07.nestjs-controllers-routing\u002F18.controller-scopes",{"title":4392,"path":4393,"stem":4394},"Основні команди NestJS CLI","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fnestjs-cli-commands","18.web-development\u002F07.nestjs-controllers-routing\u002F19.nestjs-cli-commands",{"title":4396,"path":4397,"stem":4398},"Практичний приклад: створення CRUD-контролера","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fcrud-example","18.web-development\u002F07.nestjs-controllers-routing\u002F20.crud-example",{"title":4400,"path":4401,"stem":4402},"Тестування контролерів","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Ftesting-controllers","18.web-development\u002F07.nestjs-controllers-routing\u002F21.testing-controllers",{"title":4404,"path":4405,"stem":4406},"Best Practices для контролерів та маршрутизації","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fbest-practices","18.web-development\u002F07.nestjs-controllers-routing\u002F22.best-practices",{"title":4408,"icon":4409,"path":4410,"stem":4411,"children":4412,"page":59},"Тема 8. Провайдери, сервіси та модульна система NestJS","i-lucide-package","\u002Fweb-development\u002Fnestjs-providers-modules","18.web-development\u002F08.nestjs-providers-modules",[4413,4417,4421,4425,4429,4433,4437,4441,4445,4449,4453,4457,4461,4465,4469],{"title":4414,"path":4415,"stem":4416},"Концепція провайдерів у NestJS","\u002Fweb-development\u002Fnestjs-providers-modules\u002Fproviders-concept","18.web-development\u002F08.nestjs-providers-modules\u002F01.providers-concept",{"title":4418,"path":4419,"stem":4420},"Сервіси: інкапсуляція бізнес-логіки","\u002Fweb-development\u002Fnestjs-providers-modules\u002Fservices-business-logic","18.web-development\u002F08.nestjs-providers-modules\u002F02.services-business-logic",{"title":4422,"path":4423,"stem":4424},"Практика ін","\u002Fweb-development\u002Fnestjs-providers-modules\u002Fdependency-injection-practice","18.web-development\u002F08.nestjs-providers-modules\u002F03.dependency-injection-practice",{"title":4426,"path":4427,"stem":4428},"Custom Providers: useValue, useClass, useFactory, useExisting","\u002Fweb-development\u002Fnestjs-providers-modules\u002Fcustom-providers","18.web-development\u002F08.nestjs-providers-modules\u002F04.custom-providers",{"title":4430,"path":4431,"stem":4432},"Injection Tokens: рядкові та символьні токени","\u002Fweb-development\u002Fnestjs-providers-modules\u002Finjection-tokens","18.web-development\u002F08.nestjs-providers-modules\u002F05.injection-tokens",{"title":4434,"path":4435,"stem":4436},"Опціональні провайдери та декоратор @Optional","\u002Fweb-development\u002Fnestjs-providers-modules\u002Foptional-providers","18.web-development\u002F08.nestjs-providers-modules\u002F07.optional-providers",{"title":4438,"path":4439,"stem":4440},"Структура модулів: imports, controllers, providers, exports","\u002Fweb-development\u002Fnestjs-providers-modules\u002Fmodules-structure","18.web-development\u002F08.nestjs-providers-modules\u002F08.modules-structure",{"title":4442,"path":4443,"stem":4444},"Feature Modules: ізоляція функціональності","\u002Fweb-development\u002Fnestjs-providers-modules\u002Ffeature-modules","18.web-development\u002F08.nestjs-providers-modules\u002F09.feature-modules",{"title":4446,"path":4447,"stem":4448},"Shared Modules: перевикористання провайдерів","\u002Fweb-development\u002Fnestjs-providers-modules\u002Fshared-modules","18.web-development\u002F08.nestjs-providers-modules\u002F10.shared-modules",{"title":4450,"path":4451,"stem":4452},"Global Modules та декоратор @Global","\u002Fweb-development\u002Fnestjs-providers-modules\u002Fglobal-modules","18.web-development\u002F08.nestjs-providers-modules\u002F11.global-modules",{"title":4454,"path":4455,"stem":4456},"Dynamic Modules: конфігурація під час виконання","\u002Fweb-development\u002Fnestjs-providers-modules\u002Fdynamic-modules","18.web-development\u002F08.nestjs-providers-modules\u002F12.dynamic-modules",{"title":4458,"path":4459,"stem":4460},"Циклічні залежності та forwardRef","\u002Fweb-development\u002Fnestjs-providers-modules\u002Fcircular-dependencies","18.web-development\u002F08.nestjs-providers-modules\u002F13.circular-dependencies",{"title":4462,"path":4463,"stem":4464},"Lifecycle Hooks: хуки життєвого циклу","\u002Fweb-development\u002Fnestjs-providers-modules\u002Flifecycle-hooks","18.web-development\u002F08.nestjs-providers-modules\u002F14.lifecycle-hooks",{"title":4466,"path":4467,"stem":4468},"ModuleRef: динамічний доступ до провайдерів","\u002Fweb-development\u002Fnestjs-providers-modules\u002Fmodule-reference","18.web-development\u002F08.nestjs-providers-modules\u002F15.module-reference",{"title":4470,"path":4471,"stem":4472},"Тестування сервісів та провайдерів","\u002Fweb-development\u002Fnestjs-providers-modules\u002Ftesting-services","18.web-development\u002F08.nestjs-providers-modules\u002F16.testing-services",{"title":4474,"icon":4475,"path":4476,"stem":4477,"children":4478,"page":59},"Тема 9. Валідація даних та конвеєр обробки запитів у NestJS","i-lucide-filter","\u002Fweb-development\u002Fnestjs-validation-pipeline","18.web-development\u002F09.nestjs-validation-pipeline",[4479,4483,4487,4491,4495,4499,4503,4507,4511,4515,4519,4523,4527,4531,4535,4539,4543,4547,4551],{"title":4480,"path":4481,"stem":4482},"Request Pipeline: конвеєр обробки запитів","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Frequest-pipeline","18.web-development\u002F09.nestjs-validation-pipeline\u002F01.request-pipeline",{"title":4484,"path":4485,"stem":4486},"Pipes: концепція трансформації та валідації","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fpipes-concept","18.web-development\u002F09.nestjs-validation-pipeline\u002F02.pipes-concept",{"title":4488,"path":4489,"stem":4490},"Вбудовані pipes: ParseIntPipe, ParseBoolPipe, ParseUUIDPipe","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fbuilt-in-pipes","18.web-development\u002F09.nestjs-validation-pipeline\u002F03.built-in-pipes",{"title":4492,"path":4493,"stem":4494},"ValidationPipe: автоматична валідація DTO","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fvalidation-pipe","18.web-development\u002F09.nestjs-validation-pipeline\u002F04.validation-pipe",{"title":4496,"path":4497,"stem":4498},"Декоратори class-validator для DTO","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fclass-validator-decorators","18.web-development\u002F09.nestjs-validation-pipeline\u002F05.class-validator-decorators",{"title":4500,"path":4501,"stem":4502},"Створення кастомних валідаторів","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fcustom-validators","18.web-development\u002F09.nestjs-validation-pipeline\u002F06.custom-validators",{"title":4504,"path":4505,"stem":4506},"Створення власних Pipes","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fcustom-pipes","18.web-development\u002F09.nestjs-validation-pipeline\u002F07.custom-pipes",{"title":4508,"path":4509,"stem":4510},"Основи Middleware","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fmiddleware-basics","18.web-development\u002F09.nestjs-validation-pipeline\u002F08.middleware-basics",{"title":4512,"path":4513,"stem":4514},"Практичні приклади Middleware","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fmiddleware-examples","18.web-development\u002F09.nestjs-validation-pipeline\u002F09.middleware-examples",{"title":4516,"path":4517,"stem":4518},"Guards: захисні перехоплювачі доступу","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fguards-concept","18.web-development\u002F09.nestjs-validation-pipeline\u002F10.guards-concept",{"title":4520,"path":4521,"stem":4522},"Створення кастомних Guards","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fcustom-guards","18.web-development\u002F09.nestjs-validation-pipeline\u002F11.custom-guards",{"title":4524,"path":4525,"stem":4526},"Interceptors: перехоплення та трансформація відповідей","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Finterceptors-concept","18.web-development\u002F09.nestjs-validation-pipeline\u002F12.interceptors-concept",{"title":4528,"path":4529,"stem":4530},"Практичні приклади Interceptors","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Finterceptor-examples","18.web-development\u002F09.nestjs-validation-pipeline\u002F13.interceptor-examples",{"title":4532,"path":4533,"stem":4534},"Exception Filters: обробка виключень","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fexception-filters","18.web-development\u002F09.nestjs-validation-pipeline\u002F14.exception-filters",{"title":4536,"path":4537,"stem":4538},"Custom Exception Filters: спеціалізовані фільтри","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fcustom-exception-filters","18.web-development\u002F09.nestjs-validation-pipeline\u002F15.custom-exception-filters",{"title":4540,"path":4541,"stem":4542},"Execution Context: контекст виконання","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fexecution-context","18.web-development\u002F09.nestjs-validation-pipeline\u002F16.execution-context",{"title":4544,"path":4545,"stem":4546},"Custom Decorators: власні декоратори","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fcustom-decorators","18.web-development\u002F09.nestjs-validation-pipeline\u002F17.custom-decorators",{"title":4548,"path":4549,"stem":4550},"Global Components: глобальні компоненти","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fglobal-components","18.web-development\u002F09.nestjs-validation-pipeline\u002F18.global-components",{"title":4552,"path":4553,"stem":4554},"Pipeline Best Practices: найкращі практики","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fpipeline-best-practices","18.web-development\u002F09.nestjs-validation-pipeline\u002F19.pipeline-best-practices",{"title":4556,"icon":2865,"path":4557,"stem":4558,"children":4559,"page":59},"Інтеграція реляційних баз даних засобами TypeORM","\u002Fweb-development\u002Ftypeorm-integration","18.web-development\u002F10.typeorm-integration",[4560,4564,4568,4572,4576,4580,4584],{"title":4561,"path":4562,"stem":4563},"Робота з базами даних у Node.js через нативні драйвери","\u002Fweb-development\u002Ftypeorm-integration\u002F01-nodejs-database-drivers","18.web-development\u002F10.typeorm-integration\u002F01-nodejs-database-drivers",{"title":4565,"path":4566,"stem":4567},"ORM та знайомство з TypeORM","\u002Fweb-development\u002Ftypeorm-integration\u002F02-orm-and-typeorm-intro","18.web-development\u002F10.typeorm-integration\u002F02-orm-and-typeorm-intro",{"title":4569,"path":4570,"stem":4571},"Налаштування TypeORM у NestJS проєкті","\u002Fweb-development\u002Ftypeorm-integration\u002F03-typeorm-setup-nestjs","18.web-development\u002F10.typeorm-integration\u002F03-typeorm-setup-nestjs",{"title":4573,"path":4574,"stem":4575},"Entity класи та декоратори TypeORM","\u002Fweb-development\u002Ftypeorm-integration\u002F04-entities-and-decorators","18.web-development\u002F10.typeorm-integration\u002F04-entities-and-decorators",{"title":4577,"path":4578,"stem":4579},"Repository Pattern та CRUD операції","\u002Fweb-development\u002Ftypeorm-integration\u002F05-repository-pattern-crud","18.web-development\u002F10.typeorm-integration\u002F05-repository-pattern-crud",{"title":4581,"path":4582,"stem":4583},"Пагінація та фільтрація даних","\u002Fweb-development\u002Ftypeorm-integration\u002F06-pagination-filtering","18.web-development\u002F10.typeorm-integration\u002F06-pagination-filtering",{"title":4585,"path":4586,"stem":4587},"QueryBuilder для складних запитів","\u002Fweb-development\u002Ftypeorm-integration\u002F07-query-builder","18.web-development\u002F10.typeorm-integration\u002F07-query-builder",{"title":4589,"icon":4590,"path":4591,"stem":4592,"children":4593,"page":59},"Зв'язки між сутностями, міграції та оптимізація запитів","i-lucide-git-branch","\u002Fweb-development\u002Fentity-relations-migrations","18.web-development\u002F11.entity-relations-migrations",[4594,4598,4602,4606,4610],{"title":4595,"path":4596,"stem":4597},"Зв'язки One-to-Many та Many-to-One","\u002Fweb-development\u002Fentity-relations-migrations\u002F01-one-to-many-many-to-one","18.web-development\u002F11.entity-relations-migrations\u002F01-one-to-many-many-to-one",{"title":4599,"path":4600,"stem":4601},"Зв'язки One-to-One та Many-to-Many","\u002Fweb-development\u002Fentity-relations-migrations\u002F02-one-to-one-many-to-many","18.web-development\u002F11.entity-relations-migrations\u002F02-one-to-one-many-to-many",{"title":4603,"path":4604,"stem":4605},"Керування міграціями бази даних","\u002Fweb-development\u002Fentity-relations-migrations\u002F03-migrations-management","18.web-development\u002F11.entity-relations-migrations\u002F03-migrations-management",{"title":4607,"path":4608,"stem":4609},"Транзакції у TypeORM","\u002Fweb-development\u002Fentity-relations-migrations\u002F04-transactions","18.web-development\u002F11.entity-relations-migrations\u002F04-transactions",{"title":4611,"path":4612,"stem":4613,"children":4614},"Індекси та оптимізація запитів","\u002Fweb-development\u002Fentity-relations-migrations\u002F05-indexes-optimization","18.web-development\u002F11.entity-relations-migrations\u002F05-indexes-optimization",[4615],{"title":4611,"path":4612,"stem":4613},{"title":4617,"icon":4618,"path":4619,"stem":4620,"children":4621,"page":59},"Механізми автентифікації у вебзастосунках","i-lucide-key","\u002Fweb-development\u002Fauthentication","18.web-development\u002F12.authentication",[4622,4626,4630,4634,4638,4642,4646,4650,4654],{"title":4623,"path":4624,"stem":4625},"Автентифікація vs Авторизація","\u002Fweb-development\u002Fauthentication\u002F01-authentication-vs-authorization","18.web-development\u002F12.authentication\u002F01-authentication-vs-authorization",{"title":4627,"path":4628,"stem":4629},"Стратегії автентифікації","\u002Fweb-development\u002Fauthentication\u002F02-authentication-strategies","18.web-development\u002F12.authentication\u002F02-authentication-strategies",{"title":4631,"path":4632,"stem":4633},"Автентифікація на основі сесій","\u002Fweb-development\u002Fauthentication\u002F03-session-based-authentication","18.web-development\u002F12.authentication\u002F03-session-based-authentication",{"title":4635,"path":4636,"stem":4637},"Структура JSON Web Token (JWT)","\u002Fweb-development\u002Fauthentication\u002F04-jwt-structure","18.web-development\u002F12.authentication\u002F04-jwt-structure",{"title":4639,"path":4640,"stem":4641},"Інтеграція JWT у NestJS","\u002Fweb-development\u002Fauthentication\u002F05-nestjs-jwt-integration","18.web-development\u002F12.authentication\u002F05-nestjs-jwt-integration",{"title":4643,"path":4644,"stem":4645},"Passport.js стратегії у NestJS","\u002Fweb-development\u002Fauthentication\u002F06-passport-strategies","18.web-development\u002F12.authentication\u002F06-passport-strategies",{"title":4647,"path":4648,"stem":4649},"Безпечне зберігання паролів: хешування та криптографічний захист","\u002Fweb-development\u002Fauthentication\u002F07-password-hashing","18.web-development\u002F12.authentication\u002F07-password-hashing",{"title":4651,"path":4652,"stem":4653},"Refresh Token та безпечне оновлення доступу","\u002Fweb-development\u002Fauthentication\u002F08-refresh-tokens","18.web-development\u002F12.authentication\u002F08-refresh-tokens",{"title":4655,"path":4656,"stem":4657},"OAuth 2.0 та OpenID Connect: делегована автентифікація","\u002Fweb-development\u002Fauthentication\u002F09-oauth2-openid","18.web-development\u002F12.authentication\u002F09-oauth2-openid",{"title":4659,"icon":4660,"path":4661,"stem":4662,"children":4663,"page":59},"Авторизація та безпека серверних застосунків","i-lucide-shield","\u002Fweb-development\u002Fauthorization-security","18.web-development\u002F13.authorization-security",[4664,4668,4672,4676,4680,4684,4688,4692,4696,4700],{"title":4665,"path":4666,"stem":4667},"Моделі авторизації","\u002Fweb-development\u002Fauthorization-security\u002F01-authorization-models","18.web-development\u002F13.authorization-security\u002F01-authorization-models",{"title":4669,"path":4670,"stem":4671},"Реалізація RBAC у NestJS","\u002Fweb-development\u002Fauthorization-security\u002F02-rbac-implementation","18.web-development\u002F13.authorization-security\u002F02-rbac-implementation",{"title":4673,"path":4674,"stem":4675},"Permission-Based Access Control","\u002Fweb-development\u002Fauthorization-security\u002F03-permission-based-access","18.web-development\u002F13.authorization-security\u002F03-permission-based-access",{"title":4677,"path":4678,"stem":4679},"ABAC та бібліотека CASL","\u002Fweb-development\u002Fauthorization-security\u002F04-abac-casl","18.web-development\u002F13.authorization-security\u002F04-abac-casl",{"title":4681,"path":4682,"stem":4683},"Кастомні декоратори та метадані","\u002Fweb-development\u002Fauthorization-security\u002F05-custom-decorators-metadata","18.web-development\u002F13.authorization-security\u002F05-custom-decorators-metadata",{"title":4685,"path":4686,"stem":4687},"Конфігурація CORS","\u002Fweb-development\u002Fauthorization-security\u002F06-cors-configuration","18.web-development\u002F13.authorization-security\u002F06-cors-configuration",{"title":4689,"path":4690,"stem":4691},"Захист через HTTP Security Headers (Helmet)","\u002Fweb-development\u002Fauthorization-security\u002F07-helmet-security-headers","18.web-development\u002F13.authorization-security\u002F07-helmet-security-headers",{"title":4693,"path":4694,"stem":4695},"Rate Limiting та Throttling","\u002Fweb-development\u002Fauthorization-security\u002F08-rate-limiting-throttling","18.web-development\u002F13.authorization-security\u002F08-rate-limiting-throttling",{"title":4697,"path":4698,"stem":4699},"Захист від поширених атак","\u002Fweb-development\u002Fauthorization-security\u002F09-common-attacks-protection","18.web-development\u002F13.authorization-security\u002F09-common-attacks-protection",{"title":4701,"path":4702,"stem":4703},"HTTPS у продакшені","\u002Fweb-development\u002Fauthorization-security\u002F10-https-production","18.web-development\u002F13.authorization-security\u002F10-https-production",{"title":4705,"icon":871,"path":4706,"stem":4707,"children":4708,"page":59},"Комунікація у реальному часі, нотифікації та фонові задачі","\u002Fweb-development\u002Frealtime-notifications-jobs","18.web-development\u002F14.realtime-notifications-jobs",[4709,4713,4717,4721,4725,4729,4732,4735,4739,4743],{"title":4710,"path":4711,"stem":4712},"Методи комунікації у реальному часі","\u002Fweb-development\u002Frealtime-notifications-jobs\u002F01-realtime-communication-methods","18.web-development\u002F14.realtime-notifications-jobs\u002F01-realtime-communication-methods",{"title":4714,"path":4715,"stem":4716},"WebSocket Gateway у NestJS","\u002Fweb-development\u002Frealtime-notifications-jobs\u002F02-websocket-gateway","18.web-development\u002F14.realtime-notifications-jobs\u002F02-websocket-gateway",{"title":4718,"path":4719,"stem":4720},"Lifecycle та Rooms у WebSocket","\u002Fweb-development\u002Frealtime-notifications-jobs\u002F03-websocket-lifecycle-rooms","18.web-development\u002F14.realtime-notifications-jobs\u002F03-websocket-lifecycle-rooms",{"title":4722,"path":4723,"stem":4724},"Server-Sent Events (SSE)","\u002Fweb-development\u002Frealtime-notifications-jobs\u002F04-server-sent-events","18.web-development\u002F14.realtime-notifications-jobs\u002F04-server-sent-events",{"title":4726,"path":4727,"stem":4728},"Архітектура системи нотифікацій","\u002Fweb-development\u002Frealtime-notifications-jobs\u002F05-notification-system","18.web-development\u002F14.realtime-notifications-jobs\u002F05-notification-system",{"title":904,"path":4730,"stem":4731},"\u002Fweb-development\u002Frealtime-notifications-jobs\u002F06-email-notifications","18.web-development\u002F14.realtime-notifications-jobs\u002F06-email-notifications",{"title":900,"path":4733,"stem":4734},"\u002Fweb-development\u002Frealtime-notifications-jobs\u002F07-web-push-notifications","18.web-development\u002F14.realtime-notifications-jobs\u002F07-web-push-notifications",{"title":4736,"path":4737,"stem":4738},"Фонові задачі та черги","\u002Fweb-development\u002Frealtime-notifications-jobs\u002F08-background-jobs-queues","18.web-development\u002F14.realtime-notifications-jobs\u002F08-background-jobs-queues",{"title":4740,"path":4741,"stem":4742},"Планувальники та Cron jobs","\u002Fweb-development\u002Frealtime-notifications-jobs\u002F09-schedulers-cron","18.web-development\u002F14.realtime-notifications-jobs\u002F09-schedulers-cron",{"title":4744,"path":4745,"stem":4746},"Практичні сценарії застосування","\u002Fweb-development\u002Frealtime-notifications-jobs\u002F10-practical-scenarios","18.web-development\u002F14.realtime-notifications-jobs\u002F10-practical-scenarios",{"title":4748,"icon":4749,"path":4750,"stem":4751,"children":4752,"page":59},"Тестування, документування та розгортання застосунків","i-lucide-rocket","\u002Fweb-development\u002Ftesting-documentation-deployment","18.web-development\u002F15.testing-documentation-deployment",[4753,4757,4761,4765,4769,4773,4777,4781,4785,4789],{"title":4754,"path":4755,"stem":4756},"Піраміда тестування та стратегія","\u002Fweb-development\u002Ftesting-documentation-deployment\u002F01-testing-pyramid-strategy","18.web-development\u002F15.testing-documentation-deployment\u002F01-testing-pyramid-strategy",{"title":4758,"path":4759,"stem":4760},"Основи Jest у NestJS","\u002Fweb-development\u002Ftesting-documentation-deployment\u002F02-jest-nestjs-basics","18.web-development\u002F15.testing-documentation-deployment\u002F02-jest-nestjs-basics",{"title":4762,"path":4763,"stem":4764},"Unit-тестування сервісів","\u002Fweb-development\u002Ftesting-documentation-deployment\u002F03-unit-testing-services","18.web-development\u002F15.testing-documentation-deployment\u002F03-unit-testing-services",{"title":4766,"path":4767,"stem":4768},"E2E тестування та покриття коду","\u002Fweb-development\u002Ftesting-documentation-deployment\u002F04-e2e-testing-coverage","18.web-development\u002F15.testing-documentation-deployment\u002F04-e2e-testing-coverage",{"title":4770,"path":4771,"stem":4772},"Swagger, OpenAPI, Scalar та Arazzo","\u002Fweb-development\u002Ftesting-documentation-deployment\u002F05-swagger-openapi","18.web-development\u002F15.testing-documentation-deployment\u002F05-swagger-openapi",{"title":4774,"path":4775,"stem":4776},"Керування конфігурацією","\u002Fweb-development\u002Ftesting-documentation-deployment\u002F06-configuration-management","18.web-development\u002F15.testing-documentation-deployment\u002F06-configuration-management",{"title":4778,"path":4779,"stem":4780},"Docker та контейнеризація","\u002Fweb-development\u002Ftesting-documentation-deployment\u002F07-docker-containerization","18.web-development\u002F15.testing-documentation-deployment\u002F07-docker-containerization",{"title":4782,"path":4783,"stem":4784},"CI\u002FCD Pipelines","\u002Fweb-development\u002Ftesting-documentation-deployment\u002F08-cicd-pipelines","18.web-development\u002F15.testing-documentation-deployment\u002F08-cicd-pipelines",{"title":4786,"path":4787,"stem":4788},"Логування та моніторинг","\u002Fweb-development\u002Ftesting-documentation-deployment\u002F09-logging-monitoring","18.web-development\u002F15.testing-documentation-deployment\u002F09-logging-monitoring",{"title":4790,"path":4791,"stem":4792},"Серіалізація та компресія","\u002Fweb-development\u002Ftesting-documentation-deployment\u002F10-serialization-compression","18.web-development\u002F15.testing-documentation-deployment\u002F10-serialization-compression",{"title":4794,"icon":4795,"path":4796,"stem":4797,"children":4798,"page":59},"AI Core: мислення AI","i-lucide-brain","\u002Fai-core","19.ai-core",[4799,4840,4889,4927],{"title":4800,"icon":4749,"path":4801,"stem":4802,"children":4803,"page":59},"Вхід у професію AI Native Developer","\u002Fai-core\u002Fai-native-developer","19.ai-core\u002F01.ai-native-developer",[4804,4808,4812,4816,4820,4824,4828,4832,4836],{"title":4805,"path":4806,"stem":4807},"Вступ до професії розробника цифрових продуктів","\u002Fai-core\u002Fai-native-developer\u002Fdigital-products","19.ai-core\u002F01.ai-native-developer\u002F01.digital-products",{"title":4809,"path":4810,"stem":4811},"Професія розробника програмного забезпечення","\u002Fai-core\u002Fai-native-developer\u002Fsoftware-developer","19.ai-core\u002F01.ai-native-developer\u002F02.software-developer",{"title":4813,"path":4814,"stem":4815},"Професія AI Native Developer","\u002Fai-core\u002Fai-native-developer\u002Fai-native-developer","19.ai-core\u002F01.ai-native-developer\u002F03.ai-native-developer",{"title":4817,"path":4818,"stem":4819},"Вплив AI на розробку програмного забезпечення","\u002Fai-core\u002Fai-native-developer\u002Fai-impact-on-development","19.ai-core\u002F01.ai-native-developer\u002F04.ai-impact-on-development",{"title":4821,"path":4822,"stem":4823},"Життєвий цикл цифрового продукту","\u002Fai-core\u002Fai-native-developer\u002Fproduct-lifecycle","19.ai-core\u002F01.ai-native-developer\u002F05.product-lifecycle",{"title":4825,"path":4826,"stem":4827},"Застосування AI на етапах створення цифрового продукту","\u002Fai-core\u002Fai-native-developer\u002Fai-in-product-creation","19.ai-core\u002F01.ai-native-developer\u002F06.ai-in-product-creation",{"title":4829,"path":4830,"stem":4831},"Розподіл завдань між людиною та AI","\u002Fai-core\u002Fai-native-developer\u002Fhuman-vs-ai-tasks","19.ai-core\u002F01.ai-native-developer\u002F07.human-vs-ai-tasks",{"title":4833,"path":4834,"stem":4835},"Компетенції AI Native Developer","\u002Fai-core\u002Fai-native-developer\u002Fcompetencies","19.ai-core\u002F01.ai-native-developer\u002F08.competencies",{"title":4837,"path":4838,"stem":4839},"Карта професійного розвитку AI Native Developer","\u002Fai-core\u002Fai-native-developer\u002Fcareer-roadmap","19.ai-core\u002F01.ai-native-developer\u002F09.career-roadmap",{"title":4841,"icon":255,"path":4842,"stem":4843,"children":4844,"page":59},"Штучний інтелект і машинне навчання","\u002Fai-core\u002Fai-and-machine-learning","19.ai-core\u002F02.ai-and-machine-learning",[4845,4849,4853,4857,4861,4865,4869,4873,4877,4881,4885],{"title":4846,"path":4847,"stem":4848},"Штучний інтелект","\u002Fai-core\u002Fai-and-machine-learning\u002Fwhat-is-ai","19.ai-core\u002F02.ai-and-machine-learning\u002F01.what-is-ai",{"title":4850,"path":4851,"stem":4852},"Відмінність AI від інших програмних систем","\u002Fai-core\u002Fai-and-machine-learning\u002Fai-vs-automation","19.ai-core\u002F02.ai-and-machine-learning\u002F02.ai-vs-automation",{"title":4854,"path":4855,"stem":4856},"Завдання штучного інтелекту","\u002Fai-core\u002Fai-and-machine-learning\u002Fai-tasks","19.ai-core\u002F02.ai-and-machine-learning\u002F03.ai-tasks",{"title":4858,"path":4859,"stem":4860},"Machine Learning","\u002Fai-core\u002Fai-and-machine-learning\u002Fmachine-learning","19.ai-core\u002F02.ai-and-machine-learning\u002F04.machine-learning",{"title":4862,"path":4863,"stem":4864},"Machine Learning Workflow","\u002Fai-core\u002Fai-and-machine-learning\u002Fml-workflow","19.ai-core\u002F02.ai-and-machine-learning\u002F05.ml-workflow",{"title":4866,"path":4867,"stem":4868},"Типи машинного навчання","\u002Fai-core\u002Fai-and-machine-learning\u002Fml-types","19.ai-core\u002F02.ai-and-machine-learning\u002F06.ml-types",{"title":4870,"path":4871,"stem":4872},"Generative AI","\u002Fai-core\u002Fai-and-machine-learning\u002Fgenerative-ai","19.ai-core\u002F02.ai-and-machine-learning\u002F07.generative-ai",{"title":4874,"path":4875,"stem":4876},"Типи контенту, створюваного AI","\u002Fai-core\u002Fai-and-machine-learning\u002Fai-content-types","19.ai-core\u002F02.ai-and-machine-learning\u002F08.ai-content-types",{"title":4878,"path":4879,"stem":4880},"Великі мовні моделі","\u002Fai-core\u002Fai-and-machine-learning\u002Flarge-language-models","19.ai-core\u002F02.ai-and-machine-learning\u002F09.large-language-models",{"title":4882,"path":4883,"stem":4884},"Можливості та обмеження Generative AI","\u002Fai-core\u002Fai-and-machine-learning\u002Fcapabilities-and-limitations","19.ai-core\u002F02.ai-and-machine-learning\u002F10.capabilities-and-limitations",{"title":4886,"path":4887,"stem":4888},"Сучасні AI-асистенти","\u002Fai-core\u002Fai-and-machine-learning\u002Fmodern-ai-assistants","19.ai-core\u002F02.ai-and-machine-learning\u002F11.modern-ai-assistants",{"title":4890,"icon":4891,"path":4892,"stem":4893,"children":4894,"page":59},"Постановка завдань для AI: принципи створення промптів","i-lucide-message-square-text","\u002Fai-core\u002Fprompt-engineering","19.ai-core\u002F03.prompt-engineering",[4895,4899,4903,4907,4911,4915,4919,4923],{"title":4896,"path":4897,"stem":4898},"Промпт як інструмент","\u002Fai-core\u002Fprompt-engineering\u002Fprompt-as-tool","19.ai-core\u002F03.prompt-engineering\u002F01.prompt-as-tool",{"title":4900,"path":4901,"stem":4902},"Принципи створення промптів","\u002Fai-core\u002Fprompt-engineering\u002Fprompt-principles","19.ai-core\u002F03.prompt-engineering\u002F02.prompt-principles",{"title":4904,"path":4905,"stem":4906},"Структура промпта","\u002Fai-core\u002Fprompt-engineering\u002Fprompt-structure","19.ai-core\u002F03.prompt-engineering\u002F03.prompt-structure",{"title":4908,"path":4909,"stem":4910},"Види промптів за типом задачі","\u002Fai-core\u002Fprompt-engineering\u002Fprompt-types","19.ai-core\u002F03.prompt-engineering\u002F04.prompt-types",{"title":4912,"path":4913,"stem":4914},"Прийоми посилення промпта","\u002Fai-core\u002Fprompt-engineering\u002Fprompt-enhancement","19.ai-core\u002F03.prompt-engineering\u002F05.prompt-enhancement",{"title":4916,"path":4917,"stem":4918},"Розбір і покращення промпта","\u002Fai-core\u002Fprompt-engineering\u002Fprompt-analysis","19.ai-core\u002F03.prompt-engineering\u002F06.prompt-analysis",{"title":4920,"path":4921,"stem":4922},"Типові помилки під час створення промптів","\u002Fai-core\u002Fprompt-engineering\u002Fcommon-mistakes","19.ai-core\u002F03.prompt-engineering\u002F07.common-mistakes",{"title":4924,"path":4925,"stem":4926},"Практикум: особиста бібліотека промптів","\u002Fai-core\u002Fprompt-engineering\u002Fprompt-library","19.ai-core\u002F03.prompt-engineering\u002F08.prompt-library",{"title":4928,"icon":793,"path":4929,"stem":4930,"children":4931,"page":59},"Перевірка результатів, безпека та AI Native Workflow","\u002Fai-core\u002Fverification-security-workflow","19.ai-core\u002F04.verification-security-workflow",[4932,4936,4940,4944,4948,4952,4956,4960,4964],{"title":4933,"path":4934,"stem":4935},"Межі можливостей AI","\u002Fai-core\u002Fverification-security-workflow\u002Fai-limitations","19.ai-core\u002F04.verification-security-workflow\u002F01.ai-limitations",{"title":4937,"path":4938,"stem":4939},"Галюцинації AI","\u002Fai-core\u002Fverification-security-workflow\u002Fai-hallucinations","19.ai-core\u002F04.verification-security-workflow\u002F02.ai-hallucinations",{"title":4941,"path":4942,"stem":4943},"Критичне мислення під час роботи з AI","\u002Fai-core\u002Fverification-security-workflow\u002Fcritical-thinking","19.ai-core\u002F04.verification-security-workflow\u002F03.critical-thinking",{"title":4945,"path":4946,"stem":4947},"Перевірка результатів роботи AI","\u002Fai-core\u002Fverification-security-workflow\u002Fresult-verification","19.ai-core\u002F04.verification-security-workflow\u002F04.result-verification",{"title":4949,"path":4950,"stem":4951},"Захист даних під час роботи з AI","\u002Fai-core\u002Fverification-security-workflow\u002Fdata-protection","19.ai-core\u002F04.verification-security-workflow\u002F05.data-protection",{"title":4953,"path":4954,"stem":4955},"Авторське право та навчальна доброчесність","\u002Fai-core\u002Fverification-security-workflow\u002Fcopyright-integrity","19.ai-core\u002F04.verification-security-workflow\u002F06.copyright-integrity",{"title":4957,"path":4958,"stem":4959},"Відповідальне використання AI","\u002Fai-core\u002Fverification-security-workflow\u002Fresponsible-use","19.ai-core\u002F04.verification-security-workflow\u002F07.responsible-use",{"title":4961,"path":4962,"stem":4963},"AI Native Workflow","\u002Fai-core\u002Fverification-security-workflow\u002Fai-native-workflow","19.ai-core\u002F04.verification-security-workflow\u002F08.ai-native-workflow",{"title":4965,"path":4966,"stem":4967},"Застосування AI Native Workflow під час створення цифрового продукту","\u002Fai-core\u002Fverification-security-workflow\u002Fworkflow-in-practice","19.ai-core\u002F04.verification-security-workflow\u002F09.workflow-in-practice",{"title":4969,"icon":4970,"path":4971,"stem":4972,"children":4973,"page":59},"AI Developer: Vibe Coding Sprint","i-lucide-code-xml","\u002Fai-developer","20.ai-developer",[4974,5000,5022,5043],{"title":4975,"icon":4976,"path":4977,"stem":4978,"children":4979,"page":59},"Проєктування і чорнова версія","i-lucide-pencil-ruler","\u002Fai-developer\u002Fdraft-creation","20.ai-developer\u002F01.draft-creation",[4980,4984,4988,4992,4996],{"title":4981,"path":4982,"stem":4983},"Парадигма Vibe Coding Workflow","\u002Fai-developer\u002Fdraft-creation\u002Fvibe-coding-workflow","20.ai-developer\u002F01.draft-creation\u002F01.vibe-coding-workflow",{"title":4985,"path":4986,"stem":4987},"AI-середовище швидкої розробки","\u002Fai-developer\u002Fdraft-creation\u002Fai-ide-environment","20.ai-developer\u002F01.draft-creation\u002F02.ai-ide-environment",{"title":4989,"path":4990,"stem":4991},"Користувацьке завдання та межі першої версії","\u002Fai-developer\u002Fdraft-creation\u002Fproduct-scope-and-mvp","20.ai-developer\u002F01.draft-creation\u002F03.product-scope-and-mvp",{"title":4993,"path":4994,"stem":4995},"Архітектура інтерфейсу та стани застосунку","\u002Fai-developer\u002Fdraft-creation\u002Fapplication-architecture-and-states","20.ai-developer\u002F01.draft-creation\u002F04.application-architecture-and-states",{"title":4997,"path":4998,"stem":4999},"Генерація та фіксація чорнової версії","\u002Fai-developer\u002Fdraft-creation\u002Fgenerating-draft-version","20.ai-developer\u002F01.draft-creation\u002F05.generating-draft-version",{"title":5001,"icon":5002,"path":5003,"stem":5004,"children":5005,"page":59},"Перша робоча версія","i-lucide-play-circle","\u002Fai-developer\u002Ffirst-working-version","20.ai-developer\u002F02.first-working-version",[5006,5010,5014,5018],{"title":5007,"path":5008,"stem":5009},"Уточнення контексту проєкту для AI","\u002Fai-developer\u002Ffirst-working-version\u002Frefining-project-context","20.ai-developer\u002F02.first-working-version\u002F01.refining-project-context",{"title":5011,"path":5012,"stem":5013},"Стратегія завдань для AI-розробки","\u002Fai-developer\u002Ffirst-working-version\u002Fai-prompting-strategy","20.ai-developer\u002F02.first-working-version\u002F02.ai-prompting-strategy",{"title":5015,"path":5016,"stem":5017},"Доопрацювання до першої робочої версії","\u002Fai-developer\u002Ffirst-working-version\u002Frefining-to-working-version","20.ai-developer\u002F02.first-working-version\u002F03.refining-to-working-version",{"title":5019,"path":5020,"stem":5021},"Перевірка першої робочої версії","\u002Fai-developer\u002Ffirst-working-version\u002Ftesting-first-working-version","20.ai-developer\u002F02.first-working-version\u002F04.testing-first-working-version",{"title":5023,"icon":3072,"path":5024,"stem":5025,"children":5026,"page":59},"Ітерації, дебагінг та відновлення","\u002Fai-developer\u002Fiteration-debugging-recovery","20.ai-developer\u002F03.iteration-debugging-recovery",[5027,5031,5035,5039],{"title":5028,"path":5029,"stem":5030},"Управління точковими змінами продукту","\u002Fai-developer\u002Fiteration-debugging-recovery\u002Fchange-management","20.ai-developer\u002F03.iteration-debugging-recovery\u002F01.change-management",{"title":5032,"path":5033,"stem":5034},"Надійність інтерфейсу та обробка помилок","\u002Fai-developer\u002Fiteration-debugging-recovery\u002Fscenario-reliability-and-errors","20.ai-developer\u002F03.iteration-debugging-recovery\u002F02.scenario-reliability-and-errors",{"title":5036,"path":5037,"stem":5038},"Керування контекстом і збереження версій","\u002Fai-developer\u002Fiteration-debugging-recovery\u002Fproject-context-and-versions","20.ai-developer\u002F03.iteration-debugging-recovery\u002F03.project-context-and-versions",{"title":5040,"path":5041,"stem":5042},"Збої AI-розробки, ліміти та аварійне відновлення","\u002Fai-developer\u002Fiteration-debugging-recovery\u002Fai-breakdowns-and-recovery","20.ai-developer\u002F03.iteration-debugging-recovery\u002F04.ai-breakdowns-and-recovery",{"title":5044,"icon":5045,"path":5046,"stem":5047,"children":5048,"page":59},"Перевірка та завершення продукту","i-lucide-check-check","\u002Fai-developer\u002Fverification-and-completion","20.ai-developer\u002F04.verification-and-completion",[5049,5053,5057],{"title":5050,"path":5051,"stem":5052},"Комплексний аудит та підсумкове тестування","\u002Fai-developer\u002Fverification-and-completion\u002Ffinal-product-testing","20.ai-developer\u002F04.verification-and-completion\u002F01.final-product-testing",{"title":5054,"path":5055,"stem":5056},"Підготовка підсумкової версії коду","\u002Fai-developer\u002Fverification-and-completion\u002Fpreparing-release-version","20.ai-developer\u002F04.verification-and-completion\u002F02.preparing-release-version",{"title":5058,"path":5059,"stem":5060},"Демонстрація, публікація та критерії оцінювання","\u002Fai-developer\u002Fverification-and-completion\u002Fproduct-showcase-and-publishing","20.ai-developer\u002F04.verification-and-completion\u002F03.product-showcase-and-publishing",{"title":5062,"path":5063,"stem":5064,"children":5065,"page":59},"Tailwind","\u002Ftailwind","21.tailwind",[5066,5070,5074,5078,5082,5086,5090,5094,5098,5102,5106,5110],{"title":5067,"path":5068,"stem":5069},"Що таке Tailwind CSS і навіщо він потрібен","\u002Ftailwind\u002Ftailwind-intro-philosophy","21.tailwind\u002F01.tailwind-intro-philosophy",{"title":5071,"path":5072,"stem":5073},"Встановлення та налаштування Tailwind CSS v4","\u002Ftailwind\u002Ftailwind-installation-setup","21.tailwind\u002F02.tailwind-installation-setup",{"title":5075,"path":5076,"stem":5077},"Utility-класи: основи та система Tailwind","\u002Ftailwind\u002Ftailwind-utility-classes-core","21.tailwind\u002F03.tailwind-utility-classes-core",{"title":5079,"path":5080,"stem":5081},"Layout: Flexbox та Grid через Tailwind","\u002Ftailwind\u002Ftailwind-flexbox-grid","21.tailwind\u002F04.tailwind-flexbox-grid",{"title":5083,"path":5084,"stem":5085},"Кастомізація теми через @theme у Tailwind v4","\u002Ftailwind\u002Ftailwind-theme-customization","21.tailwind\u002F05.tailwind-theme-customization",{"title":5087,"path":5088,"stem":5089},"Варіанти: hover, focus, responsive, dark mode та нові v4","\u002Ftailwind\u002Ftailwind-variants-states","21.tailwind\u002F06.tailwind-variants-states",{"title":5091,"path":5092,"stem":5093},"Типографіка та система кольорів у Tailwind v4","\u002Ftailwind\u002Ftailwind-typography-colors","21.tailwind\u002F07.tailwind-typography-colors",{"title":5095,"path":5096,"stem":5097},"Компоненти та повторюваність: @apply, @utility та патерни","\u002Ftailwind\u002Ftailwind-components-patterns","21.tailwind\u002F08.tailwind-components-patterns",{"title":5099,"path":5100,"stem":5101},"Темна тема та система дизайн-токенів у Tailwind v4","\u002Ftailwind\u002Ftailwind-dark-mode-theming","21.tailwind\u002F09.tailwind-dark-mode-theming",{"title":5103,"path":5104,"stem":5105},"Довільні значення та контейнерні запити у Tailwind v4","\u002Ftailwind\u002Ftailwind-arbitrary-container-queries","21.tailwind\u002F10.tailwind-arbitrary-container-queries",{"title":5107,"path":5108,"stem":5109},"Анімації, трансформації та 3D у Tailwind v4","\u002Ftailwind\u002Ftailwind-animations-transforms","21.tailwind\u002F11.tailwind-animations-transforms",{"title":5111,"path":5112,"stem":5113},"Tailwind CLI, PostCSS та інтеграція з фреймворками","\u002Ftailwind\u002Ftailwind-cli-tooling","21.tailwind\u002F12.tailwind-cli-tooling",{"title":5115,"path":5116,"stem":5117,"children":5118,"page":59},"React Typescript","\u002Freact-typescript","22.react-typescript",[5119,5144,5148,5152,5156,5160,5164,5168,5172],{"title":5120,"path":5121,"stem":5122,"children":5123,"page":59},"From Html To Project","\u002Freact-typescript\u002Ffrom-html-to-project","22.react-typescript\u002F01.from-html-to-project",[5124,5128,5132,5136,5140],{"title":5125,"path":5126,"stem":5127},"Від одного HTML-файлу до повноцінного проєкту","\u002Freact-typescript\u002Ffrom-html-to-project\u002Fevolution","22.react-typescript\u002F01.from-html-to-project\u002F01.evolution",{"title":5129,"path":5130,"stem":5131},"Що таке React","\u002Freact-typescript\u002Ffrom-html-to-project\u002Fwhat-is-react","22.react-typescript\u002F01.from-html-to-project\u002F02.what-is-react",{"title":5133,"path":5134,"stem":5135},"JSX та TSX — синтаксичний цукор, а не магія","\u002Freact-typescript\u002Ffrom-html-to-project\u002Fjsx-tsx-syntax","22.react-typescript\u002F01.from-html-to-project\u002F03.jsx-tsx-syntax",{"title":5137,"path":5138,"stem":5139},"Компоненти — будівельні блоки інтерфейсу","\u002Freact-typescript\u002Ffrom-html-to-project\u002Fcomponents","22.react-typescript\u002F01.from-html-to-project\u002F04.components",{"title":5141,"path":5142,"stem":5143},"JSX — розмітка всередині TypeScript","\u002Freact-typescript\u002Ffrom-html-to-project\u002Fjsx-expressions","22.react-typescript\u002F01.from-html-to-project\u002F05.jsx-expressions",{"title":5145,"path":5146,"stem":5147},"Хук useReducer: структуроване управління складним станом","\u002Freact-typescript\u002Fuse-reducer","22.react-typescript\u002F23.use-reducer",{"title":5149,"path":5150,"stem":5151},"Context API: передавання даних без «пропс-дрілінгу»","\u002Freact-typescript\u002Fcontext-api","22.react-typescript\u002F24.context-api",{"title":5153,"path":5154,"stem":5155},"Синхронізація з ефектами: хук useEffect та функції очищення","\u002Freact-typescript\u002Fuse-effect","22.react-typescript\u002F27.use-effect",{"title":5157,"path":5158,"stem":5159},"Можливо, вам не потрібен ефект: антипатерни та альтернативи","\u002Freact-typescript\u002Fyou-might-not-need-effect","22.react-typescript\u002F28.you-might-not-need-effect",{"title":5161,"path":5162,"stem":5163},"Життєвий цикл реактивних ефектів: мислення процесами синхронізації","\u002Freact-typescript\u002Flifecycle-of-reactive-effects","22.react-typescript\u002F29.lifecycle-of-reactive-effects",{"title":5165,"path":5166,"stem":5167},"Розділення подій та ефектів: реактивна проти нереактивної логіки","\u002Freact-typescript\u002Fseparating-events-from-effects","22.react-typescript\u002F30.separating-events-from-effects",{"title":5169,"path":5170,"stem":5171},"Видалення зайвих залежностей ефектів та оптимізація синхронізації","\u002Freact-typescript\u002Fremoving-effect-dependencies","22.react-typescript\u002F31.removing-effect-dependencies",{"title":5173,"path":5174,"stem":5175},"Кастомні хуки: повторне використання та композиція реактивної логіки","\u002Freact-typescript\u002Fcustom-hooks","22.react-typescript\u002F32.custom-hooks",{"title":5177,"path":5178,"stem":5179},"Тестування компонентів діаграм та пісочниць","\u002Ftest-components","98.test-components",{"id":5181,"title":4013,"body":5182,"description":17002,"extension":17003,"links":17004,"meta":17005,"navigation":5719,"path":4014,"seo":17006,"stem":4015,"__hash__":17007},"docs\u002F17.client-server-architecture\u002F07.dns-smtp-application-protocols.md",{"type":5183,"value":5184,"toc":16911},"minimark",[5185,5189,5364,5367,5372,5400,5420,5443,5448,5475,5482,5505,5507,5511,5540,5544,5551,5666,5675,5899,5903,5917,6045,6055,6057,6061,6075,6079,6089,6223,6226,6260,6267,6420,6424,6430,6479,6485,6487,6491,6497,6505,6540,6543,6547,6564,6569,6575,6584,6587,6591,6605,6609,6615,6618,6635,6639,6653,6657,6663,6676,6682,6703,6707,6721,6725,6731,6746,6759,6763,6777,6781,6787,6790,6822,6826,6840,6845,6851,6855,6861,6868,6885,6887,6891,6914,6920,6924,6945,6956,6996,7026,7049,7053,7062,7068,7076,7082,7085,7124,7147,7159,7165,7287,7291,7304,7310,7328,7331,7365,7378,7382,7396,7402,7466,7617,7621,7642,7648,7736,7740,7743,7750,7778,7787,7790,7878,7882,7896,7899,7963,7994,8009,8581,8636,8638,8642,8662,8666,8669,9021,9026,9032,9042,9046,9055,9488,9504,9508,9514,9948,9953,9959,9963,9976,10536,10554,10558,10565,11550,11556,11558,11562,11575,11597,11601,11608,11662,11827,11831,11834,11854,11870,11872,11876,11900,11904,11991,11995,12002,12090,12096,12100,12364,12366,12370,12383,12387,12404,12409,12499,12503,12515,12520,12526,12529,12556,12576,12580,12602,12924,12929,12935,12937,12941,12944,12951,13081,13085,13090,13095,13101,13104,13130,13142,13146,13159,13164,13170,13175,13181,13187,13191,13196,13201,13207,13209,13235,13239,13245,13259,13261,13265,13273,13277,13738,13752,13756,13759,14904,14908,14924,14934,14937,14967,14994,15004,15540,15598,15600,15604,15611,15615,15621,15626,15679,15684,16029,16036,16043,16047,16054,16059,16104,16111,16113,16117,16124,16128,16389,16393,16423,16456,16458,16462,16471,16475,16501,16505,16537,16541,16544,16560,16567,16573,16575,16579,16676,16678,16682,16686,16742,16746,16786,16790,16835,16837,16907],[5186,5187,4013],"h1",{"id":5188},"прикладні-мережеві-протоколи-dns-та-smtp",[5190,5191,5192,5307],"card-group",{},[5193,5194,5197],"card",{"icon":5195,"title":5196},"i-lucide-graduation-cap","🎯 Навчальні цілі",[5198,5199,5200,5209,5212,5219,5242,5262,5269,5280,5287,5293,5300],"ul",{},[5201,5202,5203,5204,5208],"li",{},"Усвідомити фундаментальну роль ",[5205,5206,5207],"strong",{},"системи доменних імен"," (DNS) як критичної інфраструктури інтернету, без якої неможливе функціонування жодного мережевого сервісу.",[5201,5210,5211],{},"Зрозуміти ієрархічну структуру DNS-простору імен від кореневих серверів до локальних зон, механізми делегування відповідальності та кешування на різних рівнях.",[5201,5213,5214,5215,5218],{},"Опанувати формат ",[5205,5216,5217],{},"DNS-повідомлень",": заголовок, секції запитів та відповідей, формат ресурсних записів (Resource Records) і роль кодів відповідей.",[5201,5220,5221,5222,5225,5226,5225,5229,5225,5232,5225,5235,5225,5238,5241],{},"Вивчити типи DNS-записів (",[5205,5223,5224],{},"A",", ",[5205,5227,5228],{},"AAAA",[5205,5230,5231],{},"CNAME",[5205,5233,5234],{},"MX",[5205,5236,5237],{},"TXT",[5205,5239,5240],{},"SRV",") та зрозуміти їхнє практичне застосування для маршрутизації трафіку, виявлення сервісів та верифікації доменів.",[5201,5243,5244,5245,5248,5249,5252,5253,5256,5257,5261],{},"Дослідити архітектурну проблему обмеження CNAME на вершині зони (",[5205,5246,5247],{},"Zone Apex",") за стандартом RFC 1034 та зрозуміти, як технології ",[5205,5250,5251],{},"CNAME Flattening \u002F ALIAS",", новий стандарт ",[5205,5254,5255],{},"RFC 9460 (HTTPS\u002FSVCB)",", заголовок Host в HTTP\u002F1.1 та розширення SNI в TLS уможливили повноцінне функціонування сайтів без піддомену ",[5258,5259,5260],"code",{},"www",".",[5201,5263,5264,5265,5268],{},"Навчитися програмно виконувати DNS-резолвінг у Go через пакет ",[5258,5266,5267],{},"net.Resolver"," із підтримкою кастомних DNS-серверів, таймаутів та обробки помилок.",[5201,5270,5271,5272,5275,5276,5279],{},"Зрозуміти архітектуру ",[5205,5273,5274],{},"електронної пошти"," та роль протоколу ",[5205,5277,5278],{},"SMTP"," (Simple Mail Transfer Protocol) як стандарту передачі повідомлень між поштовими серверами.",[5201,5281,5282,5283,5286],{},"Розібрати структуру ",[5205,5284,5285],{},"SMTP-сеансу",": команди (HELO, MAIL FROM, RCPT TO, DATA), коди відповідей та діаграму послідовності успішної доставки листа.",[5201,5288,5214,5289,5292],{},[5205,5290,5291],{},"MIME"," (Multipurpose Internet Mail Extensions): багатокомпонентні повідомлення (Multipart\u002Falternative, Multipart\u002Fmixed), кодування Base64 та вкладення файлів.",[5201,5294,5295,5296,5299],{},"Вивчити сучасні механізми ",[5205,5297,5298],{},"захисту електронної пошти",": шифрування каналу через STARTTLS, автентифікація джерела за допомогою SPF, цифрові підписи DKIM та політики DMARC.",[5201,5301,5302,5303,5306],{},"Навчитися програмно надсилати електронні листи через Go-пакет ",[5258,5304,5305],{},"net\u002Fsmtp"," із налаштуванням автентифікації, TLS та формуванням MIME-повідомлень.",[5193,5308,5310],{"icon":255,"title":5309},"🛠️ Технологічний стек",[5198,5311,5312,5318,5338,5358],{},[5201,5313,5314,5317],{},[5205,5315,5316],{},"Мова:"," Go 1.22+",[5201,5319,5320,5323,5324,5225,5327,5225,5329,5225,5332,5225,5335],{},[5205,5321,5322],{},"Пакети стандартної бібліотеки:"," ",[5258,5325,5326],{},"net",[5258,5328,5305],{},[5258,5330,5331],{},"net\u002Fmail",[5258,5333,5334],{},"mime",[5258,5336,5337],{},"encoding\u002Fbase64",[5201,5339,5340,5323,5343,5346,5347,5346,5350,5353,5354,5357],{},[5205,5341,5342],{},"Інструменти діагностики:",[5258,5344,5345],{},"dig"," \u002F ",[5258,5348,5349],{},"nslookup",[5258,5351,5352],{},"host"," для DNS-запитів, ",[5258,5355,5356],{},"telnet"," для ручного SMTP-сеансу, Wireshark для аналізу трафіку",[5201,5359,5360,5363],{},[5205,5361,5362],{},"Тестові сервіси:"," MailHog \u002F Mailpit для локального емулятора SMTP-сервера, Cloudflare DNS \u002F Google Public DNS (8.8.8.8)",[5365,5366],"hr",{},[5368,5369,5371],"h2",{"id":5370},"система-доменних-імен-dns-від-числових-адрес-до-зрозумілих-імен","Система доменних імен (DNS): від числових адрес до зрозумілих імен",[5373,5374,5375,5376,5379,5380,5383,5384,5387,5388,5391,5392,5395,5396,5399],"p",{},"У попередніх лекціях ми працювали з мережевими адресами у форматі ",[5205,5377,5378],{},"IP-адрес",": ",[5258,5381,5382],{},"127.0.0.1"," для локального сервера, ",[5258,5385,5386],{},"192.168.1.100"," для пристрою в локальній мережі, публічні адреси типу ",[5258,5389,5390],{},"93.184.216.34"," для з'єднання з віддаленими серверами в інтернеті. Але коли ви, як звичайний користувач, відкриваєте браузер і вводите в адресному рядку ",[5258,5393,5394],{},"https:\u002F\u002Fwww.google.com"," або коли ваш мобільний застосунок на React Native підключається до API за адресою ",[5258,5397,5398],{},"https:\u002F\u002Fapi.company.com\u002Fv1\u002Fusers",", — ви ніде не вказуєте IP-адресу. Як же комп'ютер дізнається, на яку конкретну числову адресу йому потрібно встановлювати TCP-з'єднання?",[5373,5401,5402,5403,5406,5407,5411,5412,5415,5416,5419],{},"Відповідь проста і водночас надзвичайно складна: за лаштунками працює ",[5205,5404,5405],{},"система доменних імен"," (",[5408,5409,5410],"em",{},"Domain Name System",", DNS) — глобальна розподілена база даних, яка перетворює зручні для людини символьні імена (як-от ",[5258,5413,5414],{},"www.google.com",") на числові IP-адреси (наприклад, ",[5258,5417,5418],{},"142.250.185.68","), необхідні для маршрутизації пакетів у мережі. DNS — це один із найстаріших і найкритичніших протоколів інтернету, без якого неможливе функціонування практично жодного сучасного мережевого сервісу: вебсайтів, REST API, електронної пошти, мобільних застосунків, IoT-пристроїв, систем потокового відео — усі вони в тому чи іншому вигляді покладаються на DNS для перетворення імен на адреси.",[5421,5422,5423,5426,5427,5430,5431,5434,5435,5438,5439,5442],"note",{},[5205,5424,5425],{},"Історична довідка:"," протокол DNS був стандартизований у 1987 році в специфікаціях ",[5205,5428,5429],{},"RFC 1034"," та ",[5205,5432,5433],{},"RFC 1035",", замінивши собою простий текстовий файл ",[5258,5436,5437],{},"HOSTS.TXT",", який у ранні дні інтернету (тоді він називався ARPANET) вручну розподілявся між усіма вузлами мережі. Із зростанням кількості хостів до тисяч і десятків тисяч стало очевидно, що централізоване керування одним файлом більше не є масштабованим рішенням, і виникла потреба в ",[5205,5440,5441],{},"розподіленій ієрархічній системі",", здатній обробляти мільярди запитів на день.",[5444,5445,5447],"h3",{"id":5446},"чому-dns-є-критично-важливим-для-клієнт-серверних-систем","Чому DNS є критично важливим для клієнт-серверних систем",[5373,5449,5450,5451,5454,5455,5458,5459,5462,5463,5466,5467,5470,5471,5474],{},"Спробуємо усвідомити масштаб впливу DNS на повсякденну роботу будь-якого інженера-програміста. Кожного разу, коли ваш Go-сервер виконує виклик ",[5258,5452,5453],{},"http.Get(\"https:\u002F\u002Fapi.external-service.com\u002Fdata\")",", перед встановленням TCP-з'єднання Go-рантайм звертається до системного DNS-резолвера операційної системи із запитом: «Яка IP-адреса відповідає імені ",[5258,5456,5457],{},"api.external-service.com","?». Резолвер, у свою чергу, може мати кешовану відповідь із попередніх запитів або звернутися до рекурсивного DNS-сервера вашого інтернет-провайдера, який запитає авторитетні DNS-сервери домену ",[5258,5460,5461],{},".com",", потім авторитетні сервери зони ",[5258,5464,5465],{},"external-service.com",", отримає відповідь, поверне її вашому резолверу, закешує на певний час (визначений полем ",[5205,5468,5469],{},"TTL"," — ",[5408,5472,5473],{},"Time To Live",") і лише після цього ваша програма зможе встановити з'єднання.",[5373,5476,5477,5478,5481],{},"Якщо на будь-якому з цих етапів станеться збій — DNS-сервер недоступний, доменне ім'я не існує, відповідь сфальсифікована зловмисником (атака ",[5205,5479,5480],{},"DNS Spoofing",") — ваш застосунок отримає помилку, навіть якщо сам сервер, до якого ви намагаєтеся підключитися, працює ідеально. Саме тому розуміння архітектури DNS, форматів запитів і відповідей, типів ресурсних записів та механізмів безпеки є абсолютно критичним для будь-якого бекенд-розробника.",[5483,5484,5485,5488,5489,5492,5493,5496,5497,5500,5501,5504],"warning",{},[5205,5486,5487],{},"DNS як вектор атак:"," оскільки DNS працює переважно через протокол ",[5205,5490,5491],{},"UDP"," (хоча існує і DNS-over-TCP, і сучасні DNS-over-HTTPS\u002FTLS), запити та відповіді передаються без шифрування і можуть бути підроблені атакуючим, який контролює проміжний мережевий вузол. Це дозволяє перенаправити клієнта на фальшивий сервер, навіть якщо сам клієнт вважає, що підключається до легітимного домену. Саме тому з'явилися розширення безпеки DNS: ",[5205,5494,5495],{},"DNSSEC"," (цифрові підписи DNS-записів) та ",[5205,5498,5499],{},"DNS-over-HTTPS"," (DoH) \u002F ",[5205,5502,5503],{},"DNS-over-TLS"," (DoT), які шифрують і автентифікують DNS-трафік.",[5365,5506],{},[5368,5508,5510],{"id":5509},"ієрархічна-структура-dns-простору-імен-від-кореня-до-вузла","Ієрархічна структура DNS-простору імен: від кореня до вузла",[5373,5512,5513,5514,5517,5518,5406,5521,5524,5525,5406,5528,5531,5532,5535,5536,5539],{},"Система доменних імен побудована як ",[5205,5515,5516],{},"ієрархічне дерево",", структурно схоже на файлову систему Unix, де кожен вузол дерева представляє ",[5205,5519,5520],{},"зону відповідальності",[5408,5522,5523],{},"zone","), а кожна зона керується набором ",[5205,5526,5527],{},"авторитетних DNS-серверів",[5408,5529,5530],{},"authoritative nameservers","). Розглянемо повне доменне ім'я (",[5408,5533,5534],{},"Fully Qualified Domain Name",", FQDN) ",[5258,5537,5538],{},"www.example.com."," — зверніть увагу на крапку в кінці, яка є важливою, хоча зазвичай її опускають у повсякденному користуванні.",[5444,5541,5543],{"id":5542},"розбір-структури-fqdn-зправа-наліво","Розбір структури FQDN зправа наліво",[5373,5545,5546,5547,5550],{},"Доменне ім'я читається ",[5205,5548,5549],{},"справа наліво",", від загального до конкретного:",[5552,5553,5554,5587,5626,5640],"ol",{},[5201,5555,5556,5562,5563,5406,5566,5569,5570,5573,5574,5576,5577,5379,5580,5225,5583,5586],{},[5205,5557,5558,5559,5561],{},"Крапка в кінці (",[5258,5560,5261],{},")"," — це ",[5205,5564,5565],{},"корінь дерева DNS",[5408,5567,5568],{},"root zone","). Він не має імені, але є початковою точкою всієї ієрархії. Кореневі DNS-сервери (їх усього ",[5205,5571,5572],{},"13 логічних кластерів"," по всьому світу, позначених літерами від ",[5258,5575,5224],{}," до ",[5258,5578,5579],{},"M",[5258,5581,5582],{},"a.root-servers.net",[5258,5584,5585],{},"b.root-servers.net"," тощо) зберігають інформацію про те, які сервери відповідають за домени верхнього рівня (TLD).",[5201,5588,5589,5562,5594,5406,5597,5600,5601,5225,5603,5225,5606,5225,5609,5612,5613,5225,5616,5225,5619,5622,5623,5625],{},[5205,5590,5591],{},[5258,5592,5593],{},"com",[5205,5595,5596],{},"домен верхнього рівня",[5408,5598,5599],{},"Top-Level Domain",", TLD). Існують загальні TLD (gTLD) як-от ",[5258,5602,5461],{},[5258,5604,5605],{},".org",[5258,5607,5608],{},".net",[5258,5610,5611],{},".edu",", і національні TLD (ccTLD) як-от ",[5258,5614,5615],{},".ua",[5258,5617,5618],{},".us",[5258,5620,5621],{},".uk",". За кожен TLD відповідають окремі авторитетні сервери, наприклад, зону ",[5258,5624,5461],{}," керує організація Verisign.",[5201,5627,5628,5562,5633,5406,5636,5639],{},[5205,5629,5630],{},[5258,5631,5632],{},"example",[5205,5634,5635],{},"домен другого рівня",[5408,5637,5638],{},"second-level domain","), зареєстрований власником (фізичною особою, компанією, організацією) через акредитованого реєстратора доменів (наприклад, GoDaddy, Namecheap). Власник домену налаштовує власні авторитетні DNS-сервери (або використовує сервіси на кшталт Cloudflare DNS, AWS Route 53), які зберігають інформацію про всі піддомени третього рівня.",[5201,5641,5642,5562,5646,5406,5649,5652,5653,5655,5656,5225,5659,5225,5662,5665],{},[5205,5643,5644],{},[5258,5645,5260],{},[5205,5647,5648],{},"піддомен третього рівня",[5408,5650,5651],{},"subdomain","), який вказує на конкретний сервер або сервіс. Традиційно ",[5258,5654,5260],{}," використовується для вебсерверів, але можуть існувати будь-які інші імена: ",[5258,5657,5658],{},"api.example.com",[5258,5660,5661],{},"mail.example.com",[5258,5663,5664],{},"cdn.example.com"," тощо.",[5373,5667,5668],{},[5669,5670],"img",{"alt":5671,"className":5672,"src":5674},"Ієрархічна структура DNS-дерева від кореневих серверів до авторитетних зон",[5673],"diagram-img","\u002Fimages\u002Fclient-server-architecture\u002Fdns-smtp-application-protocols\u002F01.png",[5676,5677,5679],"plant-uml",{"alt":5678},"Ієрархічна структура DNS-дерева від кореня до вузла",[5680,5681,5686],"pre",{"className":5682,"code":5683,"language":5684,"meta":5685,"style":5685},"language-plantuml shiki shiki-themes light-plus dark-plus dark-plus","@startuml\nskinparam style plain\nskinparam backgroundColor #FFFFFF\nskinparam linetype ortho\n\npackage \"Корінь DNS (.)\" #F1F5F9 {\n    [a.root-servers.net]\n    [b.root-servers.net]\n    [... m.root-servers.net]\n}\n\npackage \"TLD: .com\" #DBEAFE {\n    [a.gtld-servers.net]\n    [b.gtld-servers.net]\n}\n\npackage \"Домен: example.com\" #FEF3C7 {\n    [ns1.example.com]\n    [ns2.example.com]\n}\n\npackage \"Піддомени\" #DCFCE7 {\n    [www.example.com → 93.184.216.34]\n    [api.example.com → 192.0.2.10]\n    [mail.example.com → MX-запис]\n}\n\n[a.root-servers.net] --> [a.gtld-servers.net] : Делегування зони .com\n[a.gtld-servers.net] --> [ns1.example.com] : Делегування зони example.com\n[ns1.example.com] --> [www.example.com → 93.184.216.34] : Авторитетна відповідь\n\nnote right of [www.example.com → 93.184.216.34] #DCFCE7\n  Кінцева IP-адреса,\n  яка повертається клієнту\nend note\n@enduml\n","plantuml","",[5258,5687,5688,5696,5702,5708,5714,5721,5727,5733,5739,5745,5751,5756,5762,5768,5774,5779,5784,5790,5796,5802,5807,5812,5818,5824,5830,5836,5841,5846,5852,5858,5864,5869,5875,5881,5887,5893],{"__ignoreMap":5685},[5689,5690,5693],"span",{"class":5691,"line":5692},"line",1,[5689,5694,5695],{},"@startuml\n",[5689,5697,5699],{"class":5691,"line":5698},2,[5689,5700,5701],{},"skinparam style plain\n",[5689,5703,5705],{"class":5691,"line":5704},3,[5689,5706,5707],{},"skinparam backgroundColor #FFFFFF\n",[5689,5709,5711],{"class":5691,"line":5710},4,[5689,5712,5713],{},"skinparam linetype ortho\n",[5689,5715,5717],{"class":5691,"line":5716},5,[5689,5718,5720],{"emptyLinePlaceholder":5719},true,"\n",[5689,5722,5724],{"class":5691,"line":5723},6,[5689,5725,5726],{},"package \"Корінь DNS (.)\" #F1F5F9 {\n",[5689,5728,5730],{"class":5691,"line":5729},7,[5689,5731,5732],{},"    [a.root-servers.net]\n",[5689,5734,5736],{"class":5691,"line":5735},8,[5689,5737,5738],{},"    [b.root-servers.net]\n",[5689,5740,5742],{"class":5691,"line":5741},9,[5689,5743,5744],{},"    [... m.root-servers.net]\n",[5689,5746,5748],{"class":5691,"line":5747},10,[5689,5749,5750],{},"}\n",[5689,5752,5754],{"class":5691,"line":5753},11,[5689,5755,5720],{"emptyLinePlaceholder":5719},[5689,5757,5759],{"class":5691,"line":5758},12,[5689,5760,5761],{},"package \"TLD: .com\" #DBEAFE {\n",[5689,5763,5765],{"class":5691,"line":5764},13,[5689,5766,5767],{},"    [a.gtld-servers.net]\n",[5689,5769,5771],{"class":5691,"line":5770},14,[5689,5772,5773],{},"    [b.gtld-servers.net]\n",[5689,5775,5777],{"class":5691,"line":5776},15,[5689,5778,5750],{},[5689,5780,5782],{"class":5691,"line":5781},16,[5689,5783,5720],{"emptyLinePlaceholder":5719},[5689,5785,5787],{"class":5691,"line":5786},17,[5689,5788,5789],{},"package \"Домен: example.com\" #FEF3C7 {\n",[5689,5791,5793],{"class":5691,"line":5792},18,[5689,5794,5795],{},"    [ns1.example.com]\n",[5689,5797,5799],{"class":5691,"line":5798},19,[5689,5800,5801],{},"    [ns2.example.com]\n",[5689,5803,5805],{"class":5691,"line":5804},20,[5689,5806,5750],{},[5689,5808,5810],{"class":5691,"line":5809},21,[5689,5811,5720],{"emptyLinePlaceholder":5719},[5689,5813,5815],{"class":5691,"line":5814},22,[5689,5816,5817],{},"package \"Піддомени\" #DCFCE7 {\n",[5689,5819,5821],{"class":5691,"line":5820},23,[5689,5822,5823],{},"    [www.example.com → 93.184.216.34]\n",[5689,5825,5827],{"class":5691,"line":5826},24,[5689,5828,5829],{},"    [api.example.com → 192.0.2.10]\n",[5689,5831,5833],{"class":5691,"line":5832},25,[5689,5834,5835],{},"    [mail.example.com → MX-запис]\n",[5689,5837,5839],{"class":5691,"line":5838},26,[5689,5840,5750],{},[5689,5842,5844],{"class":5691,"line":5843},27,[5689,5845,5720],{"emptyLinePlaceholder":5719},[5689,5847,5849],{"class":5691,"line":5848},28,[5689,5850,5851],{},"[a.root-servers.net] --> [a.gtld-servers.net] : Делегування зони .com\n",[5689,5853,5855],{"class":5691,"line":5854},29,[5689,5856,5857],{},"[a.gtld-servers.net] --> [ns1.example.com] : Делегування зони example.com\n",[5689,5859,5861],{"class":5691,"line":5860},30,[5689,5862,5863],{},"[ns1.example.com] --> [www.example.com → 93.184.216.34] : Авторитетна відповідь\n",[5689,5865,5867],{"class":5691,"line":5866},31,[5689,5868,5720],{"emptyLinePlaceholder":5719},[5689,5870,5872],{"class":5691,"line":5871},32,[5689,5873,5874],{},"note right of [www.example.com → 93.184.216.34] #DCFCE7\n",[5689,5876,5878],{"class":5691,"line":5877},33,[5689,5879,5880],{},"  Кінцева IP-адреса,\n",[5689,5882,5884],{"class":5691,"line":5883},34,[5689,5885,5886],{},"  яка повертається клієнту\n",[5689,5888,5890],{"class":5691,"line":5889},35,[5689,5891,5892],{},"end note\n",[5689,5894,5896],{"class":5691,"line":5895},36,[5689,5897,5898],{},"@enduml\n",[5444,5900,5902],{"id":5901},"процес-рекурсивного-резолвінгу-як-клієнт-отримує-відповідь","Процес рекурсивного резолвінгу: як клієнт отримує відповідь",[5373,5904,5905,5906,5909,5910,5406,5913,5916],{},"Коли ваш застосунок (наприклад, Go-клієнт) викликає ",[5258,5907,5908],{},"net.LookupHost(\"www.example.com\")",", за лаштунками відбувається ",[5205,5911,5912],{},"рекурсивний процес резолвінгу",[5408,5914,5915],{},"recursive resolution","), який можна розбити на наступні кроки:",[5918,5919,5920,5924,5939,5943,5958,5962,5981,5985,5995,5999,6031,6035],"steps",{},[5444,5921,5923],{"id":5922},"крок-1-перевірка-локального-кешу-резолвера","Крок 1. Перевірка локального кешу резолвера",[5373,5925,5926,5927,5930,5931,5934,5935,5938],{},"Операційна система має власний DNS-резолвер (у Linux це зазвичай ",[5258,5928,5929],{},"systemd-resolved",", у macOS — ",[5258,5932,5933],{},"mDNSResponder","), який зберігає кеш недавніх DNS-відповідей. Якщо запис для ",[5258,5936,5937],{},"www.example.com"," уже є в кеші і його час життя (TTL) ще не вичерпано — відповідь повертається негайно, без мережевих запитів.",[5444,5940,5942],{"id":5941},"крок-2-звернення-до-рекурсивного-dns-сервера","Крок 2. Звернення до рекурсивного DNS-сервера",[5373,5944,5945,5946,5949,5950,5953,5954,5957],{},"Якщо кешу немає, резолвер надсилає запит до налаштованого ",[5205,5947,5948],{},"рекурсивного DNS-сервера"," (зазвичай це сервер інтернет-провайдера або публічні резолвери на кшталт Google ",[5258,5951,5952],{},"8.8.8.8",", Cloudflare ",[5258,5955,5956],{},"1.1.1.1","). Цей сервер бере на себе відповідальність за виконання всього ланцюжка запитів замість клієнта.",[5444,5959,5961],{"id":5960},"крок-3-запит-до-кореневого-сервера","Крок 3. Запит до кореневого сервера",[5373,5963,5964,5965,5967,5968,5970,5971,5973,5974,5470,5977,5980],{},"Рекурсивний сервер звертається до одного з 13 кореневих серверів із запитом: «Хто відповідає за зону ",[5258,5966,5461],{},"?». Кореневий сервер не знає кінцевої адреси ",[5258,5969,5937],{},", але знає адреси авторитетних серверів для TLD ",[5258,5972,5461],{}," і повертає їх у відповіді (тип запису ",[5205,5975,5976],{},"NS",[5408,5978,5979],{},"Name Server",").",[5444,5982,5984],{"id":5983},"крок-4-запит-до-tld-сервера","Крок 4. Запит до TLD-сервера",[5373,5986,5987,5988,5990,5991,5994],{},"Рекурсивний сервер звертається до TLD-сервера ",[5258,5989,5461],{}," із тим самим запитом. TLD-сервер також не знає кінцевої адреси, але знає, які сервери відповідають за зону ",[5258,5992,5993],{},"example.com",", і повертає їхні адреси (знову NS-записи).",[5444,5996,5998],{"id":5997},"крок-5-запит-до-авторитетного-сервера-домену","Крок 5. Запит до авторитетного сервера домену",[5373,6000,6001,6002,6004,6005,6008,6009,6011,6012,5406,6015,6018,6019,6021,6022,6024,6025,6027,6028,6030],{},"Нарешті, рекурсивний сервер звертається до авторитетного DNS-сервера зони ",[5258,6003,5993],{}," (наприклад, ",[5258,6006,6007],{},"ns1.example.com",") із запитом про ",[5258,6010,5937],{},". Цей сервер має ",[5205,6013,6014],{},"авторитетну відповідь",[5408,6016,6017],{},"authoritative answer",") — він точно знає, що ",[5258,6020,5937],{}," вказує на IP-адресу ",[5258,6023,5390],{},", і повертає запис типу ",[5205,6026,5224],{}," (для IPv4) або ",[5205,6029,5228],{}," (для IPv6).",[5444,6032,6034],{"id":6033},"крок-6-повернення-відповіді-клієнту-та-кешування","Крок 6. Повернення відповіді клієнту та кешування",[5373,6036,6037,6038,6040,6041,6044],{},"Рекурсивний сервер отримує кінцеву відповідь, кешує її на час, визначений полем ",[5205,6039,5469],{}," (наприклад, 300 секунд), і повертає IP-адресу клієнтській програмі. Тепер Go-застосунок може встановити TCP-з'єднання з ",[5258,6042,6043],{},"93.184.216.34:443"," і розпочати TLS-рукостискання для HTTPS-запиту.",[6046,6047,6048,6051,6052,6054],"tip",{},[5205,6049,6050],{},"Чому рекурсивний резолвер кешує відповіді:"," уявімо, що мільйони користувачів одночасно звертаються до популярного сайту ",[5258,6053,5414],{},". Якщо кожен запит вимагатиме проходження всього ланцюжка від кореневих серверів до авторитетних — це створило б колосальне навантаження на DNS-інфраструктуру. Кешування на рівні рекурсивних резолверів (які обслуговують тисячі клієнтів) різко зменшує кількість запитів до авторитетних серверів і прискорює час відповіді для кінцевих користувачів.",[5365,6056],{},[5368,6058,6060],{"id":6059},"формат-dns-повідомлень-структура-запитів-та-відповідей","Формат DNS-повідомлень: структура запитів та відповідей",[5373,6062,6063,6064,6066,6067,6070,6071,6074],{},"Протокол DNS працює переважно через ",[5205,6065,5491],{}," на порту ",[5205,6068,6069],{},"53"," (хоча для великих відповідей розміром понад 512 байт може використовуватися TCP). Кожне DNS-повідомлення — як запит від клієнта, так і відповідь від сервера — має ",[5205,6072,6073],{},"єдиний бінарний формат",", визначений у RFC 1035. Розуміння цієї структури є критично важливим, якщо вам потрібно реалізовувати власний DNS-клієнт, проксі-сервер або аналізувати DNS-трафік за допомогою Wireshark.",[5444,6076,6078],{"id":6077},"структура-заголовка-dns-повідомлення","Структура заголовка DNS-повідомлення",[5373,6080,6081,6082,5406,6085,6088],{},"Кожне DNS-повідомлення починається з ",[5205,6083,6084],{},"12-байтного заголовка",[5408,6086,6087],{},"header","), який містить метадані про тип повідомлення, кількість записів та прапорці керування. Заголовок складається з наступних полів:",[5552,6090,6091,6097,6187,6196,6205,6214],{},[5201,6092,6093,6096],{},[5205,6094,6095],{},"Transaction ID (16 біт)"," — унікальний ідентифікатор запиту, згенерований клієнтом. Коли сервер надсилає відповідь, він копіює цей ідентифікатор у свою відповідь, щоб клієнт міг зіставити відповідь із початковим запитом.",[5201,6098,6099,6102,6103],{},[5205,6100,6101],{},"Flags (16 біт)"," — набір прапорців, які визначають характер повідомлення:",[5198,6104,6105,6126,6135,6144,6157,6166,6175,6181],{},[5201,6106,6107,6110,6111,6114,6115,6118,6119,6122,6123,5980],{},[5205,6108,6109],{},"QR"," (1 біт): ",[5258,6112,6113],{},"0"," = запит (",[5408,6116,6117],{},"query","), ",[5258,6120,6121],{},"1"," = відповідь (",[5408,6124,6125],{},"response",[5201,6127,6128,6131,6132,6134],{},[5205,6129,6130],{},"Opcode"," (4 біти): тип операції (зазвичай ",[5258,6133,6113],{}," = стандартний запит).",[5201,6136,6137,6110,6140,6143],{},[5205,6138,6139],{},"AA",[5408,6141,6142],{},"Authoritative Answer"," — чи є відповідь авторитетною (від сервера, який безпосередньо відповідає за цю зону).",[5201,6145,6146,6110,6149,6152,6153,6156],{},[5205,6147,6148],{},"TC",[5408,6150,6151],{},"Truncated"," — чи було повідомлення обрізане через обмеження розміру UDP (512 байт). Якщо ",[5258,6154,6155],{},"TC=1",", клієнт повинен повторити запит через TCP.",[5201,6158,6159,6110,6162,6165],{},[5205,6160,6161],{},"RD",[5408,6163,6164],{},"Recursion Desired"," — клієнт просить сервер виконати рекурсивний резолвінг.",[5201,6167,6168,6110,6171,6174],{},[5205,6169,6170],{},"RA",[5408,6172,6173],{},"Recursion Available"," — сервер підтримує рекурсію.",[5201,6176,6177,6180],{},[5205,6178,6179],{},"Z"," (3 біти): зарезервовані біти (повинні бути нульовими).",[5201,6182,6183,6186],{},[5205,6184,6185],{},"RCODE"," (4 біти): код відповіді (успіх, помилка, домен не існує тощо).",[5201,6188,6189,6192,6193,5980],{},[5205,6190,6191],{},"QDCOUNT (16 біт)"," — кількість записів у секції запитів (",[5408,6194,6195],{},"Questions",[5201,6197,6198,6201,6202,5980],{},[5205,6199,6200],{},"ANCOUNT (16 біт)"," — кількість записів у секції відповідей (",[5408,6203,6204],{},"Answers",[5201,6206,6207,6210,6211,5980],{},[5205,6208,6209],{},"NSCOUNT (16 біт)"," — кількість записів у секції авторитетних серверів (",[5408,6212,6213],{},"Authority",[5201,6215,6216,6219,6220,5980],{},[5205,6217,6218],{},"ARCOUNT (16 біт)"," — кількість записів у додатковій секції (",[5408,6221,6222],{},"Additional",[5373,6224,6225],{},"Після заголовка йдуть чотири секції змінної довжини:",[5198,6227,6228,6238,6248,6254],{},[5201,6229,6230,6233,6234,6237],{},[5205,6231,6232],{},"Question Section"," — містить один або більше запитів (зазвичай один): доменне ім'я, тип запиту (A, AAAA, MX тощо) та клас (зазвичай ",[5258,6235,6236],{},"IN"," — Internet).",[5201,6239,6240,6243,6244,6247],{},[5205,6241,6242],{},"Answer Section"," — містить ресурсні записи (",[5408,6245,6246],{},"Resource Records","), які є прямою відповіддю на запит.",[5201,6249,6250,6253],{},[5205,6251,6252],{},"Authority Section"," — містить записи NS, які вказують на авторитетні сервери для зони (використовується в процесі делегування).",[5201,6255,6256,6259],{},[5205,6257,6258],{},"Additional Section"," — містить додаткові записи, які можуть бути корисними (наприклад, IP-адреси серверів, згаданих у секції Authority).",[5373,6261,6262],{},[5669,6263],{"alt":6264,"className":6265,"src":6266},"Аналіз бінарного DNS-пакета та його секцій у Wireshark",[5673],"\u002Fimages\u002Fclient-server-architecture\u002Fdns-smtp-application-protocols\u002F02.png",[5676,6268,6270],{"alt":6269},"Структура DNS-повідомлення",[5680,6271,6273],{"className":5682,"code":6272,"language":5684,"meta":5685,"style":5685},"@startuml\nskinparam style plain\nskinparam backgroundColor #FFFFFF\nskinparam packageStyle rectangle\n\npackage \"DNS Повідомлення (UDP Datagram)\" #F1F5F9 {\n    rectangle \"Заголовок (Header)\\n12 байтів\" #DBEAFE {\n        card \"Transaction ID (16 біт)\" #E2E8F0\n        card \"Flags (16 біт)\\nQR | Opcode | AA | TC | RD | RA | Z | RCODE\" #E2E8F0\n        card \"QDCOUNT | ANCOUNT | NSCOUNT | ARCOUNT\" #E2E8F0\n    }\n    \n    rectangle \"Question Section\\n(змінна довжина)\" #FEF3C7 {\n        card \"QNAME: www.example.com\" \n        card \"QTYPE: A (1)\"\n        card \"QCLASS: IN (1)\"\n    }\n    \n    rectangle \"Answer Section\\n(змінна довжина)\" #DCFCE7 {\n        card \"NAME: www.example.com\"\n        card \"TYPE: A\"\n        card \"CLASS: IN\"\n        card \"TTL: 300 сек\"\n        card \"RDLENGTH: 4\"\n        card \"RDATA: 93.184.216.34\"\n    }\n    \n    rectangle \"Authority Section\" #E2E8F0\n    rectangle \"Additional Section\" #E2E8F0\n}\n@enduml\n",[5258,6274,6275,6279,6283,6287,6292,6296,6301,6306,6311,6316,6321,6326,6331,6336,6341,6346,6351,6355,6359,6364,6369,6374,6379,6384,6389,6394,6398,6402,6407,6412,6416],{"__ignoreMap":5685},[5689,6276,6277],{"class":5691,"line":5692},[5689,6278,5695],{},[5689,6280,6281],{"class":5691,"line":5698},[5689,6282,5701],{},[5689,6284,6285],{"class":5691,"line":5704},[5689,6286,5707],{},[5689,6288,6289],{"class":5691,"line":5710},[5689,6290,6291],{},"skinparam packageStyle rectangle\n",[5689,6293,6294],{"class":5691,"line":5716},[5689,6295,5720],{"emptyLinePlaceholder":5719},[5689,6297,6298],{"class":5691,"line":5723},[5689,6299,6300],{},"package \"DNS Повідомлення (UDP Datagram)\" #F1F5F9 {\n",[5689,6302,6303],{"class":5691,"line":5729},[5689,6304,6305],{},"    rectangle \"Заголовок (Header)\\n12 байтів\" #DBEAFE {\n",[5689,6307,6308],{"class":5691,"line":5735},[5689,6309,6310],{},"        card \"Transaction ID (16 біт)\" #E2E8F0\n",[5689,6312,6313],{"class":5691,"line":5741},[5689,6314,6315],{},"        card \"Flags (16 біт)\\nQR | Opcode | AA | TC | RD | RA | Z | RCODE\" #E2E8F0\n",[5689,6317,6318],{"class":5691,"line":5747},[5689,6319,6320],{},"        card \"QDCOUNT | ANCOUNT | NSCOUNT | ARCOUNT\" #E2E8F0\n",[5689,6322,6323],{"class":5691,"line":5753},[5689,6324,6325],{},"    }\n",[5689,6327,6328],{"class":5691,"line":5758},[5689,6329,6330],{},"    \n",[5689,6332,6333],{"class":5691,"line":5764},[5689,6334,6335],{},"    rectangle \"Question Section\\n(змінна довжина)\" #FEF3C7 {\n",[5689,6337,6338],{"class":5691,"line":5770},[5689,6339,6340],{},"        card \"QNAME: www.example.com\" \n",[5689,6342,6343],{"class":5691,"line":5776},[5689,6344,6345],{},"        card \"QTYPE: A (1)\"\n",[5689,6347,6348],{"class":5691,"line":5781},[5689,6349,6350],{},"        card \"QCLASS: IN (1)\"\n",[5689,6352,6353],{"class":5691,"line":5786},[5689,6354,6325],{},[5689,6356,6357],{"class":5691,"line":5792},[5689,6358,6330],{},[5689,6360,6361],{"class":5691,"line":5798},[5689,6362,6363],{},"    rectangle \"Answer Section\\n(змінна довжина)\" #DCFCE7 {\n",[5689,6365,6366],{"class":5691,"line":5804},[5689,6367,6368],{},"        card \"NAME: www.example.com\"\n",[5689,6370,6371],{"class":5691,"line":5809},[5689,6372,6373],{},"        card \"TYPE: A\"\n",[5689,6375,6376],{"class":5691,"line":5814},[5689,6377,6378],{},"        card \"CLASS: IN\"\n",[5689,6380,6381],{"class":5691,"line":5820},[5689,6382,6383],{},"        card \"TTL: 300 сек\"\n",[5689,6385,6386],{"class":5691,"line":5826},[5689,6387,6388],{},"        card \"RDLENGTH: 4\"\n",[5689,6390,6391],{"class":5691,"line":5832},[5689,6392,6393],{},"        card \"RDATA: 93.184.216.34\"\n",[5689,6395,6396],{"class":5691,"line":5838},[5689,6397,6325],{},[5689,6399,6400],{"class":5691,"line":5843},[5689,6401,6330],{},[5689,6403,6404],{"class":5691,"line":5848},[5689,6405,6406],{},"    rectangle \"Authority Section\" #E2E8F0\n",[5689,6408,6409],{"class":5691,"line":5854},[5689,6410,6411],{},"    rectangle \"Additional Section\" #E2E8F0\n",[5689,6413,6414],{"class":5691,"line":5860},[5689,6415,5750],{},[5689,6417,6418],{"class":5691,"line":5866},[5689,6419,5898],{},[5444,6421,6423],{"id":6422},"коди-відповідей-rcode","Коди відповідей (RCODE)",[5373,6425,6426,6427,6429],{},"Поле ",[5205,6428,6185],{}," у заголовку вказує на результат обробки запиту:",[5198,6431,6432,6438,6444,6450,6467,6473],{},[5201,6433,6434,6437],{},[5205,6435,6436],{},"0 (NOERROR)"," — успішна відповідь, запис знайдено.",[5201,6439,6440,6443],{},[5205,6441,6442],{},"1 (FORMERR)"," — помилка формату запиту (сервер не зміг його розпарсити).",[5201,6445,6446,6449],{},[5205,6447,6448],{},"2 (SERVFAIL)"," — внутрішня помилка сервера під час обробки запиту.",[5201,6451,6452,5470,6455,6458,6459,6462,6463,6466],{},[5205,6453,6454],{},"3 (NXDOMAIN)",[5408,6456,6457],{},"Non-Existent Domain"," — доменне ім'я не існує. Це ",[5205,6460,6461],{},"найважливіший код помилки",": якщо ви намагаєтеся підключитися до ",[5258,6464,6465],{},"nonexistent.example.com",", і DNS повертає NXDOMAIN, ваш застосунок має обробити цю ситуацію як неіснуючий домен, а не тимчасовий збій.",[5201,6468,6469,6472],{},[5205,6470,6471],{},"4 (NOTIMP)"," — операція не підтримується сервером.",[5201,6474,6475,6478],{},[5205,6476,6477],{},"5 (REFUSED)"," — сервер відмовився обробляти запит (можливо, через політики безпеки або обмеження доступу).",[5421,6480,6481,6484],{},[5205,6482,6483],{},"Практична порада:"," при розробці клієнт-серверних застосунків завжди логуйте RCODE у разі DNS-помилок. Різниця між SERVFAIL (тимчасовий збій, можна повторити запит) і NXDOMAIN (домен не існує, повтор безглуздий) є критично важливою для правильної обробки помилок та діагностики проблем у production-середовищі.",[5365,6486],{},[5368,6488,6490],{"id":6489},"типи-dns-записів-від-базових-a-та-aaaa-до-службових-srv","Типи DNS-записів: від базових A та AAAA до службових SRV",[5373,6492,6493,6494,6496],{},"Ресурсні записи (",[5408,6495,6246],{},", RR) — це фундаментальні структури даних, які зберігаються в DNS і повертаються у відповідях. Кожен запис має наступну загальну структуру:",[5680,6498,6503],{"className":6499,"code":6501,"language":6502},[6500],"language-text","NAME    TTL    CLASS    TYPE    RDATA\n","text",[5258,6504,6501],{"__ignoreMap":5685},[5198,6506,6507,6513,6520,6528,6534],{},[5201,6508,6509,6512],{},[5205,6510,6511],{},"NAME"," — доменне ім'я, до якого відноситься запис.",[5201,6514,6515,5406,6517,6519],{},[5205,6516,5469],{},[5408,6518,5473],{},") — час у секундах, протягом якого запис може зберігатися в кеші резолверів.",[5201,6521,6522,6525,6526,6237],{},[5205,6523,6524],{},"CLASS"," — клас мережі (зазвичай ",[5258,6527,6236],{},[5201,6529,6530,6533],{},[5205,6531,6532],{},"TYPE"," — тип запису (A, AAAA, CNAME тощо).",[5201,6535,6536,6539],{},[5205,6537,6538],{},"RDATA"," — дані запису (формат залежить від типу).",[5373,6541,6542],{},"Розглянемо найважливіші типи записів, з якими ви стикатиметеся під час розробки клієнт-серверних застосунків.",[5444,6544,6546],{"id":6545},"запис-a-address-відображення-на-ipv4","Запис A (Address) — відображення на IPv4",[5373,6548,6549,5323,6552,6554,6555,5561,6557,6560,6563],{},[5205,6550,6551],{},"Тип:",[5258,6553,5224],{}," (числове значення ",[5258,6556,6121],{},[6558,6559],"br",{},[5205,6561,6562],{},"Призначення:"," зіставляє доменне ім'я з 32-бітною IPv4-адресою.",[5373,6565,6566],{},[5205,6567,6568],{},"Приклад:",[5680,6570,6573],{"className":6571,"code":6572,"language":6502},[6500],"www.example.com.    300    IN    A    93.184.216.34\n",[5258,6574,6572],{"__ignoreMap":5685},[5373,6576,6577,6578,6580,6581,6583],{},"Цей запис говорить: «Домен ",[5258,6579,5937],{}," вказує на IPv4-адресу ",[5258,6582,5390],{},", і цю інформацію можна кешувати протягом 300 секунд (5 хвилин)».",[5373,6585,6586],{},"Запити типу A — це найпоширеніший тип DNS-запитів у світі, бо вони необхідні для будь-якого підключення до вебсерверів, API, баз даних тощо через IPv4.",[5444,6588,6590],{"id":6589},"запис-aaaa-quad-a-відображення-на-ipv6","Запис AAAA (Quad-A) — відображення на IPv6",[5373,6592,6593,5323,6595,6554,6597,5561,6600,6602,6604],{},[5205,6594,6551],{},[5258,6596,5228],{},[5258,6598,6599],{},"28",[6558,6601],{},[5205,6603,6562],{}," зіставляє доменне ім'я з 128-бітною IPv6-адресою.",[5373,6606,6607],{},[5205,6608,6568],{},[5680,6610,6613],{"className":6611,"code":6612,"language":6502},[6500],"www.example.com.    300    IN    AAAA    2606:2800:220:1:248:1893:25c8:1946\n",[5258,6614,6612],{"__ignoreMap":5685},[5373,6616,6617],{},"У міру вичерпання адресного простору IPv4 та масового впровадження IPv6, записи AAAA стають дедалі важливішими. Сучасні застосунки повинні підтримувати обидва типи запитів: спочатку спробувати AAAA (якщо система підтримує IPv6), а у разі невдачі — відступити до A-запису.",[6046,6619,6620,6623,6624,6626,6627,6630,6631,6634],{},[5205,6621,6622],{},"Dual-Stack підхід:"," сучасні резолвери (включно з ",[5258,6625,5267],{}," у Go) часто виконують ",[5205,6628,6629],{},"паралельні запити"," A та AAAA одночасно і повертають обидві адреси. Клієнтська програма намагається встановити з'єднання спочатку через IPv6 (якщо доступний), а у разі невдачі — через IPv4. Цей підхід називається ",[5205,6632,6633],{},"Happy Eyeballs"," (RFC 8305) і забезпечує найкращу продуктивність незалежно від типу мережі.",[5444,6636,6638],{"id":6637},"запис-cname-canonical-name-аліас-доменного-імені","Запис CNAME (Canonical Name) — аліас доменного імені",[5373,6640,6641,5323,6643,6554,6645,5561,6648,6650,6652],{},[5205,6642,6551],{},[5258,6644,5231],{},[5258,6646,6647],{},"5",[6558,6649],{},[5205,6651,6562],{}," створює аліас (псевдонім) для іншого доменного імені. Коли клієнт запитує CNAME-запис, резолвер автоматично виконує додатковий запит для канонічного імені.",[5373,6654,6655],{},[5205,6656,6568],{},[5680,6658,6661],{"className":6659,"code":6660,"language":6502},[6500],"blog.example.com.    300    IN    CNAME    www.example.com.\nwww.example.com.     300    IN    A        93.184.216.34\n",[5258,6662,6660],{"__ignoreMap":5685},[5373,6664,6665,6666,6669,6670,6672,6673,6675],{},"Цей запис говорить: «",[5258,6667,6668],{},"blog.example.com"," насправді є аліасом для ",[5258,6671,5937],{},", тож іди і дізнайся IP-адресу ",[5258,6674,5937],{},"».",[5373,6677,6678,6679,6681],{},"CNAME-записи зручні для керування кількома піддоменами, які вказують на один і той самий сервер: якщо IP-адреса сервера зміниться, достатньо оновити лише один A-запис для ",[5258,6680,5937],{},", і всі аліаси автоматично вказуватимуть на нову адресу.",[5483,6683,6684,6687,6688,6691,6692,6694,6695,6698,6699,6702],{},[5205,6685,6686],{},"Обмеження CNAME:"," згідно зі стандартом RFC, доменне ім'я, для якого існує CNAME-запис, ",[5205,6689,6690],{},"не може мати жодних інших типів записів"," (A, MX, TXT тощо). Це означає, що ви не можете створити CNAME для кореневого домену (",[5258,6693,5993],{},"), бо для нього зазвичай потрібні MX-записи для пошти та інші службові записи. Для вирішення цієї проблеми деякі DNS-провайдери (Cloudflare, AWS Route 53) пропонують власні розширення на кшталт ",[5205,6696,6697],{},"ALIAS"," або ",[5205,6700,6701],{},"ANAME",", які працюють як CNAME, але дозволяють співіснування з іншими записами.",[5444,6704,6706],{"id":6705},"запис-mx-mail-exchanger-маршрутизація-електронної-пошти","Запис MX (Mail Exchanger) — маршрутизація електронної пошти",[5373,6708,6709,5323,6711,6554,6713,5561,6716,6718,6720],{},[5205,6710,6551],{},[5258,6712,5234],{},[5258,6714,6715],{},"15",[6558,6717],{},[5205,6719,6562],{}," вказує, на який поштовий сервер потрібно надсилати електронні листи, адресовані до домену.",[5373,6722,6723],{},[5205,6724,6568],{},[5680,6726,6729],{"className":6727,"code":6728,"language":6502},[6500],"example.com.    300    IN    MX    10 mail1.example.com.\nexample.com.    300    IN    MX    20 mail2.example.com.\n",[5258,6730,6728],{"__ignoreMap":5685},[5373,6732,6733,6734,6737,6738,6741,6742,6745],{},"Кожен MX-запис має ",[5205,6735,6736],{},"пріоритет"," (перше число): чим менше значення, тим вищий пріоритет. У цьому прикладі поштовий сервер спочатку спробує доставити лист на ",[5258,6739,6740],{},"mail1.example.com"," (пріоритет 10), і лише якщо цей сервер недоступний — звернеться до резервного ",[5258,6743,6744],{},"mail2.example.com"," (пріоритет 20).",[5421,6747,6748,6751,6752,6755,6756,6758],{},[5205,6749,6750],{},"Чому MX-записи критично важливі для електронної пошти:"," коли ви надсилаєте email на адресу ",[5258,6753,6754],{},"user@example.com",", ваш SMTP-сервер спочатку виконує DNS-запит типу MX для домену ",[5258,6757,5993],{},", отримує список поштових серверів, потім виконує A\u002FAAAA-запити для кожного з них, щоб дізнатися їхні IP-адреси, і тільки після цього встановлює SMTP-з'єднання для передачі листа. Без коректних MX-записів доставка пошти на домен неможлива.",[5444,6760,6762],{"id":6761},"запис-txt-довільні-текстові-дані","Запис TXT — довільні текстові дані",[5373,6764,6765,5323,6767,6554,6769,5561,6772,6774,6776],{},[5205,6766,6551],{},[5258,6768,5237],{},[5258,6770,6771],{},"16",[6558,6773],{},[5205,6775,6562],{}," зберігає довільні текстові рядки, які використовуються для верифікації володіння доменом, налаштування політик безпеки пошти (SPF, DKIM, DMARC) та інших службових цілей.",[5373,6778,6779],{},[5205,6780,6568],{},[5680,6782,6785],{"className":6783,"code":6784,"language":6502},[6500],"example.com.    300    IN    TXT    \"v=spf1 include:_spf.google.com ~all\"\nexample.com.    300    IN    TXT    \"google-site-verification=rXOxyZounnZasA8Z7oaD3c14JdjS9aKSWvsR1EbUSIQ\"\n",[5258,6786,6784],{"__ignoreMap":5685},[5373,6788,6789],{},"TXT-записи надзвичайно гнучкі і використовуються для багатьох цілей:",[5198,6791,6792,6801,6810,6819],{},[5201,6793,6794,5406,6797,6800],{},[5205,6795,6796],{},"SPF",[5408,6798,6799],{},"Sender Policy Framework",") — вказує, які IP-адреси мають право надсилати пошту від імені домену.",[5201,6802,6803,5406,6806,6809],{},[5205,6804,6805],{},"DKIM",[5408,6807,6808],{},"DomainKeys Identified Mail",") — містить відкритий ключ для перевірки цифрових підписів листів.",[5201,6811,6812,5406,6815,6818],{},[5205,6813,6814],{},"DMARC",[5408,6816,6817],{},"Domain-based Message Authentication, Reporting and Conformance",") — визначає політику обробки листів, які не пройшли перевірку SPF\u002FDKIM.",[5201,6820,6821],{},"Верифікація володіння доменом для сервісів на кшталт Google Workspace, AWS, Azure.",[5444,6823,6825],{"id":6824},"запис-srv-service-виявлення-сервісів","Запис SRV (Service) — виявлення сервісів",[5373,6827,6828,5323,6830,6554,6832,5561,6835,6837,6839],{},[5205,6829,6551],{},[5258,6831,5240],{},[5258,6833,6834],{},"33",[6558,6836],{},[5205,6838,6562],{}," надає інформацію про розташування конкретних сервісів: порт, пріоритет, вагу та ім'я хоста.",[5373,6841,6842],{},[5205,6843,6844],{},"Формат:",[5680,6846,6849],{"className":6847,"code":6848,"language":6502},[6500],"_service._proto.name    TTL    IN    SRV    priority weight port target\n",[5258,6850,6848],{"__ignoreMap":5685},[5373,6852,6853],{},[5205,6854,6568],{},[5680,6856,6859],{"className":6857,"code":6858,"language":6502},[6500],"_http._tcp.example.com.    300    IN    SRV    10 60 80 server1.example.com.\n_http._tcp.example.com.    300    IN    SRV    10 40 80 server2.example.com.\n",[5258,6860,6858],{"__ignoreMap":5685},[5373,6862,6863,6864,6867],{},"SRV-записи особливо корисні для мікросервісних архітектур і систем виявлення сервісів (",[5408,6865,6866],{},"service discovery","): замість жорсткого прописування адрес серверів у конфігурації, клієнт може запитати DNS про доступні екземпляри сервісу, отримати список із пріоритетами та вагами (для балансування навантаження) і динамічно підключитися до найоптимальнішого вузла.",[6869,6870,6871,6877],"accordion",{},[6872,6873,6876],"accordion-item",{"icon":6874,"label":6875},"i-lucide-help-circle","❓ Чому потрібні різні типи DNS-записів, якщо можна було б обмежитися тільки A та AAAA?","Кожен тип запису вирішує конкретну задачу інфраструктури. CNAME дозволяє уникнути дублювання конфігурації при керуванні десятками піддоменів. MX-записи з пріоритетами забезпечують відмовостійкість поштових систем (якщо основний сервер недоступний, пошта автоматично направляється на резервний). TXT-записи дають можливість впроваджувати нові протоколи безпеки без зміни структури DNS. SRV-записи дозволяють клієнтам динамічно виявляти сервіси без необхідності знати конкретні порти та хости заздалегідь. Усі ці можливості роблять DNS не просто «телефонною книгою інтернету», а потужною розподіленою базою даних метаінформації про мережеві сервіси.",[6872,6878,6880,5406,6882,6884],{"icon":6874,"label":6879},"❓ Що таке TTL і чому він такий важливий для продуктивності DNS?",[5205,6881,5469],{},[5408,6883,5473],{},") — це час у секундах, протягом якого DNS-запис може зберігатися в кеші резолверів без повторного звернення до авторитетного сервера. Високий TTL (наприклад, 86400 секунд = 24 години) зменшує навантаження на DNS-інфраструктуру та прискорює час відповіді для клієнтів, але означає, що зміни в DNS (наприклад, перенесення сервера на нову IP-адресу) поширюватимуться повільно. Низький TTL (наприклад, 60 секунд) дозволяє швидко оновлювати конфігурацію, але створює вище навантаження на DNS-сервери. У практиці зазвичай використовують TTL від 300 секунд (5 хвилин) до 3600 секунд (1 година) як компроміс між продуктивністю та гнучкістю.",[5365,6886],{},[5368,6888,6890],{"id":6889},"еволюція-доменної-адресації-чому-сучасний-веб-відмовився-від-обовязкового-піддомену-www","Еволюція доменної адресації: чому сучасний веб відмовився від обов'язкового піддомену www",[5373,6892,6893,6894,6004,6896,6698,6899,6902,6903,6906,6907,6910,6911,6913],{},"Ще на початку 2000-х років адреса будь-якого вебсайту в інтернеті обов'язково починалася з префікса ",[5258,6895,5260],{},[5258,6897,6898],{},"http:\u002F\u002Fwww.google.com",[5258,6900,6901],{},"http:\u002F\u002Fwww.yahoo.com","). Спроба ввести ім'я домену без префікса нерідко призводила до помилки з'єднання або вимагала від системних адміністраторів нетривіальних налаштувань інфраструктури. Сьогодні ж користувачі звикли вводити лаконічні імена на кшталт ",[5258,6904,6905],{},"github.com"," чи ",[5258,6908,6909],{},"kostyl.dev",", а більшість сучасних браузерів узагалі приховують ",[5258,6912,5260],{}," в адресному рядку для спрощення інтерфейсу.",[5373,6915,6916,6917,6919],{},"Проте перехід від обов'язкового піддомену ",[5258,6918,5260],{}," до так званого «голого домену» — це не просто зміна дизайнерських уподобань користувачів чи маркетологів. За цим стоїть тривала інженерна еволюція мережевих протоколів, подолання фундаментального обмеження стандарту DNS сорокарічної давнини та поява нових стандартів інтернет-маршрутизації.",[5444,6921,6923],{"id":6922},"історичні-витоки-префікса-www-та-функціональна-спеціалізація-хостів","Історичні витоки префікса www та функціональна спеціалізація хостів",[5373,6925,6926,6927,6930,6931,6934,6935,6938,6939,6942,6943,5980],{},"У 1990-х роках Всесвітнє павутиння (",[5408,6928,6929],{},"World Wide Web",") було лише однією з багатьох мережевих служб інтернету. Користувачі активно застосовували протокол передачі файлів (",[5408,6932,6933],{},"File Transfer Protocol",", FTP) для обміну документами, протокол термінального доступу (",[5408,6936,6937],{},"Telnet",") для дистанційного керування комп'ютерами, телеконференції Usenet через протокол ",[5408,6940,6941],{},"NNTP",", а також електронну пошту (",[5408,6944,5278],{},[5373,6946,6947,6948,6951,6952,6955],{},"В умовах обмежених ресурсів тогочасної комп'ютерної техніки кожен із цих сервісів зазвичай розгортався на ",[5205,6949,6950],{},"окремому фізичному сервері"," зі своєю власною апаратною мережевою картою та унікальною IP-адресою. Щоб користувачі та клієнтські програми розуміли, до якої саме машини вони звертаються, в індустрії утвердилася угода про найменування за допомогою ",[5205,6953,6954],{},"піддоменів третього рівня",", які прямо вказували на протокол або призначення вузла:",[5198,6957,6958,6964,6974,6980,6986],{},[5201,6959,6960,6963],{},[5258,6961,6962],{},"ftp.company.com"," — вказував на IP-адресу FTP-сховища файлів;",[5201,6965,6966,6969,6970,6973],{},[5258,6967,6968],{},"mail.company.com"," (або ",[5258,6971,6972],{},"smtp.company.com",") — адресував поштовий сервер організації;",[5201,6975,6976,6979],{},[5258,6977,6978],{},"news.company.com"," — спрямовував запити до сервера телеконференцій Usenet;",[5201,6981,6982,6985],{},[5258,6983,6984],{},"irc.company.com"," — сервер чатів у реальному часі;",[5201,6987,6988,6991,6992,6995],{},[5258,6989,6990],{},"www.company.com"," — окремий сервер, на якому працював HTTP-демон (",[5408,6993,6994],{},"HTTP daemon",", наприклад NCSA HTTPd або ранній Apache), призначений для роздачі HTML-сторінок.",[5373,6997,6998,6999,7002,7003,5406,7006,6118,7009,5406,7012,7015,7016,5406,7019,5225,7022,7025],{},"Домен без будь-якого піддомену — тобто домен другого рівня ",[5258,7000,7001],{},"company.com"," — називають ",[5205,7004,7005],{},"вершиною зони",[5408,7007,7008],{},"zone apex",[5205,7010,7011],{},"кореневим доменом",[5408,7013,7014],{},"root domain",") або ",[5205,7017,7018],{},"голим доменом",[5408,7020,7021],{},"naked domain",[5408,7023,7024],{},"apex domain","). Традиційно на вершині зони не розміщували вебсайти: вона асоціювалася з самою організацією або її центральним маршрутизатором мережі.",[5421,7027,7028,7031,7032,7034,7035,7038,7039,7041,7042,7044,7045,7048],{},[5205,7029,7030],{},"Походження термінології:"," у стандартах DNS вираз «вершина зони» (",[5408,7033,5247],{},") позначає точку дерева доменних імен, де починається окрема зона авторитетності, тобто вузол, у якому розташований запис SOA (",[5408,7036,7037],{},"Start of Authority","). Для зареєстрованого домену ",[5258,7040,6909],{}," вершиною зони є саме ім'я ",[5258,7043,6909],{},", тоді як ",[5258,7046,7047],{},"www.kostyl.dev"," є дочірнім вузлом (піддоменом).",[5444,7050,7052],{"id":7051},"архітектурна-проблема-обмеження-стандарту-rfc-1034-щодо-записів-cname","Архітектурна проблема: обмеження стандарту RFC 1034 щодо записів CNAME",[5373,7054,7055,7056,7058,7059,7061],{},"Коли веб став домінуючим сервісом в інтернеті, виникло закономірне бажання зробити URL-адреси простішими та вводити в браузері просто ",[5258,7057,7001],{}," замість довгого ",[5258,7060,6990],{},". Проте інженери зіткнулися з жорстким технічним бар'єром, закладеним у базових стандартах DNS.",[5373,7063,7064,7065,7067],{},"Згідно зі специфікацією ",[5205,7066,5429],{}," (розділ 3.6.2), ухваленою ще в 1987 році:",[7069,7070,7071],"blockquote",{},[5373,7072,7073],{},[5408,7074,7075],{},"«Якщо вузол дерева DNS містить запис типу CNAME, ніякі інші ресурсні записи будь-якого типу для цього вузла існувати не можуть».",[5373,7077,7078,7079,7081],{},"Це правило є абсолютно логічним з точки зору резолвера: запис ",[5258,7080,5231],{}," є канонічним аліасом (покажчиком), який наказує клієнту повністю підставити інше доменне ім'я замість поточного. Якби поруч із CNAME дозволялися інші записи, виникала б неоднозначність, які саме дані повертати — власні чи з цільового домену.",[5373,7083,7084],{},"Але тут криється фундаментальний конфлікт для вершини зони:",[5552,7086,7087,7108],{},[5201,7088,7089,7090,7092,7093,7096,7097,5406,7100,7102,7103,5406,7105,7107],{},"За стандартами DNS будь-яка валідна зона на своїй вершині (",[5258,7091,7001],{},") ",[5205,7094,7095],{},"зобов'язана"," містити запис ",[5205,7098,7099],{},"SOA",[5408,7101,7037],{},", який описує базові параметри зони, серійний номер і таймери) та щонайменше два записи ",[5205,7104,5976],{},[5408,7106,5979],{},", які вказують на авторитетні сервери, що обслуговують цю зону). Без них делегування домену в кореневих серверах верхнього рівня (TLD) неможливе.",[5201,7109,7110,7111,7114,7115,7117,7118,7120,7121,7123],{},"Крім того, майже будь-яка компанія має корпоративну електронну пошту виду ",[5258,7112,7113],{},"ceo@company.com",". Це вимагає наявності записів ",[5205,7116,5234],{}," безпосередньо на вершині зони ",[5258,7119,7001],{},", а також записів ",[5205,7122,5237],{}," для політик безпеки SPF і DKIM.",[5373,7125,7126,7129,7130,7133,7134,7136,7137,7139,7140,5225,7142,5430,7144,7146],{},[5205,7127,7128],{},"Наслідок:"," ви ",[5205,7131,7132],{},"не можете"," створити запис ",[5258,7135,5231],{}," для вершини зони ",[5258,7138,7001],{},", оскільки це автоматично суперечило б наявності обов'язкових записів ",[5258,7141,7099],{},[5258,7143,5976],{},[5258,7145,5234],{}," на цьому ж рівні! Будь-який DNS-сервер, налаштований таким чином, порушував би специфікацію RFC 1034, а доставка електронної пошти на домен або резолвінг самої зони повністю виходили б з ладу.",[5373,7148,7149,7150,7152,7153,7155,7156,7158],{},"Водночас для піддомену ",[5258,7151,6990],{}," жодного конфлікту немає: ",[5258,7154,5260],{}," не є вершиною зони, не має власних SOA та NS записів, і на нього не надсилають електронну пошту. Тому для ",[5258,7157,5260],{}," можна без будь-яких проблем створити запис CNAME:",[5680,7160,7163],{"className":7161,"code":7162,"language":6502},[6500],"www.company.com.    300    IN    CNAME    my-load-balancer.cloudprovider.com.\n",[5258,7164,7162],{"__ignoreMap":5685},[5676,7166,7168],{"alt":7167},"Порівняння дозволених записів на Zone Apex та на Subdomain",[5680,7169,7171],{"className":5682,"code":7170,"language":5684,"meta":5685,"style":5685},"@startuml\nskinparam style plain\nskinparam backgroundColor #FFFFFF\nskinparam packageStyle rectangle\n\npackage \"Вершина зони: example.com (Apex Domain)\" #FEF3C7 {\n    card \"SOA-запис (Обов'язковий за стандартом DNS)\" as SOA #DBEAFE\n    card \"NS-записи (Обов'язкові для делегування зони)\" as NS #DBEAFE\n    card \"MX-записи (Маршрутизація пошти @example.com)\" as MX #DCFCE7\n    card \"TXT-записи (Політики захисту SPF, DKIM, DMARC)\" as TXT #DCFCE7\n    card \"Заборонений CNAME ❌\\nRFC 1034 забороняє співіснування CNAME\\nіз будь-якими іншими записами для одного імені!\" as BadCNAME #FEE2E2\n}\n\npackage \"Піддомен: www.example.com (Subdomain)\" #DCFCE7 {\n    card \"Не містить записів SOA та NS\\nНе використовується для прийому пошти (MX)\" as SubFree #F1F5F9\n    card \"Легітимний CNAME-запис ✅\\nwww.example.com CNAME lb.cdn-provider.com\\nПовністю відповідає RFC 1034\" as GoodCNAME #DCFCE7\n}\n\nSOA -[hidden]down-> NS\nNS -[hidden]down-> MX\nMX -[hidden]down-> TXT\nTXT -[hidden]down-> BadCNAME\n\nSubFree -[hidden]down-> GoodCNAME\n@enduml\n",[5258,7172,7173,7177,7181,7185,7189,7193,7198,7203,7208,7213,7218,7223,7227,7231,7236,7241,7246,7250,7254,7259,7264,7269,7274,7278,7283],{"__ignoreMap":5685},[5689,7174,7175],{"class":5691,"line":5692},[5689,7176,5695],{},[5689,7178,7179],{"class":5691,"line":5698},[5689,7180,5701],{},[5689,7182,7183],{"class":5691,"line":5704},[5689,7184,5707],{},[5689,7186,7187],{"class":5691,"line":5710},[5689,7188,6291],{},[5689,7190,7191],{"class":5691,"line":5716},[5689,7192,5720],{"emptyLinePlaceholder":5719},[5689,7194,7195],{"class":5691,"line":5723},[5689,7196,7197],{},"package \"Вершина зони: example.com (Apex Domain)\" #FEF3C7 {\n",[5689,7199,7200],{"class":5691,"line":5729},[5689,7201,7202],{},"    card \"SOA-запис (Обов'язковий за стандартом DNS)\" as SOA #DBEAFE\n",[5689,7204,7205],{"class":5691,"line":5735},[5689,7206,7207],{},"    card \"NS-записи (Обов'язкові для делегування зони)\" as NS #DBEAFE\n",[5689,7209,7210],{"class":5691,"line":5741},[5689,7211,7212],{},"    card \"MX-записи (Маршрутизація пошти @example.com)\" as MX #DCFCE7\n",[5689,7214,7215],{"class":5691,"line":5747},[5689,7216,7217],{},"    card \"TXT-записи (Політики захисту SPF, DKIM, DMARC)\" as TXT #DCFCE7\n",[5689,7219,7220],{"class":5691,"line":5753},[5689,7221,7222],{},"    card \"Заборонений CNAME ❌\\nRFC 1034 забороняє співіснування CNAME\\nіз будь-якими іншими записами для одного імені!\" as BadCNAME #FEE2E2\n",[5689,7224,7225],{"class":5691,"line":5758},[5689,7226,5750],{},[5689,7228,7229],{"class":5691,"line":5764},[5689,7230,5720],{"emptyLinePlaceholder":5719},[5689,7232,7233],{"class":5691,"line":5770},[5689,7234,7235],{},"package \"Піддомен: www.example.com (Subdomain)\" #DCFCE7 {\n",[5689,7237,7238],{"class":5691,"line":5776},[5689,7239,7240],{},"    card \"Не містить записів SOA та NS\\nНе використовується для прийому пошти (MX)\" as SubFree #F1F5F9\n",[5689,7242,7243],{"class":5691,"line":5781},[5689,7244,7245],{},"    card \"Легітимний CNAME-запис ✅\\nwww.example.com CNAME lb.cdn-provider.com\\nПовністю відповідає RFC 1034\" as GoodCNAME #DCFCE7\n",[5689,7247,7248],{"class":5691,"line":5786},[5689,7249,5750],{},[5689,7251,7252],{"class":5691,"line":5792},[5689,7253,5720],{"emptyLinePlaceholder":5719},[5689,7255,7256],{"class":5691,"line":5798},[5689,7257,7258],{},"SOA -[hidden]down-> NS\n",[5689,7260,7261],{"class":5691,"line":5804},[5689,7262,7263],{},"NS -[hidden]down-> MX\n",[5689,7265,7266],{"class":5691,"line":5809},[5689,7267,7268],{},"MX -[hidden]down-> TXT\n",[5689,7270,7271],{"class":5691,"line":5814},[5689,7272,7273],{},"TXT -[hidden]down-> BadCNAME\n",[5689,7275,7276],{"class":5691,"line":5820},[5689,7277,5720],{"emptyLinePlaceholder":5719},[5689,7279,7280],{"class":5691,"line":5826},[5689,7281,7282],{},"SubFree -[hidden]down-> GoodCNAME\n",[5689,7284,7285],{"class":5691,"line":5832},[5689,7286,5898],{},[5444,7288,7290],{"id":7289},"хмарна-революція-та-глухий-кут-зі-статичними-a-записами","Хмарна революція та глухий кут зі статичними A-записами",[5373,7292,7293,7294,7297,7298,7300,7301,7303],{},"Поки вебсервери розміщувалися на фізичних машинах із фіксованими IP-адресами, адміністратори могли обходитися простим рішенням: прописувати однакові ",[5205,7295,7296],{},"A-записи"," (IPv4) як для ",[5258,7299,7001],{},", так і для ",[5258,7302,6990],{},":",[5680,7305,7308],{"className":7306,"code":7307,"language":6502},[6500],"company.com.        300    IN    A    198.51.100.10\nwww.company.com.    300    IN    A    198.51.100.10\n",[5258,7309,7307],{"__ignoreMap":5685},[5373,7311,7312,7313,5406,7316,7319,7320,7323,7324,7327],{},"Проте наприкінці 2000-х років індустрія перейшла до ",[5205,7314,7315],{},"хмарних обчислень",[5408,7317,7318],{},"Cloud Computing","), платформ як послуги (",[5408,7321,7322],{},"PaaS",") та глобальних мереж доставки контенту (",[5408,7325,7326],{},"Content Delivery Networks",", CDN) — таких як AWS CloudFront \u002F ELB, Cloudflare, Akamai, Fastly, Heroku, GitHub Pages, Vercel тощо.",[5373,7329,7330],{},"У сучасній хмарній архітектурі виділені постійні IP-адреси відійшли в минуле:",[5552,7332,7333,7340,7356],{},[5201,7334,7335,7336,7339],{},"Балансувальники навантаження та точки присутності CDN (",[5408,7337,7338],{},"Points of Presence",", PoP) використовують динамічні пули IP-адрес або маршрутизацію Anycast, які постійно масштабуються, змінюються при міграції трафіку або планових роботах провайдера.",[5201,7341,7342,7343,7346,7347,5225,7350,6698,7353,5261],{},"Замість статичної IP-адреси хмарний провайдер видає клієнту ",[5205,7344,7345],{},"канонічне доменне ім'я",", наприклад: ",[5258,7348,7349],{},"d123456abcdef.cloudfront.net",[5258,7351,7352],{},"myapp.herokuapp.com",[5258,7354,7355],{},"custom.cname.cloudflare.net",[5201,7357,7358,7359,7361,7362,7364],{},"Для піддомену ",[5258,7360,6990],{}," це налаштовується миттєво через CNAME. Але як направити відвідувачів на цей самий хмарний балансувальник за адресою ",[5258,7363,7001],{},", якщо CNAME там суворо заборонений стандартом?",[5373,7366,7367,7368,7370,7371,7373,7374,7377],{},"Утворений глухий кут змушував інженерів тримати спеціальні проміжні сервери з фіксованими IP-адресами виключно для виконання HTTP-редиректу з ",[5258,7369,7001],{}," на ",[5258,7372,6990],{},". Це було надзвичайно неефективно, дорого та створювало єдину точку відмови (",[5408,7375,7376],{},"Single Point of Failure",", SPoF).",[5444,7379,7381],{"id":7380},"подолання-обмежень-механізм-cname-flattening-alias-aname","Подолання обмежень: механізм CNAME Flattening (ALIAS \u002F ANAME)",[5373,7383,7384,7385,5406,7388,7391,7392,5430,7394,5261],{},"Перший справжній прорив у цій проблемі відбувся на рівні авторитетних DNS-провайдерів (зокрема Cloudflare, AWS Route 53, DNSimple, DNS Made Easy). Вони створили технологію, яка дістала назву ",[5205,7386,7387],{},"сплющення CNAME",[5408,7389,7390],{},"CNAME Flattening","), або віртуальні записи типу ",[5205,7393,6697],{},[5205,7395,6701],{},[5373,7397,7398,7399,7303],{},"Суть цієї технології полягає в перенесенні обробки псевдоніма на бік ",[5205,7400,7401],{},"авторитетного DNS-сервера",[5918,7403,7404,7408,7421,7425,7438,7442,7459,7463],{},[5444,7405,7407],{"id":7406},"крок-1-конфігурація-розширеного-запису-в-панелі-dns","Крок 1. Конфігурація розширеного запису в панелі DNS",[5373,7409,7410,7411,7414,7415,7417,7418,5261],{},"Власник домену вказує для вершини зони ",[5258,7412,7413],{},"@"," (тобто ",[5258,7416,7001],{},") цільове хмарне ім'я, наприклад ",[5258,7419,7420],{},"ALIAS my-app.edge.cdn.net",[5444,7422,7424],{"id":7423},"крок-2-перехоплення-запиту-авторитетним-dns-сервером","Крок 2. Перехоплення запиту авторитетним DNS-сервером",[5373,7426,7427,7428,7430,7431,7434,7435,5261],{},"Коли клієнтський або рекурсивний DNS-резолвер запитує A чи AAAA-запис для ",[5258,7429,7001],{},", авторитетний DNS-сервер ",[5205,7432,7433],{},"не віддає клієнту CNAME"," (що порушило б RFC). Натомість авторитетний сервер сам виконує внутрішній рекурсивний запит: звертається до DNS для резолвінгу імені ",[5258,7436,7437],{},"my-app.edge.cdn.net",[5444,7439,7441],{"id":7440},"крок-3-синтез-стандартних-ресурсних-записів","Крок 3. Синтез стандартних ресурсних записів",[5373,7443,7444,7445,5430,7448,7451,7452,7455,7456,7458],{},"Авторитетний сервер отримує реальні актуальні IP-адреси вузлів CDN (наприклад, ",[5258,7446,7447],{},"104.16.132.5",[5258,7449,7450],{},"2606:4700::6810:8405",") і динамічно ",[5205,7453,7454],{},"синтезує стандартні A та AAAA записи"," для ",[5258,7457,7001],{}," на льоту.",[5444,7460,7462],{"id":7461},"крок-4-доставка-валідної-відповіді-клієнту","Крок 4. Доставка валідної відповіді клієнту",[5373,7464,7465],{},"Клієнт отримує звичайнісіньку відповідь із записами типу A\u002FAAAA, наче домен мав статичні адреси. Стандарти RFC 1034 жодним чином не порушуються: у відповіді немає забороненого CNAME, а записи SOA, NS і MX на вершині зони продовжують функціонувати абсолютно автономно.",[5676,7467,7469],{"alt":7468},"Діаграма послідовності процесу CNAME Flattening на авторитетному DNS-сервері",[5680,7470,7472],{"className":5682,"code":7471,"language":5684,"meta":5685,"style":5685},"@startuml\nskinparam style plain\nskinparam backgroundColor #FFFFFF\nskinparam sequenceMessageAlign center\nautonumber\n\nactor \"Клієнт (Браузер)\" as Client #DBEAFE\nparticipant \"Рекурсивний DNS-резолвер\\n(наприклад, 8.8.8.8)\" as RecDNS #E2E8F0\nparticipant \"Авторитетний DNS-сервер\\n(Cloudflare \u002F Route 53)\" as AuthDNS #FEF3C7\nparticipant \"DNS-зона хмарного провайдера\\n(my-cdn.net)\" as CloudDNS #DCFCE7\n\nClient -> RecDNS : Запит типу A: company.com\nRecDNS -> AuthDNS : Запит типу A: company.com\n\nnote over AuthDNS #FEF3C7\n  На вершині зони company.com\n  налаштовано ALIAS на app.my-cdn.net.\n  Сервер НЕ повертає CNAME (заборонено RFC).\n  Сервер самостійно резолвить app.my-cdn.net\nend note\n\nAuthDNS -> CloudDNS : Запит A\u002FAAAA: app.my-cdn.net\nCloudDNS -> AuthDNS : Відповідь: IP 104.18.25.100, 104.18.26.100\n\nAuthDNS -> AuthDNS : Синтезує стандартні A-записи\\nдля імені company.com\n\nAuthDNS -> RecDNS : Відповідь: company.com A 104.18.25.100 (TTL 300)\nRecDNS -> Client : Відповідь: IP 104.18.25.100\n\nClient -> Client : Встановлює пряме TCP\u002FTLS з'єднання\\nз сервером за адресою 104.18.25.100:443\n@enduml\n",[5258,7473,7474,7478,7482,7486,7491,7496,7500,7505,7510,7515,7520,7524,7529,7534,7538,7543,7548,7553,7558,7563,7567,7571,7576,7581,7585,7590,7594,7599,7604,7608,7613],{"__ignoreMap":5685},[5689,7475,7476],{"class":5691,"line":5692},[5689,7477,5695],{},[5689,7479,7480],{"class":5691,"line":5698},[5689,7481,5701],{},[5689,7483,7484],{"class":5691,"line":5704},[5689,7485,5707],{},[5689,7487,7488],{"class":5691,"line":5710},[5689,7489,7490],{},"skinparam sequenceMessageAlign center\n",[5689,7492,7493],{"class":5691,"line":5716},[5689,7494,7495],{},"autonumber\n",[5689,7497,7498],{"class":5691,"line":5723},[5689,7499,5720],{"emptyLinePlaceholder":5719},[5689,7501,7502],{"class":5691,"line":5729},[5689,7503,7504],{},"actor \"Клієнт (Браузер)\" as Client #DBEAFE\n",[5689,7506,7507],{"class":5691,"line":5735},[5689,7508,7509],{},"participant \"Рекурсивний DNS-резолвер\\n(наприклад, 8.8.8.8)\" as RecDNS #E2E8F0\n",[5689,7511,7512],{"class":5691,"line":5741},[5689,7513,7514],{},"participant \"Авторитетний DNS-сервер\\n(Cloudflare \u002F Route 53)\" as AuthDNS #FEF3C7\n",[5689,7516,7517],{"class":5691,"line":5747},[5689,7518,7519],{},"participant \"DNS-зона хмарного провайдера\\n(my-cdn.net)\" as CloudDNS #DCFCE7\n",[5689,7521,7522],{"class":5691,"line":5753},[5689,7523,5720],{"emptyLinePlaceholder":5719},[5689,7525,7526],{"class":5691,"line":5758},[5689,7527,7528],{},"Client -> RecDNS : Запит типу A: company.com\n",[5689,7530,7531],{"class":5691,"line":5764},[5689,7532,7533],{},"RecDNS -> AuthDNS : Запит типу A: company.com\n",[5689,7535,7536],{"class":5691,"line":5770},[5689,7537,5720],{"emptyLinePlaceholder":5719},[5689,7539,7540],{"class":5691,"line":5776},[5689,7541,7542],{},"note over AuthDNS #FEF3C7\n",[5689,7544,7545],{"class":5691,"line":5781},[5689,7546,7547],{},"  На вершині зони company.com\n",[5689,7549,7550],{"class":5691,"line":5786},[5689,7551,7552],{},"  налаштовано ALIAS на app.my-cdn.net.\n",[5689,7554,7555],{"class":5691,"line":5792},[5689,7556,7557],{},"  Сервер НЕ повертає CNAME (заборонено RFC).\n",[5689,7559,7560],{"class":5691,"line":5798},[5689,7561,7562],{},"  Сервер самостійно резолвить app.my-cdn.net\n",[5689,7564,7565],{"class":5691,"line":5804},[5689,7566,5892],{},[5689,7568,7569],{"class":5691,"line":5809},[5689,7570,5720],{"emptyLinePlaceholder":5719},[5689,7572,7573],{"class":5691,"line":5814},[5689,7574,7575],{},"AuthDNS -> CloudDNS : Запит A\u002FAAAA: app.my-cdn.net\n",[5689,7577,7578],{"class":5691,"line":5820},[5689,7579,7580],{},"CloudDNS -> AuthDNS : Відповідь: IP 104.18.25.100, 104.18.26.100\n",[5689,7582,7583],{"class":5691,"line":5826},[5689,7584,5720],{"emptyLinePlaceholder":5719},[5689,7586,7587],{"class":5691,"line":5832},[5689,7588,7589],{},"AuthDNS -> AuthDNS : Синтезує стандартні A-записи\\nдля імені company.com\n",[5689,7591,7592],{"class":5691,"line":5838},[5689,7593,5720],{"emptyLinePlaceholder":5719},[5689,7595,7596],{"class":5691,"line":5843},[5689,7597,7598],{},"AuthDNS -> RecDNS : Відповідь: company.com A 104.18.25.100 (TTL 300)\n",[5689,7600,7601],{"class":5691,"line":5848},[5689,7602,7603],{},"RecDNS -> Client : Відповідь: IP 104.18.25.100\n",[5689,7605,7606],{"class":5691,"line":5854},[5689,7607,5720],{"emptyLinePlaceholder":5719},[5689,7609,7610],{"class":5691,"line":5860},[5689,7611,7612],{},"Client -> Client : Встановлює пряме TCP\u002FTLS з'єднання\\nз сервером за адресою 104.18.25.100:443\n",[5689,7614,7615],{"class":5691,"line":5866},[5689,7616,5898],{},[5444,7618,7620],{"id":7619},"новий-офіційний-стандарт-ietf-dns-записи-https-та-svcb-rfc-9460","Новий офіційний стандарт IETF: DNS-записи HTTPS та SVCB (RFC 9460)",[5373,7622,7623,7624,7627,7628,5406,7631,7634,7635,7638,7639,5980],{},"Хоча CNAME Flattening розв'язав проблему на практиці, він залишався специфічною функцією конкретних комерційних DNS-провайдерів і не був універсальним стандартом IETF. Ситуація змінилася в листопаді 2023 року, коли IETF після багаторічної розробки спільно з інженерами Apple, Google, Cloudflare та Mozilla опублікував офіційний стандарт ",[5205,7625,7626],{},"RFC 9460",", що визначає нові типи DNS-записів: ",[5205,7629,7630],{},"SVCB",[5408,7632,7633],{},"Service Binding",") та його веб-спеціалізацію — запис типу ",[5205,7636,7637],{},"HTTPS"," (тип ",[5258,7640,7641],{},"65",[5373,7643,7644,7645,7647],{},"Запис типу ",[5258,7646,7637],{}," вирішує проблему вершини зони офіційно на рівні самого протоколу DNS через два фундаментальні режими роботи:",[5552,7649,7650,7684],{},[5201,7651,7652,7659,7661,7662,7664,7665,5323,7667,7670,7671,7677,7679,7680,7683],{},[5205,7653,7654,7655,7658],{},"Режим аліасу (AliasMode, пріоритет ",[5258,7656,7657],{},"Priority = 0","):",[6558,7660],{},"\nДозволяє прямо на вершині зони вказати канонічне доменне ім'я іншого цільового хоста. На відміну від старого CNAME, наявність запису ",[5258,7663,7637],{}," з ",[5258,7666,7657],{},[5205,7668,7669],{},"не конфліктує"," з іншими записами (SOA, NS, MX, TXT) на цьому ж вузлі:",[5680,7672,7675],{"className":7673,"code":7674,"language":6502},[6500],"company.com.    300    IN    HTTPS    0 www.company.com.\n",[5258,7676,7674],{"__ignoreMap":5685},[6558,7678],{},"Сучасний браузер, надсилаючи паралельний запит на запис типу HTTPS (разом із запитами A\u002FAAAA), розпізнає вказівку ",[5258,7681,7682],{},"AliasMode"," і негайно резолвить цільове ім'я без додаткових HTTP-редиректів.",[5201,7685,7686,7692,7694,7695,7701,7703,7704],{},[5205,7687,7688,7689,7658],{},"Сервісний режим (ServiceMode, пріоритет ",[5258,7690,7691],{},"Priority > 0",[6558,7693],{},"\nПередає клієнтові повний набір метаданих для встановлення з'єднання ще до надсилання першого TCP-пакета:",[5680,7696,7699],{"className":7697,"code":7698,"language":6502},[6500],"company.com.    300    IN    HTTPS    1 . (\n                       alpn=\"h3,h2\"\n                       ipv4hint=104.18.25.100,104.18.26.100\n                       ipv6hint=2606:4700::6812:1964\n                       ech=\"...\"\n                       )\n",[5258,7700,7698],{"__ignoreMap":5685},[6558,7702],{},"Цей запис повідомляє браузеру:",[5198,7705,7706,7714,7725],{},[5201,7707,7708,7713],{},[5205,7709,7710],{},[5258,7711,7712],{},"alpn=\"h3,h2\""," — сервер підтримує сучасні протоколи HTTP\u002F3 поверх QUIC та HTTP\u002F2. Клієнт може одразу відправляти QUIC-пакети без попереднього «промацування» через HTTP\u002F1.1.",[5201,7715,7716,7724],{},[5205,7717,7718,5346,7721],{},[5258,7719,7720],{},"ipv4hint",[5258,7722,7723],{},"ipv6hint"," — IP-адреси для підключення передаються прямо всередині HTTPS-відповіді, що усуває необхідність виконання окремих додаткових DNS-запитів типу A та AAAA.",[5201,7726,7727,5406,7732,7735],{},[5205,7728,7729],{},[5258,7730,7731],{},"ech",[5408,7733,7734],{},"Encrypted Client Hello",") — публічний ключ для шифрування імені домену (SNI) на етапі TLS-рукостискання, що надійно приховує від інтернет-провайдерів та цензорів, який саме сайт відвідує користувач.",[5444,7737,7739],{"id":7738},"роль-протоколів-http-та-tls-virtual-hosting-та-server-name-indication-sni","Роль протоколів HTTP та TLS: Virtual Hosting та Server Name Indication (SNI)",[5373,7741,7742],{},"Здатність DNS спрямовувати запити до apex domain була лише половиною справи. Друга половина полягала в тому, щоб сам вебсервер міг зрозуміти, який саме домен запитує клієнт, і надати коректний SSL\u002FTLS сертифікат.",[5373,7744,7745,7746,7749],{},"У ранньому протоколі ",[5205,7747,7748],{},"HTTP\u002F1.0"," клієнт відкривав TCP-з'єднання з IP-адресою і надсилав запит виду:",[5680,7751,7755],{"className":7752,"code":7753,"language":7754,"meta":5685,"style":5685},"language-http shiki shiki-themes light-plus dark-plus dark-plus","GET \u002Findex.html HTTP\u002F1.0\n","http",[5258,7756,7757],{"__ignoreMap":5685},[5689,7758,7759,7763,7767,7771,7774],{"class":5691,"line":5692},[5689,7760,7762],{"class":7761},"s8xlr","GET",[5689,7764,7766],{"class":7765},"sHH4Y"," \u002Findex.html ",[5689,7768,7770],{"class":7769},"su1O8","HTTP",[5689,7772,7773],{"class":7765},"\u002F",[5689,7775,7777],{"class":7776},"sJj4R","1.0\n",[5373,7779,7780,7781,5430,7783,7786],{},"У цьому запиті не було вказано, до якого саме доменного імені звертається браузер. Якщо на одній IP-адресі розташовувалися сайти ",[5258,7782,7001],{},[5258,7784,7785],{},"other.org",", сервер не міг знати, яку сторінку повертати. Тому кожен домен вимагав окремої виділеної IP-адреси.",[5373,7788,7789],{},"Цю проблему розв'язали два стандарти:",[5552,7791,7792,7845],{},[5201,7793,7794,7801,7802,7831,7832,5406,7835,7838,7839,7842,7843,5261],{},[5205,7795,7796,7797,7800],{},"Заголовок ",[5258,7798,7799],{},"Host"," в HTTP\u002F1.1 (RFC 2616):"," заголовок став обов'язковим для всіх HTTP-запитів:\n",[5680,7803,7805],{"className":7752,"code":7804,"language":7754,"meta":5685,"style":5685},"GET \u002Findex.html HTTP\u002F1.1\nHost: company.com\n",[5258,7806,7807,7820],{"__ignoreMap":5685},[5689,7808,7809,7811,7813,7815,7817],{"class":5691,"line":5692},[5689,7810,7762],{"class":7761},[5689,7812,7766],{"class":7765},[5689,7814,7770],{"class":7769},[5689,7816,7773],{"class":7765},[5689,7818,7819],{"class":7776},"1.1\n",[5689,7821,7822,7825,7827],{"class":5691,"line":5698},[5689,7823,7799],{"class":7824},"sKtos",[5689,7826,7303],{"class":7769},[5689,7828,7830],{"class":7829},"sbdoH"," company.com\n","\nЦе дало початок технології ",[5205,7833,7834],{},"віртуального хостингу на основі імен",[5408,7836,7837],{},"name-based virtual hosting","). Один вебсервер (Nginx, Apache, Caddy) відтепер міг обслуговувати тисячі різних сайтів на одній-єдиній IP-адресі, спрямовуючи запит до потрібного віртуального блоку ",[5258,7840,7841],{},"server"," за значенням заголовка ",[5258,7844,7799],{},[5201,7846,7847,7850,7851,7854,7855,7857,7858,5406,7861,7864,7865,7868,7869,7872,7873,7875,7876,5980],{},[5205,7848,7849],{},"Розширення SNI для TLS (RFC 6066):"," коли інтернет перейшов на шифрування HTTPS, виникла нова перешкода. Оскільки TLS-рукостискання відбувається ",[5205,7852,7853],{},"до"," того, як клієнт передасть зашифрований HTTP-заголовок ",[5258,7856,7799],{},", вебсервер не знав, який SSL-сертифікат пред'явити клієнту при встановленні зашифрованого каналу. Стандарт ",[5205,7859,7860],{},"SNI",[5408,7862,7863],{},"Server Name Indication",") додав можливість передавати ім'я потрібного домену у відкритому полі розширення ",[5258,7866,7867],{},"ClientHello"," на першому кроці TLS-з'єднання. Завдяки SNI сервер віддає правильний сертифікат (наприклад, мультидоменний SAN або wildcard ",[5258,7870,7871],{},"*.company.com",", що охоплює як ",[5258,7874,7001],{},", так і ",[5258,7877,6990],{},[5444,7879,7881],{"id":7880},"сучасна-інженерна-практика-канонізація-доменів-та-налаштування-перенаправлень","Сучасна інженерна практика: канонізація доменів та налаштування перенаправлень",[5373,7883,7884,7885,7888,7889,7892,7893,5261],{},"Хоча сьогодні завдяки CNAME Flattening та запису HTTPS вебсайт чудово відкривається як за адресою ",[5258,7886,7887],{},"https:\u002F\u002Fcompany.com",", так і за адресою ",[5258,7890,7891],{},"https:\u002F\u002Fwww.company.com",", дозволяти сайту одночасно жити за обома адресами вважається ",[5205,7894,7895],{},"грубою архітектурною помилкою",[5373,7897,7898],{},"Існує дві критичні причини, чому трафік слід примусово зводити до одного канонічного варіанта:",[5552,7900,7901,7920],{},[5201,7902,7903,7906,7907,5430,7909,7911,7912,7915,7916,7919],{},[5205,7904,7905],{},"SEO та уникнення дублювання сторінок:"," пошукові роботи (Googlebot) сприймають ",[5258,7908,7001],{},[5258,7910,6990],{}," як два абсолютно різні вебсайти. Якщо обидва повертають однаковий контент із кодом ",[5258,7913,7914],{},"200 OK",", виникає штраф за дублювання вмісту (",[5408,7917,7918],{},"duplicate content penalty","), а посилальна вага сторінок розмивається навпіл.",[5201,7921,7922,7925,7926],{},[5205,7923,7924],{},"Безпека та ізоляція файлів Cookie (Cookie Scoping):"," це найважливіший аспект безпеки бекенд-розробки:\n",[5198,7927,7928,7954],{},[5201,7929,7930,7931,7933,7934,7937,7938,5379,7941,5225,7944,5225,7947,7950,7951,5980],{},"Якщо вебзастосунок на ",[5258,7932,7001],{}," встановлює Cookie без суворого обмеження або з атрибутом ",[5258,7935,7936],{},"Domain=company.com",", ці Cookie автоматично надсилатимуться браузером ",[5205,7939,7940],{},"до всіх піддоменів",[5258,7942,7943],{},"api.company.com",[5258,7945,7946],{},"admin.company.com",[5258,7948,7949],{},"staging.company.com",". Це може призвести до ненавмисного витоку сесійних токенів у разі компрометації будь-якого допоміжного піддомену, а також збільшує розмір заголовків кожного мережевого запиту (наприклад, до статичних CDN-ресурсів ",[5258,7952,7953],{},"static.company.com",[5201,7955,7956,7957,7959,7960,7962],{},"Якщо ж основним доменом обрано ",[5258,7958,6990],{},", файли Cookie встановлюються виключно для вузла ",[5258,7961,5260],{}," і за замовчуванням фізично ізольовані від інших піддоменів системи.",[6046,7964,7965,7970],{},[5373,7966,7967],{},[5205,7968,7969],{},"Що обрати сьогодні — www чи apex domain?",[5198,7971,7972,7982],{},[5201,7973,7974,7975,5406,7977,5225,7979,7981],{},"Для невеликих проєктів, портфоліо, лендінгів, сайтів документації та SaaS-сервісів стандартом став ",[5205,7976,7024],{},[5258,7978,6909],{},[5258,7980,6905],{},") через його візуальну естетичність, зручність запам'ятовування та лаконічність.",[5201,7983,7984,7985,5225,7987,7990,7991,7993],{},"Для масштабних корпоративних порталів (як-от ",[5258,7986,5414],{},[5258,7988,7989],{},"www.facebook.com",") часто зберігають ",[5205,7992,5260],{}," саме через тонкий контроль над ізоляцією Cookie від численних глобальних піддоменів та оптимізацію передачі статичного контенту.",[5373,7995,7996,7997,8000,8001,8004,8005,8008],{},"Для реалізації канонізації на рівні зворотного проксі (",[5408,7998,7999],{},"reverse proxy",") або вебсервера налаштовують постійне перенаправлення з HTTP-кодом ",[5205,8002,8003],{},"301 Moved Permanently"," або сучасним ",[5205,8006,8007],{},"308 Permanent Redirect"," (який суворо зберігає початковий HTTP-метод запиту):",[8010,8011,8012,8153,8207],"code-group",{},[5680,8013,8018],{"className":8014,"code":8015,"filename":8016,"language":8017,"meta":5685,"style":5685},"language-nginx shiki shiki-themes light-plus dark-plus dark-plus","# 1. Перенаправлення з www на канонічний голий домен\nserver {\n    listen 80;\n    listen 443 ssl http2;\n    server_name www.example.com;\n\n    ssl_certificate \u002Fetc\u002Fletsencrypt\u002Flive\u002Fexample.com\u002Ffullchain.pem;\n    ssl_certificate_key \u002Fetc\u002Fletsencrypt\u002Flive\u002Fexample.com\u002Fprivkey.pem;\n\n    # 301 перенаправлення зі збереженням повного шляху та параметрів запиту\n    return 301 https:\u002F\u002Fexample.com$request_uri;\n}\n\n# 2. Основний сервер застосунку\nserver {\n    listen 443 ssl http2;\n    server_name example.com;\n\n    ssl_certificate \u002Fetc\u002Fletsencrypt\u002Flive\u002Fexample.com\u002Ffullchain.pem;\n    ssl_certificate_key \u002Fetc\u002Fletsencrypt\u002Flive\u002Fexample.com\u002Fprivkey.pem;\n\n    location \u002F {\n        proxy_pass http:\u002F\u002F127.0.0.1:8080;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n    }\n}\n","Nginx (www → apex)","nginx",[5258,8019,8020,8025,8030,8035,8040,8045,8049,8054,8059,8063,8068,8073,8077,8081,8086,8090,8094,8099,8103,8107,8111,8115,8120,8125,8130,8135,8140,8145,8149],{"__ignoreMap":5685},[5689,8021,8022],{"class":5691,"line":5692},[5689,8023,8024],{},"# 1. Перенаправлення з www на канонічний голий домен\n",[5689,8026,8027],{"class":5691,"line":5698},[5689,8028,8029],{},"server {\n",[5689,8031,8032],{"class":5691,"line":5704},[5689,8033,8034],{},"    listen 80;\n",[5689,8036,8037],{"class":5691,"line":5710},[5689,8038,8039],{},"    listen 443 ssl http2;\n",[5689,8041,8042],{"class":5691,"line":5716},[5689,8043,8044],{},"    server_name www.example.com;\n",[5689,8046,8047],{"class":5691,"line":5723},[5689,8048,5720],{"emptyLinePlaceholder":5719},[5689,8050,8051],{"class":5691,"line":5729},[5689,8052,8053],{},"    ssl_certificate \u002Fetc\u002Fletsencrypt\u002Flive\u002Fexample.com\u002Ffullchain.pem;\n",[5689,8055,8056],{"class":5691,"line":5735},[5689,8057,8058],{},"    ssl_certificate_key \u002Fetc\u002Fletsencrypt\u002Flive\u002Fexample.com\u002Fprivkey.pem;\n",[5689,8060,8061],{"class":5691,"line":5741},[5689,8062,5720],{"emptyLinePlaceholder":5719},[5689,8064,8065],{"class":5691,"line":5747},[5689,8066,8067],{},"    # 301 перенаправлення зі збереженням повного шляху та параметрів запиту\n",[5689,8069,8070],{"class":5691,"line":5753},[5689,8071,8072],{},"    return 301 https:\u002F\u002Fexample.com$request_uri;\n",[5689,8074,8075],{"class":5691,"line":5758},[5689,8076,5750],{},[5689,8078,8079],{"class":5691,"line":5764},[5689,8080,5720],{"emptyLinePlaceholder":5719},[5689,8082,8083],{"class":5691,"line":5770},[5689,8084,8085],{},"# 2. Основний сервер застосунку\n",[5689,8087,8088],{"class":5691,"line":5776},[5689,8089,8029],{},[5689,8091,8092],{"class":5691,"line":5781},[5689,8093,8039],{},[5689,8095,8096],{"class":5691,"line":5786},[5689,8097,8098],{},"    server_name example.com;\n",[5689,8100,8101],{"class":5691,"line":5792},[5689,8102,5720],{"emptyLinePlaceholder":5719},[5689,8104,8105],{"class":5691,"line":5798},[5689,8106,8053],{},[5689,8108,8109],{"class":5691,"line":5804},[5689,8110,8058],{},[5689,8112,8113],{"class":5691,"line":5809},[5689,8114,5720],{"emptyLinePlaceholder":5719},[5689,8116,8117],{"class":5691,"line":5814},[5689,8118,8119],{},"    location \u002F {\n",[5689,8121,8122],{"class":5691,"line":5820},[5689,8123,8124],{},"        proxy_pass http:\u002F\u002F127.0.0.1:8080;\n",[5689,8126,8127],{"class":5691,"line":5826},[5689,8128,8129],{},"        proxy_set_header Host $host;\n",[5689,8131,8132],{"class":5691,"line":5832},[5689,8133,8134],{},"        proxy_set_header X-Real-IP $remote_addr;\n",[5689,8136,8137],{"class":5691,"line":5838},[5689,8138,8139],{},"        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n",[5689,8141,8142],{"class":5691,"line":5843},[5689,8143,8144],{},"        proxy_set_header X-Forwarded-Proto $scheme;\n",[5689,8146,8147],{"class":5691,"line":5848},[5689,8148,6325],{},[5689,8150,8151],{"class":5691,"line":5854},[5689,8152,5750],{},[5680,8154,8159],{"className":8155,"code":8156,"filename":8157,"language":8158,"meta":5685,"style":5685},"language-caddyfile shiki shiki-themes light-plus dark-plus dark-plus","# У вебсервері Caddy автоматичне отримання сертифікатів\n# та канонічний редирект налаштовуються надзвичайно лаконічно:\n\nwww.example.com {\n    redir https:\u002F\u002Fexample.com{uri} permanent\n}\n\nexample.com {\n    reverse_proxy localhost:8080\n}\n","Caddyfile (www → apex)","caddyfile",[5258,8160,8161,8166,8171,8175,8180,8185,8189,8193,8198,8203],{"__ignoreMap":5685},[5689,8162,8163],{"class":5691,"line":5692},[5689,8164,8165],{},"# У вебсервері Caddy автоматичне отримання сертифікатів\n",[5689,8167,8168],{"class":5691,"line":5698},[5689,8169,8170],{},"# та канонічний редирект налаштовуються надзвичайно лаконічно:\n",[5689,8172,8173],{"class":5691,"line":5704},[5689,8174,5720],{"emptyLinePlaceholder":5719},[5689,8176,8177],{"class":5691,"line":5710},[5689,8178,8179],{},"www.example.com {\n",[5689,8181,8182],{"class":5691,"line":5716},[5689,8183,8184],{},"    redir https:\u002F\u002Fexample.com{uri} permanent\n",[5689,8186,8187],{"class":5691,"line":5723},[5689,8188,5750],{},[5689,8190,8191],{"class":5691,"line":5729},[5689,8192,5720],{"emptyLinePlaceholder":5719},[5689,8194,8195],{"class":5691,"line":5735},[5689,8196,8197],{},"example.com {\n",[5689,8199,8200],{"class":5691,"line":5741},[5689,8201,8202],{},"    reverse_proxy localhost:8080\n",[5689,8204,8205],{"class":5691,"line":5747},[5689,8206,5750],{},[5680,8208,8213],{"className":8209,"code":8210,"filename":8211,"language":8212,"meta":5685,"style":5685},"language-go shiki shiki-themes light-plus dark-plus dark-plus","package main\n\nimport (\n    \"net\u002Fhttp\"\n    \"strings\"\n)\n\n\u002F\u002F CanonicalHostMiddleware гарантує, що всі запити спрямовуються на єдине канонічне ім'я хоста\nfunc CanonicalHostMiddleware(canonicalHost string, next http.Handler) http.Handler {\n    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n        host := r.Host\n\n        \u002F\u002F Відкидаємо порт, якщо запит містить host:port (наприклад, :8080)\n        if colonIdx := strings.IndexByte(host, ':'); colonIdx != -1 {\n            host = host[:colonIdx]\n        }\n\n        \u002F\u002F Якщо хост не відповідає канонічному (наприклад, прийшов www.example.com замість example.com)\n        if !strings.EqualFold(host, canonicalHost) {\n            targetURL := \"https:\u002F\u002F\" + canonicalHost + r.URL.RequestURI()\n            http.Redirect(w, r, targetURL, http.StatusMovedPermanently) \u002F\u002F HTTP 301\n            return\n        }\n\n        next.ServeHTTP(w, r)\n    })\n}\n","Go HTTP Middleware (Canonical Host)","go",[5258,8214,8215,8224,8228,8236,8241,8246,8251,8255,8261,8304,8350,8365,8369,8374,8414,8432,8437,8441,8446,8470,8502,8539,8544,8548,8552,8572,8577],{"__ignoreMap":5685},[5689,8216,8217,8220],{"class":5691,"line":5692},[5689,8218,8219],{"class":7769},"package",[5689,8221,8223],{"class":8222},"sN1BT"," main\n",[5689,8225,8226],{"class":5691,"line":5698},[5689,8227,5720],{"emptyLinePlaceholder":5719},[5689,8229,8230,8233],{"class":5691,"line":5704},[5689,8231,8232],{"class":7761},"import",[5689,8234,8235],{"class":7765}," (\n",[5689,8237,8238],{"class":5691,"line":5710},[5689,8239,8240],{"class":7829},"    \"net\u002Fhttp\"\n",[5689,8242,8243],{"class":5691,"line":5716},[5689,8244,8245],{"class":7829},"    \"strings\"\n",[5689,8247,8248],{"class":5691,"line":5723},[5689,8249,8250],{"class":7765},")\n",[5689,8252,8253],{"class":5691,"line":5729},[5689,8254,5720],{"emptyLinePlaceholder":5719},[5689,8256,8257],{"class":5691,"line":5735},[5689,8258,8260],{"class":8259},"spJ8K","\u002F\u002F CanonicalHostMiddleware гарантує, що всі запити спрямовуються на єдине канонічне ім'я хоста\n",[5689,8262,8263,8266,8270,8273,8277,8280,8282,8285,8288,8290,8293,8295,8297,8299,8301],{"class":5691,"line":5741},[5689,8264,8265],{"class":7769},"func",[5689,8267,8269],{"class":8268},"s8Opu"," CanonicalHostMiddleware",[5689,8271,8272],{"class":7765},"(",[5689,8274,8276],{"class":8275},"siwwj","canonicalHost",[5689,8278,8279],{"class":8222}," string",[5689,8281,5225],{"class":7765},[5689,8283,8284],{"class":8275},"next",[5689,8286,8287],{"class":8222}," http",[5689,8289,5261],{"class":7765},[5689,8291,8292],{"class":8222},"Handler",[5689,8294,7092],{"class":7765},[5689,8296,7754],{"class":8222},[5689,8298,5261],{"class":7765},[5689,8300,8292],{"class":8222},[5689,8302,8303],{"class":7765}," {\n",[5689,8305,8306,8309,8311,8313,8316,8318,8320,8322,8325,8327,8329,8332,8334,8337,8340,8342,8344,8347],{"class":5691,"line":5747},[5689,8307,8308],{"class":7761},"    return",[5689,8310,8287],{"class":8275},[5689,8312,5261],{"class":7765},[5689,8314,8315],{"class":8268},"HandlerFunc",[5689,8317,8272],{"class":7765},[5689,8319,8265],{"class":7769},[5689,8321,8272],{"class":7765},[5689,8323,8324],{"class":8275},"w",[5689,8326,8287],{"class":8222},[5689,8328,5261],{"class":7765},[5689,8330,8331],{"class":8222},"ResponseWriter",[5689,8333,5225],{"class":7765},[5689,8335,8336],{"class":8275},"r",[5689,8338,8339],{"class":7765}," *",[5689,8341,7754],{"class":8222},[5689,8343,5261],{"class":7765},[5689,8345,8346],{"class":8222},"Request",[5689,8348,8349],{"class":7765},") {\n",[5689,8351,8352,8355,8358,8360,8362],{"class":5691,"line":5753},[5689,8353,8354],{"class":8275},"        host",[5689,8356,8357],{"class":7765}," := ",[5689,8359,8336],{"class":8275},[5689,8361,5261],{"class":7765},[5689,8363,8364],{"class":8275},"Host\n",[5689,8366,8367],{"class":5691,"line":5758},[5689,8368,5720],{"emptyLinePlaceholder":5719},[5689,8370,8371],{"class":5691,"line":5764},[5689,8372,8373],{"class":8259},"        \u002F\u002F Відкидаємо порт, якщо запит містить host:port (наприклад, :8080)\n",[5689,8375,8376,8379,8382,8384,8387,8389,8392,8394,8396,8398,8401,8404,8407,8410,8412],{"class":5691,"line":5770},[5689,8377,8378],{"class":7761},"        if",[5689,8380,8381],{"class":8275}," colonIdx",[5689,8383,8357],{"class":7765},[5689,8385,8386],{"class":8275},"strings",[5689,8388,5261],{"class":7765},[5689,8390,8391],{"class":8268},"IndexByte",[5689,8393,8272],{"class":7765},[5689,8395,5352],{"class":8275},[5689,8397,5225],{"class":7765},[5689,8399,8400],{"class":7829},"':'",[5689,8402,8403],{"class":7765},"); ",[5689,8405,8406],{"class":8275},"colonIdx",[5689,8408,8409],{"class":7765}," != -",[5689,8411,6121],{"class":7776},[5689,8413,8303],{"class":7765},[5689,8415,8416,8419,8422,8424,8427,8429],{"class":5691,"line":5776},[5689,8417,8418],{"class":8275},"            host",[5689,8420,8421],{"class":7765}," = ",[5689,8423,5352],{"class":8275},[5689,8425,8426],{"class":7765},"[:",[5689,8428,8406],{"class":8275},[5689,8430,8431],{"class":7765},"]\n",[5689,8433,8434],{"class":5691,"line":5781},[5689,8435,8436],{"class":7765},"        }\n",[5689,8438,8439],{"class":5691,"line":5786},[5689,8440,5720],{"emptyLinePlaceholder":5719},[5689,8442,8443],{"class":5691,"line":5792},[5689,8444,8445],{"class":8259},"        \u002F\u002F Якщо хост не відповідає канонічному (наприклад, прийшов www.example.com замість example.com)\n",[5689,8447,8448,8450,8453,8455,8457,8460,8462,8464,8466,8468],{"class":5691,"line":5798},[5689,8449,8378],{"class":7761},[5689,8451,8452],{"class":7765}," !",[5689,8454,8386],{"class":8275},[5689,8456,5261],{"class":7765},[5689,8458,8459],{"class":8268},"EqualFold",[5689,8461,8272],{"class":7765},[5689,8463,5352],{"class":8275},[5689,8465,5225],{"class":7765},[5689,8467,8276],{"class":8275},[5689,8469,8349],{"class":7765},[5689,8471,8472,8475,8477,8480,8483,8485,8487,8489,8491,8494,8496,8499],{"class":5691,"line":5804},[5689,8473,8474],{"class":8275},"            targetURL",[5689,8476,8357],{"class":7765},[5689,8478,8479],{"class":7829},"\"https:\u002F\u002F\"",[5689,8481,8482],{"class":7765}," + ",[5689,8484,8276],{"class":8275},[5689,8486,8482],{"class":7765},[5689,8488,8336],{"class":8275},[5689,8490,5261],{"class":7765},[5689,8492,8493],{"class":8275},"URL",[5689,8495,5261],{"class":7765},[5689,8497,8498],{"class":8268},"RequestURI",[5689,8500,8501],{"class":7765},"()\n",[5689,8503,8504,8507,8509,8512,8514,8516,8518,8520,8522,8525,8527,8529,8531,8534,8536],{"class":5691,"line":5809},[5689,8505,8506],{"class":8275},"            http",[5689,8508,5261],{"class":7765},[5689,8510,8511],{"class":8268},"Redirect",[5689,8513,8272],{"class":7765},[5689,8515,8324],{"class":8275},[5689,8517,5225],{"class":7765},[5689,8519,8336],{"class":8275},[5689,8521,5225],{"class":7765},[5689,8523,8524],{"class":8275},"targetURL",[5689,8526,5225],{"class":7765},[5689,8528,7754],{"class":8275},[5689,8530,5261],{"class":7765},[5689,8532,8533],{"class":8275},"StatusMovedPermanently",[5689,8535,7092],{"class":7765},[5689,8537,8538],{"class":8259},"\u002F\u002F HTTP 301\n",[5689,8540,8541],{"class":5691,"line":5814},[5689,8542,8543],{"class":7761},"            return\n",[5689,8545,8546],{"class":5691,"line":5820},[5689,8547,8436],{"class":7765},[5689,8549,8550],{"class":5691,"line":5826},[5689,8551,5720],{"emptyLinePlaceholder":5719},[5689,8553,8554,8557,8559,8562,8564,8566,8568,8570],{"class":5691,"line":5832},[5689,8555,8556],{"class":8275},"        next",[5689,8558,5261],{"class":7765},[5689,8560,8561],{"class":8268},"ServeHTTP",[5689,8563,8272],{"class":7765},[5689,8565,8324],{"class":8275},[5689,8567,5225],{"class":7765},[5689,8569,8336],{"class":8275},[5689,8571,8250],{"class":7765},[5689,8573,8574],{"class":5691,"line":5838},[5689,8575,8576],{"class":7765},"    })\n",[5689,8578,8579],{"class":5691,"line":5843},[5689,8580,5750],{"class":7765},[6869,8582,8583,8604],{},[6872,8584,8586,8587,8590,8591,8593,8594,8596,8597,5430,8600,8603],{"icon":6874,"label":8585},"❓ Чому Google Chrome та Safari приховують www в адресному рядку?","Розробники сучасних браузерів ухвалили рішення приховувати схему (",[5258,8588,8589],{},"https:\u002F\u002F",") та піддомен ",[5258,8592,5260],{}," з метою спрощення сприйняття та захисту користувачів від фішингу. Для більшості пересічних людей ",[5258,8595,5260],{}," не несе корисної інформації, а довгий рядок відволікає увагу від справжнього зареєстрованого домену другого рівня. Приховування другорядних префіксів допомагає користувачеві швидше помітити потенційну підміну домену в атаках соціальної інженерії (наприклад, різницю між ",[5258,8598,8599],{},"paypal.com",[5258,8601,8602],{},"paypal.com.fraud-site.ru","). При подвійному кліку по адресному рядку браузер завжди розгортає повне канонічне ім'я з усіма префіксами.",[6872,8605,8608,8609,8612,8613,8616,8617,8620,8621,8623,8624,5225,8626,8628,8629,5225,8632,8635],{"icon":8606,"label":8607},"i-lucide-shield-alert","❓ Чи можна встановити cookie для всього інтернету, встановивши домен у .com або .ua?","Ні, це суворо заблоковано браузерами завдяки механізму ",[5205,8610,8611],{},"Public Suffix List"," (PSL). Якщо зловмисник на сайті ",[5258,8614,8615],{},"evil.com"," спробує встановити заголовок ",[5258,8618,8619],{},"Set-Cookie: token=123; Domain=com",", це дозволило б перехоплювати або перезаписувати cookie для всіх доменів зони ",[5258,8622,5461],{},". Браузери звіряються зі списком публічних суфіксів і забороняють встановлювати cookie на рівні TLD (наприклад, ",[5258,8625,5461],{},[5258,8627,5605],{},") або складових національних доменів (",[5258,8630,8631],{},".kiev.ua",[5258,8633,8634],{},".co.uk","), дозволяючи це лише для зареєстрованих організаційних доменів та їхніх прямих піддоменів.",[5365,8637],{},[5368,8639,8641],{"id":8640},"програмний-dns-резолвінг-у-go-через-пакет-netresolver","Програмний DNS-резолвінг у Go через пакет net.Resolver",[5373,8643,8644,8645,8649,8650,8654,8655,8658,8659,8661],{},"Стандартна бібліотека Go надає потужний та гнучкий інструментарій для виконання DNS-запитів через пакет ",[5205,8646,8647],{},[5258,8648,5326],{},", зокрема структуру ",[5205,8651,8652],{},[5258,8653,5267],{},". На відміну від простих функцій на кшталт ",[5258,8656,8657],{},"net.LookupHost",", які використовують системний резолвер операційної системи, ",[5258,8660,5267],{}," дозволяє налаштувати власні DNS-сервери, таймаути, контексти скасування та детально контролювати процес резолвінгу.",[5444,8663,8665],{"id":8664},"базовий-приклад-резолвінг-a-записів","Базовий приклад: резолвінг A-записів",[5373,8667,8668],{},"Розглянемо найпростіший випадок — отримання IPv4-адреси для доменного імені:",[5680,8670,8672],{"className":8209,"code":8671,"language":8212,"meta":5685,"style":5685},"package main\n\nimport (\n    \"context\"\n    \"fmt\"\n    \"log\"\n    \"net\"\n    \"time\"\n)\n\nfunc main() {\n    \u002F\u002F Створюємо резолвер за замовчуванням (використовує системні налаштування DNS)\n    resolver := &net.Resolver{}\n    \n    \u002F\u002F Контекст із таймаутом 5 секунд\n    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n    defer cancel()\n    \n    \u002F\u002F Виконуємо резолвінг доменного імені\n    hostname := \"www.example.com\"\n    addrs, err := resolver.LookupHost(ctx, hostname)\n    if err != nil {\n        log.Fatalf(\"Помилка DNS-резолвінгу для %s: %v\", hostname, err)\n    }\n    \n    fmt.Printf(\"DNS-записи для %s:\\n\", hostname)\n    for _, addr := range addrs {\n        fmt.Printf(\"  - %s\\n\", addr)\n    }\n}\n",[5258,8673,8674,8680,8684,8690,8695,8700,8705,8710,8715,8719,8723,8733,8738,8756,8760,8765,8812,8822,8826,8831,8841,8873,8889,8925,8929,8933,8964,8987,9013,9017],{"__ignoreMap":5685},[5689,8675,8676,8678],{"class":5691,"line":5692},[5689,8677,8219],{"class":7769},[5689,8679,8223],{"class":8222},[5689,8681,8682],{"class":5691,"line":5698},[5689,8683,5720],{"emptyLinePlaceholder":5719},[5689,8685,8686,8688],{"class":5691,"line":5704},[5689,8687,8232],{"class":7761},[5689,8689,8235],{"class":7765},[5689,8691,8692],{"class":5691,"line":5710},[5689,8693,8694],{"class":7829},"    \"context\"\n",[5689,8696,8697],{"class":5691,"line":5716},[5689,8698,8699],{"class":7829},"    \"fmt\"\n",[5689,8701,8702],{"class":5691,"line":5723},[5689,8703,8704],{"class":7829},"    \"log\"\n",[5689,8706,8707],{"class":5691,"line":5729},[5689,8708,8709],{"class":7829},"    \"net\"\n",[5689,8711,8712],{"class":5691,"line":5735},[5689,8713,8714],{"class":7829},"    \"time\"\n",[5689,8716,8717],{"class":5691,"line":5741},[5689,8718,8250],{"class":7765},[5689,8720,8721],{"class":5691,"line":5747},[5689,8722,5720],{"emptyLinePlaceholder":5719},[5689,8724,8725,8727,8730],{"class":5691,"line":5753},[5689,8726,8265],{"class":7769},[5689,8728,8729],{"class":8268}," main",[5689,8731,8732],{"class":7765},"() {\n",[5689,8734,8735],{"class":5691,"line":5758},[5689,8736,8737],{"class":8259},"    \u002F\u002F Створюємо резолвер за замовчуванням (використовує системні налаштування DNS)\n",[5689,8739,8740,8743,8746,8748,8750,8753],{"class":5691,"line":5764},[5689,8741,8742],{"class":8275},"    resolver",[5689,8744,8745],{"class":7765}," := &",[5689,8747,5326],{"class":8222},[5689,8749,5261],{"class":7765},[5689,8751,8752],{"class":8222},"Resolver",[5689,8754,8755],{"class":7765},"{}\n",[5689,8757,8758],{"class":5691,"line":5770},[5689,8759,6330],{"class":7765},[5689,8761,8762],{"class":5691,"line":5776},[5689,8763,8764],{"class":8259},"    \u002F\u002F Контекст із таймаутом 5 секунд\n",[5689,8766,8767,8770,8772,8775,8777,8780,8782,8785,8787,8789,8791,8794,8797,8799,8802,8805,8807,8810],{"class":5691,"line":5781},[5689,8768,8769],{"class":8275},"    ctx",[5689,8771,5225],{"class":7765},[5689,8773,8774],{"class":8275},"cancel",[5689,8776,8357],{"class":7765},[5689,8778,8779],{"class":8275},"context",[5689,8781,5261],{"class":7765},[5689,8783,8784],{"class":8268},"WithTimeout",[5689,8786,8272],{"class":7765},[5689,8788,8779],{"class":8275},[5689,8790,5261],{"class":7765},[5689,8792,8793],{"class":8268},"Background",[5689,8795,8796],{"class":7765},"(), ",[5689,8798,6647],{"class":7776},[5689,8800,8801],{"class":7765},"*",[5689,8803,8804],{"class":8275},"time",[5689,8806,5261],{"class":7765},[5689,8808,8809],{"class":8275},"Second",[5689,8811,8250],{"class":7765},[5689,8813,8814,8817,8820],{"class":5691,"line":5786},[5689,8815,8816],{"class":7761},"    defer",[5689,8818,8819],{"class":8268}," cancel",[5689,8821,8501],{"class":7765},[5689,8823,8824],{"class":5691,"line":5792},[5689,8825,6330],{"class":7765},[5689,8827,8828],{"class":5691,"line":5798},[5689,8829,8830],{"class":8259},"    \u002F\u002F Виконуємо резолвінг доменного імені\n",[5689,8832,8833,8836,8838],{"class":5691,"line":5804},[5689,8834,8835],{"class":8275},"    hostname",[5689,8837,8357],{"class":7765},[5689,8839,8840],{"class":7829},"\"www.example.com\"\n",[5689,8842,8843,8846,8848,8851,8853,8856,8858,8861,8863,8866,8868,8871],{"class":5691,"line":5809},[5689,8844,8845],{"class":8275},"    addrs",[5689,8847,5225],{"class":7765},[5689,8849,8850],{"class":8275},"err",[5689,8852,8357],{"class":7765},[5689,8854,8855],{"class":8275},"resolver",[5689,8857,5261],{"class":7765},[5689,8859,8860],{"class":8268},"LookupHost",[5689,8862,8272],{"class":7765},[5689,8864,8865],{"class":8275},"ctx",[5689,8867,5225],{"class":7765},[5689,8869,8870],{"class":8275},"hostname",[5689,8872,8250],{"class":7765},[5689,8874,8875,8878,8881,8884,8887],{"class":5691,"line":5814},[5689,8876,8877],{"class":7761},"    if",[5689,8879,8880],{"class":8275}," err",[5689,8882,8883],{"class":7765}," != ",[5689,8885,8886],{"class":7769},"nil",[5689,8888,8303],{"class":7765},[5689,8890,8891,8894,8896,8899,8901,8904,8907,8909,8912,8915,8917,8919,8921,8923],{"class":5691,"line":5820},[5689,8892,8893],{"class":8275},"        log",[5689,8895,5261],{"class":7765},[5689,8897,8898],{"class":8268},"Fatalf",[5689,8900,8272],{"class":7765},[5689,8902,8903],{"class":7829},"\"Помилка DNS-резолвінгу для ",[5689,8905,8906],{"class":8275},"%s",[5689,8908,5379],{"class":7829},[5689,8910,8911],{"class":8275},"%v",[5689,8913,8914],{"class":7829},"\"",[5689,8916,5225],{"class":7765},[5689,8918,8870],{"class":8275},[5689,8920,5225],{"class":7765},[5689,8922,8850],{"class":8275},[5689,8924,8250],{"class":7765},[5689,8926,8927],{"class":5691,"line":5826},[5689,8928,6325],{"class":7765},[5689,8930,8931],{"class":5691,"line":5832},[5689,8932,6330],{"class":7765},[5689,8934,8935,8938,8940,8943,8945,8948,8950,8952,8956,8958,8960,8962],{"class":5691,"line":5838},[5689,8936,8937],{"class":8275},"    fmt",[5689,8939,5261],{"class":7765},[5689,8941,8942],{"class":8268},"Printf",[5689,8944,8272],{"class":7765},[5689,8946,8947],{"class":7829},"\"DNS-записи для ",[5689,8949,8906],{"class":8275},[5689,8951,7303],{"class":7829},[5689,8953,8955],{"class":8954},"sjcCO","\\n",[5689,8957,8914],{"class":7829},[5689,8959,5225],{"class":7765},[5689,8961,8870],{"class":8275},[5689,8963,8250],{"class":7765},[5689,8965,8966,8969,8972,8974,8977,8979,8982,8985],{"class":5691,"line":5843},[5689,8967,8968],{"class":7761},"    for",[5689,8970,8971],{"class":8275}," _",[5689,8973,5225],{"class":7765},[5689,8975,8976],{"class":8275},"addr",[5689,8978,8357],{"class":7765},[5689,8980,8981],{"class":7761},"range",[5689,8983,8984],{"class":8275}," addrs",[5689,8986,8303],{"class":7765},[5689,8988,8989,8992,8994,8996,8998,9001,9003,9005,9007,9009,9011],{"class":5691,"line":5848},[5689,8990,8991],{"class":8275},"        fmt",[5689,8993,5261],{"class":7765},[5689,8995,8942],{"class":8268},[5689,8997,8272],{"class":7765},[5689,8999,9000],{"class":7829},"\"  - ",[5689,9002,8906],{"class":8275},[5689,9004,8955],{"class":8954},[5689,9006,8914],{"class":7829},[5689,9008,5225],{"class":7765},[5689,9010,8976],{"class":8275},[5689,9012,8250],{"class":7765},[5689,9014,9015],{"class":5691,"line":5854},[5689,9016,6325],{"class":7765},[5689,9018,9019],{"class":5691,"line":5860},[5689,9020,5750],{"class":7765},[5373,9022,9023],{},[5205,9024,9025],{},"Вихід програми:",[5680,9027,9030],{"className":9028,"code":9029,"language":6502},[6500],"DNS-записи для www.example.com:\n  - 93.184.216.34\n  - 2606:2800:220:1:248:1893:25c8:1946\n",[5258,9031,9029],{"__ignoreMap":5685},[5373,9033,9034,9035,9037,9038,9041],{},"Зверніть увагу, що ",[5258,9036,8860],{}," повертає ",[5205,9039,9040],{},"як IPv4, так і IPv6"," адреси (якщо обидва типи записів існують). Це зручно для реалізації dual-stack підтримки в клієнтських застосунках.",[5444,9043,9045],{"id":9044},"використання-кастомного-dns-сервера","Використання кастомного DNS-сервера",[5373,9047,9048,9049,9051,9052,7303],{},"Часто у production-середовищах потрібно використовувати конкретні DNS-сервери замість системних (наприклад, внутрішній корпоративний DNS або публічні резолвери Cloudflare\u002FGoogle для кращої продуктивності). ",[5258,9050,5267],{}," дозволяє налаштувати це через поле ",[5258,9053,9054],{},"Dial",[5680,9056,9058],{"className":8209,"code":9057,"language":8212,"meta":5685,"style":5685},"package main\n\nimport (\n    \"context\"\n    \"fmt\"\n    \"log\"\n    \"net\"\n    \"time\"\n)\n\nfunc main() {\n    \u002F\u002F Створюємо резолвер із кастомним DNS-сервером (Google Public DNS 8.8.8.8)\n    resolver := &net.Resolver{\n        PreferGo: true, \u002F\u002F Використовувати власну реалізацію Go замість системної\n        Dial: func(ctx context.Context, network, address string) (net.Conn, error) {\n            d := net.Dialer{\n                Timeout: 3 * time.Second,\n            }\n            return d.DialContext(ctx, \"udp\", \"8.8.8.8:53\")\n        },\n    }\n    \n    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n    defer cancel()\n    \n    hostname := \"www.google.com\"\n    addrs, err := resolver.LookupHost(ctx, hostname)\n    if err != nil {\n        log.Fatalf(\"Помилка резолвінгу: %v\", err)\n    }\n    \n    fmt.Printf(\"Адреси для %s (через DNS 8.8.8.8):\\n\", hostname)\n    for _, addr := range addrs {\n        fmt.Printf(\"  - %s\\n\", addr)\n    }\n}\n",[5258,9059,9060,9066,9070,9076,9080,9084,9088,9092,9096,9100,9104,9112,9117,9132,9147,9197,9213,9235,9240,9269,9274,9278,9282,9320,9328,9332,9341,9367,9379,9402,9406,9410,9438,9456,9480,9484],{"__ignoreMap":5685},[5689,9061,9062,9064],{"class":5691,"line":5692},[5689,9063,8219],{"class":7769},[5689,9065,8223],{"class":8222},[5689,9067,9068],{"class":5691,"line":5698},[5689,9069,5720],{"emptyLinePlaceholder":5719},[5689,9071,9072,9074],{"class":5691,"line":5704},[5689,9073,8232],{"class":7761},[5689,9075,8235],{"class":7765},[5689,9077,9078],{"class":5691,"line":5710},[5689,9079,8694],{"class":7829},[5689,9081,9082],{"class":5691,"line":5716},[5689,9083,8699],{"class":7829},[5689,9085,9086],{"class":5691,"line":5723},[5689,9087,8704],{"class":7829},[5689,9089,9090],{"class":5691,"line":5729},[5689,9091,8709],{"class":7829},[5689,9093,9094],{"class":5691,"line":5735},[5689,9095,8714],{"class":7829},[5689,9097,9098],{"class":5691,"line":5741},[5689,9099,8250],{"class":7765},[5689,9101,9102],{"class":5691,"line":5747},[5689,9103,5720],{"emptyLinePlaceholder":5719},[5689,9105,9106,9108,9110],{"class":5691,"line":5753},[5689,9107,8265],{"class":7769},[5689,9109,8729],{"class":8268},[5689,9111,8732],{"class":7765},[5689,9113,9114],{"class":5691,"line":5758},[5689,9115,9116],{"class":8259},"    \u002F\u002F Створюємо резолвер із кастомним DNS-сервером (Google Public DNS 8.8.8.8)\n",[5689,9118,9119,9121,9123,9125,9127,9129],{"class":5691,"line":5764},[5689,9120,8742],{"class":8275},[5689,9122,8745],{"class":7765},[5689,9124,5326],{"class":8222},[5689,9126,5261],{"class":7765},[5689,9128,8752],{"class":8222},[5689,9130,9131],{"class":7765},"{\n",[5689,9133,9134,9137,9139,9142,9144],{"class":5691,"line":5770},[5689,9135,9136],{"class":8275},"        PreferGo",[5689,9138,5379],{"class":7765},[5689,9140,9141],{"class":7769},"true",[5689,9143,5225],{"class":7765},[5689,9145,9146],{"class":8259},"\u002F\u002F Використовувати власну реалізацію Go замість системної\n",[5689,9148,9149,9152,9154,9156,9158,9160,9163,9165,9168,9170,9173,9175,9178,9180,9183,9185,9187,9190,9192,9195],{"class":5691,"line":5776},[5689,9150,9151],{"class":8275},"        Dial",[5689,9153,5379],{"class":7765},[5689,9155,8265],{"class":7769},[5689,9157,8272],{"class":7765},[5689,9159,8865],{"class":8275},[5689,9161,9162],{"class":8222}," context",[5689,9164,5261],{"class":7765},[5689,9166,9167],{"class":8222},"Context",[5689,9169,5225],{"class":7765},[5689,9171,9172],{"class":8275},"network",[5689,9174,5225],{"class":7765},[5689,9176,9177],{"class":8275},"address",[5689,9179,8279],{"class":8222},[5689,9181,9182],{"class":7765},") (",[5689,9184,5326],{"class":8222},[5689,9186,5261],{"class":7765},[5689,9188,9189],{"class":8222},"Conn",[5689,9191,5225],{"class":7765},[5689,9193,9194],{"class":8222},"error",[5689,9196,8349],{"class":7765},[5689,9198,9199,9202,9204,9206,9208,9211],{"class":5691,"line":5781},[5689,9200,9201],{"class":8275},"            d",[5689,9203,8357],{"class":7765},[5689,9205,5326],{"class":8222},[5689,9207,5261],{"class":7765},[5689,9209,9210],{"class":8222},"Dialer",[5689,9212,9131],{"class":7765},[5689,9214,9215,9218,9220,9223,9226,9228,9230,9232],{"class":5691,"line":5786},[5689,9216,9217],{"class":8275},"                Timeout",[5689,9219,5379],{"class":7765},[5689,9221,9222],{"class":7776},"3",[5689,9224,9225],{"class":7765}," * ",[5689,9227,8804],{"class":8275},[5689,9229,5261],{"class":7765},[5689,9231,8809],{"class":8275},[5689,9233,9234],{"class":7765},",\n",[5689,9236,9237],{"class":5691,"line":5792},[5689,9238,9239],{"class":7765},"            }\n",[5689,9241,9242,9245,9248,9250,9253,9255,9257,9259,9262,9264,9267],{"class":5691,"line":5798},[5689,9243,9244],{"class":7761},"            return",[5689,9246,9247],{"class":8275}," d",[5689,9249,5261],{"class":7765},[5689,9251,9252],{"class":8268},"DialContext",[5689,9254,8272],{"class":7765},[5689,9256,8865],{"class":8275},[5689,9258,5225],{"class":7765},[5689,9260,9261],{"class":7829},"\"udp\"",[5689,9263,5225],{"class":7765},[5689,9265,9266],{"class":7829},"\"8.8.8.8:53\"",[5689,9268,8250],{"class":7765},[5689,9270,9271],{"class":5691,"line":5804},[5689,9272,9273],{"class":7765},"        },\n",[5689,9275,9276],{"class":5691,"line":5809},[5689,9277,6325],{"class":7765},[5689,9279,9280],{"class":5691,"line":5814},[5689,9281,6330],{"class":7765},[5689,9283,9284,9286,9288,9290,9292,9294,9296,9298,9300,9302,9304,9306,9308,9310,9312,9314,9316,9318],{"class":5691,"line":5820},[5689,9285,8769],{"class":8275},[5689,9287,5225],{"class":7765},[5689,9289,8774],{"class":8275},[5689,9291,8357],{"class":7765},[5689,9293,8779],{"class":8275},[5689,9295,5261],{"class":7765},[5689,9297,8784],{"class":8268},[5689,9299,8272],{"class":7765},[5689,9301,8779],{"class":8275},[5689,9303,5261],{"class":7765},[5689,9305,8793],{"class":8268},[5689,9307,8796],{"class":7765},[5689,9309,6647],{"class":7776},[5689,9311,8801],{"class":7765},[5689,9313,8804],{"class":8275},[5689,9315,5261],{"class":7765},[5689,9317,8809],{"class":8275},[5689,9319,8250],{"class":7765},[5689,9321,9322,9324,9326],{"class":5691,"line":5826},[5689,9323,8816],{"class":7761},[5689,9325,8819],{"class":8268},[5689,9327,8501],{"class":7765},[5689,9329,9330],{"class":5691,"line":5832},[5689,9331,6330],{"class":7765},[5689,9333,9334,9336,9338],{"class":5691,"line":5838},[5689,9335,8835],{"class":8275},[5689,9337,8357],{"class":7765},[5689,9339,9340],{"class":7829},"\"www.google.com\"\n",[5689,9342,9343,9345,9347,9349,9351,9353,9355,9357,9359,9361,9363,9365],{"class":5691,"line":5843},[5689,9344,8845],{"class":8275},[5689,9346,5225],{"class":7765},[5689,9348,8850],{"class":8275},[5689,9350,8357],{"class":7765},[5689,9352,8855],{"class":8275},[5689,9354,5261],{"class":7765},[5689,9356,8860],{"class":8268},[5689,9358,8272],{"class":7765},[5689,9360,8865],{"class":8275},[5689,9362,5225],{"class":7765},[5689,9364,8870],{"class":8275},[5689,9366,8250],{"class":7765},[5689,9368,9369,9371,9373,9375,9377],{"class":5691,"line":5848},[5689,9370,8877],{"class":7761},[5689,9372,8880],{"class":8275},[5689,9374,8883],{"class":7765},[5689,9376,8886],{"class":7769},[5689,9378,8303],{"class":7765},[5689,9380,9381,9383,9385,9387,9389,9392,9394,9396,9398,9400],{"class":5691,"line":5854},[5689,9382,8893],{"class":8275},[5689,9384,5261],{"class":7765},[5689,9386,8898],{"class":8268},[5689,9388,8272],{"class":7765},[5689,9390,9391],{"class":7829},"\"Помилка резолвінгу: ",[5689,9393,8911],{"class":8275},[5689,9395,8914],{"class":7829},[5689,9397,5225],{"class":7765},[5689,9399,8850],{"class":8275},[5689,9401,8250],{"class":7765},[5689,9403,9404],{"class":5691,"line":5860},[5689,9405,6325],{"class":7765},[5689,9407,9408],{"class":5691,"line":5866},[5689,9409,6330],{"class":7765},[5689,9411,9412,9414,9416,9418,9420,9423,9425,9428,9430,9432,9434,9436],{"class":5691,"line":5871},[5689,9413,8937],{"class":8275},[5689,9415,5261],{"class":7765},[5689,9417,8942],{"class":8268},[5689,9419,8272],{"class":7765},[5689,9421,9422],{"class":7829},"\"Адреси для ",[5689,9424,8906],{"class":8275},[5689,9426,9427],{"class":7829}," (через DNS 8.8.8.8):",[5689,9429,8955],{"class":8954},[5689,9431,8914],{"class":7829},[5689,9433,5225],{"class":7765},[5689,9435,8870],{"class":8275},[5689,9437,8250],{"class":7765},[5689,9439,9440,9442,9444,9446,9448,9450,9452,9454],{"class":5691,"line":5877},[5689,9441,8968],{"class":7761},[5689,9443,8971],{"class":8275},[5689,9445,5225],{"class":7765},[5689,9447,8976],{"class":8275},[5689,9449,8357],{"class":7765},[5689,9451,8981],{"class":7761},[5689,9453,8984],{"class":8275},[5689,9455,8303],{"class":7765},[5689,9457,9458,9460,9462,9464,9466,9468,9470,9472,9474,9476,9478],{"class":5691,"line":5883},[5689,9459,8991],{"class":8275},[5689,9461,5261],{"class":7765},[5689,9463,8942],{"class":8268},[5689,9465,8272],{"class":7765},[5689,9467,9000],{"class":7829},[5689,9469,8906],{"class":8275},[5689,9471,8955],{"class":8954},[5689,9473,8914],{"class":7829},[5689,9475,5225],{"class":7765},[5689,9477,8976],{"class":8275},[5689,9479,8250],{"class":7765},[5689,9481,9482],{"class":5691,"line":5889},[5689,9483,6325],{"class":7765},[5689,9485,9486],{"class":5691,"line":5895},[5689,9487,5750],{"class":7765},[6046,9489,9490,9493,9494,9497,9498,9500,9501,9503],{},[5205,9491,9492],{},"Коли використовувати кастомні DNS-сервери:"," у корпоративних мережах часто є внутрішні DNS-сервери, які резолвлять приватні доменні імена (наприклад, ",[5258,9495,9496],{},"internal-api.company.local","), недоступні через публічні резолвери. У таких випадках ваш Go-застосунок повинен бути налаштований на використання корпоративного DNS. Крім того, публічні резолвери на кшталт Cloudflare (",[5258,9499,5956],{},") або Google (",[5258,9502,5952],{},") часто працюють швидше за DNS інтернет-провайдерів та підтримують сучасні стандарти безпеки (DNS-over-HTTPS).",[5444,9505,9507],{"id":9506},"запит-конкретних-типів-dns-записів","Запит конкретних типів DNS-записів",[5373,9509,9510,9511,9513],{},"Іноді потрібно отримати не просто IP-адреси, а конкретні типи записів: MX для налаштування поштового клієнта, TXT для перевірки SPF-політик, SRV для виявлення мікросервісів. ",[5258,9512,5326],{}," надає спеціалізовані методи для кожного типу:",[5680,9515,9517],{"className":8209,"code":9516,"language":8212,"meta":5685,"style":5685},"package main\n\nimport (\n    \"context\"\n    \"fmt\"\n    \"log\"\n    \"net\"\n)\n\nfunc main() {\n    resolver := &net.Resolver{}\n    ctx := context.Background()\n    \n    domain := \"example.com\"\n    \n    \u002F\u002F Запит MX-записів (поштові сервери)\n    mxRecords, err := resolver.LookupMX(ctx, domain)\n    if err != nil {\n        log.Fatalf(\"Помилка запиту MX: %v\", err)\n    }\n    \n    fmt.Printf(\"MX-записи для %s:\\n\", domain)\n    for _, mx := range mxRecords {\n        fmt.Printf(\"  Пріоритет %d: %s\\n\", mx.Pref, mx.Host)\n    }\n    \n    \u002F\u002F Запит TXT-записів (SPF, DKIM, верифікація)\n    txtRecords, err := resolver.LookupTXT(ctx, domain)\n    if err != nil {\n        log.Fatalf(\"Помилка запиту TXT: %v\", err)\n    }\n    \n    fmt.Printf(\"\\nTXT-записи для %s:\\n\", domain)\n    for _, txt := range txtRecords {\n        fmt.Printf(\"  - %s\\n\", txt)\n    }\n}\n",[5258,9518,9519,9525,9529,9535,9539,9543,9547,9551,9555,9559,9567,9581,9595,9599,9609,9613,9618,9647,9659,9682,9686,9690,9717,9737,9780,9784,9788,9793,9821,9833,9856,9860,9864,9895,9915,9939,9943],{"__ignoreMap":5685},[5689,9520,9521,9523],{"class":5691,"line":5692},[5689,9522,8219],{"class":7769},[5689,9524,8223],{"class":8222},[5689,9526,9527],{"class":5691,"line":5698},[5689,9528,5720],{"emptyLinePlaceholder":5719},[5689,9530,9531,9533],{"class":5691,"line":5704},[5689,9532,8232],{"class":7761},[5689,9534,8235],{"class":7765},[5689,9536,9537],{"class":5691,"line":5710},[5689,9538,8694],{"class":7829},[5689,9540,9541],{"class":5691,"line":5716},[5689,9542,8699],{"class":7829},[5689,9544,9545],{"class":5691,"line":5723},[5689,9546,8704],{"class":7829},[5689,9548,9549],{"class":5691,"line":5729},[5689,9550,8709],{"class":7829},[5689,9552,9553],{"class":5691,"line":5735},[5689,9554,8250],{"class":7765},[5689,9556,9557],{"class":5691,"line":5741},[5689,9558,5720],{"emptyLinePlaceholder":5719},[5689,9560,9561,9563,9565],{"class":5691,"line":5747},[5689,9562,8265],{"class":7769},[5689,9564,8729],{"class":8268},[5689,9566,8732],{"class":7765},[5689,9568,9569,9571,9573,9575,9577,9579],{"class":5691,"line":5753},[5689,9570,8742],{"class":8275},[5689,9572,8745],{"class":7765},[5689,9574,5326],{"class":8222},[5689,9576,5261],{"class":7765},[5689,9578,8752],{"class":8222},[5689,9580,8755],{"class":7765},[5689,9582,9583,9585,9587,9589,9591,9593],{"class":5691,"line":5758},[5689,9584,8769],{"class":8275},[5689,9586,8357],{"class":7765},[5689,9588,8779],{"class":8275},[5689,9590,5261],{"class":7765},[5689,9592,8793],{"class":8268},[5689,9594,8501],{"class":7765},[5689,9596,9597],{"class":5691,"line":5764},[5689,9598,6330],{"class":7765},[5689,9600,9601,9604,9606],{"class":5691,"line":5770},[5689,9602,9603],{"class":8275},"    domain",[5689,9605,8357],{"class":7765},[5689,9607,9608],{"class":7829},"\"example.com\"\n",[5689,9610,9611],{"class":5691,"line":5776},[5689,9612,6330],{"class":7765},[5689,9614,9615],{"class":5691,"line":5781},[5689,9616,9617],{"class":8259},"    \u002F\u002F Запит MX-записів (поштові сервери)\n",[5689,9619,9620,9623,9625,9627,9629,9631,9633,9636,9638,9640,9642,9645],{"class":5691,"line":5786},[5689,9621,9622],{"class":8275},"    mxRecords",[5689,9624,5225],{"class":7765},[5689,9626,8850],{"class":8275},[5689,9628,8357],{"class":7765},[5689,9630,8855],{"class":8275},[5689,9632,5261],{"class":7765},[5689,9634,9635],{"class":8268},"LookupMX",[5689,9637,8272],{"class":7765},[5689,9639,8865],{"class":8275},[5689,9641,5225],{"class":7765},[5689,9643,9644],{"class":8275},"domain",[5689,9646,8250],{"class":7765},[5689,9648,9649,9651,9653,9655,9657],{"class":5691,"line":5792},[5689,9650,8877],{"class":7761},[5689,9652,8880],{"class":8275},[5689,9654,8883],{"class":7765},[5689,9656,8886],{"class":7769},[5689,9658,8303],{"class":7765},[5689,9660,9661,9663,9665,9667,9669,9672,9674,9676,9678,9680],{"class":5691,"line":5798},[5689,9662,8893],{"class":8275},[5689,9664,5261],{"class":7765},[5689,9666,8898],{"class":8268},[5689,9668,8272],{"class":7765},[5689,9670,9671],{"class":7829},"\"Помилка запиту MX: ",[5689,9673,8911],{"class":8275},[5689,9675,8914],{"class":7829},[5689,9677,5225],{"class":7765},[5689,9679,8850],{"class":8275},[5689,9681,8250],{"class":7765},[5689,9683,9684],{"class":5691,"line":5804},[5689,9685,6325],{"class":7765},[5689,9687,9688],{"class":5691,"line":5809},[5689,9689,6330],{"class":7765},[5689,9691,9692,9694,9696,9698,9700,9703,9705,9707,9709,9711,9713,9715],{"class":5691,"line":5814},[5689,9693,8937],{"class":8275},[5689,9695,5261],{"class":7765},[5689,9697,8942],{"class":8268},[5689,9699,8272],{"class":7765},[5689,9701,9702],{"class":7829},"\"MX-записи для ",[5689,9704,8906],{"class":8275},[5689,9706,7303],{"class":7829},[5689,9708,8955],{"class":8954},[5689,9710,8914],{"class":7829},[5689,9712,5225],{"class":7765},[5689,9714,9644],{"class":8275},[5689,9716,8250],{"class":7765},[5689,9718,9719,9721,9723,9725,9728,9730,9732,9735],{"class":5691,"line":5820},[5689,9720,8968],{"class":7761},[5689,9722,8971],{"class":8275},[5689,9724,5225],{"class":7765},[5689,9726,9727],{"class":8275},"mx",[5689,9729,8357],{"class":7765},[5689,9731,8981],{"class":7761},[5689,9733,9734],{"class":8275}," mxRecords",[5689,9736,8303],{"class":7765},[5689,9738,9739,9741,9743,9745,9747,9750,9753,9755,9757,9759,9761,9763,9765,9767,9770,9772,9774,9776,9778],{"class":5691,"line":5826},[5689,9740,8991],{"class":8275},[5689,9742,5261],{"class":7765},[5689,9744,8942],{"class":8268},[5689,9746,8272],{"class":7765},[5689,9748,9749],{"class":7829},"\"  Пріоритет ",[5689,9751,9752],{"class":8275},"%d",[5689,9754,5379],{"class":7829},[5689,9756,8906],{"class":8275},[5689,9758,8955],{"class":8954},[5689,9760,8914],{"class":7829},[5689,9762,5225],{"class":7765},[5689,9764,9727],{"class":8275},[5689,9766,5261],{"class":7765},[5689,9768,9769],{"class":8275},"Pref",[5689,9771,5225],{"class":7765},[5689,9773,9727],{"class":8275},[5689,9775,5261],{"class":7765},[5689,9777,7799],{"class":8275},[5689,9779,8250],{"class":7765},[5689,9781,9782],{"class":5691,"line":5832},[5689,9783,6325],{"class":7765},[5689,9785,9786],{"class":5691,"line":5838},[5689,9787,6330],{"class":7765},[5689,9789,9790],{"class":5691,"line":5843},[5689,9791,9792],{"class":8259},"    \u002F\u002F Запит TXT-записів (SPF, DKIM, верифікація)\n",[5689,9794,9795,9798,9800,9802,9804,9806,9808,9811,9813,9815,9817,9819],{"class":5691,"line":5848},[5689,9796,9797],{"class":8275},"    txtRecords",[5689,9799,5225],{"class":7765},[5689,9801,8850],{"class":8275},[5689,9803,8357],{"class":7765},[5689,9805,8855],{"class":8275},[5689,9807,5261],{"class":7765},[5689,9809,9810],{"class":8268},"LookupTXT",[5689,9812,8272],{"class":7765},[5689,9814,8865],{"class":8275},[5689,9816,5225],{"class":7765},[5689,9818,9644],{"class":8275},[5689,9820,8250],{"class":7765},[5689,9822,9823,9825,9827,9829,9831],{"class":5691,"line":5854},[5689,9824,8877],{"class":7761},[5689,9826,8880],{"class":8275},[5689,9828,8883],{"class":7765},[5689,9830,8886],{"class":7769},[5689,9832,8303],{"class":7765},[5689,9834,9835,9837,9839,9841,9843,9846,9848,9850,9852,9854],{"class":5691,"line":5860},[5689,9836,8893],{"class":8275},[5689,9838,5261],{"class":7765},[5689,9840,8898],{"class":8268},[5689,9842,8272],{"class":7765},[5689,9844,9845],{"class":7829},"\"Помилка запиту TXT: ",[5689,9847,8911],{"class":8275},[5689,9849,8914],{"class":7829},[5689,9851,5225],{"class":7765},[5689,9853,8850],{"class":8275},[5689,9855,8250],{"class":7765},[5689,9857,9858],{"class":5691,"line":5866},[5689,9859,6325],{"class":7765},[5689,9861,9862],{"class":5691,"line":5871},[5689,9863,6330],{"class":7765},[5689,9865,9866,9868,9870,9872,9874,9876,9878,9881,9883,9885,9887,9889,9891,9893],{"class":5691,"line":5877},[5689,9867,8937],{"class":8275},[5689,9869,5261],{"class":7765},[5689,9871,8942],{"class":8268},[5689,9873,8272],{"class":7765},[5689,9875,8914],{"class":7829},[5689,9877,8955],{"class":8954},[5689,9879,9880],{"class":7829},"TXT-записи для ",[5689,9882,8906],{"class":8275},[5689,9884,7303],{"class":7829},[5689,9886,8955],{"class":8954},[5689,9888,8914],{"class":7829},[5689,9890,5225],{"class":7765},[5689,9892,9644],{"class":8275},[5689,9894,8250],{"class":7765},[5689,9896,9897,9899,9901,9903,9906,9908,9910,9913],{"class":5691,"line":5883},[5689,9898,8968],{"class":7761},[5689,9900,8971],{"class":8275},[5689,9902,5225],{"class":7765},[5689,9904,9905],{"class":8275},"txt",[5689,9907,8357],{"class":7765},[5689,9909,8981],{"class":7761},[5689,9911,9912],{"class":8275}," txtRecords",[5689,9914,8303],{"class":7765},[5689,9916,9917,9919,9921,9923,9925,9927,9929,9931,9933,9935,9937],{"class":5691,"line":5889},[5689,9918,8991],{"class":8275},[5689,9920,5261],{"class":7765},[5689,9922,8942],{"class":8268},[5689,9924,8272],{"class":7765},[5689,9926,9000],{"class":7829},[5689,9928,8906],{"class":8275},[5689,9930,8955],{"class":8954},[5689,9932,8914],{"class":7829},[5689,9934,5225],{"class":7765},[5689,9936,9905],{"class":8275},[5689,9938,8250],{"class":7765},[5689,9940,9941],{"class":5691,"line":5895},[5689,9942,6325],{"class":7765},[5689,9944,9946],{"class":5691,"line":9945},37,[5689,9947,5750],{"class":7765},[5373,9949,9950],{},[5205,9951,9952],{},"Приклад виходу:",[5680,9954,9957],{"className":9955,"code":9956,"language":6502},[6500],"MX-записи для example.com:\n  Пріоритет 10: mail1.example.com.\n  Пріоритет 20: mail2.example.com.\n\nTXT-записи для example.com:\n  - v=spf1 include:_spf.google.com ~all\n  - google-site-verification=rXOxyZounnZasA8Z7oaD3c14JdjS9aKSWvsR1EbUSIQ\n",[5258,9958,9956],{"__ignoreMap":5685},[5444,9960,9962],{"id":9961},"обробка-помилок-dns-та-діагностика-проблем","Обробка помилок DNS та діагностика проблем",[5373,9964,9965,9966,9969,9970,9972,9973,7303],{},"Одна з найважливіших навичок при роботі з DNS — це вміння ",[5205,9967,9968],{},"коректно інтерпретувати помилки"," та відрізняти тимчасові збої від постійних. Пакет ",[5258,9971,5326],{}," у Go повертає типізовані помилки, які можна перевірити через механізм ",[5258,9974,9975],{},"errors.As",[5680,9977,9979],{"className":8209,"code":9978,"language":8212,"meta":5685,"style":5685},"package main\n\nimport (\n    \"context\"\n    \"errors\"\n    \"fmt\"\n    \"log\"\n    \"net\"\n    \"time\"\n)\n\nfunc main() {\n    resolver := &net.Resolver{}\n    ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)\n    defer cancel()\n    \n    hostname := \"nonexistent-domain-12345.com\"\n    addrs, err := resolver.LookupHost(ctx, hostname)\n    \n    if err != nil {\n        \u002F\u002F Перевіряємо конкретний тип помилки\n        var dnsErr *net.DNSError\n        if errors.As(err, &dnsErr) {\n            if dnsErr.IsNotFound {\n                \u002F\u002F Домен не існує (NXDOMAIN) — постійна помилка\n                log.Printf(\"❌ Домен %s не існує в DNS. Перевірте правильність імені.\", hostname)\n            } else if dnsErr.IsTimeout {\n                \u002F\u002F Таймаут DNS-запиту — тимчасова помилка, можна повторити\n                log.Printf(\"⏱️ Таймаут DNS-запиту для %s. Спробуйте пізніше.\", hostname)\n            } else if dnsErr.IsTemporary {\n                \u002F\u002F Інша тимчасова помилка (наприклад, SERVFAIL)\n                log.Printf(\"⚠️ Тимчасова помилка DNS для %s: %v\", hostname, dnsErr)\n            } else {\n                \u002F\u002F Постійна помилка іншого характеру\n                log.Printf(\"🚫 Постійна помилка DNS для %s: %v\", hostname, dnsErr)\n            }\n        } else if errors.Is(err, context.DeadlineExceeded) {\n            log.Printf(\"⏱️ Контекст вичерпав таймаут під час DNS-резолвінгу %s\", hostname)\n        } else {\n            log.Printf(\"Невідома помилка: %v\", err)\n        }\n        return\n    }\n    \n    fmt.Printf(\"Успішний резолвінг: %v\\n\", addrs)\n}\n",[5258,9980,9981,9987,9991,9997,10001,10006,10010,10014,10018,10022,10026,10030,10038,10052,10091,10099,10103,10112,10138,10142,10154,10159,10176,10200,10214,10219,10244,10264,10269,10293,10310,10315,10346,10354,10359,10390,10394,10425,10450,10459,10483,10488,10494,10499,10504,10531],{"__ignoreMap":5685},[5689,9982,9983,9985],{"class":5691,"line":5692},[5689,9984,8219],{"class":7769},[5689,9986,8223],{"class":8222},[5689,9988,9989],{"class":5691,"line":5698},[5689,9990,5720],{"emptyLinePlaceholder":5719},[5689,9992,9993,9995],{"class":5691,"line":5704},[5689,9994,8232],{"class":7761},[5689,9996,8235],{"class":7765},[5689,9998,9999],{"class":5691,"line":5710},[5689,10000,8694],{"class":7829},[5689,10002,10003],{"class":5691,"line":5716},[5689,10004,10005],{"class":7829},"    \"errors\"\n",[5689,10007,10008],{"class":5691,"line":5723},[5689,10009,8699],{"class":7829},[5689,10011,10012],{"class":5691,"line":5729},[5689,10013,8704],{"class":7829},[5689,10015,10016],{"class":5691,"line":5735},[5689,10017,8709],{"class":7829},[5689,10019,10020],{"class":5691,"line":5741},[5689,10021,8714],{"class":7829},[5689,10023,10024],{"class":5691,"line":5747},[5689,10025,8250],{"class":7765},[5689,10027,10028],{"class":5691,"line":5753},[5689,10029,5720],{"emptyLinePlaceholder":5719},[5689,10031,10032,10034,10036],{"class":5691,"line":5758},[5689,10033,8265],{"class":7769},[5689,10035,8729],{"class":8268},[5689,10037,8732],{"class":7765},[5689,10039,10040,10042,10044,10046,10048,10050],{"class":5691,"line":5764},[5689,10041,8742],{"class":8275},[5689,10043,8745],{"class":7765},[5689,10045,5326],{"class":8222},[5689,10047,5261],{"class":7765},[5689,10049,8752],{"class":8222},[5689,10051,8755],{"class":7765},[5689,10053,10054,10056,10058,10060,10062,10064,10066,10068,10070,10072,10074,10076,10078,10081,10083,10085,10087,10089],{"class":5691,"line":5770},[5689,10055,8769],{"class":8275},[5689,10057,5225],{"class":7765},[5689,10059,8774],{"class":8275},[5689,10061,8357],{"class":7765},[5689,10063,8779],{"class":8275},[5689,10065,5261],{"class":7765},[5689,10067,8784],{"class":8268},[5689,10069,8272],{"class":7765},[5689,10071,8779],{"class":8275},[5689,10073,5261],{"class":7765},[5689,10075,8793],{"class":8268},[5689,10077,8796],{"class":7765},[5689,10079,10080],{"class":7776},"2",[5689,10082,8801],{"class":7765},[5689,10084,8804],{"class":8275},[5689,10086,5261],{"class":7765},[5689,10088,8809],{"class":8275},[5689,10090,8250],{"class":7765},[5689,10092,10093,10095,10097],{"class":5691,"line":5776},[5689,10094,8816],{"class":7761},[5689,10096,8819],{"class":8268},[5689,10098,8501],{"class":7765},[5689,10100,10101],{"class":5691,"line":5781},[5689,10102,6330],{"class":7765},[5689,10104,10105,10107,10109],{"class":5691,"line":5786},[5689,10106,8835],{"class":8275},[5689,10108,8357],{"class":7765},[5689,10110,10111],{"class":7829},"\"nonexistent-domain-12345.com\"\n",[5689,10113,10114,10116,10118,10120,10122,10124,10126,10128,10130,10132,10134,10136],{"class":5691,"line":5792},[5689,10115,8845],{"class":8275},[5689,10117,5225],{"class":7765},[5689,10119,8850],{"class":8275},[5689,10121,8357],{"class":7765},[5689,10123,8855],{"class":8275},[5689,10125,5261],{"class":7765},[5689,10127,8860],{"class":8268},[5689,10129,8272],{"class":7765},[5689,10131,8865],{"class":8275},[5689,10133,5225],{"class":7765},[5689,10135,8870],{"class":8275},[5689,10137,8250],{"class":7765},[5689,10139,10140],{"class":5691,"line":5798},[5689,10141,6330],{"class":7765},[5689,10143,10144,10146,10148,10150,10152],{"class":5691,"line":5804},[5689,10145,8877],{"class":7761},[5689,10147,8880],{"class":8275},[5689,10149,8883],{"class":7765},[5689,10151,8886],{"class":7769},[5689,10153,8303],{"class":7765},[5689,10155,10156],{"class":5691,"line":5809},[5689,10157,10158],{"class":8259},"        \u002F\u002F Перевіряємо конкретний тип помилки\n",[5689,10160,10161,10164,10167,10169,10171,10173],{"class":5691,"line":5814},[5689,10162,10163],{"class":7769},"        var",[5689,10165,10166],{"class":8275}," dnsErr",[5689,10168,8339],{"class":7765},[5689,10170,5326],{"class":8222},[5689,10172,5261],{"class":7765},[5689,10174,10175],{"class":8222},"DNSError\n",[5689,10177,10178,10180,10183,10185,10188,10190,10192,10195,10198],{"class":5691,"line":5820},[5689,10179,8378],{"class":7761},[5689,10181,10182],{"class":8275}," errors",[5689,10184,5261],{"class":7765},[5689,10186,10187],{"class":8268},"As",[5689,10189,8272],{"class":7765},[5689,10191,8850],{"class":8275},[5689,10193,10194],{"class":7765},", &",[5689,10196,10197],{"class":8275},"dnsErr",[5689,10199,8349],{"class":7765},[5689,10201,10202,10205,10207,10209,10212],{"class":5691,"line":5826},[5689,10203,10204],{"class":7761},"            if",[5689,10206,10166],{"class":8275},[5689,10208,5261],{"class":7765},[5689,10210,10211],{"class":8275},"IsNotFound",[5689,10213,8303],{"class":7765},[5689,10215,10216],{"class":5691,"line":5832},[5689,10217,10218],{"class":8259},"                \u002F\u002F Домен не існує (NXDOMAIN) — постійна помилка\n",[5689,10220,10221,10224,10226,10228,10230,10233,10235,10238,10240,10242],{"class":5691,"line":5838},[5689,10222,10223],{"class":8275},"                log",[5689,10225,5261],{"class":7765},[5689,10227,8942],{"class":8268},[5689,10229,8272],{"class":7765},[5689,10231,10232],{"class":7829},"\"❌ Домен ",[5689,10234,8906],{"class":8275},[5689,10236,10237],{"class":7829}," не існує в DNS. Перевірте правильність імені.\"",[5689,10239,5225],{"class":7765},[5689,10241,8870],{"class":8275},[5689,10243,8250],{"class":7765},[5689,10245,10246,10249,10252,10255,10257,10259,10262],{"class":5691,"line":5843},[5689,10247,10248],{"class":7765},"            } ",[5689,10250,10251],{"class":7761},"else",[5689,10253,10254],{"class":7761}," if",[5689,10256,10166],{"class":8275},[5689,10258,5261],{"class":7765},[5689,10260,10261],{"class":8275},"IsTimeout",[5689,10263,8303],{"class":7765},[5689,10265,10266],{"class":5691,"line":5848},[5689,10267,10268],{"class":8259},"                \u002F\u002F Таймаут DNS-запиту — тимчасова помилка, можна повторити\n",[5689,10270,10271,10273,10275,10277,10279,10282,10284,10287,10289,10291],{"class":5691,"line":5854},[5689,10272,10223],{"class":8275},[5689,10274,5261],{"class":7765},[5689,10276,8942],{"class":8268},[5689,10278,8272],{"class":7765},[5689,10280,10281],{"class":7829},"\"⏱️ Таймаут DNS-запиту для ",[5689,10283,8906],{"class":8275},[5689,10285,10286],{"class":7829},". Спробуйте пізніше.\"",[5689,10288,5225],{"class":7765},[5689,10290,8870],{"class":8275},[5689,10292,8250],{"class":7765},[5689,10294,10295,10297,10299,10301,10303,10305,10308],{"class":5691,"line":5860},[5689,10296,10248],{"class":7765},[5689,10298,10251],{"class":7761},[5689,10300,10254],{"class":7761},[5689,10302,10166],{"class":8275},[5689,10304,5261],{"class":7765},[5689,10306,10307],{"class":8275},"IsTemporary",[5689,10309,8303],{"class":7765},[5689,10311,10312],{"class":5691,"line":5866},[5689,10313,10314],{"class":8259},"                \u002F\u002F Інша тимчасова помилка (наприклад, SERVFAIL)\n",[5689,10316,10317,10319,10321,10323,10325,10328,10330,10332,10334,10336,10338,10340,10342,10344],{"class":5691,"line":5871},[5689,10318,10223],{"class":8275},[5689,10320,5261],{"class":7765},[5689,10322,8942],{"class":8268},[5689,10324,8272],{"class":7765},[5689,10326,10327],{"class":7829},"\"⚠️ Тимчасова помилка DNS для ",[5689,10329,8906],{"class":8275},[5689,10331,5379],{"class":7829},[5689,10333,8911],{"class":8275},[5689,10335,8914],{"class":7829},[5689,10337,5225],{"class":7765},[5689,10339,8870],{"class":8275},[5689,10341,5225],{"class":7765},[5689,10343,10197],{"class":8275},[5689,10345,8250],{"class":7765},[5689,10347,10348,10350,10352],{"class":5691,"line":5877},[5689,10349,10248],{"class":7765},[5689,10351,10251],{"class":7761},[5689,10353,8303],{"class":7765},[5689,10355,10356],{"class":5691,"line":5883},[5689,10357,10358],{"class":8259},"                \u002F\u002F Постійна помилка іншого характеру\n",[5689,10360,10361,10363,10365,10367,10369,10372,10374,10376,10378,10380,10382,10384,10386,10388],{"class":5691,"line":5889},[5689,10362,10223],{"class":8275},[5689,10364,5261],{"class":7765},[5689,10366,8942],{"class":8268},[5689,10368,8272],{"class":7765},[5689,10370,10371],{"class":7829},"\"🚫 Постійна помилка DNS для ",[5689,10373,8906],{"class":8275},[5689,10375,5379],{"class":7829},[5689,10377,8911],{"class":8275},[5689,10379,8914],{"class":7829},[5689,10381,5225],{"class":7765},[5689,10383,8870],{"class":8275},[5689,10385,5225],{"class":7765},[5689,10387,10197],{"class":8275},[5689,10389,8250],{"class":7765},[5689,10391,10392],{"class":5691,"line":5895},[5689,10393,9239],{"class":7765},[5689,10395,10396,10399,10401,10403,10405,10407,10410,10412,10414,10416,10418,10420,10423],{"class":5691,"line":9945},[5689,10397,10398],{"class":7765},"        } ",[5689,10400,10251],{"class":7761},[5689,10402,10254],{"class":7761},[5689,10404,10182],{"class":8275},[5689,10406,5261],{"class":7765},[5689,10408,10409],{"class":8268},"Is",[5689,10411,8272],{"class":7765},[5689,10413,8850],{"class":8275},[5689,10415,5225],{"class":7765},[5689,10417,8779],{"class":8275},[5689,10419,5261],{"class":7765},[5689,10421,10422],{"class":8275},"DeadlineExceeded",[5689,10424,8349],{"class":7765},[5689,10426,10428,10431,10433,10435,10437,10440,10442,10444,10446,10448],{"class":5691,"line":10427},38,[5689,10429,10430],{"class":8275},"            log",[5689,10432,5261],{"class":7765},[5689,10434,8942],{"class":8268},[5689,10436,8272],{"class":7765},[5689,10438,10439],{"class":7829},"\"⏱️ Контекст вичерпав таймаут під час DNS-резолвінгу ",[5689,10441,8906],{"class":8275},[5689,10443,8914],{"class":7829},[5689,10445,5225],{"class":7765},[5689,10447,8870],{"class":8275},[5689,10449,8250],{"class":7765},[5689,10451,10453,10455,10457],{"class":5691,"line":10452},39,[5689,10454,10398],{"class":7765},[5689,10456,10251],{"class":7761},[5689,10458,8303],{"class":7765},[5689,10460,10462,10464,10466,10468,10470,10473,10475,10477,10479,10481],{"class":5691,"line":10461},40,[5689,10463,10430],{"class":8275},[5689,10465,5261],{"class":7765},[5689,10467,8942],{"class":8268},[5689,10469,8272],{"class":7765},[5689,10471,10472],{"class":7829},"\"Невідома помилка: ",[5689,10474,8911],{"class":8275},[5689,10476,8914],{"class":7829},[5689,10478,5225],{"class":7765},[5689,10480,8850],{"class":8275},[5689,10482,8250],{"class":7765},[5689,10484,10486],{"class":5691,"line":10485},41,[5689,10487,8436],{"class":7765},[5689,10489,10491],{"class":5691,"line":10490},42,[5689,10492,10493],{"class":7761},"        return\n",[5689,10495,10497],{"class":5691,"line":10496},43,[5689,10498,6325],{"class":7765},[5689,10500,10502],{"class":5691,"line":10501},44,[5689,10503,6330],{"class":7765},[5689,10505,10507,10509,10511,10513,10515,10518,10520,10522,10524,10526,10529],{"class":5691,"line":10506},45,[5689,10508,8937],{"class":8275},[5689,10510,5261],{"class":7765},[5689,10512,8942],{"class":8268},[5689,10514,8272],{"class":7765},[5689,10516,10517],{"class":7829},"\"Успішний резолвінг: ",[5689,10519,8911],{"class":8275},[5689,10521,8955],{"class":8954},[5689,10523,8914],{"class":7829},[5689,10525,5225],{"class":7765},[5689,10527,10528],{"class":8275},"addrs",[5689,10530,8250],{"class":7765},[5689,10532,10534],{"class":5691,"line":10533},46,[5689,10535,5750],{"class":7765},[5483,10537,10538,10541,10542,10544,10545,6698,10547,10549,10550,10553],{},[5205,10539,10540],{},"Критична помилка в production:"," ніколи не ігноруйте помилки DNS і не вважайте, що відсутність адреси означає «сервер недоступний, спробуємо пізніше». Якщо DNS повертає ",[5205,10543,10211],{}," (NXDOMAIN), домен дійсно не існує, і повторні спроби не допоможуть. Водночас ",[5205,10546,10261],{},[5205,10548,10307],{}," сигналізують про тимчасові проблеми мережі або перевантаження DNS-серверів — у такому випадку варто реалізувати експоненційну затримку (",[5408,10551,10552],{},"exponential backoff",") перед повторною спробою.",[5444,10555,10557],{"id":10556},"кешування-dns-відповідей-на-рівні-застосунку","Кешування DNS-відповідей на рівні застосунку",[5373,10559,10560,10561,10564],{},"Хоча операційна система та рекурсивні резолвери кешують DNS-відповіді, іноді корисно реалізувати ",[5205,10562,10563],{},"власний кеш на рівні застосунку",", особливо якщо ваш сервіс виконує тисячі DNS-запитів на секунду до одних і тих самих доменів. Це зменшує латентність та навантаження на мережу:",[5680,10566,10568],{"className":8209,"code":10567,"language":8212,"meta":5685,"style":5685},"package main\n\nimport (\n    \"context\"\n    \"fmt\"\n    \"net\"\n    \"sync\"\n    \"time\"\n)\n\n\u002F\u002F Проста структура для кешування DNS-адрес\ntype DNSCache struct {\n    mu      sync.RWMutex\n    entries map[string]cacheEntry\n}\n\ntype cacheEntry struct {\n    addrs     []string\n    expiresAt time.Time\n}\n\nfunc NewDNSCache() *DNSCache {\n    return &DNSCache{\n        entries: make(map[string]cacheEntry),\n    }\n}\n\nfunc (c *DNSCache) Lookup(ctx context.Context, hostname string, ttl time.Duration) ([]string, error) {\n    \u002F\u002F Спочатку перевіряємо кеш\n    c.mu.RLock()\n    entry, exists := c.entries[hostname]\n    c.mu.RUnlock()\n    \n    if exists && time.Now().Before(entry.expiresAt) {\n        fmt.Printf(\"✅ Кеш: повертаємо адреси для %s з кешу\\n\", hostname)\n        return entry.addrs, nil\n    }\n    \n    \u002F\u002F Якщо в кеші немає або TTL вичерпано — виконуємо реальний DNS-запит\n    fmt.Printf(\"🔍 DNS: виконуємо резолвінг для %s\\n\", hostname)\n    resolver := &net.Resolver{}\n    addrs, err := resolver.LookupHost(ctx, hostname)\n    if err != nil {\n        return nil, err\n    }\n    \n    \u002F\u002F Зберігаємо в кеш\n    c.mu.Lock()\n    c.entries[hostname] = cacheEntry{\n        addrs:     addrs,\n        expiresAt: time.Now().Add(ttl),\n    }\n    c.mu.Unlock()\n    \n    return addrs, nil\n}\n\nfunc main() {\n    cache := NewDNSCache()\n    ctx := context.Background()\n    \n    \u002F\u002F Перший запит — виконується реальний DNS-резолвінг\n    addrs1, _ := cache.Lookup(ctx, \"www.example.com\", 10*time.Second)\n    fmt.Printf(\"Адреси: %v\\n\\n\", addrs1)\n    \n    \u002F\u002F Другий запит через 2 секунди — береться з кешу\n    time.Sleep(2 * time.Second)\n    addrs2, _ := cache.Lookup(ctx, \"www.example.com\", 10*time.Second)\n    fmt.Printf(\"Адреси: %v\\n\\n\", addrs2)\n    \n    \u002F\u002F Третій запит через 12 секунд — TTL вичерпано, виконується новий резолвінг\n    time.Sleep(12 * time.Second)\n    addrs3, _ := cache.Lookup(ctx, \"www.example.com\", 10*time.Second)\n    fmt.Printf(\"Адреси: %v\\n\", addrs3)\n}\n",[5258,10569,10570,10576,10580,10586,10590,10594,10598,10603,10607,10611,10615,10620,10633,10646,10666,10670,10674,10685,10695,10708,10712,10716,10731,10742,10769,10773,10777,10781,10838,10843,10860,10886,10901,10905,10940,10968,10985,10989,10993,10998,11023,11037,11063,11075,11087,11091,11095,11101,11117,11137,11150,11175,11180,11196,11201,11212,11217,11222,11231,11244,11259,11264,11270,11314,11342,11347,11353,11378,11418,11444,11449,11455,11479,11519,11545],{"__ignoreMap":5685},[5689,10571,10572,10574],{"class":5691,"line":5692},[5689,10573,8219],{"class":7769},[5689,10575,8223],{"class":8222},[5689,10577,10578],{"class":5691,"line":5698},[5689,10579,5720],{"emptyLinePlaceholder":5719},[5689,10581,10582,10584],{"class":5691,"line":5704},[5689,10583,8232],{"class":7761},[5689,10585,8235],{"class":7765},[5689,10587,10588],{"class":5691,"line":5710},[5689,10589,8694],{"class":7829},[5689,10591,10592],{"class":5691,"line":5716},[5689,10593,8699],{"class":7829},[5689,10595,10596],{"class":5691,"line":5723},[5689,10597,8709],{"class":7829},[5689,10599,10600],{"class":5691,"line":5729},[5689,10601,10602],{"class":7829},"    \"sync\"\n",[5689,10604,10605],{"class":5691,"line":5735},[5689,10606,8714],{"class":7829},[5689,10608,10609],{"class":5691,"line":5741},[5689,10610,8250],{"class":7765},[5689,10612,10613],{"class":5691,"line":5747},[5689,10614,5720],{"emptyLinePlaceholder":5719},[5689,10616,10617],{"class":5691,"line":5753},[5689,10618,10619],{"class":8259},"\u002F\u002F Проста структура для кешування DNS-адрес\n",[5689,10621,10622,10625,10628,10631],{"class":5691,"line":5758},[5689,10623,10624],{"class":7769},"type",[5689,10626,10627],{"class":8222}," DNSCache",[5689,10629,10630],{"class":7769}," struct",[5689,10632,8303],{"class":7765},[5689,10634,10635,10638,10641,10643],{"class":5691,"line":5764},[5689,10636,10637],{"class":8275},"    mu",[5689,10639,10640],{"class":8222},"      sync",[5689,10642,5261],{"class":7765},[5689,10644,10645],{"class":8222},"RWMutex\n",[5689,10647,10648,10651,10654,10657,10660,10663],{"class":5691,"line":5770},[5689,10649,10650],{"class":8275},"    entries",[5689,10652,10653],{"class":7769}," map",[5689,10655,10656],{"class":7765},"[",[5689,10658,10659],{"class":8222},"string",[5689,10661,10662],{"class":7765},"]",[5689,10664,10665],{"class":8222},"cacheEntry\n",[5689,10667,10668],{"class":5691,"line":5776},[5689,10669,5750],{"class":7765},[5689,10671,10672],{"class":5691,"line":5781},[5689,10673,5720],{"emptyLinePlaceholder":5719},[5689,10675,10676,10678,10681,10683],{"class":5691,"line":5786},[5689,10677,10624],{"class":7769},[5689,10679,10680],{"class":8222}," cacheEntry",[5689,10682,10630],{"class":7769},[5689,10684,8303],{"class":7765},[5689,10686,10687,10689,10692],{"class":5691,"line":5792},[5689,10688,8845],{"class":8275},[5689,10690,10691],{"class":7765},"     []",[5689,10693,10694],{"class":8222},"string\n",[5689,10696,10697,10700,10703,10705],{"class":5691,"line":5798},[5689,10698,10699],{"class":8275},"    expiresAt",[5689,10701,10702],{"class":8222}," time",[5689,10704,5261],{"class":7765},[5689,10706,10707],{"class":8222},"Time\n",[5689,10709,10710],{"class":5691,"line":5804},[5689,10711,5750],{"class":7765},[5689,10713,10714],{"class":5691,"line":5809},[5689,10715,5720],{"emptyLinePlaceholder":5719},[5689,10717,10718,10720,10723,10726,10729],{"class":5691,"line":5814},[5689,10719,8265],{"class":7769},[5689,10721,10722],{"class":8268}," NewDNSCache",[5689,10724,10725],{"class":7765},"() *",[5689,10727,10728],{"class":8222},"DNSCache",[5689,10730,8303],{"class":7765},[5689,10732,10733,10735,10738,10740],{"class":5691,"line":5820},[5689,10734,8308],{"class":7761},[5689,10736,10737],{"class":7765}," &",[5689,10739,10728],{"class":8222},[5689,10741,9131],{"class":7765},[5689,10743,10744,10747,10749,10752,10754,10757,10759,10761,10763,10766],{"class":5691,"line":5826},[5689,10745,10746],{"class":8275},"        entries",[5689,10748,5379],{"class":7765},[5689,10750,10751],{"class":8268},"make",[5689,10753,8272],{"class":7765},[5689,10755,10756],{"class":7769},"map",[5689,10758,10656],{"class":7765},[5689,10760,10659],{"class":8222},[5689,10762,10662],{"class":7765},[5689,10764,10765],{"class":8222},"cacheEntry",[5689,10767,10768],{"class":7765},"),\n",[5689,10770,10771],{"class":5691,"line":5832},[5689,10772,6325],{"class":7765},[5689,10774,10775],{"class":5691,"line":5838},[5689,10776,5750],{"class":7765},[5689,10778,10779],{"class":5691,"line":5843},[5689,10780,5720],{"emptyLinePlaceholder":5719},[5689,10782,10783,10785,10787,10790,10792,10794,10796,10799,10801,10803,10805,10807,10809,10811,10813,10815,10817,10820,10822,10824,10827,10830,10832,10834,10836],{"class":5691,"line":5848},[5689,10784,8265],{"class":7769},[5689,10786,5406],{"class":7765},[5689,10788,10789],{"class":8275},"c ",[5689,10791,8801],{"class":7765},[5689,10793,10728],{"class":8222},[5689,10795,7092],{"class":7765},[5689,10797,10798],{"class":8268},"Lookup",[5689,10800,8272],{"class":7765},[5689,10802,8865],{"class":8275},[5689,10804,9162],{"class":8222},[5689,10806,5261],{"class":7765},[5689,10808,9167],{"class":8222},[5689,10810,5225],{"class":7765},[5689,10812,8870],{"class":8275},[5689,10814,8279],{"class":8222},[5689,10816,5225],{"class":7765},[5689,10818,10819],{"class":8275},"ttl",[5689,10821,10702],{"class":8222},[5689,10823,5261],{"class":7765},[5689,10825,10826],{"class":8222},"Duration",[5689,10828,10829],{"class":7765},") ([]",[5689,10831,10659],{"class":8222},[5689,10833,5225],{"class":7765},[5689,10835,9194],{"class":8222},[5689,10837,8349],{"class":7765},[5689,10839,10840],{"class":5691,"line":5854},[5689,10841,10842],{"class":8259},"    \u002F\u002F Спочатку перевіряємо кеш\n",[5689,10844,10845,10848,10850,10853,10855,10858],{"class":5691,"line":5860},[5689,10846,10847],{"class":8275},"    c",[5689,10849,5261],{"class":7765},[5689,10851,10852],{"class":8275},"mu",[5689,10854,5261],{"class":7765},[5689,10856,10857],{"class":8268},"RLock",[5689,10859,8501],{"class":7765},[5689,10861,10862,10865,10867,10870,10872,10875,10877,10880,10882,10884],{"class":5691,"line":5866},[5689,10863,10864],{"class":8275},"    entry",[5689,10866,5225],{"class":7765},[5689,10868,10869],{"class":8275},"exists",[5689,10871,8357],{"class":7765},[5689,10873,10874],{"class":8275},"c",[5689,10876,5261],{"class":7765},[5689,10878,10879],{"class":8275},"entries",[5689,10881,10656],{"class":7765},[5689,10883,8870],{"class":8275},[5689,10885,8431],{"class":7765},[5689,10887,10888,10890,10892,10894,10896,10899],{"class":5691,"line":5871},[5689,10889,10847],{"class":8275},[5689,10891,5261],{"class":7765},[5689,10893,10852],{"class":8275},[5689,10895,5261],{"class":7765},[5689,10897,10898],{"class":8268},"RUnlock",[5689,10900,8501],{"class":7765},[5689,10902,10903],{"class":5691,"line":5877},[5689,10904,6330],{"class":7765},[5689,10906,10907,10909,10912,10915,10917,10919,10922,10925,10928,10930,10933,10935,10938],{"class":5691,"line":5883},[5689,10908,8877],{"class":7761},[5689,10910,10911],{"class":8275}," exists",[5689,10913,10914],{"class":7765}," && ",[5689,10916,8804],{"class":8275},[5689,10918,5261],{"class":7765},[5689,10920,10921],{"class":8268},"Now",[5689,10923,10924],{"class":7765},"().",[5689,10926,10927],{"class":8268},"Before",[5689,10929,8272],{"class":7765},[5689,10931,10932],{"class":8275},"entry",[5689,10934,5261],{"class":7765},[5689,10936,10937],{"class":8275},"expiresAt",[5689,10939,8349],{"class":7765},[5689,10941,10942,10944,10946,10948,10950,10953,10955,10958,10960,10962,10964,10966],{"class":5691,"line":5889},[5689,10943,8991],{"class":8275},[5689,10945,5261],{"class":7765},[5689,10947,8942],{"class":8268},[5689,10949,8272],{"class":7765},[5689,10951,10952],{"class":7829},"\"✅ Кеш: повертаємо адреси для ",[5689,10954,8906],{"class":8275},[5689,10956,10957],{"class":7829}," з кешу",[5689,10959,8955],{"class":8954},[5689,10961,8914],{"class":7829},[5689,10963,5225],{"class":7765},[5689,10965,8870],{"class":8275},[5689,10967,8250],{"class":7765},[5689,10969,10970,10973,10976,10978,10980,10982],{"class":5691,"line":5895},[5689,10971,10972],{"class":7761},"        return",[5689,10974,10975],{"class":8275}," entry",[5689,10977,5261],{"class":7765},[5689,10979,10528],{"class":8275},[5689,10981,5225],{"class":7765},[5689,10983,10984],{"class":7769},"nil\n",[5689,10986,10987],{"class":5691,"line":9945},[5689,10988,6325],{"class":7765},[5689,10990,10991],{"class":5691,"line":10427},[5689,10992,6330],{"class":7765},[5689,10994,10995],{"class":5691,"line":10452},[5689,10996,10997],{"class":8259},"    \u002F\u002F Якщо в кеші немає або TTL вичерпано — виконуємо реальний DNS-запит\n",[5689,10999,11000,11002,11004,11006,11008,11011,11013,11015,11017,11019,11021],{"class":5691,"line":10461},[5689,11001,8937],{"class":8275},[5689,11003,5261],{"class":7765},[5689,11005,8942],{"class":8268},[5689,11007,8272],{"class":7765},[5689,11009,11010],{"class":7829},"\"🔍 DNS: виконуємо резолвінг для ",[5689,11012,8906],{"class":8275},[5689,11014,8955],{"class":8954},[5689,11016,8914],{"class":7829},[5689,11018,5225],{"class":7765},[5689,11020,8870],{"class":8275},[5689,11022,8250],{"class":7765},[5689,11024,11025,11027,11029,11031,11033,11035],{"class":5691,"line":10485},[5689,11026,8742],{"class":8275},[5689,11028,8745],{"class":7765},[5689,11030,5326],{"class":8222},[5689,11032,5261],{"class":7765},[5689,11034,8752],{"class":8222},[5689,11036,8755],{"class":7765},[5689,11038,11039,11041,11043,11045,11047,11049,11051,11053,11055,11057,11059,11061],{"class":5691,"line":10490},[5689,11040,8845],{"class":8275},[5689,11042,5225],{"class":7765},[5689,11044,8850],{"class":8275},[5689,11046,8357],{"class":7765},[5689,11048,8855],{"class":8275},[5689,11050,5261],{"class":7765},[5689,11052,8860],{"class":8268},[5689,11054,8272],{"class":7765},[5689,11056,8865],{"class":8275},[5689,11058,5225],{"class":7765},[5689,11060,8870],{"class":8275},[5689,11062,8250],{"class":7765},[5689,11064,11065,11067,11069,11071,11073],{"class":5691,"line":10496},[5689,11066,8877],{"class":7761},[5689,11068,8880],{"class":8275},[5689,11070,8883],{"class":7765},[5689,11072,8886],{"class":7769},[5689,11074,8303],{"class":7765},[5689,11076,11077,11079,11082,11084],{"class":5691,"line":10501},[5689,11078,10972],{"class":7761},[5689,11080,11081],{"class":7769}," nil",[5689,11083,5225],{"class":7765},[5689,11085,11086],{"class":8275},"err\n",[5689,11088,11089],{"class":5691,"line":10506},[5689,11090,6325],{"class":7765},[5689,11092,11093],{"class":5691,"line":10533},[5689,11094,6330],{"class":7765},[5689,11096,11098],{"class":5691,"line":11097},47,[5689,11099,11100],{"class":8259},"    \u002F\u002F Зберігаємо в кеш\n",[5689,11102,11104,11106,11108,11110,11112,11115],{"class":5691,"line":11103},48,[5689,11105,10847],{"class":8275},[5689,11107,5261],{"class":7765},[5689,11109,10852],{"class":8275},[5689,11111,5261],{"class":7765},[5689,11113,11114],{"class":8268},"Lock",[5689,11116,8501],{"class":7765},[5689,11118,11120,11122,11124,11126,11128,11130,11133,11135],{"class":5691,"line":11119},49,[5689,11121,10847],{"class":8275},[5689,11123,5261],{"class":7765},[5689,11125,10879],{"class":8275},[5689,11127,10656],{"class":7765},[5689,11129,8870],{"class":8275},[5689,11131,11132],{"class":7765},"] = ",[5689,11134,10765],{"class":8222},[5689,11136,9131],{"class":7765},[5689,11138,11140,11143,11146,11148],{"class":5691,"line":11139},50,[5689,11141,11142],{"class":8275},"        addrs",[5689,11144,11145],{"class":7765},":     ",[5689,11147,10528],{"class":8275},[5689,11149,9234],{"class":7765},[5689,11151,11153,11156,11158,11160,11162,11164,11166,11169,11171,11173],{"class":5691,"line":11152},51,[5689,11154,11155],{"class":8275},"        expiresAt",[5689,11157,5379],{"class":7765},[5689,11159,8804],{"class":8275},[5689,11161,5261],{"class":7765},[5689,11163,10921],{"class":8268},[5689,11165,10924],{"class":7765},[5689,11167,11168],{"class":8268},"Add",[5689,11170,8272],{"class":7765},[5689,11172,10819],{"class":8275},[5689,11174,10768],{"class":7765},[5689,11176,11178],{"class":5691,"line":11177},52,[5689,11179,6325],{"class":7765},[5689,11181,11183,11185,11187,11189,11191,11194],{"class":5691,"line":11182},53,[5689,11184,10847],{"class":8275},[5689,11186,5261],{"class":7765},[5689,11188,10852],{"class":8275},[5689,11190,5261],{"class":7765},[5689,11192,11193],{"class":8268},"Unlock",[5689,11195,8501],{"class":7765},[5689,11197,11199],{"class":5691,"line":11198},54,[5689,11200,6330],{"class":7765},[5689,11202,11204,11206,11208,11210],{"class":5691,"line":11203},55,[5689,11205,8308],{"class":7761},[5689,11207,8984],{"class":8275},[5689,11209,5225],{"class":7765},[5689,11211,10984],{"class":7769},[5689,11213,11215],{"class":5691,"line":11214},56,[5689,11216,5750],{"class":7765},[5689,11218,11220],{"class":5691,"line":11219},57,[5689,11221,5720],{"emptyLinePlaceholder":5719},[5689,11223,11225,11227,11229],{"class":5691,"line":11224},58,[5689,11226,8265],{"class":7769},[5689,11228,8729],{"class":8268},[5689,11230,8732],{"class":7765},[5689,11232,11234,11237,11239,11242],{"class":5691,"line":11233},59,[5689,11235,11236],{"class":8275},"    cache",[5689,11238,8357],{"class":7765},[5689,11240,11241],{"class":8268},"NewDNSCache",[5689,11243,8501],{"class":7765},[5689,11245,11247,11249,11251,11253,11255,11257],{"class":5691,"line":11246},60,[5689,11248,8769],{"class":8275},[5689,11250,8357],{"class":7765},[5689,11252,8779],{"class":8275},[5689,11254,5261],{"class":7765},[5689,11256,8793],{"class":8268},[5689,11258,8501],{"class":7765},[5689,11260,11262],{"class":5691,"line":11261},61,[5689,11263,6330],{"class":7765},[5689,11265,11267],{"class":5691,"line":11266},62,[5689,11268,11269],{"class":8259},"    \u002F\u002F Перший запит — виконується реальний DNS-резолвінг\n",[5689,11271,11273,11276,11278,11281,11283,11286,11288,11290,11292,11294,11296,11299,11301,11304,11306,11308,11310,11312],{"class":5691,"line":11272},63,[5689,11274,11275],{"class":8275},"    addrs1",[5689,11277,5225],{"class":7765},[5689,11279,11280],{"class":8275},"_",[5689,11282,8357],{"class":7765},[5689,11284,11285],{"class":8275},"cache",[5689,11287,5261],{"class":7765},[5689,11289,10798],{"class":8268},[5689,11291,8272],{"class":7765},[5689,11293,8865],{"class":8275},[5689,11295,5225],{"class":7765},[5689,11297,11298],{"class":7829},"\"www.example.com\"",[5689,11300,5225],{"class":7765},[5689,11302,11303],{"class":7776},"10",[5689,11305,8801],{"class":7765},[5689,11307,8804],{"class":8275},[5689,11309,5261],{"class":7765},[5689,11311,8809],{"class":8275},[5689,11313,8250],{"class":7765},[5689,11315,11317,11319,11321,11323,11325,11328,11330,11333,11335,11337,11340],{"class":5691,"line":11316},64,[5689,11318,8937],{"class":8275},[5689,11320,5261],{"class":7765},[5689,11322,8942],{"class":8268},[5689,11324,8272],{"class":7765},[5689,11326,11327],{"class":7829},"\"Адреси: ",[5689,11329,8911],{"class":8275},[5689,11331,11332],{"class":8954},"\\n\\n",[5689,11334,8914],{"class":7829},[5689,11336,5225],{"class":7765},[5689,11338,11339],{"class":8275},"addrs1",[5689,11341,8250],{"class":7765},[5689,11343,11345],{"class":5691,"line":11344},65,[5689,11346,6330],{"class":7765},[5689,11348,11350],{"class":5691,"line":11349},66,[5689,11351,11352],{"class":8259},"    \u002F\u002F Другий запит через 2 секунди — береться з кешу\n",[5689,11354,11356,11359,11361,11364,11366,11368,11370,11372,11374,11376],{"class":5691,"line":11355},67,[5689,11357,11358],{"class":8275},"    time",[5689,11360,5261],{"class":7765},[5689,11362,11363],{"class":8268},"Sleep",[5689,11365,8272],{"class":7765},[5689,11367,10080],{"class":7776},[5689,11369,9225],{"class":7765},[5689,11371,8804],{"class":8275},[5689,11373,5261],{"class":7765},[5689,11375,8809],{"class":8275},[5689,11377,8250],{"class":7765},[5689,11379,11381,11384,11386,11388,11390,11392,11394,11396,11398,11400,11402,11404,11406,11408,11410,11412,11414,11416],{"class":5691,"line":11380},68,[5689,11382,11383],{"class":8275},"    addrs2",[5689,11385,5225],{"class":7765},[5689,11387,11280],{"class":8275},[5689,11389,8357],{"class":7765},[5689,11391,11285],{"class":8275},[5689,11393,5261],{"class":7765},[5689,11395,10798],{"class":8268},[5689,11397,8272],{"class":7765},[5689,11399,8865],{"class":8275},[5689,11401,5225],{"class":7765},[5689,11403,11298],{"class":7829},[5689,11405,5225],{"class":7765},[5689,11407,11303],{"class":7776},[5689,11409,8801],{"class":7765},[5689,11411,8804],{"class":8275},[5689,11413,5261],{"class":7765},[5689,11415,8809],{"class":8275},[5689,11417,8250],{"class":7765},[5689,11419,11421,11423,11425,11427,11429,11431,11433,11435,11437,11439,11442],{"class":5691,"line":11420},69,[5689,11422,8937],{"class":8275},[5689,11424,5261],{"class":7765},[5689,11426,8942],{"class":8268},[5689,11428,8272],{"class":7765},[5689,11430,11327],{"class":7829},[5689,11432,8911],{"class":8275},[5689,11434,11332],{"class":8954},[5689,11436,8914],{"class":7829},[5689,11438,5225],{"class":7765},[5689,11440,11441],{"class":8275},"addrs2",[5689,11443,8250],{"class":7765},[5689,11445,11447],{"class":5691,"line":11446},70,[5689,11448,6330],{"class":7765},[5689,11450,11452],{"class":5691,"line":11451},71,[5689,11453,11454],{"class":8259},"    \u002F\u002F Третій запит через 12 секунд — TTL вичерпано, виконується новий резолвінг\n",[5689,11456,11458,11460,11462,11464,11466,11469,11471,11473,11475,11477],{"class":5691,"line":11457},72,[5689,11459,11358],{"class":8275},[5689,11461,5261],{"class":7765},[5689,11463,11363],{"class":8268},[5689,11465,8272],{"class":7765},[5689,11467,11468],{"class":7776},"12",[5689,11470,9225],{"class":7765},[5689,11472,8804],{"class":8275},[5689,11474,5261],{"class":7765},[5689,11476,8809],{"class":8275},[5689,11478,8250],{"class":7765},[5689,11480,11482,11485,11487,11489,11491,11493,11495,11497,11499,11501,11503,11505,11507,11509,11511,11513,11515,11517],{"class":5691,"line":11481},73,[5689,11483,11484],{"class":8275},"    addrs3",[5689,11486,5225],{"class":7765},[5689,11488,11280],{"class":8275},[5689,11490,8357],{"class":7765},[5689,11492,11285],{"class":8275},[5689,11494,5261],{"class":7765},[5689,11496,10798],{"class":8268},[5689,11498,8272],{"class":7765},[5689,11500,8865],{"class":8275},[5689,11502,5225],{"class":7765},[5689,11504,11298],{"class":7829},[5689,11506,5225],{"class":7765},[5689,11508,11303],{"class":7776},[5689,11510,8801],{"class":7765},[5689,11512,8804],{"class":8275},[5689,11514,5261],{"class":7765},[5689,11516,8809],{"class":8275},[5689,11518,8250],{"class":7765},[5689,11520,11522,11524,11526,11528,11530,11532,11534,11536,11538,11540,11543],{"class":5691,"line":11521},74,[5689,11523,8937],{"class":8275},[5689,11525,5261],{"class":7765},[5689,11527,8942],{"class":8268},[5689,11529,8272],{"class":7765},[5689,11531,11327],{"class":7829},[5689,11533,8911],{"class":8275},[5689,11535,8955],{"class":8954},[5689,11537,8914],{"class":7829},[5689,11539,5225],{"class":7765},[5689,11541,11542],{"class":8275},"addrs3",[5689,11544,8250],{"class":7765},[5689,11546,11548],{"class":5691,"line":11547},75,[5689,11549,5750],{"class":7765},[5421,11551,11552,11555],{},[5205,11553,11554],{},"Застереження щодо власного кешування:"," реалізуючи DNS-кеш на рівні застосунку, будьте обережні з TTL. Якщо ви встановите занадто великий TTL (наприклад, кілька годин), ваш застосунок може продовжувати звертатися до старої IP-адреси навіть після того, як адміністратор домену перевів сервіс на нову адресу. Зазвичай безпечно використовувати TTL від 60 до 300 секунд для високонавантажених сценаріїв.",[5365,11557],{},[5368,11559,11561],{"id":11560},"протокол-smtp-основа-архітектури-електронної-пошти","Протокол SMTP: основа архітектури електронної пошти",[5373,11563,11564,11565,5406,11567,11570,11571,11574],{},"Тепер, коли ми глибоко розібралися з системою доменних імен, перейдемо до другого фундаментального протоколу прикладного рівня — ",[5205,11566,5278],{},[5408,11568,11569],{},"Simple Mail Transfer Protocol","). Цей протокол, стандартизований у 1982 році в RFC 821 (пізніше оновлений у RFC 5321), є основою ",[5205,11572,11573],{},"архітектури електронної пошти"," в інтернеті. Саме завдяки SMTP мільярди листів щодня доставляються між поштовими серверами по всьому світу.",[5373,11576,11577,11578,11581,11582,6066,11585,11588,11589,11592,11593,11596],{},"На відміну від DNS, який працює переважно через UDP і оптимізований для швидких запитів-відповідей малого розміру, SMTP є ",[5205,11579,11580],{},"текстовим протоколом",", що працює поверх ",[5205,11583,11584],{},"надійного TCP-з'єднання",[5205,11586,11587],{},"25"," (для передачі між серверами) або портах ",[5205,11590,11591],{},"587"," (для відправки від клієнта до сервера з автентифікацією) і ",[5205,11594,11595],{},"465"," (застарілий порт для SMTP-over-TLS).",[5444,11598,11600],{"id":11599},"архітектура-поштової-системи-від-відправника-до-отримувача","Архітектура поштової системи: від відправника до отримувача",[5373,11602,11603,11604,11607],{},"Перш ніж заглиблюватися в технічні деталі протоколу, важливо зрозуміти ",[5205,11605,11606],{},"загальну архітектуру електронної пошти",", яка складається з кількох окремих компонентів:",[5552,11609,11610,11619,11628,11641],{},[5201,11611,11612,5406,11615,11618],{},[5205,11613,11614],{},"MUA",[5408,11616,11617],{},"Mail User Agent",") — поштовий клієнт користувача (Outlook, Thunderbird, Gmail у браузері, мобільний застосунок на React Native). Це те, через що ви пишете та читаєте листи.",[5201,11620,11621,5406,11624,11627],{},[5205,11622,11623],{},"MSA",[5408,11625,11626],{},"Mail Submission Agent",") — сервер, який приймає листи від MUA для відправки. Зазвичай це той самий поштовий сервер, але який працює на порту 587 і вимагає автентифікації (логін\u002Fпароль).",[5201,11629,11630,5406,11633,11636,11637,11640],{},[5205,11631,11632],{},"MTA",[5408,11634,11635],{},"Mail Transfer Agent",") — поштовий сервер, який ",[5205,11638,11639],{},"передає листи"," між серверами через порт 25. Саме MTA виконують DNS-запити типу MX, щоб дізнатися, на який сервер доставляти лист для конкретного домену.",[5201,11642,11643,5406,11646,11649,11650,11653,11654,11657,11658,11661],{},[5205,11644,11645],{},"MDA",[5408,11647,11648],{},"Mail Delivery Agent",") — компонент, який ",[5205,11651,11652],{},"доставляє лист"," у поштову скриньку отримувача на сервері. Користувач потім завантажує листи через протоколи ",[5205,11655,11656],{},"IMAP"," (порт 143\u002F993) або ",[5205,11659,11660],{},"POP3"," (порт 110\u002F995).",[5676,11663,11665],{"alt":11664},"Архітектура електронної пошти від відправника до отримувача",[5680,11666,11668],{"className":5682,"code":11667,"language":5684,"meta":5685,"style":5685},"@startuml\nskinparam style plain\nskinparam backgroundColor #FFFFFF\nautonumber\n\nactor \"Відправник\\n(alice@example.com)\" as Alice #DBEAFE\nparticipant \"MUA (Клієнт пошти)\\nThunderbird \u002F Outlook\" as MUA #E2E8F0\nparticipant \"MSA\u002FMTA\\nmail.example.com\\n(порт 587)\" as MSA #FEF3C7\nparticipant \"DNS Сервер\" as DNS #DCFCE7\nparticipant \"MTA Отримувача\\nmail.recipient.com\\n(порт 25)\" as RecvMTA #FEF3C7\nparticipant \"MDA\" as MDA #E2E8F0\nactor \"Отримувач\\n(bob@recipient.com)\" as Bob #DBEAFE\n\nAlice -> MUA : Пише лист для bob@recipient.com\nMUA -> MSA : SMTP-з'єднання + автентифікація\\n(STARTTLS, логін\u002Fпароль)\nMSA -> MSA : Перевіряє права відправника,\\nдодає заголовки (Received, Message-ID)\n\nMSA -> DNS : MX-запит для recipient.com\nDNS -> MSA : MX: mail.recipient.com (пріоритет 10)\n\nMSA -> RecvMTA : TCP-з'єднання на порт 25\\nSMTP Handshake\nRecvMTA -> RecvMTA : Перевіряє SPF\u002FDKIM\u002FDMARC,\\nантиспам-фільтри\n\nRecvMTA -> MDA : Доставка в поштову скриньку bob@recipient.com\nMDA -> MDA : Зберігає лист у mailbox\n\nBob -> MUA : Завантажує листи через IMAP\u002FPOP3\nMUA -> Bob : Відображає лист\n\nnote over Alice, Bob #DCFCE7\n  Повний цикл доставки електронного листа\n  через ланцюжок поштових серверів\nend note\n@enduml\n",[5258,11669,11670,11674,11678,11682,11686,11690,11695,11700,11705,11710,11715,11720,11725,11729,11734,11739,11744,11748,11753,11758,11762,11767,11772,11776,11781,11786,11790,11795,11800,11804,11809,11814,11819,11823],{"__ignoreMap":5685},[5689,11671,11672],{"class":5691,"line":5692},[5689,11673,5695],{},[5689,11675,11676],{"class":5691,"line":5698},[5689,11677,5701],{},[5689,11679,11680],{"class":5691,"line":5704},[5689,11681,5707],{},[5689,11683,11684],{"class":5691,"line":5710},[5689,11685,7495],{},[5689,11687,11688],{"class":5691,"line":5716},[5689,11689,5720],{"emptyLinePlaceholder":5719},[5689,11691,11692],{"class":5691,"line":5723},[5689,11693,11694],{},"actor \"Відправник\\n(alice@example.com)\" as Alice #DBEAFE\n",[5689,11696,11697],{"class":5691,"line":5729},[5689,11698,11699],{},"participant \"MUA (Клієнт пошти)\\nThunderbird \u002F Outlook\" as MUA #E2E8F0\n",[5689,11701,11702],{"class":5691,"line":5735},[5689,11703,11704],{},"participant \"MSA\u002FMTA\\nmail.example.com\\n(порт 587)\" as MSA #FEF3C7\n",[5689,11706,11707],{"class":5691,"line":5741},[5689,11708,11709],{},"participant \"DNS Сервер\" as DNS #DCFCE7\n",[5689,11711,11712],{"class":5691,"line":5747},[5689,11713,11714],{},"participant \"MTA Отримувача\\nmail.recipient.com\\n(порт 25)\" as RecvMTA #FEF3C7\n",[5689,11716,11717],{"class":5691,"line":5753},[5689,11718,11719],{},"participant \"MDA\" as MDA #E2E8F0\n",[5689,11721,11722],{"class":5691,"line":5758},[5689,11723,11724],{},"actor \"Отримувач\\n(bob@recipient.com)\" as Bob #DBEAFE\n",[5689,11726,11727],{"class":5691,"line":5764},[5689,11728,5720],{"emptyLinePlaceholder":5719},[5689,11730,11731],{"class":5691,"line":5770},[5689,11732,11733],{},"Alice -> MUA : Пише лист для bob@recipient.com\n",[5689,11735,11736],{"class":5691,"line":5776},[5689,11737,11738],{},"MUA -> MSA : SMTP-з'єднання + автентифікація\\n(STARTTLS, логін\u002Fпароль)\n",[5689,11740,11741],{"class":5691,"line":5781},[5689,11742,11743],{},"MSA -> MSA : Перевіряє права відправника,\\nдодає заголовки (Received, Message-ID)\n",[5689,11745,11746],{"class":5691,"line":5786},[5689,11747,5720],{"emptyLinePlaceholder":5719},[5689,11749,11750],{"class":5691,"line":5792},[5689,11751,11752],{},"MSA -> DNS : MX-запит для recipient.com\n",[5689,11754,11755],{"class":5691,"line":5798},[5689,11756,11757],{},"DNS -> MSA : MX: mail.recipient.com (пріоритет 10)\n",[5689,11759,11760],{"class":5691,"line":5804},[5689,11761,5720],{"emptyLinePlaceholder":5719},[5689,11763,11764],{"class":5691,"line":5809},[5689,11765,11766],{},"MSA -> RecvMTA : TCP-з'єднання на порт 25\\nSMTP Handshake\n",[5689,11768,11769],{"class":5691,"line":5814},[5689,11770,11771],{},"RecvMTA -> RecvMTA : Перевіряє SPF\u002FDKIM\u002FDMARC,\\nантиспам-фільтри\n",[5689,11773,11774],{"class":5691,"line":5820},[5689,11775,5720],{"emptyLinePlaceholder":5719},[5689,11777,11778],{"class":5691,"line":5826},[5689,11779,11780],{},"RecvMTA -> MDA : Доставка в поштову скриньку bob@recipient.com\n",[5689,11782,11783],{"class":5691,"line":5832},[5689,11784,11785],{},"MDA -> MDA : Зберігає лист у mailbox\n",[5689,11787,11788],{"class":5691,"line":5838},[5689,11789,5720],{"emptyLinePlaceholder":5719},[5689,11791,11792],{"class":5691,"line":5843},[5689,11793,11794],{},"Bob -> MUA : Завантажує листи через IMAP\u002FPOP3\n",[5689,11796,11797],{"class":5691,"line":5848},[5689,11798,11799],{},"MUA -> Bob : Відображає лист\n",[5689,11801,11802],{"class":5691,"line":5854},[5689,11803,5720],{"emptyLinePlaceholder":5719},[5689,11805,11806],{"class":5691,"line":5860},[5689,11807,11808],{},"note over Alice, Bob #DCFCE7\n",[5689,11810,11811],{"class":5691,"line":5866},[5689,11812,11813],{},"  Повний цикл доставки електронного листа\n",[5689,11815,11816],{"class":5691,"line":5871},[5689,11817,11818],{},"  через ланцюжок поштових серверів\n",[5689,11820,11821],{"class":5691,"line":5877},[5689,11822,5892],{},[5689,11824,11825],{"class":5691,"line":5883},[5689,11826,5898],{},[5444,11828,11830],{"id":11829},"чому-smtp-розділений-на-окремі-етапи","Чому SMTP розділений на окремі етапи",[5373,11832,11833],{},"Розділення на MSA (submission) та MTA (relay) може здатися надмірним ускладненням, але воно вирішує важливі проблеми безпеки:",[5198,11835,11836,11845],{},[5201,11837,11838,11840,11841,11844],{},[5205,11839,11623],{}," (порт 587) вимагає ",[5205,11842,11843],{},"автентифікації"," перед відправкою листа. Це запобігає використанню поштового сервера для масового розсилання спаму з випадкових IP-адрес.",[5201,11846,11847,11849,11850,11853],{},[5205,11848,11632],{}," (порт 25) працює ",[5205,11851,11852],{},"без автентифікації"," (бо поштові сервери довіряють один одному в межах глобальної інфраструктури інтернету), але застосовує інші механізми захисту: перевірку SPF-записів, валідацію DKIM-підписів, аналіз репутації відправника.",[6046,11855,11856,11859,11860,11862,11863,11865,11866,11869],{},[5205,11857,11858],{},"Історична еволюція портів SMTP:"," спочатку весь SMTP-трафік йшов через порт 25, але в міру зростання спаму інтернет-провайдери почали блокувати вихідні з'єднання на цей порт для звичайних користувачів (щоб заражені комп'ютери не могли масово розсилати спам). Тому був введений порт ",[5205,11861,11591],{}," із обов'язковою автентифікацією для легітимних відправників. Порт ",[5205,11864,11595],{}," був короткочасно призначений для SMTP-over-SSL, але пізніше відкинутий на користь механізму ",[5205,11867,11868],{},"STARTTLS",", який дозволяє розпочати з'єднання як звичайний текст і потім оновити його до шифрованого.",[5365,11871],{},[5368,11873,11875],{"id":11874},"структура-smtp-сеансу-команди-та-коди-відповідей","Структура SMTP-сеансу: команди та коди відповідей",[5373,11877,11878,11879,11882,11883,5430,11886,11889,11890,11893,11894,11897,11898,5261],{},"Протокол SMTP побудований як ",[5205,11880,11881],{},"діалог"," між клієнтом (відправником) і сервером (отримувачем), де кожна сторона по черзі надсилає ",[5205,11884,11885],{},"текстові команди",[5205,11887,11888],{},"відповіді",". Усі команди та відповіді є ",[5205,11891,11892],{},"читабельними ASCII-рядками",", завершеними символами ",[5258,11895,11896],{},"\\r\\n"," (carriage return + line feed), що робить протокол надзвичайно зручним для налагодження вручну через ",[5258,11899,5356],{},[5444,11901,11903],{"id":11902},"основні-команди-smtp","Основні команди SMTP",[5552,11905,11906,11921,11937,11949,11968,11980],{},[5201,11907,11908,5406,11911,11914,11915],{},[5205,11909,11910],{},"HELO \u002F EHLO",[5408,11912,11913],{},"Extended Hello",") — перше повідомлення клієнта після встановлення TCP-з'єднання. Клієнт представляється, вказуючи своє доменне ім'я або IP-адресу.",[5680,11916,11919],{"className":11917,"code":11918,"language":6502},[6500],"EHLO mail.example.com\n",[5258,11920,11918],{"__ignoreMap":5685},[5201,11922,11923,11926,11927,11930,11931],{},[5205,11924,11925],{},"MAIL FROM"," — вказує адресу відправника (так званий «конверт» листа, який може відрізнятися від поля ",[5258,11928,11929],{},"From:"," у заголовках листа).",[5680,11932,11935],{"className":11933,"code":11934,"language":6502},[6500],"MAIL FROM:\u003Calice@example.com>\n",[5258,11936,11934],{"__ignoreMap":5685},[5201,11938,11939,11942,11943],{},[5205,11940,11941],{},"RCPT TO"," — вказує адресу отримувача. Можна надіслати кілька команд RCPT TO, щоб доставити один лист кільком отримувачам.",[5680,11944,11947],{"className":11945,"code":11946,"language":6502},[6500],"RCPT TO:\u003Cbob@recipient.com>\n",[5258,11948,11946],{"__ignoreMap":5685},[5201,11950,11951,11954,11955,11958,11959,11961,11962],{},[5205,11952,11953],{},"DATA"," — сигналізує початок передачі ",[5205,11956,11957],{},"тіла листа"," (заголовки + текст повідомлення). Після цієї команди клієнт надсилає багаторядковий текст, завершуючи його рядком із однією крапкою ",[5258,11960,5261],{}," на окремому рядку.",[5680,11963,11966],{"className":11964,"code":11965,"language":6502},[6500],"DATA\nSubject: Тестовий лист\nFrom: alice@example.com\nTo: bob@recipient.com\n\nЦе тіло листа.\n.\n",[5258,11967,11965],{"__ignoreMap":5685},[5201,11969,11970,11973,11974],{},[5205,11971,11972],{},"QUIT"," — завершує SMTP-сеанс і закриває TCP-з'єднання.",[5680,11975,11978],{"className":11976,"code":11977,"language":6502},[6500],"QUIT\n",[5258,11979,11977],{"__ignoreMap":5685},[5201,11981,11982,11984,11985],{},[5205,11983,11868],{}," — оновлює з'єднання з відкритого текстового на шифроване TLS. Після успішного TLS-рукостискання клієнт повинен знову надіслати EHLO.",[5680,11986,11989],{"className":11987,"code":11988,"language":6502},[6500],"STARTTLS\n",[5258,11990,11988],{"__ignoreMap":5685},[5444,11992,11994],{"id":11993},"коди-відповідей-smtp","Коди відповідей SMTP",[5373,11996,11997,11998,12001],{},"Кожна команда клієнта отримує у відповідь ",[5205,11999,12000],{},"тризначний числовий код"," із текстовим описом. Перша цифра коду вказує на категорію відповіді:",[5198,12003,12004,12030,12044,12064],{},[5201,12005,12006,12009,12010],{},[5205,12007,12008],{},"2xx"," — успіх (команда прийнята і виконана).",[5198,12011,12012,12018,12024],{},[5201,12013,12014,12017],{},[5205,12015,12016],{},"220"," — сервер готовий (привітання при з'єднанні).",[5201,12019,12020,12023],{},[5205,12021,12022],{},"250"," — команда успішно виконана.",[5201,12025,12026,12029],{},[5205,12027,12028],{},"221"," — сервер закриває з'єднання (відповідь на QUIT).",[5201,12031,12032,12035,12036],{},[5205,12033,12034],{},"3xx"," — проміжний успіх (потрібна додаткова інформація).",[5198,12037,12038],{},[5201,12039,12040,12043],{},[5205,12041,12042],{},"354"," — почніть передачу тіла листа (відповідь на DATA).",[5201,12045,12046,12049,12050],{},[5205,12047,12048],{},"4xx"," — тимчасова помилка (спробуйте пізніше).",[5198,12051,12052,12058],{},[5201,12053,12054,12057],{},[5205,12055,12056],{},"421"," — сервіс недоступний, з'єднання буде закрито.",[5201,12059,12060,12063],{},[5205,12061,12062],{},"450"," — поштова скринька тимчасово недоступна.",[5201,12065,12066,12069,12070],{},[5205,12067,12068],{},"5xx"," — постійна помилка (операція неможлива, повтор безглуздий).",[5198,12071,12072,12078,12084],{},[5201,12073,12074,12077],{},[5205,12075,12076],{},"550"," — поштова скринька не існує або доступ заборонено.",[5201,12079,12080,12083],{},[5205,12081,12082],{},"552"," — перевищено квоту зберігання.",[5201,12085,12086,12089],{},[5205,12087,12088],{},"554"," — транзакція відхилена (часто через антиспам-фільтри).",[5421,12091,12092,12095],{},[5205,12093,12094],{},"Важливість коректної обробки кодів відповідей:"," при розробці поштових клієнтів або сервісів масового розсилання критично важливо розрізняти тимчасові помилки (4xx), які вимагають повторної спроби через деякий час, і постійні помилки (5xx), які означають, що доставка неможлива і потрібно повідомити відправника про невдачу. Ігнорування цієї різниці призводить до безглуздих повторних спроб надіслати лист на неіснуючу адресу або, навпаки, до передчасної відмови від доставки при тимчасових збоях.",[5444,12097,12099],{"id":12098},"повна-діаграма-типового-smtp-сеансу","Повна діаграма типового SMTP-сеансу",[5676,12101,12103],{"alt":12102},"Діаграма послідовності успішного SMTP-сеансу",[5680,12104,12106],{"className":5682,"code":12105,"language":5684,"meta":5685,"style":5685},"@startuml\nskinparam style plain\nskinparam backgroundColor #FFFFFF\nautonumber\n\nparticipant \"SMTP-клієнт\\n(mail.example.com)\" as Client #DBEAFE\nparticipant \"SMTP-сервер\\n(mail.recipient.com:25)\" as Server #DCFCE7\n\nClient -> Server : TCP SYN (встановлення з'єднання)\nServer -> Client : TCP SYN-ACK\nClient -> Server : TCP ACK\n\nnote over Client, Server #FEF3C7\n  TCP-з'єднання встановлено\nend note\n\nServer -> Client : **220** mail.recipient.com ESMTP готовий\nClient -> Server : **EHLO** mail.example.com\n\nServer -> Client : **250-**mail.recipient.com Hello\\n**250-SIZE** 52428800\\n**250 STARTTLS**\nnote right #E2E8F0\n  Сервер повідомляє про підтримку\n  розширень ESMTP (розмір листа, TLS)\nend note\n\nClient -> Server : **STARTTLS**\nServer -> Client : **220** Готовий до TLS Handshake\n\nnote over Client, Server #FEF3C7\n  Виконується TLS-рукостискання\n  (ClientHello, ServerHello, Certificate...)\n  Канал тепер зашифрований 🔒\nend note\n\nClient -> Server : **EHLO** mail.example.com (знову після TLS)\nServer -> Client : **250** Hello (підтвердження)\n\nClient -> Server : **MAIL FROM:**\u003Calice@example.com>\nServer -> Client : **250** Відправника прийнято\n\nClient -> Server : **RCPT TO:**\u003Cbob@recipient.com>\nServer -> Client : **250** Отримувача прийнято\n\nClient -> Server : **DATA**\nServer -> Client : **354** Починайте передачу, завершіть рядком \".\"\n\nClient -> Server : Subject: Важливе повідомлення\\nFrom: alice@example.com\\nTo: bob@recipient.com\\n\\nТекст листа.\\n**.**\nServer -> Client : **250** Лист прийнято (Message-ID: \u003Cxyz@mail.recipient.com>)\n\nClient -> Server : **QUIT**\nServer -> Client : **221** До побачення\n\nnote over Client, Server #DCFCE7\n  TCP-з'єднання закривається\nend note\n@enduml\n",[5258,12107,12108,12112,12116,12120,12124,12128,12133,12138,12142,12147,12152,12157,12161,12166,12171,12175,12179,12184,12189,12193,12198,12203,12208,12213,12217,12221,12226,12231,12235,12239,12244,12249,12254,12258,12262,12267,12272,12276,12281,12286,12290,12295,12300,12304,12309,12314,12318,12323,12328,12332,12337,12342,12346,12351,12356,12360],{"__ignoreMap":5685},[5689,12109,12110],{"class":5691,"line":5692},[5689,12111,5695],{},[5689,12113,12114],{"class":5691,"line":5698},[5689,12115,5701],{},[5689,12117,12118],{"class":5691,"line":5704},[5689,12119,5707],{},[5689,12121,12122],{"class":5691,"line":5710},[5689,12123,7495],{},[5689,12125,12126],{"class":5691,"line":5716},[5689,12127,5720],{"emptyLinePlaceholder":5719},[5689,12129,12130],{"class":5691,"line":5723},[5689,12131,12132],{},"participant \"SMTP-клієнт\\n(mail.example.com)\" as Client #DBEAFE\n",[5689,12134,12135],{"class":5691,"line":5729},[5689,12136,12137],{},"participant \"SMTP-сервер\\n(mail.recipient.com:25)\" as Server #DCFCE7\n",[5689,12139,12140],{"class":5691,"line":5735},[5689,12141,5720],{"emptyLinePlaceholder":5719},[5689,12143,12144],{"class":5691,"line":5741},[5689,12145,12146],{},"Client -> Server : TCP SYN (встановлення з'єднання)\n",[5689,12148,12149],{"class":5691,"line":5747},[5689,12150,12151],{},"Server -> Client : TCP SYN-ACK\n",[5689,12153,12154],{"class":5691,"line":5753},[5689,12155,12156],{},"Client -> Server : TCP ACK\n",[5689,12158,12159],{"class":5691,"line":5758},[5689,12160,5720],{"emptyLinePlaceholder":5719},[5689,12162,12163],{"class":5691,"line":5764},[5689,12164,12165],{},"note over Client, Server #FEF3C7\n",[5689,12167,12168],{"class":5691,"line":5770},[5689,12169,12170],{},"  TCP-з'єднання встановлено\n",[5689,12172,12173],{"class":5691,"line":5776},[5689,12174,5892],{},[5689,12176,12177],{"class":5691,"line":5781},[5689,12178,5720],{"emptyLinePlaceholder":5719},[5689,12180,12181],{"class":5691,"line":5786},[5689,12182,12183],{},"Server -> Client : **220** mail.recipient.com ESMTP готовий\n",[5689,12185,12186],{"class":5691,"line":5792},[5689,12187,12188],{},"Client -> Server : **EHLO** mail.example.com\n",[5689,12190,12191],{"class":5691,"line":5798},[5689,12192,5720],{"emptyLinePlaceholder":5719},[5689,12194,12195],{"class":5691,"line":5804},[5689,12196,12197],{},"Server -> Client : **250-**mail.recipient.com Hello\\n**250-SIZE** 52428800\\n**250 STARTTLS**\n",[5689,12199,12200],{"class":5691,"line":5809},[5689,12201,12202],{},"note right #E2E8F0\n",[5689,12204,12205],{"class":5691,"line":5814},[5689,12206,12207],{},"  Сервер повідомляє про підтримку\n",[5689,12209,12210],{"class":5691,"line":5820},[5689,12211,12212],{},"  розширень ESMTP (розмір листа, TLS)\n",[5689,12214,12215],{"class":5691,"line":5826},[5689,12216,5892],{},[5689,12218,12219],{"class":5691,"line":5832},[5689,12220,5720],{"emptyLinePlaceholder":5719},[5689,12222,12223],{"class":5691,"line":5838},[5689,12224,12225],{},"Client -> Server : **STARTTLS**\n",[5689,12227,12228],{"class":5691,"line":5843},[5689,12229,12230],{},"Server -> Client : **220** Готовий до TLS Handshake\n",[5689,12232,12233],{"class":5691,"line":5848},[5689,12234,5720],{"emptyLinePlaceholder":5719},[5689,12236,12237],{"class":5691,"line":5854},[5689,12238,12165],{},[5689,12240,12241],{"class":5691,"line":5860},[5689,12242,12243],{},"  Виконується TLS-рукостискання\n",[5689,12245,12246],{"class":5691,"line":5866},[5689,12247,12248],{},"  (ClientHello, ServerHello, Certificate...)\n",[5689,12250,12251],{"class":5691,"line":5871},[5689,12252,12253],{},"  Канал тепер зашифрований 🔒\n",[5689,12255,12256],{"class":5691,"line":5877},[5689,12257,5892],{},[5689,12259,12260],{"class":5691,"line":5883},[5689,12261,5720],{"emptyLinePlaceholder":5719},[5689,12263,12264],{"class":5691,"line":5889},[5689,12265,12266],{},"Client -> Server : **EHLO** mail.example.com (знову після TLS)\n",[5689,12268,12269],{"class":5691,"line":5895},[5689,12270,12271],{},"Server -> Client : **250** Hello (підтвердження)\n",[5689,12273,12274],{"class":5691,"line":9945},[5689,12275,5720],{"emptyLinePlaceholder":5719},[5689,12277,12278],{"class":5691,"line":10427},[5689,12279,12280],{},"Client -> Server : **MAIL FROM:**\u003Calice@example.com>\n",[5689,12282,12283],{"class":5691,"line":10452},[5689,12284,12285],{},"Server -> Client : **250** Відправника прийнято\n",[5689,12287,12288],{"class":5691,"line":10461},[5689,12289,5720],{"emptyLinePlaceholder":5719},[5689,12291,12292],{"class":5691,"line":10485},[5689,12293,12294],{},"Client -> Server : **RCPT TO:**\u003Cbob@recipient.com>\n",[5689,12296,12297],{"class":5691,"line":10490},[5689,12298,12299],{},"Server -> Client : **250** Отримувача прийнято\n",[5689,12301,12302],{"class":5691,"line":10496},[5689,12303,5720],{"emptyLinePlaceholder":5719},[5689,12305,12306],{"class":5691,"line":10501},[5689,12307,12308],{},"Client -> Server : **DATA**\n",[5689,12310,12311],{"class":5691,"line":10506},[5689,12312,12313],{},"Server -> Client : **354** Починайте передачу, завершіть рядком \".\"\n",[5689,12315,12316],{"class":5691,"line":10533},[5689,12317,5720],{"emptyLinePlaceholder":5719},[5689,12319,12320],{"class":5691,"line":11097},[5689,12321,12322],{},"Client -> Server : Subject: Важливе повідомлення\\nFrom: alice@example.com\\nTo: bob@recipient.com\\n\\nТекст листа.\\n**.**\n",[5689,12324,12325],{"class":5691,"line":11103},[5689,12326,12327],{},"Server -> Client : **250** Лист прийнято (Message-ID: \u003Cxyz@mail.recipient.com>)\n",[5689,12329,12330],{"class":5691,"line":11119},[5689,12331,5720],{"emptyLinePlaceholder":5719},[5689,12333,12334],{"class":5691,"line":11139},[5689,12335,12336],{},"Client -> Server : **QUIT**\n",[5689,12338,12339],{"class":5691,"line":11152},[5689,12340,12341],{},"Server -> Client : **221** До побачення\n",[5689,12343,12344],{"class":5691,"line":11177},[5689,12345,5720],{"emptyLinePlaceholder":5719},[5689,12347,12348],{"class":5691,"line":11182},[5689,12349,12350],{},"note over Client, Server #DCFCE7\n",[5689,12352,12353],{"class":5691,"line":11198},[5689,12354,12355],{},"  TCP-з'єднання закривається\n",[5689,12357,12358],{"class":5691,"line":11203},[5689,12359,5892],{},[5689,12361,12362],{"class":5691,"line":11214},[5689,12363,5898],{},[5365,12365],{},[5368,12367,12369],{"id":12368},"формат-mime-багатокомпонентні-листи-та-вкладення-файлів","Формат MIME: багатокомпонентні листи та вкладення файлів",[5373,12371,12372,12373,12376,12377,5406,12379,12382],{},"Оригінальний стандарт SMTP, визначений у RFC 821, передбачав передачу лише ",[5205,12374,12375],{},"простого ASCII-тексту"," без можливості включення зображень, документів, HTML-розмітки чи символів національних алфавітів (кирилиця, ієрогліфи тощо). Але вже на початку 1990-х років стало очевидно, що електронна пошта має підтримувати багатий контент. Саме тому був розроблений стандарт ",[5205,12378,5291],{},[5408,12380,12381],{},"Multipurpose Internet Mail Extensions",", RFC 2045–2049), який розширив можливості формату електронних листів, не змінюючи сам протокол SMTP.",[5444,12384,12386],{"id":12385},"основні-концепції-mime","Основні концепції MIME",[5373,12388,12389,12390,5406,12393,12396,12397,5406,12400,12403],{},"MIME вводить поняття ",[5205,12391,12392],{},"заголовків типу контенту",[5408,12394,12395],{},"Content-Type",") та ",[5205,12398,12399],{},"кодування",[5408,12401,12402],{},"Content-Transfer-Encoding","), які дозволяють передавати через текстовий протокол бінарні дані (зображення, PDF-файли, аудіо) та текст у будь-яких кодуваннях (UTF-8 для кирилиці, Shift-JIS для японської мови тощо).",[5373,12405,12406],{},[5205,12407,12408],{},"Ключові MIME-заголовки:",[5552,12410,12411,12454,12479],{},[5201,12412,12413,12415,12416],{},[5205,12414,12395],{}," — вказує тип вмісту частини листа:",[5198,12417,12418,12424,12430,12436,12442,12448],{},[5201,12419,12420,12423],{},[5258,12421,12422],{},"text\u002Fplain; charset=utf-8"," — простий текст у кодуванні UTF-8.",[5201,12425,12426,12429],{},[5258,12427,12428],{},"text\u002Fhtml; charset=utf-8"," — HTML-розмітка (для красивих листів із форматуванням).",[5201,12431,12432,12435],{},[5258,12433,12434],{},"image\u002Fjpeg"," — зображення JPEG.",[5201,12437,12438,12441],{},[5258,12439,12440],{},"application\u002Fpdf"," — PDF-документ.",[5201,12443,12444,12447],{},[5258,12445,12446],{},"multipart\u002Fmixed"," — лист складається з кількох частин (наприклад, текст + вкладення).",[5201,12449,12450,12453],{},[5258,12451,12452],{},"multipart\u002Falternative"," — кілька альтернативних версій того самого контенту (наприклад, plain text і HTML).",[5201,12455,12456,12458,12459],{},[5205,12457,12402],{}," — спосіб кодування бінарних даних у текстову форму:",[5198,12460,12461,12467,12473],{},[5201,12462,12463,12466],{},[5258,12464,12465],{},"7bit"," — чистий ASCII (типово для простого тексту).",[5201,12468,12469,12472],{},[5258,12470,12471],{},"quoted-printable"," — кодування для тексту з небагатьма не-ASCII символами (економить місце порівняно з Base64).",[5201,12474,12475,12478],{},[5258,12476,12477],{},"base64"," — бінарне кодування, де кожні 3 байти вихідних даних перетворюються на 4 символи ASCII (збільшення розміру на ~33%, але універсальне для будь-яких бінарних файлів).",[5201,12480,12481,12484,12485],{},[5205,12482,12483],{},"Content-Disposition"," — вказує, як обробляти частину:",[5198,12486,12487,12493],{},[5201,12488,12489,12492],{},[5258,12490,12491],{},"inline"," — відобразити вміст безпосередньо в листі (для вбудованих зображень).",[5201,12494,12495,12498],{},[5258,12496,12497],{},"attachment; filename=\"document.pdf\""," — вкладений файл, який потрібно завантажити окремо.",[5444,12500,12502],{"id":12501},"структура-багатокомпонентного-листа-multipart","Структура багатокомпонентного листа (Multipart)",[5373,12504,12505,12506,6698,12508,12510,12511,12514],{},"Коли лист містить кілька частин (наприклад, текстова версія + HTML-версія + вкладений файл), він оформляється як ",[5205,12507,12446],{},[5205,12509,12452],{},". Кожна частина відокремлюється унікальним ",[5205,12512,12513],{},"boundary"," (розділювачем) — довільним рядком, який не зустрічається в жодній із частин.",[5373,12516,12517],{},[5205,12518,12519],{},"Приклад структури MIME-листа з текстом і PDF-вкладенням:",[5680,12521,12524],{"className":12522,"code":12523,"language":6502},[6500],"From: alice@example.com\nTo: bob@recipient.com\nSubject: Звіт за квартал\nMIME-Version: 1.0\nContent-Type: multipart\u002Fmixed; boundary=\"----=_Part_12345\"\n\n------=_Part_12345\nContent-Type: text\u002Fplain; charset=utf-8\nContent-Transfer-Encoding: quoted-printable\n\nДоброго дня, Боб!\n\nНадсилаю звіт за третій квартал у вкладенні.\n\nЗ повагою,\nАліса\n\n------=_Part_12345\nContent-Type: application\u002Fpdf; name=\"report_Q3.pdf\"\nContent-Transfer-Encoding: base64\nContent-Disposition: attachment; filename=\"report_Q3.pdf\"\n\nJVBERi0xLjQKJeLjz9MKMyAwIG9iago8PC9UeXBlIC9QYWdlCi9QYXJlbnQgMSAw\n... (багато рядків Base64-коду) ...\nRU9GCg==\n\n------=_Part_12345--\n",[5258,12525,12523],{"__ignoreMap":5685},[5373,12527,12528],{},"Зверніть увагу:",[5198,12530,12531,12540,12549],{},[5201,12532,7796,12533,12536,12537,5261],{},[5258,12534,12535],{},"Content-Type: multipart\u002Fmixed; boundary=\"----=_Part_12345\""," оголошує, що лист складається з кількох частин, розділених рядком ",[5258,12538,12539],{},"------=_Part_12345",[5201,12541,12542,12543,5225,12545,5430,12547,5261],{},"Кожна частина має власні заголовки ",[5258,12544,12395],{},[5258,12546,12402],{},[5258,12548,12483],{},[5201,12550,12551,12552,12555],{},"Останній розділювач завершується двома дефісами ",[5258,12553,12554],{},"--",", що сигналізує кінець багатокомпонентної структури.",[6046,12557,12558,12561,12562,12565,12566,12568,12569,12572,12573,12575],{},[5205,12559,12560],{},"Multipart\u002Falternative vs Multipart\u002Fmixed:"," якщо лист містить дві версії ",[5205,12563,12564],{},"одного і того ж контенту"," (наприклад, plain text для старих поштових клієнтів і HTML для сучасних), використовується ",[5258,12567,12452],{}," — клієнт вибирає кращу для себе версію. Якщо ж лист містить ",[5205,12570,12571],{},"різний контент"," (текст листа + вкладений файл), використовується ",[5258,12574,12446],{}," — клієнт відображає всі частини.",[5444,12577,12579],{"id":12578},"кодування-base64-для-вкладень","Кодування Base64 для вкладень",[5373,12581,12582,12583,12586,12587,5225,12590,5225,12593,5225,12596,5225,12599,12601],{},"Бінарні файли (зображення, документи, архіви) не можна передати через текстовий SMTP-протокол напряму, тому вони кодуються в ",[5205,12584,12585],{},"Base64"," — алгоритм, який перетворює довільні байти в набір символів ",[5258,12588,12589],{},"A-Z",[5258,12591,12592],{},"a-z",[5258,12594,12595],{},"0-9",[5258,12597,12598],{},"+",[5258,12600,7773],{},". У Go кодування Base64 є частиною стандартної бібліотеки:",[5680,12603,12605],{"className":8209,"code":12604,"language":8212,"meta":5685,"style":5685},"package main\n\nimport (\n    \"encoding\u002Fbase64\"\n    \"fmt\"\n    \"os\"\n)\n\nfunc main() {\n    \u002F\u002F Читаємо бінарний файл\n    fileData, err := os.ReadFile(\"example.pdf\")\n    if err != nil {\n        panic(err)\n    }\n    \n    \u002F\u002F Кодуємо в Base64\n    encoded := base64.StdEncoding.EncodeToString(fileData)\n    \n    fmt.Printf(\"Розмір оригіналу: %d байтів\\n\", len(fileData))\n    fmt.Printf(\"Розмір після Base64: %d байтів\\n\", len(encoded))\n    fmt.Printf(\"Збільшення: %.1f%%\\n\", (float64(len(encoded))\u002Ffloat64(len(fileData))-1)*100)\n    \n    \u002F\u002F Виводимо перші 100 символів закодованого вмісту\n    fmt.Printf(\"Початок закодованих даних:\\n%s...\\n\", encoded[:100])\n}\n",[5258,12606,12607,12613,12617,12623,12628,12632,12637,12641,12645,12653,12658,12684,12696,12707,12711,12715,12720,12746,12750,12784,12816,12876,12880,12885,12920],{"__ignoreMap":5685},[5689,12608,12609,12611],{"class":5691,"line":5692},[5689,12610,8219],{"class":7769},[5689,12612,8223],{"class":8222},[5689,12614,12615],{"class":5691,"line":5698},[5689,12616,5720],{"emptyLinePlaceholder":5719},[5689,12618,12619,12621],{"class":5691,"line":5704},[5689,12620,8232],{"class":7761},[5689,12622,8235],{"class":7765},[5689,12624,12625],{"class":5691,"line":5710},[5689,12626,12627],{"class":7829},"    \"encoding\u002Fbase64\"\n",[5689,12629,12630],{"class":5691,"line":5716},[5689,12631,8699],{"class":7829},[5689,12633,12634],{"class":5691,"line":5723},[5689,12635,12636],{"class":7829},"    \"os\"\n",[5689,12638,12639],{"class":5691,"line":5729},[5689,12640,8250],{"class":7765},[5689,12642,12643],{"class":5691,"line":5735},[5689,12644,5720],{"emptyLinePlaceholder":5719},[5689,12646,12647,12649,12651],{"class":5691,"line":5741},[5689,12648,8265],{"class":7769},[5689,12650,8729],{"class":8268},[5689,12652,8732],{"class":7765},[5689,12654,12655],{"class":5691,"line":5747},[5689,12656,12657],{"class":8259},"    \u002F\u002F Читаємо бінарний файл\n",[5689,12659,12660,12663,12665,12667,12669,12672,12674,12677,12679,12682],{"class":5691,"line":5753},[5689,12661,12662],{"class":8275},"    fileData",[5689,12664,5225],{"class":7765},[5689,12666,8850],{"class":8275},[5689,12668,8357],{"class":7765},[5689,12670,12671],{"class":8275},"os",[5689,12673,5261],{"class":7765},[5689,12675,12676],{"class":8268},"ReadFile",[5689,12678,8272],{"class":7765},[5689,12680,12681],{"class":7829},"\"example.pdf\"",[5689,12683,8250],{"class":7765},[5689,12685,12686,12688,12690,12692,12694],{"class":5691,"line":5758},[5689,12687,8877],{"class":7761},[5689,12689,8880],{"class":8275},[5689,12691,8883],{"class":7765},[5689,12693,8886],{"class":7769},[5689,12695,8303],{"class":7765},[5689,12697,12698,12701,12703,12705],{"class":5691,"line":5764},[5689,12699,12700],{"class":8268},"        panic",[5689,12702,8272],{"class":7765},[5689,12704,8850],{"class":8275},[5689,12706,8250],{"class":7765},[5689,12708,12709],{"class":5691,"line":5770},[5689,12710,6325],{"class":7765},[5689,12712,12713],{"class":5691,"line":5776},[5689,12714,6330],{"class":7765},[5689,12716,12717],{"class":5691,"line":5781},[5689,12718,12719],{"class":8259},"    \u002F\u002F Кодуємо в Base64\n",[5689,12721,12722,12725,12727,12729,12731,12734,12736,12739,12741,12744],{"class":5691,"line":5786},[5689,12723,12724],{"class":8275},"    encoded",[5689,12726,8357],{"class":7765},[5689,12728,12477],{"class":8275},[5689,12730,5261],{"class":7765},[5689,12732,12733],{"class":8275},"StdEncoding",[5689,12735,5261],{"class":7765},[5689,12737,12738],{"class":8268},"EncodeToString",[5689,12740,8272],{"class":7765},[5689,12742,12743],{"class":8275},"fileData",[5689,12745,8250],{"class":7765},[5689,12747,12748],{"class":5691,"line":5792},[5689,12749,6330],{"class":7765},[5689,12751,12752,12754,12756,12758,12760,12763,12765,12768,12770,12772,12774,12777,12779,12781],{"class":5691,"line":5798},[5689,12753,8937],{"class":8275},[5689,12755,5261],{"class":7765},[5689,12757,8942],{"class":8268},[5689,12759,8272],{"class":7765},[5689,12761,12762],{"class":7829},"\"Розмір оригіналу: ",[5689,12764,9752],{"class":8275},[5689,12766,12767],{"class":7829}," байтів",[5689,12769,8955],{"class":8954},[5689,12771,8914],{"class":7829},[5689,12773,5225],{"class":7765},[5689,12775,12776],{"class":8268},"len",[5689,12778,8272],{"class":7765},[5689,12780,12743],{"class":8275},[5689,12782,12783],{"class":7765},"))\n",[5689,12785,12786,12788,12790,12792,12794,12797,12799,12801,12803,12805,12807,12809,12811,12814],{"class":5691,"line":5804},[5689,12787,8937],{"class":8275},[5689,12789,5261],{"class":7765},[5689,12791,8942],{"class":8268},[5689,12793,8272],{"class":7765},[5689,12795,12796],{"class":7829},"\"Розмір після Base64: ",[5689,12798,9752],{"class":8275},[5689,12800,12767],{"class":7829},[5689,12802,8955],{"class":8954},[5689,12804,8914],{"class":7829},[5689,12806,5225],{"class":7765},[5689,12808,12776],{"class":8268},[5689,12810,8272],{"class":7765},[5689,12812,12813],{"class":8275},"encoded",[5689,12815,12783],{"class":7765},[5689,12817,12818,12820,12822,12824,12826,12829,12832,12834,12836,12839,12842,12844,12846,12848,12850,12853,12855,12857,12859,12861,12863,12866,12868,12871,12874],{"class":5691,"line":5809},[5689,12819,8937],{"class":8275},[5689,12821,5261],{"class":7765},[5689,12823,8942],{"class":8268},[5689,12825,8272],{"class":7765},[5689,12827,12828],{"class":7829},"\"Збільшення: ",[5689,12830,12831],{"class":8275},"%.1f%%",[5689,12833,8955],{"class":8954},[5689,12835,8914],{"class":7829},[5689,12837,12838],{"class":7765},", (",[5689,12840,12841],{"class":8222},"float64",[5689,12843,8272],{"class":7765},[5689,12845,12776],{"class":8268},[5689,12847,8272],{"class":7765},[5689,12849,12813],{"class":8275},[5689,12851,12852],{"class":7765},"))\u002F",[5689,12854,12841],{"class":8222},[5689,12856,8272],{"class":7765},[5689,12858,12776],{"class":8268},[5689,12860,8272],{"class":7765},[5689,12862,12743],{"class":8275},[5689,12864,12865],{"class":7765},"))-",[5689,12867,6121],{"class":7776},[5689,12869,12870],{"class":7765},")*",[5689,12872,12873],{"class":7776},"100",[5689,12875,8250],{"class":7765},[5689,12877,12878],{"class":5691,"line":5814},[5689,12879,6330],{"class":7765},[5689,12881,12882],{"class":5691,"line":5820},[5689,12883,12884],{"class":8259},"    \u002F\u002F Виводимо перші 100 символів закодованого вмісту\n",[5689,12886,12887,12889,12891,12893,12895,12898,12900,12902,12905,12907,12909,12911,12913,12915,12917],{"class":5691,"line":5826},[5689,12888,8937],{"class":8275},[5689,12890,5261],{"class":7765},[5689,12892,8942],{"class":8268},[5689,12894,8272],{"class":7765},[5689,12896,12897],{"class":7829},"\"Початок закодованих даних:",[5689,12899,8955],{"class":8954},[5689,12901,8906],{"class":8275},[5689,12903,12904],{"class":7829},"...",[5689,12906,8955],{"class":8954},[5689,12908,8914],{"class":7829},[5689,12910,5225],{"class":7765},[5689,12912,12813],{"class":8275},[5689,12914,8426],{"class":7765},[5689,12916,12873],{"class":7776},[5689,12918,12919],{"class":7765},"])\n",[5689,12921,12922],{"class":5691,"line":5832},[5689,12923,5750],{"class":7765},[5373,12925,12926],{},[5205,12927,12928],{},"Типовий вихід:",[5680,12930,12933],{"className":12931,"code":12932,"language":6502},[6500],"Розмір оригіналу: 245760 байтів\nРозмір після Base64: 327680 байтів\nЗбільшення: 33.3%\nПочаток закодованих даних:\nJVBERi0xLjQKJeLjz9MKMyAwIG9iago8PC9UeXBlIC9QYWdlCi9QYXJlbnQgMSAwIFIKL01lZGlhQm94IFswIDAgNjEy...\n",[5258,12934,12932],{"__ignoreMap":5685},[5365,12936],{},[5368,12938,12940],{"id":12939},"механізми-захисту-електронної-пошти-spf-dkim-dmarc-та-starttls","Механізми захисту електронної пошти: SPF, DKIM, DMARC та STARTTLS",[5373,12942,12943],{},"Протокол SMTP у своїй оригінальній формі не передбачав жодних механізмів автентифікації відправника: будь-який сервер міг видати себе за будь-який домен, що призвело до епідемії спаму та фішингу. Протягом останніх двох десятиліть було розроблено кілька стандартів, які закривають ці прогалини безпеки.",[5373,12945,12946],{},[5669,12947],{"alt":12948,"className":12949,"src":12950},"Комплексна схема перевірки автентичності електронної пошти через SPF, DKIM та DMARC",[5673],"\u002Fimages\u002Fclient-server-architecture\u002Fdns-smtp-application-protocols\u002F03.png",[5676,12952,12954],{"alt":12953},"Послідовність перевірки автентичності листа через SPF, DKIM та DMARC",[5680,12955,12957],{"className":5682,"code":12956,"language":5684,"meta":5685,"style":5685},"@startuml\nskinparam style plain\nskinparam backgroundColor #FFFFFF\nskinparam sequenceMessageAlign center\nautonumber\n\nparticipant \"Сервер відправника\\n(MTA mail.example.com)\" as Sender #DBEAFE\nparticipant \"Сервер отримувача\\n(MTA mail.recipient.com)\" as Receiver #FEF3C7\nparticipant \"DNS-сервери домену\\nexample.com\" as DNS #DCFCE7\n\nSender -> Receiver : SMTP-з'єднання: лист від user@example.com\\n(IP: 198.51.100.1, заголовок DKIM-Signature)\n\nReceiver -> DNS : 1. DNS TXT-запит SPF: example.com\nDNS --> Receiver : \"v=spf1 ip4:198.51.100.0\u002F24 ~all\"\\n(IP 198.51.100.1 дозволено -> SPF PASS)\n\nReceiver -> DNS : 2. DNS TXT-запит DKIM: default._domainkey.example.com\nDNS --> Receiver : Відкритий RSA-ключ для валідації підпису\\n(Підпис співпав -> DKIM PASS)\n\nReceiver -> DNS : 3. DNS TXT-запит DMARC: _dmarc.example.com\nDNS --> Receiver : \"v=DMARC1; p=quarantine; ...\"\\n(SPF і DKIM дійсні -> DMARC PASS)\n\nnote over Receiver #DCFCE7\n  Всі рівні перевірки пройдено успішно.\n  Лист доставляється у поштову скриньку\n  користувача без підозри на спам.\nend note\n@enduml\n",[5258,12958,12959,12963,12967,12971,12975,12979,12983,12988,12993,12998,13002,13007,13011,13016,13021,13025,13030,13035,13039,13044,13049,13053,13058,13063,13068,13073,13077],{"__ignoreMap":5685},[5689,12960,12961],{"class":5691,"line":5692},[5689,12962,5695],{},[5689,12964,12965],{"class":5691,"line":5698},[5689,12966,5701],{},[5689,12968,12969],{"class":5691,"line":5704},[5689,12970,5707],{},[5689,12972,12973],{"class":5691,"line":5710},[5689,12974,7490],{},[5689,12976,12977],{"class":5691,"line":5716},[5689,12978,7495],{},[5689,12980,12981],{"class":5691,"line":5723},[5689,12982,5720],{"emptyLinePlaceholder":5719},[5689,12984,12985],{"class":5691,"line":5729},[5689,12986,12987],{},"participant \"Сервер відправника\\n(MTA mail.example.com)\" as Sender #DBEAFE\n",[5689,12989,12990],{"class":5691,"line":5735},[5689,12991,12992],{},"participant \"Сервер отримувача\\n(MTA mail.recipient.com)\" as Receiver #FEF3C7\n",[5689,12994,12995],{"class":5691,"line":5741},[5689,12996,12997],{},"participant \"DNS-сервери домену\\nexample.com\" as DNS #DCFCE7\n",[5689,12999,13000],{"class":5691,"line":5747},[5689,13001,5720],{"emptyLinePlaceholder":5719},[5689,13003,13004],{"class":5691,"line":5753},[5689,13005,13006],{},"Sender -> Receiver : SMTP-з'єднання: лист від user@example.com\\n(IP: 198.51.100.1, заголовок DKIM-Signature)\n",[5689,13008,13009],{"class":5691,"line":5758},[5689,13010,5720],{"emptyLinePlaceholder":5719},[5689,13012,13013],{"class":5691,"line":5764},[5689,13014,13015],{},"Receiver -> DNS : 1. DNS TXT-запит SPF: example.com\n",[5689,13017,13018],{"class":5691,"line":5770},[5689,13019,13020],{},"DNS --> Receiver : \"v=spf1 ip4:198.51.100.0\u002F24 ~all\"\\n(IP 198.51.100.1 дозволено -> SPF PASS)\n",[5689,13022,13023],{"class":5691,"line":5776},[5689,13024,5720],{"emptyLinePlaceholder":5719},[5689,13026,13027],{"class":5691,"line":5781},[5689,13028,13029],{},"Receiver -> DNS : 2. DNS TXT-запит DKIM: default._domainkey.example.com\n",[5689,13031,13032],{"class":5691,"line":5786},[5689,13033,13034],{},"DNS --> Receiver : Відкритий RSA-ключ для валідації підпису\\n(Підпис співпав -> DKIM PASS)\n",[5689,13036,13037],{"class":5691,"line":5792},[5689,13038,5720],{"emptyLinePlaceholder":5719},[5689,13040,13041],{"class":5691,"line":5798},[5689,13042,13043],{},"Receiver -> DNS : 3. DNS TXT-запит DMARC: _dmarc.example.com\n",[5689,13045,13046],{"class":5691,"line":5804},[5689,13047,13048],{},"DNS --> Receiver : \"v=DMARC1; p=quarantine; ...\"\\n(SPF і DKIM дійсні -> DMARC PASS)\n",[5689,13050,13051],{"class":5691,"line":5809},[5689,13052,5720],{"emptyLinePlaceholder":5719},[5689,13054,13055],{"class":5691,"line":5814},[5689,13056,13057],{},"note over Receiver #DCFCE7\n",[5689,13059,13060],{"class":5691,"line":5820},[5689,13061,13062],{},"  Всі рівні перевірки пройдено успішно.\n",[5689,13064,13065],{"class":5691,"line":5826},[5689,13066,13067],{},"  Лист доставляється у поштову скриньку\n",[5689,13069,13070],{"class":5691,"line":5832},[5689,13071,13072],{},"  користувача без підозри на спам.\n",[5689,13074,13075],{"class":5691,"line":5838},[5689,13076,5892],{},[5689,13078,13079],{"class":5691,"line":5843},[5689,13080,5898],{},[5444,13082,13084],{"id":13083},"spf-sender-policy-framework","SPF (Sender Policy Framework)",[5373,13086,13087,13089],{},[5205,13088,6796],{}," — це TXT-запис у DNS, який визначає, які IP-адреси мають право надсилати пошту від імені домену. Коли поштовий сервер отримує лист, він виконує DNS-запит типу TXT для домену відправника та перевіряє, чи IP-адреса відправника входить до дозволеного списку.",[5373,13091,13092],{},[5205,13093,13094],{},"Приклад SPF-запису:",[5680,13096,13099],{"className":13097,"code":13098,"language":6502},[6500],"example.com.    IN    TXT    \"v=spf1 ip4:192.0.2.0\u002F24 include:_spf.google.com ~all\"\n",[5258,13100,13098],{"__ignoreMap":5685},[5373,13102,13103],{},"Розшифровка:",[5198,13105,13106,13112,13118,13124],{},[5201,13107,13108,13111],{},[5258,13109,13110],{},"v=spf1"," — версія SPF.",[5201,13113,13114,13117],{},[5258,13115,13116],{},"ip4:192.0.2.0\u002F24"," — дозволена підмережа IPv4.",[5201,13119,13120,13123],{},[5258,13121,13122],{},"include:_spf.google.com"," — дозволити IP-адреси, вказані в SPF-записі Google (якщо компанія використовує Gmail для корпоративної пошти).",[5201,13125,13126,13129],{},[5258,13127,13128],{},"~all"," — soft fail для всіх інших адрес (позначити як підозріле, але не відхиляти одразу).",[5483,13131,13132,13135,13136,13138,13139,13141],{},[5205,13133,13134],{},"SPF не захищає від підробки поля From у заголовках:"," SPF перевіряє лише адресу ",[5205,13137,11925],{}," (так званий «конверт»), яку користувач не бачить. Поле ",[5205,13140,11929],{}," у заголовках листа, яке відображається в поштовому клієнті, може бути підроблено. Саме тому потрібен DKIM.",[5444,13143,13145],{"id":13144},"dkim-domainkeys-identified-mail","DKIM (DomainKeys Identified Mail)",[5373,13147,13148,13150,13151,13154,13155,13158],{},[5205,13149,6805],{}," додає до кожного відправленого листа ",[5205,13152,13153],{},"цифровий підпис",", створений закритим ключем домену. Підпис обчислюється для заголовків та тіла листа і додається як заголовок ",[5258,13156,13157],{},"DKIM-Signature",". Отримуючий сервер завантажує відкритий ключ домену з DNS (TXT-запис) і перевіряє підпис.",[5373,13160,13161],{},[5205,13162,13163],{},"Приклад DKIM-підпису в листі:",[5680,13165,13168],{"className":13166,"code":13167,"language":6502},[6500],"DKIM-Signature: v=1; a=rsa-sha256; c=relaxed\u002Frelaxed;\n  d=example.com; s=default;\n  h=from:to:subject:date:message-id;\n  bh=2jmj7l5rSw0yVb\u002FvlWAYkK\u002FYBwk=;\n  b=dzdVyOf8SdaTK4N...\n",[5258,13169,13167],{"__ignoreMap":5685},[5373,13171,13172],{},[5205,13173,13174],{},"TXT-запис з відкритим ключем DKIM:",[5680,13176,13179],{"className":13177,"code":13178,"language":6502},[6500],"default._domainkey.example.com.    IN    TXT    \"v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3...\"\n",[5258,13180,13178],{"__ignoreMap":5685},[5373,13182,13183,13184,13186],{},"DKIM гарантує, що лист дійсно надісланий із серверів домену ",[5258,13185,5993],{}," і не був модифікований у дорозі.",[5444,13188,13190],{"id":13189},"dmarc-domain-based-message-authentication-reporting-and-conformance","DMARC (Domain-based Message Authentication, Reporting and Conformance)",[5373,13192,13193,13195],{},[5205,13194,6814],{}," об'єднує SPF та DKIM у єдину політику та визначає, що робити з листами, які не пройшли перевірку. Це теж TXT-запис у DNS.",[5373,13197,13198],{},[5205,13199,13200],{},"Приклад DMARC-запису:",[5680,13202,13205],{"className":13203,"code":13204,"language":6502},[6500],"_dmarc.example.com.    IN    TXT    \"v=DMARC1; p=quarantine; rua=mailto:dmarc-reports@example.com\"\n",[5258,13206,13204],{"__ignoreMap":5685},[5373,13208,13103],{},[5198,13210,13211,13217,13223,13229],{},[5201,13212,13213,13216],{},[5258,13214,13215],{},"v=DMARC1"," — версія протоколу.",[5201,13218,13219,13222],{},[5258,13220,13221],{},"p=quarantine"," — політика: помістити листи, які не пройшли перевірку, у папку «Спам».",[5201,13224,13225,13228],{},[5258,13226,13227],{},"p=reject"," — більш жорстка політика: відхилити такі листи повністю.",[5201,13230,13231,13234],{},[5258,13232,13233],{},"rua=mailto:..."," — адреса для отримання агрегованих звітів про перевірки.",[5444,13236,13238],{"id":13237},"starttls-шифрування-smtp-каналу","STARTTLS — шифрування SMTP-каналу",[5373,13240,13241,13242,13244],{},"За замовчуванням SMTP передає дані (включно з паролями автентифікації та вмістом листів) у відкритому вигляді. Команда ",[5205,13243,11868],{}," дозволяє оновити з'єднання до шифрованого TLS після початкового рукостискання. Це обов'язкова практика для портів 587 (submission) і бажана для порту 25 (relay).",[5421,13246,13247,13250,13251,13254,13255,13258],{},[5205,13248,13249],{},"Opportunistic TLS:"," на відміну від HTTPS, де TLS є обов'язковим із самого початку (порт 443), SMTP-сервери часто використовують ",[5205,13252,13253],{},"opportunistic TLS"," — спочатку з'єднання встановлюється як plain text, і лише якщо обидві сторони підтримують STARTTLS, воно оновлюється до шифрованого. Це забезпечує зворотну сумісність зі старими серверами, які не підтримують TLS, але створює ризик атаки ",[5205,13256,13257],{},"downgrade",", коли зловмисник блокує команду STARTTLS, змушуючи сторони залишитися на незахищеному з'єднанні.",[5365,13260],{},[5368,13262,13264],{"id":13263},"програмне-надсилання-листів-через-go-пакет-netsmtp","Програмне надсилання листів через Go: пакет net\u002Fsmtp",[5373,13266,13267,13268,13272],{},"Стандартна бібліотека Go надає пакет ",[5205,13269,13270],{},[5258,13271,5305],{},", який реалізує клієнтську частину протоколу SMTP і дозволяє надсилати електронні листи з Go-застосунків без зовнішніх залежностей. Розглянемо практичні приклади від найпростішого до повноцінного з MIME-вкладеннями.",[5444,13274,13276],{"id":13275},"базовий-приклад-відправка-простого-текстового-листа","Базовий приклад: відправка простого текстового листа",[5680,13278,13280],{"className":8209,"code":13279,"language":8212,"meta":5685,"style":5685},"package main\n\nimport (\n    \"fmt\"\n    \"log\"\n    \"net\u002Fsmtp\"\n)\n\nfunc main() {\n    \u002F\u002F Налаштування SMTP-сервера (приклад з Gmail)\n    smtpHost := \"smtp.gmail.com\"\n    smtpPort := \"587\"\n    senderEmail := \"your-email@gmail.com\"\n    senderPassword := \"your-app-password\" \u002F\u002F Використовуйте App Password, не основний пароль!\n    \n    \u002F\u002F Дані листа\n    from := senderEmail\n    to := []string{\"recipient@example.com\"}\n    subject := \"Тестовий лист з Go\"\n    body := \"Це простий текстовий лист, надісланий через пакет net\u002Fsmtp.\"\n    \n    \u002F\u002F Формуємо повідомлення (заголовки + тіло)\n    message := []byte(\n        \"From: \" + from + \"\\r\\n\" +\n        \"To: \" + to[0] + \"\\r\\n\" +\n        \"Subject: \" + subject + \"\\r\\n\" +\n        \"\\r\\n\" +\n        body + \"\\r\\n\",\n    )\n    \n    \u002F\u002F Автентифікація PLAIN\n    auth := smtp.PlainAuth(\"\", senderEmail, senderPassword, smtpHost)\n    \n    \u002F\u002F Надсилаємо лист\n    err := smtp.SendMail(\n        smtpHost+\":\"+smtpPort,\n        auth,\n        from,\n        to,\n        message,\n    )\n    \n    if err != nil {\n        log.Fatalf(\"Помилка надсилання листа: %v\", err)\n    }\n    \n    fmt.Println(\"✅ Лист успішно надіслано!\")\n}\n",[5258,13281,13282,13288,13292,13298,13302,13306,13311,13315,13319,13327,13332,13342,13352,13362,13375,13379,13384,13394,13412,13422,13432,13436,13441,13454,13475,13500,13520,13531,13546,13551,13555,13560,13597,13601,13606,13622,13639,13646,13653,13660,13667,13671,13675,13687,13710,13714,13718,13734],{"__ignoreMap":5685},[5689,13283,13284,13286],{"class":5691,"line":5692},[5689,13285,8219],{"class":7769},[5689,13287,8223],{"class":8222},[5689,13289,13290],{"class":5691,"line":5698},[5689,13291,5720],{"emptyLinePlaceholder":5719},[5689,13293,13294,13296],{"class":5691,"line":5704},[5689,13295,8232],{"class":7761},[5689,13297,8235],{"class":7765},[5689,13299,13300],{"class":5691,"line":5710},[5689,13301,8699],{"class":7829},[5689,13303,13304],{"class":5691,"line":5716},[5689,13305,8704],{"class":7829},[5689,13307,13308],{"class":5691,"line":5723},[5689,13309,13310],{"class":7829},"    \"net\u002Fsmtp\"\n",[5689,13312,13313],{"class":5691,"line":5729},[5689,13314,8250],{"class":7765},[5689,13316,13317],{"class":5691,"line":5735},[5689,13318,5720],{"emptyLinePlaceholder":5719},[5689,13320,13321,13323,13325],{"class":5691,"line":5741},[5689,13322,8265],{"class":7769},[5689,13324,8729],{"class":8268},[5689,13326,8732],{"class":7765},[5689,13328,13329],{"class":5691,"line":5747},[5689,13330,13331],{"class":8259},"    \u002F\u002F Налаштування SMTP-сервера (приклад з Gmail)\n",[5689,13333,13334,13337,13339],{"class":5691,"line":5753},[5689,13335,13336],{"class":8275},"    smtpHost",[5689,13338,8357],{"class":7765},[5689,13340,13341],{"class":7829},"\"smtp.gmail.com\"\n",[5689,13343,13344,13347,13349],{"class":5691,"line":5758},[5689,13345,13346],{"class":8275},"    smtpPort",[5689,13348,8357],{"class":7765},[5689,13350,13351],{"class":7829},"\"587\"\n",[5689,13353,13354,13357,13359],{"class":5691,"line":5764},[5689,13355,13356],{"class":8275},"    senderEmail",[5689,13358,8357],{"class":7765},[5689,13360,13361],{"class":7829},"\"your-email@gmail.com\"\n",[5689,13363,13364,13367,13369,13372],{"class":5691,"line":5770},[5689,13365,13366],{"class":8275},"    senderPassword",[5689,13368,8357],{"class":7765},[5689,13370,13371],{"class":7829},"\"your-app-password\"",[5689,13373,13374],{"class":8259}," \u002F\u002F Використовуйте App Password, не основний пароль!\n",[5689,13376,13377],{"class":5691,"line":5776},[5689,13378,6330],{"class":7765},[5689,13380,13381],{"class":5691,"line":5781},[5689,13382,13383],{"class":8259},"    \u002F\u002F Дані листа\n",[5689,13385,13386,13389,13391],{"class":5691,"line":5786},[5689,13387,13388],{"class":8275},"    from",[5689,13390,8357],{"class":7765},[5689,13392,13393],{"class":8275},"senderEmail\n",[5689,13395,13396,13399,13402,13404,13407,13410],{"class":5691,"line":5792},[5689,13397,13398],{"class":8275},"    to",[5689,13400,13401],{"class":7765}," := []",[5689,13403,10659],{"class":8222},[5689,13405,13406],{"class":7765},"{",[5689,13408,13409],{"class":7829},"\"recipient@example.com\"",[5689,13411,5750],{"class":7765},[5689,13413,13414,13417,13419],{"class":5691,"line":5798},[5689,13415,13416],{"class":8275},"    subject",[5689,13418,8357],{"class":7765},[5689,13420,13421],{"class":7829},"\"Тестовий лист з Go\"\n",[5689,13423,13424,13427,13429],{"class":5691,"line":5804},[5689,13425,13426],{"class":8275},"    body",[5689,13428,8357],{"class":7765},[5689,13430,13431],{"class":7829},"\"Це простий текстовий лист, надісланий через пакет net\u002Fsmtp.\"\n",[5689,13433,13434],{"class":5691,"line":5809},[5689,13435,6330],{"class":7765},[5689,13437,13438],{"class":5691,"line":5814},[5689,13439,13440],{"class":8259},"    \u002F\u002F Формуємо повідомлення (заголовки + тіло)\n",[5689,13442,13443,13446,13448,13451],{"class":5691,"line":5820},[5689,13444,13445],{"class":8275},"    message",[5689,13447,13401],{"class":7765},[5689,13449,13450],{"class":8222},"byte",[5689,13452,13453],{"class":7765},"(\n",[5689,13455,13456,13459,13461,13464,13466,13468,13470,13472],{"class":5691,"line":5826},[5689,13457,13458],{"class":7829},"        \"From: \"",[5689,13460,8482],{"class":7765},[5689,13462,13463],{"class":8275},"from",[5689,13465,8482],{"class":7765},[5689,13467,8914],{"class":7829},[5689,13469,11896],{"class":8954},[5689,13471,8914],{"class":7829},[5689,13473,13474],{"class":7765}," +\n",[5689,13476,13477,13480,13482,13485,13487,13489,13492,13494,13496,13498],{"class":5691,"line":5832},[5689,13478,13479],{"class":7829},"        \"To: \"",[5689,13481,8482],{"class":7765},[5689,13483,13484],{"class":8275},"to",[5689,13486,10656],{"class":7765},[5689,13488,6113],{"class":7776},[5689,13490,13491],{"class":7765},"] + ",[5689,13493,8914],{"class":7829},[5689,13495,11896],{"class":8954},[5689,13497,8914],{"class":7829},[5689,13499,13474],{"class":7765},[5689,13501,13502,13505,13507,13510,13512,13514,13516,13518],{"class":5691,"line":5838},[5689,13503,13504],{"class":7829},"        \"Subject: \"",[5689,13506,8482],{"class":7765},[5689,13508,13509],{"class":8275},"subject",[5689,13511,8482],{"class":7765},[5689,13513,8914],{"class":7829},[5689,13515,11896],{"class":8954},[5689,13517,8914],{"class":7829},[5689,13519,13474],{"class":7765},[5689,13521,13522,13525,13527,13529],{"class":5691,"line":5843},[5689,13523,13524],{"class":7829},"        \"",[5689,13526,11896],{"class":8954},[5689,13528,8914],{"class":7829},[5689,13530,13474],{"class":7765},[5689,13532,13533,13536,13538,13540,13542,13544],{"class":5691,"line":5848},[5689,13534,13535],{"class":8275},"        body",[5689,13537,8482],{"class":7765},[5689,13539,8914],{"class":7829},[5689,13541,11896],{"class":8954},[5689,13543,8914],{"class":7829},[5689,13545,9234],{"class":7765},[5689,13547,13548],{"class":5691,"line":5854},[5689,13549,13550],{"class":7765},"    )\n",[5689,13552,13553],{"class":5691,"line":5860},[5689,13554,6330],{"class":7765},[5689,13556,13557],{"class":5691,"line":5866},[5689,13558,13559],{"class":8259},"    \u002F\u002F Автентифікація PLAIN\n",[5689,13561,13562,13565,13567,13570,13572,13575,13577,13580,13582,13585,13587,13590,13592,13595],{"class":5691,"line":5871},[5689,13563,13564],{"class":8275},"    auth",[5689,13566,8357],{"class":7765},[5689,13568,13569],{"class":8275},"smtp",[5689,13571,5261],{"class":7765},[5689,13573,13574],{"class":8268},"PlainAuth",[5689,13576,8272],{"class":7765},[5689,13578,13579],{"class":7829},"\"\"",[5689,13581,5225],{"class":7765},[5689,13583,13584],{"class":8275},"senderEmail",[5689,13586,5225],{"class":7765},[5689,13588,13589],{"class":8275},"senderPassword",[5689,13591,5225],{"class":7765},[5689,13593,13594],{"class":8275},"smtpHost",[5689,13596,8250],{"class":7765},[5689,13598,13599],{"class":5691,"line":5877},[5689,13600,6330],{"class":7765},[5689,13602,13603],{"class":5691,"line":5883},[5689,13604,13605],{"class":8259},"    \u002F\u002F Надсилаємо лист\n",[5689,13607,13608,13611,13613,13615,13617,13620],{"class":5691,"line":5889},[5689,13609,13610],{"class":8275},"    err",[5689,13612,8357],{"class":7765},[5689,13614,13569],{"class":8275},[5689,13616,5261],{"class":7765},[5689,13618,13619],{"class":8268},"SendMail",[5689,13621,13453],{"class":7765},[5689,13623,13624,13627,13629,13632,13634,13637],{"class":5691,"line":5895},[5689,13625,13626],{"class":8275},"        smtpHost",[5689,13628,12598],{"class":7765},[5689,13630,13631],{"class":7829},"\":\"",[5689,13633,12598],{"class":7765},[5689,13635,13636],{"class":8275},"smtpPort",[5689,13638,9234],{"class":7765},[5689,13640,13641,13644],{"class":5691,"line":9945},[5689,13642,13643],{"class":8275},"        auth",[5689,13645,9234],{"class":7765},[5689,13647,13648,13651],{"class":5691,"line":10427},[5689,13649,13650],{"class":8275},"        from",[5689,13652,9234],{"class":7765},[5689,13654,13655,13658],{"class":5691,"line":10452},[5689,13656,13657],{"class":8275},"        to",[5689,13659,9234],{"class":7765},[5689,13661,13662,13665],{"class":5691,"line":10461},[5689,13663,13664],{"class":8275},"        message",[5689,13666,9234],{"class":7765},[5689,13668,13669],{"class":5691,"line":10485},[5689,13670,13550],{"class":7765},[5689,13672,13673],{"class":5691,"line":10490},[5689,13674,6330],{"class":7765},[5689,13676,13677,13679,13681,13683,13685],{"class":5691,"line":10496},[5689,13678,8877],{"class":7761},[5689,13680,8880],{"class":8275},[5689,13682,8883],{"class":7765},[5689,13684,8886],{"class":7769},[5689,13686,8303],{"class":7765},[5689,13688,13689,13691,13693,13695,13697,13700,13702,13704,13706,13708],{"class":5691,"line":10501},[5689,13690,8893],{"class":8275},[5689,13692,5261],{"class":7765},[5689,13694,8898],{"class":8268},[5689,13696,8272],{"class":7765},[5689,13698,13699],{"class":7829},"\"Помилка надсилання листа: ",[5689,13701,8911],{"class":8275},[5689,13703,8914],{"class":7829},[5689,13705,5225],{"class":7765},[5689,13707,8850],{"class":8275},[5689,13709,8250],{"class":7765},[5689,13711,13712],{"class":5691,"line":10506},[5689,13713,6325],{"class":7765},[5689,13715,13716],{"class":5691,"line":10533},[5689,13717,6330],{"class":7765},[5689,13719,13720,13722,13724,13727,13729,13732],{"class":5691,"line":11097},[5689,13721,8937],{"class":8275},[5689,13723,5261],{"class":7765},[5689,13725,13726],{"class":8268},"Println",[5689,13728,8272],{"class":7765},[5689,13730,13731],{"class":7829},"\"✅ Лист успішно надіслано!\"",[5689,13733,8250],{"class":7765},[5689,13735,13736],{"class":5691,"line":11103},[5689,13737,5750],{"class":7765},[5483,13739,13740,13743,13744,13747,13748,13751],{},[5205,13741,13742],{},"Безпека паролів:"," ніколи не зберігайте паролі SMTP напряму в коді! Використовуйте змінні оточення (",[5258,13745,13746],{},"os.Getenv(\"SMTP_PASSWORD\")",") або секрети з систем керування конфігурацією (AWS Secrets Manager, HashiCorp Vault). Для Gmail обов'язково створіть ",[5205,13749,13750],{},"App Password"," у налаштуваннях облікового запису, а не використовуйте основний пароль.",[5444,13753,13755],{"id":13754},"розширений-приклад-html-лист-із-вкладенням","Розширений приклад: HTML-лист із вкладенням",[5373,13757,13758],{},"Для формування складних MIME-листів зручно використовувати допоміжні функції. Ось повноцінний приклад із HTML-версією та PDF-вкладенням:",[5680,13760,13762],{"className":8209,"code":13761,"language":8212,"meta":5685,"style":5685},"package main\n\nimport (\n    \"encoding\u002Fbase64\"\n    \"fmt\"\n    \"log\"\n    \"net\u002Fsmtp\"\n    \"os\"\n    \"strings\"\n)\n\nfunc main() {\n    smtpHost := \"smtp.gmail.com\"\n    smtpPort := \"587\"\n    senderEmail := \"your-email@gmail.com\"\n    senderPassword := \"your-app-password\"\n    \n    from := senderEmail\n    to := []string{\"recipient@example.com\"}\n    subject := \"Звіт за квартал\"\n    \n    \u002F\u002F Читаємо вкладений файл\n    attachmentPath := \"report.pdf\"\n    attachmentData, err := os.ReadFile(attachmentPath)\n    if err != nil {\n        log.Fatalf(\"Не вдалося прочитати вкладення: %v\", err)\n    }\n    \n    \u002F\u002F Формуємо MIME-лист\n    boundary := \"----=_Part_Boundary_12345\"\n    \n    var messageBuilder strings.Builder\n    messageBuilder.WriteString(fmt.Sprintf(\"From: %s\\r\\n\", from))\n    messageBuilder.WriteString(fmt.Sprintf(\"To: %s\\r\\n\", to[0]))\n    messageBuilder.WriteString(fmt.Sprintf(\"Subject: %s\\r\\n\", subject))\n    messageBuilder.WriteString(\"MIME-Version: 1.0\\r\\n\")\n    messageBuilder.WriteString(fmt.Sprintf(\"Content-Type: multipart\u002Fmixed; boundary=\\\"%s\\\"\\r\\n\", boundary))\n    messageBuilder.WriteString(\"\\r\\n\")\n    \n    \u002F\u002F Частина 1: HTML-текст\n    messageBuilder.WriteString(fmt.Sprintf(\"--%s\\r\\n\", boundary))\n    messageBuilder.WriteString(\"Content-Type: text\u002Fhtml; charset=utf-8\\r\\n\")\n    messageBuilder.WriteString(\"Content-Transfer-Encoding: quoted-printable\\r\\n\")\n    messageBuilder.WriteString(\"\\r\\n\")\n    messageBuilder.WriteString(\"\u003Chtml>\u003Cbody>\\r\\n\")\n    messageBuilder.WriteString(\"\u003Ch1>Доброго дня!\u003C\u002Fh1>\\r\\n\")\n    messageBuilder.WriteString(\"\u003Cp>Надсилаю звіт за третій квартал у вкладенні.\u003C\u002Fp>\\r\\n\")\n    messageBuilder.WriteString(\"\u003Cp>З повагою,\u003Cbr>\u003Cstrong>Аліса\u003C\u002Fstrong>\u003C\u002Fp>\\r\\n\")\n    messageBuilder.WriteString(\"\u003C\u002Fbody>\u003C\u002Fhtml>\\r\\n\")\n    messageBuilder.WriteString(\"\\r\\n\")\n    \n    \u002F\u002F Частина 2: PDF-вкладення\n    messageBuilder.WriteString(fmt.Sprintf(\"--%s\\r\\n\", boundary))\n    messageBuilder.WriteString(\"Content-Type: application\u002Fpdf; name=\\\"report.pdf\\\"\\r\\n\")\n    messageBuilder.WriteString(\"Content-Transfer-Encoding: base64\\r\\n\")\n    messageBuilder.WriteString(\"Content-Disposition: attachment; filename=\\\"report.pdf\\\"\\r\\n\")\n    messageBuilder.WriteString(\"\\r\\n\")\n    \n    \u002F\u002F Кодуємо вкладення в Base64 і розбиваємо на рядки по 76 символів\n    encoded := base64.StdEncoding.EncodeToString(attachmentData)\n    for i := 0; i \u003C len(encoded); i += 76 {\n        end := i + 76\n        if end > len(encoded) {\n            end = len(encoded)\n        }\n        messageBuilder.WriteString(encoded[i:end] + \"\\r\\n\")\n    }\n    \n    \u002F\u002F Завершальний boundary\n    messageBuilder.WriteString(fmt.Sprintf(\"--%s--\\r\\n\", boundary))\n    \n    message := []byte(messageBuilder.String())\n    \n    \u002F\u002F Надсилаємо\n    auth := smtp.PlainAuth(\"\", senderEmail, senderPassword, smtpHost)\n    err = smtp.SendMail(smtpHost+\":\"+smtpPort, auth, from, to, message)\n    if err != nil {\n        log.Fatalf(\"Помилка надсилання: %v\", err)\n    }\n    \n    fmt.Println(\"✅ HTML-лист із вкладенням успішно надіслано!\")\n}\n",[5258,13763,13764,13770,13774,13780,13784,13788,13792,13796,13800,13804,13808,13812,13820,13828,13836,13844,13853,13857,13865,13879,13888,13892,13897,13907,13931,13943,13966,13970,13974,13979,13989,13993,14009,14046,14084,14117,14136,14173,14191,14195,14200,14233,14252,14271,14289,14308,14327,14346,14365,14384,14402,14406,14411,14443,14467,14486,14509,14527,14531,14536,14559,14597,14611,14629,14644,14648,14680,14684,14688,14693,14727,14731,14752,14756,14761,14791,14836,14849,14873,14878,14883,14899],{"__ignoreMap":5685},[5689,13765,13766,13768],{"class":5691,"line":5692},[5689,13767,8219],{"class":7769},[5689,13769,8223],{"class":8222},[5689,13771,13772],{"class":5691,"line":5698},[5689,13773,5720],{"emptyLinePlaceholder":5719},[5689,13775,13776,13778],{"class":5691,"line":5704},[5689,13777,8232],{"class":7761},[5689,13779,8235],{"class":7765},[5689,13781,13782],{"class":5691,"line":5710},[5689,13783,12627],{"class":7829},[5689,13785,13786],{"class":5691,"line":5716},[5689,13787,8699],{"class":7829},[5689,13789,13790],{"class":5691,"line":5723},[5689,13791,8704],{"class":7829},[5689,13793,13794],{"class":5691,"line":5729},[5689,13795,13310],{"class":7829},[5689,13797,13798],{"class":5691,"line":5735},[5689,13799,12636],{"class":7829},[5689,13801,13802],{"class":5691,"line":5741},[5689,13803,8245],{"class":7829},[5689,13805,13806],{"class":5691,"line":5747},[5689,13807,8250],{"class":7765},[5689,13809,13810],{"class":5691,"line":5753},[5689,13811,5720],{"emptyLinePlaceholder":5719},[5689,13813,13814,13816,13818],{"class":5691,"line":5758},[5689,13815,8265],{"class":7769},[5689,13817,8729],{"class":8268},[5689,13819,8732],{"class":7765},[5689,13821,13822,13824,13826],{"class":5691,"line":5764},[5689,13823,13336],{"class":8275},[5689,13825,8357],{"class":7765},[5689,13827,13341],{"class":7829},[5689,13829,13830,13832,13834],{"class":5691,"line":5770},[5689,13831,13346],{"class":8275},[5689,13833,8357],{"class":7765},[5689,13835,13351],{"class":7829},[5689,13837,13838,13840,13842],{"class":5691,"line":5776},[5689,13839,13356],{"class":8275},[5689,13841,8357],{"class":7765},[5689,13843,13361],{"class":7829},[5689,13845,13846,13848,13850],{"class":5691,"line":5781},[5689,13847,13366],{"class":8275},[5689,13849,8357],{"class":7765},[5689,13851,13852],{"class":7829},"\"your-app-password\"\n",[5689,13854,13855],{"class":5691,"line":5786},[5689,13856,6330],{"class":7765},[5689,13858,13859,13861,13863],{"class":5691,"line":5792},[5689,13860,13388],{"class":8275},[5689,13862,8357],{"class":7765},[5689,13864,13393],{"class":8275},[5689,13866,13867,13869,13871,13873,13875,13877],{"class":5691,"line":5798},[5689,13868,13398],{"class":8275},[5689,13870,13401],{"class":7765},[5689,13872,10659],{"class":8222},[5689,13874,13406],{"class":7765},[5689,13876,13409],{"class":7829},[5689,13878,5750],{"class":7765},[5689,13880,13881,13883,13885],{"class":5691,"line":5804},[5689,13882,13416],{"class":8275},[5689,13884,8357],{"class":7765},[5689,13886,13887],{"class":7829},"\"Звіт за квартал\"\n",[5689,13889,13890],{"class":5691,"line":5809},[5689,13891,6330],{"class":7765},[5689,13893,13894],{"class":5691,"line":5814},[5689,13895,13896],{"class":8259},"    \u002F\u002F Читаємо вкладений файл\n",[5689,13898,13899,13902,13904],{"class":5691,"line":5820},[5689,13900,13901],{"class":8275},"    attachmentPath",[5689,13903,8357],{"class":7765},[5689,13905,13906],{"class":7829},"\"report.pdf\"\n",[5689,13908,13909,13912,13914,13916,13918,13920,13922,13924,13926,13929],{"class":5691,"line":5826},[5689,13910,13911],{"class":8275},"    attachmentData",[5689,13913,5225],{"class":7765},[5689,13915,8850],{"class":8275},[5689,13917,8357],{"class":7765},[5689,13919,12671],{"class":8275},[5689,13921,5261],{"class":7765},[5689,13923,12676],{"class":8268},[5689,13925,8272],{"class":7765},[5689,13927,13928],{"class":8275},"attachmentPath",[5689,13930,8250],{"class":7765},[5689,13932,13933,13935,13937,13939,13941],{"class":5691,"line":5832},[5689,13934,8877],{"class":7761},[5689,13936,8880],{"class":8275},[5689,13938,8883],{"class":7765},[5689,13940,8886],{"class":7769},[5689,13942,8303],{"class":7765},[5689,13944,13945,13947,13949,13951,13953,13956,13958,13960,13962,13964],{"class":5691,"line":5838},[5689,13946,8893],{"class":8275},[5689,13948,5261],{"class":7765},[5689,13950,8898],{"class":8268},[5689,13952,8272],{"class":7765},[5689,13954,13955],{"class":7829},"\"Не вдалося прочитати вкладення: ",[5689,13957,8911],{"class":8275},[5689,13959,8914],{"class":7829},[5689,13961,5225],{"class":7765},[5689,13963,8850],{"class":8275},[5689,13965,8250],{"class":7765},[5689,13967,13968],{"class":5691,"line":5843},[5689,13969,6325],{"class":7765},[5689,13971,13972],{"class":5691,"line":5848},[5689,13973,6330],{"class":7765},[5689,13975,13976],{"class":5691,"line":5854},[5689,13977,13978],{"class":8259},"    \u002F\u002F Формуємо MIME-лист\n",[5689,13980,13981,13984,13986],{"class":5691,"line":5860},[5689,13982,13983],{"class":8275},"    boundary",[5689,13985,8357],{"class":7765},[5689,13987,13988],{"class":7829},"\"----=_Part_Boundary_12345\"\n",[5689,13990,13991],{"class":5691,"line":5866},[5689,13992,6330],{"class":7765},[5689,13994,13995,13998,14001,14004,14006],{"class":5691,"line":5871},[5689,13996,13997],{"class":7769},"    var",[5689,13999,14000],{"class":8275}," messageBuilder",[5689,14002,14003],{"class":8222}," strings",[5689,14005,5261],{"class":7765},[5689,14007,14008],{"class":8222},"Builder\n",[5689,14010,14011,14014,14016,14019,14021,14024,14026,14029,14031,14034,14036,14038,14040,14042,14044],{"class":5691,"line":5877},[5689,14012,14013],{"class":8275},"    messageBuilder",[5689,14015,5261],{"class":7765},[5689,14017,14018],{"class":8268},"WriteString",[5689,14020,8272],{"class":7765},[5689,14022,14023],{"class":8275},"fmt",[5689,14025,5261],{"class":7765},[5689,14027,14028],{"class":8268},"Sprintf",[5689,14030,8272],{"class":7765},[5689,14032,14033],{"class":7829},"\"From: ",[5689,14035,8906],{"class":8275},[5689,14037,11896],{"class":8954},[5689,14039,8914],{"class":7829},[5689,14041,5225],{"class":7765},[5689,14043,13463],{"class":8275},[5689,14045,12783],{"class":7765},[5689,14047,14048,14050,14052,14054,14056,14058,14060,14062,14064,14067,14069,14071,14073,14075,14077,14079,14081],{"class":5691,"line":5883},[5689,14049,14013],{"class":8275},[5689,14051,5261],{"class":7765},[5689,14053,14018],{"class":8268},[5689,14055,8272],{"class":7765},[5689,14057,14023],{"class":8275},[5689,14059,5261],{"class":7765},[5689,14061,14028],{"class":8268},[5689,14063,8272],{"class":7765},[5689,14065,14066],{"class":7829},"\"To: ",[5689,14068,8906],{"class":8275},[5689,14070,11896],{"class":8954},[5689,14072,8914],{"class":7829},[5689,14074,5225],{"class":7765},[5689,14076,13484],{"class":8275},[5689,14078,10656],{"class":7765},[5689,14080,6113],{"class":7776},[5689,14082,14083],{"class":7765},"]))\n",[5689,14085,14086,14088,14090,14092,14094,14096,14098,14100,14102,14105,14107,14109,14111,14113,14115],{"class":5691,"line":5889},[5689,14087,14013],{"class":8275},[5689,14089,5261],{"class":7765},[5689,14091,14018],{"class":8268},[5689,14093,8272],{"class":7765},[5689,14095,14023],{"class":8275},[5689,14097,5261],{"class":7765},[5689,14099,14028],{"class":8268},[5689,14101,8272],{"class":7765},[5689,14103,14104],{"class":7829},"\"Subject: ",[5689,14106,8906],{"class":8275},[5689,14108,11896],{"class":8954},[5689,14110,8914],{"class":7829},[5689,14112,5225],{"class":7765},[5689,14114,13509],{"class":8275},[5689,14116,12783],{"class":7765},[5689,14118,14119,14121,14123,14125,14127,14130,14132,14134],{"class":5691,"line":5895},[5689,14120,14013],{"class":8275},[5689,14122,5261],{"class":7765},[5689,14124,14018],{"class":8268},[5689,14126,8272],{"class":7765},[5689,14128,14129],{"class":7829},"\"MIME-Version: 1.0",[5689,14131,11896],{"class":8954},[5689,14133,8914],{"class":7829},[5689,14135,8250],{"class":7765},[5689,14137,14138,14140,14142,14144,14146,14148,14150,14152,14154,14157,14160,14162,14165,14167,14169,14171],{"class":5691,"line":9945},[5689,14139,14013],{"class":8275},[5689,14141,5261],{"class":7765},[5689,14143,14018],{"class":8268},[5689,14145,8272],{"class":7765},[5689,14147,14023],{"class":8275},[5689,14149,5261],{"class":7765},[5689,14151,14028],{"class":8268},[5689,14153,8272],{"class":7765},[5689,14155,14156],{"class":7829},"\"Content-Type: multipart\u002Fmixed; boundary=",[5689,14158,14159],{"class":8954},"\\\"",[5689,14161,8906],{"class":8275},[5689,14163,14164],{"class":8954},"\\\"\\r\\n",[5689,14166,8914],{"class":7829},[5689,14168,5225],{"class":7765},[5689,14170,12513],{"class":8275},[5689,14172,12783],{"class":7765},[5689,14174,14175,14177,14179,14181,14183,14185,14187,14189],{"class":5691,"line":10427},[5689,14176,14013],{"class":8275},[5689,14178,5261],{"class":7765},[5689,14180,14018],{"class":8268},[5689,14182,8272],{"class":7765},[5689,14184,8914],{"class":7829},[5689,14186,11896],{"class":8954},[5689,14188,8914],{"class":7829},[5689,14190,8250],{"class":7765},[5689,14192,14193],{"class":5691,"line":10452},[5689,14194,6330],{"class":7765},[5689,14196,14197],{"class":5691,"line":10461},[5689,14198,14199],{"class":8259},"    \u002F\u002F Частина 1: HTML-текст\n",[5689,14201,14202,14204,14206,14208,14210,14212,14214,14216,14218,14221,14223,14225,14227,14229,14231],{"class":5691,"line":10485},[5689,14203,14013],{"class":8275},[5689,14205,5261],{"class":7765},[5689,14207,14018],{"class":8268},[5689,14209,8272],{"class":7765},[5689,14211,14023],{"class":8275},[5689,14213,5261],{"class":7765},[5689,14215,14028],{"class":8268},[5689,14217,8272],{"class":7765},[5689,14219,14220],{"class":7829},"\"--",[5689,14222,8906],{"class":8275},[5689,14224,11896],{"class":8954},[5689,14226,8914],{"class":7829},[5689,14228,5225],{"class":7765},[5689,14230,12513],{"class":8275},[5689,14232,12783],{"class":7765},[5689,14234,14235,14237,14239,14241,14243,14246,14248,14250],{"class":5691,"line":10490},[5689,14236,14013],{"class":8275},[5689,14238,5261],{"class":7765},[5689,14240,14018],{"class":8268},[5689,14242,8272],{"class":7765},[5689,14244,14245],{"class":7829},"\"Content-Type: text\u002Fhtml; charset=utf-8",[5689,14247,11896],{"class":8954},[5689,14249,8914],{"class":7829},[5689,14251,8250],{"class":7765},[5689,14253,14254,14256,14258,14260,14262,14265,14267,14269],{"class":5691,"line":10496},[5689,14255,14013],{"class":8275},[5689,14257,5261],{"class":7765},[5689,14259,14018],{"class":8268},[5689,14261,8272],{"class":7765},[5689,14263,14264],{"class":7829},"\"Content-Transfer-Encoding: quoted-printable",[5689,14266,11896],{"class":8954},[5689,14268,8914],{"class":7829},[5689,14270,8250],{"class":7765},[5689,14272,14273,14275,14277,14279,14281,14283,14285,14287],{"class":5691,"line":10501},[5689,14274,14013],{"class":8275},[5689,14276,5261],{"class":7765},[5689,14278,14018],{"class":8268},[5689,14280,8272],{"class":7765},[5689,14282,8914],{"class":7829},[5689,14284,11896],{"class":8954},[5689,14286,8914],{"class":7829},[5689,14288,8250],{"class":7765},[5689,14290,14291,14293,14295,14297,14299,14302,14304,14306],{"class":5691,"line":10506},[5689,14292,14013],{"class":8275},[5689,14294,5261],{"class":7765},[5689,14296,14018],{"class":8268},[5689,14298,8272],{"class":7765},[5689,14300,14301],{"class":7829},"\"\u003Chtml>\u003Cbody>",[5689,14303,11896],{"class":8954},[5689,14305,8914],{"class":7829},[5689,14307,8250],{"class":7765},[5689,14309,14310,14312,14314,14316,14318,14321,14323,14325],{"class":5691,"line":10533},[5689,14311,14013],{"class":8275},[5689,14313,5261],{"class":7765},[5689,14315,14018],{"class":8268},[5689,14317,8272],{"class":7765},[5689,14319,14320],{"class":7829},"\"\u003Ch1>Доброго дня!\u003C\u002Fh1>",[5689,14322,11896],{"class":8954},[5689,14324,8914],{"class":7829},[5689,14326,8250],{"class":7765},[5689,14328,14329,14331,14333,14335,14337,14340,14342,14344],{"class":5691,"line":11097},[5689,14330,14013],{"class":8275},[5689,14332,5261],{"class":7765},[5689,14334,14018],{"class":8268},[5689,14336,8272],{"class":7765},[5689,14338,14339],{"class":7829},"\"\u003Cp>Надсилаю звіт за третій квартал у вкладенні.\u003C\u002Fp>",[5689,14341,11896],{"class":8954},[5689,14343,8914],{"class":7829},[5689,14345,8250],{"class":7765},[5689,14347,14348,14350,14352,14354,14356,14359,14361,14363],{"class":5691,"line":11103},[5689,14349,14013],{"class":8275},[5689,14351,5261],{"class":7765},[5689,14353,14018],{"class":8268},[5689,14355,8272],{"class":7765},[5689,14357,14358],{"class":7829},"\"\u003Cp>З повагою,\u003Cbr>\u003Cstrong>Аліса\u003C\u002Fstrong>\u003C\u002Fp>",[5689,14360,11896],{"class":8954},[5689,14362,8914],{"class":7829},[5689,14364,8250],{"class":7765},[5689,14366,14367,14369,14371,14373,14375,14378,14380,14382],{"class":5691,"line":11119},[5689,14368,14013],{"class":8275},[5689,14370,5261],{"class":7765},[5689,14372,14018],{"class":8268},[5689,14374,8272],{"class":7765},[5689,14376,14377],{"class":7829},"\"\u003C\u002Fbody>\u003C\u002Fhtml>",[5689,14379,11896],{"class":8954},[5689,14381,8914],{"class":7829},[5689,14383,8250],{"class":7765},[5689,14385,14386,14388,14390,14392,14394,14396,14398,14400],{"class":5691,"line":11139},[5689,14387,14013],{"class":8275},[5689,14389,5261],{"class":7765},[5689,14391,14018],{"class":8268},[5689,14393,8272],{"class":7765},[5689,14395,8914],{"class":7829},[5689,14397,11896],{"class":8954},[5689,14399,8914],{"class":7829},[5689,14401,8250],{"class":7765},[5689,14403,14404],{"class":5691,"line":11152},[5689,14405,6330],{"class":7765},[5689,14407,14408],{"class":5691,"line":11177},[5689,14409,14410],{"class":8259},"    \u002F\u002F Частина 2: PDF-вкладення\n",[5689,14412,14413,14415,14417,14419,14421,14423,14425,14427,14429,14431,14433,14435,14437,14439,14441],{"class":5691,"line":11182},[5689,14414,14013],{"class":8275},[5689,14416,5261],{"class":7765},[5689,14418,14018],{"class":8268},[5689,14420,8272],{"class":7765},[5689,14422,14023],{"class":8275},[5689,14424,5261],{"class":7765},[5689,14426,14028],{"class":8268},[5689,14428,8272],{"class":7765},[5689,14430,14220],{"class":7829},[5689,14432,8906],{"class":8275},[5689,14434,11896],{"class":8954},[5689,14436,8914],{"class":7829},[5689,14438,5225],{"class":7765},[5689,14440,12513],{"class":8275},[5689,14442,12783],{"class":7765},[5689,14444,14445,14447,14449,14451,14453,14456,14458,14461,14463,14465],{"class":5691,"line":11198},[5689,14446,14013],{"class":8275},[5689,14448,5261],{"class":7765},[5689,14450,14018],{"class":8268},[5689,14452,8272],{"class":7765},[5689,14454,14455],{"class":7829},"\"Content-Type: application\u002Fpdf; name=",[5689,14457,14159],{"class":8954},[5689,14459,14460],{"class":7829},"report.pdf",[5689,14462,14164],{"class":8954},[5689,14464,8914],{"class":7829},[5689,14466,8250],{"class":7765},[5689,14468,14469,14471,14473,14475,14477,14480,14482,14484],{"class":5691,"line":11203},[5689,14470,14013],{"class":8275},[5689,14472,5261],{"class":7765},[5689,14474,14018],{"class":8268},[5689,14476,8272],{"class":7765},[5689,14478,14479],{"class":7829},"\"Content-Transfer-Encoding: base64",[5689,14481,11896],{"class":8954},[5689,14483,8914],{"class":7829},[5689,14485,8250],{"class":7765},[5689,14487,14488,14490,14492,14494,14496,14499,14501,14503,14505,14507],{"class":5691,"line":11214},[5689,14489,14013],{"class":8275},[5689,14491,5261],{"class":7765},[5689,14493,14018],{"class":8268},[5689,14495,8272],{"class":7765},[5689,14497,14498],{"class":7829},"\"Content-Disposition: attachment; filename=",[5689,14500,14159],{"class":8954},[5689,14502,14460],{"class":7829},[5689,14504,14164],{"class":8954},[5689,14506,8914],{"class":7829},[5689,14508,8250],{"class":7765},[5689,14510,14511,14513,14515,14517,14519,14521,14523,14525],{"class":5691,"line":11219},[5689,14512,14013],{"class":8275},[5689,14514,5261],{"class":7765},[5689,14516,14018],{"class":8268},[5689,14518,8272],{"class":7765},[5689,14520,8914],{"class":7829},[5689,14522,11896],{"class":8954},[5689,14524,8914],{"class":7829},[5689,14526,8250],{"class":7765},[5689,14528,14529],{"class":5691,"line":11224},[5689,14530,6330],{"class":7765},[5689,14532,14533],{"class":5691,"line":11233},[5689,14534,14535],{"class":8259},"    \u002F\u002F Кодуємо вкладення в Base64 і розбиваємо на рядки по 76 символів\n",[5689,14537,14538,14540,14542,14544,14546,14548,14550,14552,14554,14557],{"class":5691,"line":11246},[5689,14539,12724],{"class":8275},[5689,14541,8357],{"class":7765},[5689,14543,12477],{"class":8275},[5689,14545,5261],{"class":7765},[5689,14547,12733],{"class":8275},[5689,14549,5261],{"class":7765},[5689,14551,12738],{"class":8268},[5689,14553,8272],{"class":7765},[5689,14555,14556],{"class":8275},"attachmentData",[5689,14558,8250],{"class":7765},[5689,14560,14561,14563,14566,14568,14570,14573,14576,14579,14581,14583,14585,14587,14589,14592,14595],{"class":5691,"line":11261},[5689,14562,8968],{"class":7761},[5689,14564,14565],{"class":8275}," i",[5689,14567,8357],{"class":7765},[5689,14569,6113],{"class":7776},[5689,14571,14572],{"class":7765},"; ",[5689,14574,14575],{"class":8275},"i",[5689,14577,14578],{"class":7765}," \u003C ",[5689,14580,12776],{"class":8268},[5689,14582,8272],{"class":7765},[5689,14584,12813],{"class":8275},[5689,14586,8403],{"class":7765},[5689,14588,14575],{"class":8275},[5689,14590,14591],{"class":7765}," += ",[5689,14593,14594],{"class":7776},"76",[5689,14596,8303],{"class":7765},[5689,14598,14599,14602,14604,14606,14608],{"class":5691,"line":11266},[5689,14600,14601],{"class":8275},"        end",[5689,14603,8357],{"class":7765},[5689,14605,14575],{"class":8275},[5689,14607,8482],{"class":7765},[5689,14609,14610],{"class":7776},"76\n",[5689,14612,14613,14615,14618,14621,14623,14625,14627],{"class":5691,"line":11272},[5689,14614,8378],{"class":7761},[5689,14616,14617],{"class":8275}," end",[5689,14619,14620],{"class":7765}," > ",[5689,14622,12776],{"class":8268},[5689,14624,8272],{"class":7765},[5689,14626,12813],{"class":8275},[5689,14628,8349],{"class":7765},[5689,14630,14631,14634,14636,14638,14640,14642],{"class":5691,"line":11316},[5689,14632,14633],{"class":8275},"            end",[5689,14635,8421],{"class":7765},[5689,14637,12776],{"class":8268},[5689,14639,8272],{"class":7765},[5689,14641,12813],{"class":8275},[5689,14643,8250],{"class":7765},[5689,14645,14646],{"class":5691,"line":11344},[5689,14647,8436],{"class":7765},[5689,14649,14650,14653,14655,14657,14659,14661,14663,14665,14667,14670,14672,14674,14676,14678],{"class":5691,"line":11349},[5689,14651,14652],{"class":8275},"        messageBuilder",[5689,14654,5261],{"class":7765},[5689,14656,14018],{"class":8268},[5689,14658,8272],{"class":7765},[5689,14660,12813],{"class":8275},[5689,14662,10656],{"class":7765},[5689,14664,14575],{"class":8275},[5689,14666,7303],{"class":7765},[5689,14668,14669],{"class":8275},"end",[5689,14671,13491],{"class":7765},[5689,14673,8914],{"class":7829},[5689,14675,11896],{"class":8954},[5689,14677,8914],{"class":7829},[5689,14679,8250],{"class":7765},[5689,14681,14682],{"class":5691,"line":11355},[5689,14683,6325],{"class":7765},[5689,14685,14686],{"class":5691,"line":11380},[5689,14687,6330],{"class":7765},[5689,14689,14690],{"class":5691,"line":11420},[5689,14691,14692],{"class":8259},"    \u002F\u002F Завершальний boundary\n",[5689,14694,14695,14697,14699,14701,14703,14705,14707,14709,14711,14713,14715,14717,14719,14721,14723,14725],{"class":5691,"line":11446},[5689,14696,14013],{"class":8275},[5689,14698,5261],{"class":7765},[5689,14700,14018],{"class":8268},[5689,14702,8272],{"class":7765},[5689,14704,14023],{"class":8275},[5689,14706,5261],{"class":7765},[5689,14708,14028],{"class":8268},[5689,14710,8272],{"class":7765},[5689,14712,14220],{"class":7829},[5689,14714,8906],{"class":8275},[5689,14716,12554],{"class":7829},[5689,14718,11896],{"class":8954},[5689,14720,8914],{"class":7829},[5689,14722,5225],{"class":7765},[5689,14724,12513],{"class":8275},[5689,14726,12783],{"class":7765},[5689,14728,14729],{"class":5691,"line":11451},[5689,14730,6330],{"class":7765},[5689,14732,14733,14735,14737,14739,14741,14744,14746,14749],{"class":5691,"line":11457},[5689,14734,13445],{"class":8275},[5689,14736,13401],{"class":7765},[5689,14738,13450],{"class":8222},[5689,14740,8272],{"class":7765},[5689,14742,14743],{"class":8275},"messageBuilder",[5689,14745,5261],{"class":7765},[5689,14747,14748],{"class":8268},"String",[5689,14750,14751],{"class":7765},"())\n",[5689,14753,14754],{"class":5691,"line":11481},[5689,14755,6330],{"class":7765},[5689,14757,14758],{"class":5691,"line":11521},[5689,14759,14760],{"class":8259},"    \u002F\u002F Надсилаємо\n",[5689,14762,14763,14765,14767,14769,14771,14773,14775,14777,14779,14781,14783,14785,14787,14789],{"class":5691,"line":11547},[5689,14764,13564],{"class":8275},[5689,14766,8357],{"class":7765},[5689,14768,13569],{"class":8275},[5689,14770,5261],{"class":7765},[5689,14772,13574],{"class":8268},[5689,14774,8272],{"class":7765},[5689,14776,13579],{"class":7829},[5689,14778,5225],{"class":7765},[5689,14780,13584],{"class":8275},[5689,14782,5225],{"class":7765},[5689,14784,13589],{"class":8275},[5689,14786,5225],{"class":7765},[5689,14788,13594],{"class":8275},[5689,14790,8250],{"class":7765},[5689,14792,14794,14796,14798,14800,14802,14804,14806,14808,14810,14812,14814,14816,14818,14821,14823,14825,14827,14829,14831,14834],{"class":5691,"line":14793},76,[5689,14795,13610],{"class":8275},[5689,14797,8421],{"class":7765},[5689,14799,13569],{"class":8275},[5689,14801,5261],{"class":7765},[5689,14803,13619],{"class":8268},[5689,14805,8272],{"class":7765},[5689,14807,13594],{"class":8275},[5689,14809,12598],{"class":7765},[5689,14811,13631],{"class":7829},[5689,14813,12598],{"class":7765},[5689,14815,13636],{"class":8275},[5689,14817,5225],{"class":7765},[5689,14819,14820],{"class":8275},"auth",[5689,14822,5225],{"class":7765},[5689,14824,13463],{"class":8275},[5689,14826,5225],{"class":7765},[5689,14828,13484],{"class":8275},[5689,14830,5225],{"class":7765},[5689,14832,14833],{"class":8275},"message",[5689,14835,8250],{"class":7765},[5689,14837,14839,14841,14843,14845,14847],{"class":5691,"line":14838},77,[5689,14840,8877],{"class":7761},[5689,14842,8880],{"class":8275},[5689,14844,8883],{"class":7765},[5689,14846,8886],{"class":7769},[5689,14848,8303],{"class":7765},[5689,14850,14852,14854,14856,14858,14860,14863,14865,14867,14869,14871],{"class":5691,"line":14851},78,[5689,14853,8893],{"class":8275},[5689,14855,5261],{"class":7765},[5689,14857,8898],{"class":8268},[5689,14859,8272],{"class":7765},[5689,14861,14862],{"class":7829},"\"Помилка надсилання: ",[5689,14864,8911],{"class":8275},[5689,14866,8914],{"class":7829},[5689,14868,5225],{"class":7765},[5689,14870,8850],{"class":8275},[5689,14872,8250],{"class":7765},[5689,14874,14876],{"class":5691,"line":14875},79,[5689,14877,6325],{"class":7765},[5689,14879,14881],{"class":5691,"line":14880},80,[5689,14882,6330],{"class":7765},[5689,14884,14886,14888,14890,14892,14894,14897],{"class":5691,"line":14885},81,[5689,14887,8937],{"class":8275},[5689,14889,5261],{"class":7765},[5689,14891,13726],{"class":8268},[5689,14893,8272],{"class":7765},[5689,14895,14896],{"class":7829},"\"✅ HTML-лист із вкладенням успішно надіслано!\"",[5689,14898,8250],{"class":7765},[5689,14900,14902],{"class":5691,"line":14901},82,[5689,14903,5750],{"class":7765},[5444,14905,14907],{"id":14906},"використання-сторонніх-бібліотек-для-роботи-з-mime-пакет-jordan-wrightemail","Використання сторонніх бібліотек для роботи з MIME: пакет jordan-wright\u002Femail",[5373,14909,14910,14911,14913,14914,14917,14918,14920,14921,14923],{},"Стандартний пакет ",[5258,14912,5305],{}," у Go є ",[5205,14915,14916],{},"транспортним клієнтом низького рівня",": він відповідає виключно за встановлення TCP-з'єднання, проходження TLS-рукостискання та відправку сирих рядків протоколу SMTP. Сама стандартна бібліотека свідомо не містить високорівневого конструктора MIME-повідомлень. У попередньому прикладі ми власноруч генерували унікальні ",[5258,14919,12513],{},", вручну прописували службові заголовки ",[5258,14922,12395],{},", обчислювали Base64 і розбивали його на рядки фіксованої довжини по 76 символів згідно з RFC 2045.",[5373,14925,14926,14927,14929,14930,14933],{},"У промисловій розробці писати такий низькорівневий код вручну недоцільно та ризиковано: найменша помилка в розділювачах ",[5258,14928,11896],{},", пропущений дефіс чи відсутність кодування кириличних символів у темі листа за стандартом ",[5205,14931,14932],{},"RFC 2047"," призведуть до того, що поштовий клієнт (Gmail або Outlook) відобразить лист як пошкоджений або надішле вкладення у вигляді нечитабельного тексту.",[5373,14935,14936],{},"В екосистемі Go історично склалося кілька рішень:",[5198,14938,14939,14951],{},[5201,14940,14941,14946,14947,14950],{},[5205,14942,14943],{},[5258,14944,14945],{},"gopkg.in\u002Fgomail.v2"," — тривалий час був найвідомішим інструментом, проте проєкт є непідтримуваним (",[5408,14948,14949],{},"deprecated \u002F unmaintained",") ще з 2016 року, не розвивається під сучасні версії Go та не враховує нові стандарти.",[5201,14952,14953,14958,14959,5430,14961,14963,14964,5261],{},[5205,14954,14955],{},[5258,14956,14957],{},"github.com\u002Fjordan-wright\u002Femail"," — найпопулярніша, перевірена часом та елегантна бібліотека в сучасному Go. Вона розроблена як легковагова обгортка над стандартними пакетами ",[5258,14960,5305],{},[5258,14962,5331],{},", яка бере на себе всю складність формування валідних багатокомпонентних MIME-повідомлень, зберігаючи при цьому повну сумісність зі стандартним інтерфейсом ",[5258,14965,14966],{},"smtp.Auth",[14968,14969,14970],"tabs",{},[14971,14972,14974],"tabs-item",{"label":14973},"Go Modules",[5680,14975,14979],{"className":14976,"code":14977,"language":14978,"meta":5685,"style":5685},"language-bash shiki shiki-themes light-plus dark-plus dark-plus","go get -u github.com\u002Fjordan-wright\u002Femail\n","bash",[5258,14980,14981],{"__ignoreMap":5685},[5689,14982,14983,14985,14988,14991],{"class":5691,"line":5692},[5689,14984,8212],{"class":8268},[5689,14986,14987],{"class":7829}," get",[5689,14989,14990],{"class":7769}," -u",[5689,14992,14993],{"class":7829}," github.com\u002Fjordan-wright\u002Femail\n",[5373,14995,14996,14997,15000,15001,7303],{},"Розглянемо, як той самий сценарій надсилання ",[5205,14998,14999],{},"HTML-листа з вкладеним PDF-файлом"," реалізується за допомогою бібліотеки ",[5258,15002,15003],{},"jordan-wright\u002Femail",[5680,15005,15007],{"className":8209,"code":15006,"language":8212,"meta":5685,"style":5685},"package main\n\nimport (\n    \"fmt\"\n    \"log\"\n    \"net\u002Fsmtp\"\n\n    \"github.com\u002Fjordan-wright\u002Femail\"\n)\n\nfunc main() {\n    \u002F\u002F Параметри підключення до SMTP-сервера\n    smtpHost := \"smtp.gmail.com\"\n    smtpPort := \"587\"\n    senderEmail := \"your-email@gmail.com\"\n    senderPassword := \"your-app-password\" \u002F\u002F Пароль застосунку (App Password)\n\n    \u002F\u002F Створюємо новий об'єкт повідомлення\n    e := email.NewEmail()\n\n    \u002F\u002F Налаштовуємо адресні поля та тему\n    e.From = fmt.Sprintf(\"Аліса \u003C%s>\", senderEmail)\n    e.To = []string{\"recipient@example.com\"}\n    e.Subject = \"Звіт за квартал\"\n\n    \u002F\u002F Текстова альтернатива (для поштових клієнтів без підтримки HTML)\n    e.Text = []byte(\"Доброго дня!\\n\\nНадсилаю звіт за третій квартал у вкладенні.\\n\\nЗ повагою,\\nАліса\")\n\n    \u002F\u002F Основне тіло листа у форматі HTML\n    e.HTML = []byte(`\n        \u003Chtml>\n        \u003Cbody>\n            \u003Ch1>Доброго дня!\u003C\u002Fh1>\n            \u003Cp>Надсилаю звіт за третій квартал у вкладенні.\u003C\u002Fp>\n            \u003Cp>З повагою,\u003Cbr>\u003Cstrong>Аліса\u003C\u002Fstrong>\u003C\u002Fp>\n        \u003C\u002Fbody>\n        \u003C\u002Fhtml>\n    `)\n\n    \u002F\u002F Прикріплюємо файл звіту\n    \u002F\u002F Бібліотека автоматично визначає MIME-тип, кодує дані в Base64\n    \u002F\u002F та генерує коректні заголовки Content-Disposition і Content-Transfer-Encoding\n    _, err := e.AttachFile(\"report.pdf\")\n    if err != nil {\n        log.Fatalf(\"Не вдалося прикріпити файл report.pdf: %v\", err)\n    }\n\n    \u002F\u002F Автентифікація через стандартний пакет Go net\u002Fsmtp\n    auth := smtp.PlainAuth(\"\", senderEmail, senderPassword, smtpHost)\n\n    \u002F\u002F Відправка повідомлення через SMTP із автоматичним STARTTLS\n    err = e.Send(smtpHost+\":\"+smtpPort, auth)\n    if err != nil {\n        log.Fatalf(\"Помилка надсилання листа: %v\", err)\n    }\n\n    fmt.Println(\"✅ HTML-лист із вкладенням успішно надіслано через jordan-wright\u002Femail!\")\n}\n",[5258,15008,15009,15015,15019,15025,15029,15033,15037,15041,15046,15050,15054,15062,15067,15075,15083,15091,15102,15106,15111,15128,15132,15137,15170,15190,15203,15207,15212,15247,15251,15256,15274,15279,15284,15289,15294,15299,15304,15309,15316,15320,15325,15330,15335,15361,15373,15396,15400,15404,15409,15439,15443,15448,15479,15491,15513,15517,15521,15536],{"__ignoreMap":5685},[5689,15010,15011,15013],{"class":5691,"line":5692},[5689,15012,8219],{"class":7769},[5689,15014,8223],{"class":8222},[5689,15016,15017],{"class":5691,"line":5698},[5689,15018,5720],{"emptyLinePlaceholder":5719},[5689,15020,15021,15023],{"class":5691,"line":5704},[5689,15022,8232],{"class":7761},[5689,15024,8235],{"class":7765},[5689,15026,15027],{"class":5691,"line":5710},[5689,15028,8699],{"class":7829},[5689,15030,15031],{"class":5691,"line":5716},[5689,15032,8704],{"class":7829},[5689,15034,15035],{"class":5691,"line":5723},[5689,15036,13310],{"class":7829},[5689,15038,15039],{"class":5691,"line":5729},[5689,15040,5720],{"emptyLinePlaceholder":5719},[5689,15042,15043],{"class":5691,"line":5735},[5689,15044,15045],{"class":7829},"    \"github.com\u002Fjordan-wright\u002Femail\"\n",[5689,15047,15048],{"class":5691,"line":5741},[5689,15049,8250],{"class":7765},[5689,15051,15052],{"class":5691,"line":5747},[5689,15053,5720],{"emptyLinePlaceholder":5719},[5689,15055,15056,15058,15060],{"class":5691,"line":5753},[5689,15057,8265],{"class":7769},[5689,15059,8729],{"class":8268},[5689,15061,8732],{"class":7765},[5689,15063,15064],{"class":5691,"line":5758},[5689,15065,15066],{"class":8259},"    \u002F\u002F Параметри підключення до SMTP-сервера\n",[5689,15068,15069,15071,15073],{"class":5691,"line":5764},[5689,15070,13336],{"class":8275},[5689,15072,8357],{"class":7765},[5689,15074,13341],{"class":7829},[5689,15076,15077,15079,15081],{"class":5691,"line":5770},[5689,15078,13346],{"class":8275},[5689,15080,8357],{"class":7765},[5689,15082,13351],{"class":7829},[5689,15084,15085,15087,15089],{"class":5691,"line":5776},[5689,15086,13356],{"class":8275},[5689,15088,8357],{"class":7765},[5689,15090,13361],{"class":7829},[5689,15092,15093,15095,15097,15099],{"class":5691,"line":5781},[5689,15094,13366],{"class":8275},[5689,15096,8357],{"class":7765},[5689,15098,13371],{"class":7829},[5689,15100,15101],{"class":8259}," \u002F\u002F Пароль застосунку (App Password)\n",[5689,15103,15104],{"class":5691,"line":5786},[5689,15105,5720],{"emptyLinePlaceholder":5719},[5689,15107,15108],{"class":5691,"line":5792},[5689,15109,15110],{"class":8259},"    \u002F\u002F Створюємо новий об'єкт повідомлення\n",[5689,15112,15113,15116,15118,15121,15123,15126],{"class":5691,"line":5798},[5689,15114,15115],{"class":8275},"    e",[5689,15117,8357],{"class":7765},[5689,15119,15120],{"class":8275},"email",[5689,15122,5261],{"class":7765},[5689,15124,15125],{"class":8268},"NewEmail",[5689,15127,8501],{"class":7765},[5689,15129,15130],{"class":5691,"line":5804},[5689,15131,5720],{"emptyLinePlaceholder":5719},[5689,15133,15134],{"class":5691,"line":5809},[5689,15135,15136],{"class":8259},"    \u002F\u002F Налаштовуємо адресні поля та тему\n",[5689,15138,15139,15141,15143,15146,15148,15150,15152,15154,15156,15159,15161,15164,15166,15168],{"class":5691,"line":5814},[5689,15140,15115],{"class":8275},[5689,15142,5261],{"class":7765},[5689,15144,15145],{"class":8275},"From",[5689,15147,8421],{"class":7765},[5689,15149,14023],{"class":8275},[5689,15151,5261],{"class":7765},[5689,15153,14028],{"class":8268},[5689,15155,8272],{"class":7765},[5689,15157,15158],{"class":7829},"\"Аліса \u003C",[5689,15160,8906],{"class":8275},[5689,15162,15163],{"class":7829},">\"",[5689,15165,5225],{"class":7765},[5689,15167,13584],{"class":8275},[5689,15169,8250],{"class":7765},[5689,15171,15172,15174,15176,15179,15182,15184,15186,15188],{"class":5691,"line":5820},[5689,15173,15115],{"class":8275},[5689,15175,5261],{"class":7765},[5689,15177,15178],{"class":8275},"To",[5689,15180,15181],{"class":7765}," = []",[5689,15183,10659],{"class":8222},[5689,15185,13406],{"class":7765},[5689,15187,13409],{"class":7829},[5689,15189,5750],{"class":7765},[5689,15191,15192,15194,15196,15199,15201],{"class":5691,"line":5826},[5689,15193,15115],{"class":8275},[5689,15195,5261],{"class":7765},[5689,15197,15198],{"class":8275},"Subject",[5689,15200,8421],{"class":7765},[5689,15202,13887],{"class":7829},[5689,15204,15205],{"class":5691,"line":5832},[5689,15206,5720],{"emptyLinePlaceholder":5719},[5689,15208,15209],{"class":5691,"line":5838},[5689,15210,15211],{"class":8259},"    \u002F\u002F Текстова альтернатива (для поштових клієнтів без підтримки HTML)\n",[5689,15213,15214,15216,15218,15221,15223,15225,15227,15230,15232,15235,15237,15240,15242,15245],{"class":5691,"line":5843},[5689,15215,15115],{"class":8275},[5689,15217,5261],{"class":7765},[5689,15219,15220],{"class":8275},"Text",[5689,15222,15181],{"class":7765},[5689,15224,13450],{"class":8222},[5689,15226,8272],{"class":7765},[5689,15228,15229],{"class":7829},"\"Доброго дня!",[5689,15231,11332],{"class":8954},[5689,15233,15234],{"class":7829},"Надсилаю звіт за третій квартал у вкладенні.",[5689,15236,11332],{"class":8954},[5689,15238,15239],{"class":7829},"З повагою,",[5689,15241,8955],{"class":8954},[5689,15243,15244],{"class":7829},"Аліса\"",[5689,15246,8250],{"class":7765},[5689,15248,15249],{"class":5691,"line":5848},[5689,15250,5720],{"emptyLinePlaceholder":5719},[5689,15252,15253],{"class":5691,"line":5854},[5689,15254,15255],{"class":8259},"    \u002F\u002F Основне тіло листа у форматі HTML\n",[5689,15257,15258,15260,15262,15265,15267,15269,15271],{"class":5691,"line":5860},[5689,15259,15115],{"class":8275},[5689,15261,5261],{"class":7765},[5689,15263,15264],{"class":8275},"HTML",[5689,15266,15181],{"class":7765},[5689,15268,13450],{"class":8222},[5689,15270,8272],{"class":7765},[5689,15272,15273],{"class":7829},"`\n",[5689,15275,15276],{"class":5691,"line":5866},[5689,15277,15278],{"class":7829},"        \u003Chtml>\n",[5689,15280,15281],{"class":5691,"line":5871},[5689,15282,15283],{"class":7829},"        \u003Cbody>\n",[5689,15285,15286],{"class":5691,"line":5877},[5689,15287,15288],{"class":7829},"            \u003Ch1>Доброго дня!\u003C\u002Fh1>\n",[5689,15290,15291],{"class":5691,"line":5883},[5689,15292,15293],{"class":7829},"            \u003Cp>Надсилаю звіт за третій квартал у вкладенні.\u003C\u002Fp>\n",[5689,15295,15296],{"class":5691,"line":5889},[5689,15297,15298],{"class":7829},"            \u003Cp>З повагою,\u003Cbr>\u003Cstrong>Аліса\u003C\u002Fstrong>\u003C\u002Fp>\n",[5689,15300,15301],{"class":5691,"line":5895},[5689,15302,15303],{"class":7829},"        \u003C\u002Fbody>\n",[5689,15305,15306],{"class":5691,"line":9945},[5689,15307,15308],{"class":7829},"        \u003C\u002Fhtml>\n",[5689,15310,15311,15314],{"class":5691,"line":10427},[5689,15312,15313],{"class":7829},"    `",[5689,15315,8250],{"class":7765},[5689,15317,15318],{"class":5691,"line":10452},[5689,15319,5720],{"emptyLinePlaceholder":5719},[5689,15321,15322],{"class":5691,"line":10461},[5689,15323,15324],{"class":8259},"    \u002F\u002F Прикріплюємо файл звіту\n",[5689,15326,15327],{"class":5691,"line":10485},[5689,15328,15329],{"class":8259},"    \u002F\u002F Бібліотека автоматично визначає MIME-тип, кодує дані в Base64\n",[5689,15331,15332],{"class":5691,"line":10490},[5689,15333,15334],{"class":8259},"    \u002F\u002F та генерує коректні заголовки Content-Disposition і Content-Transfer-Encoding\n",[5689,15336,15337,15340,15342,15344,15346,15349,15351,15354,15356,15359],{"class":5691,"line":10496},[5689,15338,15339],{"class":8275},"    _",[5689,15341,5225],{"class":7765},[5689,15343,8850],{"class":8275},[5689,15345,8357],{"class":7765},[5689,15347,15348],{"class":8275},"e",[5689,15350,5261],{"class":7765},[5689,15352,15353],{"class":8268},"AttachFile",[5689,15355,8272],{"class":7765},[5689,15357,15358],{"class":7829},"\"report.pdf\"",[5689,15360,8250],{"class":7765},[5689,15362,15363,15365,15367,15369,15371],{"class":5691,"line":10501},[5689,15364,8877],{"class":7761},[5689,15366,8880],{"class":8275},[5689,15368,8883],{"class":7765},[5689,15370,8886],{"class":7769},[5689,15372,8303],{"class":7765},[5689,15374,15375,15377,15379,15381,15383,15386,15388,15390,15392,15394],{"class":5691,"line":10506},[5689,15376,8893],{"class":8275},[5689,15378,5261],{"class":7765},[5689,15380,8898],{"class":8268},[5689,15382,8272],{"class":7765},[5689,15384,15385],{"class":7829},"\"Не вдалося прикріпити файл report.pdf: ",[5689,15387,8911],{"class":8275},[5689,15389,8914],{"class":7829},[5689,15391,5225],{"class":7765},[5689,15393,8850],{"class":8275},[5689,15395,8250],{"class":7765},[5689,15397,15398],{"class":5691,"line":10533},[5689,15399,6325],{"class":7765},[5689,15401,15402],{"class":5691,"line":11097},[5689,15403,5720],{"emptyLinePlaceholder":5719},[5689,15405,15406],{"class":5691,"line":11103},[5689,15407,15408],{"class":8259},"    \u002F\u002F Автентифікація через стандартний пакет Go net\u002Fsmtp\n",[5689,15410,15411,15413,15415,15417,15419,15421,15423,15425,15427,15429,15431,15433,15435,15437],{"class":5691,"line":11119},[5689,15412,13564],{"class":8275},[5689,15414,8357],{"class":7765},[5689,15416,13569],{"class":8275},[5689,15418,5261],{"class":7765},[5689,15420,13574],{"class":8268},[5689,15422,8272],{"class":7765},[5689,15424,13579],{"class":7829},[5689,15426,5225],{"class":7765},[5689,15428,13584],{"class":8275},[5689,15430,5225],{"class":7765},[5689,15432,13589],{"class":8275},[5689,15434,5225],{"class":7765},[5689,15436,13594],{"class":8275},[5689,15438,8250],{"class":7765},[5689,15440,15441],{"class":5691,"line":11139},[5689,15442,5720],{"emptyLinePlaceholder":5719},[5689,15444,15445],{"class":5691,"line":11152},[5689,15446,15447],{"class":8259},"    \u002F\u002F Відправка повідомлення через SMTP із автоматичним STARTTLS\n",[5689,15449,15450,15452,15454,15456,15458,15461,15463,15465,15467,15469,15471,15473,15475,15477],{"class":5691,"line":11177},[5689,15451,13610],{"class":8275},[5689,15453,8421],{"class":7765},[5689,15455,15348],{"class":8275},[5689,15457,5261],{"class":7765},[5689,15459,15460],{"class":8268},"Send",[5689,15462,8272],{"class":7765},[5689,15464,13594],{"class":8275},[5689,15466,12598],{"class":7765},[5689,15468,13631],{"class":7829},[5689,15470,12598],{"class":7765},[5689,15472,13636],{"class":8275},[5689,15474,5225],{"class":7765},[5689,15476,14820],{"class":8275},[5689,15478,8250],{"class":7765},[5689,15480,15481,15483,15485,15487,15489],{"class":5691,"line":11182},[5689,15482,8877],{"class":7761},[5689,15484,8880],{"class":8275},[5689,15486,8883],{"class":7765},[5689,15488,8886],{"class":7769},[5689,15490,8303],{"class":7765},[5689,15492,15493,15495,15497,15499,15501,15503,15505,15507,15509,15511],{"class":5691,"line":11198},[5689,15494,8893],{"class":8275},[5689,15496,5261],{"class":7765},[5689,15498,8898],{"class":8268},[5689,15500,8272],{"class":7765},[5689,15502,13699],{"class":7829},[5689,15504,8911],{"class":8275},[5689,15506,8914],{"class":7829},[5689,15508,5225],{"class":7765},[5689,15510,8850],{"class":8275},[5689,15512,8250],{"class":7765},[5689,15514,15515],{"class":5691,"line":11203},[5689,15516,6325],{"class":7765},[5689,15518,15519],{"class":5691,"line":11214},[5689,15520,5720],{"emptyLinePlaceholder":5719},[5689,15522,15523,15525,15527,15529,15531,15534],{"class":5691,"line":11219},[5689,15524,8937],{"class":8275},[5689,15526,5261],{"class":7765},[5689,15528,13726],{"class":8268},[5689,15530,8272],{"class":7765},[5689,15532,15533],{"class":7829},"\"✅ HTML-лист із вкладенням успішно надіслано через jordan-wright\u002Femail!\"",[5689,15535,8250],{"class":7765},[5689,15537,15538],{"class":5691,"line":11224},[5689,15539,5750],{"class":7765},[5421,15541,15542,15549],{},[5373,15543,15544],{},[5205,15545,15546,15547,7303],{},"Переваги підходу бібліотеки ",[5258,15548,15003],{},[5552,15550,15551,15572,15585],{},[5201,15552,15553,15560,15561,5225,15564,15567,15568,15571],{},[5205,15554,15555,15556,8482,15558,7303],{},"Автоматична гібридна структура ",[5258,15557,12452],{},[5258,15559,12446],{}," якщо вказати одночасно ",[5258,15562,15563],{},"e.Text",[5258,15565,15566],{},"e.HTML"," та вкладення через ",[5258,15569,15570],{},"e.AttachFile()",", бібліотека створить правильне вкладене дерево MIME-розділювачів, де клієнт зможе вибрати між HTML і Text, а вкладення відобразяться окремими файлами.",[5201,15573,15574,15577,15578,15580,15581,15584],{},[5205,15575,15576],{},"Безпечне кодування UTF-8 заголовків:"," якщо поле ",[5258,15579,15198],{}," містить кирилицю чи емодзі, бібліотека автоматично закодує його у відповідність до стандарту RFC 2047 (",[5258,15582,15583],{},"=?utf-8?b?...?=","), що запобігає появі «знаків запитання» замість букв в Outlook або Apple Mail.",[5201,15586,15587,15590,15591,15594,15595,15597],{},[5205,15588,15589],{},"Пряма сумісність:"," метод ",[5258,15592,15593],{},"e.Send()"," приймає стандартну адресу хоста та стандартний ",[5258,15596,14966],{},", не вимагаючи сторонніх конфігурацій з'єднання.",[5365,15599],{},[5368,15601,15603],{"id":15602},"локальне-тестування-smtp-емулятори-mailhog-та-mailpit","Локальне тестування SMTP: емулятори MailHog та Mailpit",[5373,15605,15606,15607,15610],{},"Під час розробки та налагодження функціональності надсилання листів критично важливо мати можливість перевіряти роботу без фактичної відправки листів у реальні поштові скриньки (що може призвести до спаму, випадкового розголошення тестових даних або витрати квот на сервісах розсилки). Для цього існують ",[5205,15608,15609],{},"локальні SMTP-емулятори",", які приймають листи, зберігають їх у пам'яті та надають вебінтерфейс для перегляду.",[5444,15612,15614],{"id":15613},"налаштування-mailhog-через-docker","Налаштування MailHog через Docker",[5373,15616,15617,15620],{},[5205,15618,15619],{},"MailHog"," — це легковаговий SMTP-сервер на Go, який ідеально підходить для розробки. Він слухає на порту 1025 для SMTP-з'єднань та надає вебінтерфейс на порту 8025 для перегляду отриманих листів.",[5373,15622,15623],{},[5205,15624,15625],{},"Запуск через Docker:",[5680,15627,15629],{"className":14976,"code":15628,"language":14978,"meta":5685,"style":5685},"docker run -d \\\n  --name mailhog \\\n  -p 1025:1025 \\\n  -p 8025:8025 \\\n  mailhog\u002Fmailhog\n",[5258,15630,15631,15645,15655,15665,15674],{"__ignoreMap":5685},[5689,15632,15633,15636,15639,15642],{"class":5691,"line":5692},[5689,15634,15635],{"class":8268},"docker",[5689,15637,15638],{"class":7829}," run",[5689,15640,15641],{"class":7769}," -d",[5689,15643,15644],{"class":8954}," \\\n",[5689,15646,15647,15650,15653],{"class":5691,"line":5698},[5689,15648,15649],{"class":7769},"  --name",[5689,15651,15652],{"class":7829}," mailhog",[5689,15654,15644],{"class":8954},[5689,15656,15657,15660,15663],{"class":5691,"line":5704},[5689,15658,15659],{"class":7769},"  -p",[5689,15661,15662],{"class":7829}," 1025:1025",[5689,15664,15644],{"class":8954},[5689,15666,15667,15669,15672],{"class":5691,"line":5710},[5689,15668,15659],{"class":7769},[5689,15670,15671],{"class":7829}," 8025:8025",[5689,15673,15644],{"class":8954},[5689,15675,15676],{"class":5691,"line":5716},[5689,15677,15678],{"class":7829},"  mailhog\u002Fmailhog\n",[5373,15680,15681],{},[5205,15682,15683],{},"Налаштування Go-клієнта для MailHog:",[5680,15685,15687],{"className":8209,"code":15686,"language":8212,"meta":5685,"style":5685},"package main\n\nimport (\n    \"fmt\"\n    \"log\"\n    \"net\u002Fsmtp\"\n)\n\nfunc main() {\n    \u002F\u002F MailHog слухає на localhost:1025 і НЕ вимагає автентифікації\n    smtpHost := \"localhost\"\n    smtpPort := \"1025\"\n    \n    from := \"test@example.com\"\n    to := []string{\"recipient@example.com\"}\n    subject := \"Тестовий лист через MailHog\"\n    body := \"Цей лист ніколи не буде надісланий у реальну мережу, але його можна переглянути в вебінтерфейсі.\"\n    \n    message := []byte(\n        \"From: \" + from + \"\\r\\n\" +\n        \"To: \" + to[0] + \"\\r\\n\" +\n        \"Subject: \" + subject + \"\\r\\n\" +\n        \"\\r\\n\" +\n        body + \"\\r\\n\",\n    )\n    \n    \u002F\u002F Без автентифікації (auth = nil)\n    err := smtp.SendMail(smtpHost+\":\"+smtpPort, nil, from, to, message)\n    if err != nil {\n        log.Fatalf(\"Помилка: %v\", err)\n    }\n    \n    fmt.Println(\"✅ Лист надіслано в MailHog!\")\n    fmt.Println(\"🌐 Переглянути: http:\u002F\u002Flocalhost:8025\")\n}\n",[5258,15688,15689,15695,15699,15705,15709,15713,15717,15721,15725,15733,15738,15747,15756,15760,15769,15783,15792,15801,15805,15815,15833,15855,15873,15883,15897,15901,15905,15910,15952,15964,15987,15991,15995,16010,16025],{"__ignoreMap":5685},[5689,15690,15691,15693],{"class":5691,"line":5692},[5689,15692,8219],{"class":7769},[5689,15694,8223],{"class":8222},[5689,15696,15697],{"class":5691,"line":5698},[5689,15698,5720],{"emptyLinePlaceholder":5719},[5689,15700,15701,15703],{"class":5691,"line":5704},[5689,15702,8232],{"class":7761},[5689,15704,8235],{"class":7765},[5689,15706,15707],{"class":5691,"line":5710},[5689,15708,8699],{"class":7829},[5689,15710,15711],{"class":5691,"line":5716},[5689,15712,8704],{"class":7829},[5689,15714,15715],{"class":5691,"line":5723},[5689,15716,13310],{"class":7829},[5689,15718,15719],{"class":5691,"line":5729},[5689,15720,8250],{"class":7765},[5689,15722,15723],{"class":5691,"line":5735},[5689,15724,5720],{"emptyLinePlaceholder":5719},[5689,15726,15727,15729,15731],{"class":5691,"line":5741},[5689,15728,8265],{"class":7769},[5689,15730,8729],{"class":8268},[5689,15732,8732],{"class":7765},[5689,15734,15735],{"class":5691,"line":5747},[5689,15736,15737],{"class":8259},"    \u002F\u002F MailHog слухає на localhost:1025 і НЕ вимагає автентифікації\n",[5689,15739,15740,15742,15744],{"class":5691,"line":5753},[5689,15741,13336],{"class":8275},[5689,15743,8357],{"class":7765},[5689,15745,15746],{"class":7829},"\"localhost\"\n",[5689,15748,15749,15751,15753],{"class":5691,"line":5758},[5689,15750,13346],{"class":8275},[5689,15752,8357],{"class":7765},[5689,15754,15755],{"class":7829},"\"1025\"\n",[5689,15757,15758],{"class":5691,"line":5764},[5689,15759,6330],{"class":7765},[5689,15761,15762,15764,15766],{"class":5691,"line":5770},[5689,15763,13388],{"class":8275},[5689,15765,8357],{"class":7765},[5689,15767,15768],{"class":7829},"\"test@example.com\"\n",[5689,15770,15771,15773,15775,15777,15779,15781],{"class":5691,"line":5776},[5689,15772,13398],{"class":8275},[5689,15774,13401],{"class":7765},[5689,15776,10659],{"class":8222},[5689,15778,13406],{"class":7765},[5689,15780,13409],{"class":7829},[5689,15782,5750],{"class":7765},[5689,15784,15785,15787,15789],{"class":5691,"line":5781},[5689,15786,13416],{"class":8275},[5689,15788,8357],{"class":7765},[5689,15790,15791],{"class":7829},"\"Тестовий лист через MailHog\"\n",[5689,15793,15794,15796,15798],{"class":5691,"line":5786},[5689,15795,13426],{"class":8275},[5689,15797,8357],{"class":7765},[5689,15799,15800],{"class":7829},"\"Цей лист ніколи не буде надісланий у реальну мережу, але його можна переглянути в вебінтерфейсі.\"\n",[5689,15802,15803],{"class":5691,"line":5792},[5689,15804,6330],{"class":7765},[5689,15806,15807,15809,15811,15813],{"class":5691,"line":5798},[5689,15808,13445],{"class":8275},[5689,15810,13401],{"class":7765},[5689,15812,13450],{"class":8222},[5689,15814,13453],{"class":7765},[5689,15816,15817,15819,15821,15823,15825,15827,15829,15831],{"class":5691,"line":5804},[5689,15818,13458],{"class":7829},[5689,15820,8482],{"class":7765},[5689,15822,13463],{"class":8275},[5689,15824,8482],{"class":7765},[5689,15826,8914],{"class":7829},[5689,15828,11896],{"class":8954},[5689,15830,8914],{"class":7829},[5689,15832,13474],{"class":7765},[5689,15834,15835,15837,15839,15841,15843,15845,15847,15849,15851,15853],{"class":5691,"line":5809},[5689,15836,13479],{"class":7829},[5689,15838,8482],{"class":7765},[5689,15840,13484],{"class":8275},[5689,15842,10656],{"class":7765},[5689,15844,6113],{"class":7776},[5689,15846,13491],{"class":7765},[5689,15848,8914],{"class":7829},[5689,15850,11896],{"class":8954},[5689,15852,8914],{"class":7829},[5689,15854,13474],{"class":7765},[5689,15856,15857,15859,15861,15863,15865,15867,15869,15871],{"class":5691,"line":5814},[5689,15858,13504],{"class":7829},[5689,15860,8482],{"class":7765},[5689,15862,13509],{"class":8275},[5689,15864,8482],{"class":7765},[5689,15866,8914],{"class":7829},[5689,15868,11896],{"class":8954},[5689,15870,8914],{"class":7829},[5689,15872,13474],{"class":7765},[5689,15874,15875,15877,15879,15881],{"class":5691,"line":5820},[5689,15876,13524],{"class":7829},[5689,15878,11896],{"class":8954},[5689,15880,8914],{"class":7829},[5689,15882,13474],{"class":7765},[5689,15884,15885,15887,15889,15891,15893,15895],{"class":5691,"line":5826},[5689,15886,13535],{"class":8275},[5689,15888,8482],{"class":7765},[5689,15890,8914],{"class":7829},[5689,15892,11896],{"class":8954},[5689,15894,8914],{"class":7829},[5689,15896,9234],{"class":7765},[5689,15898,15899],{"class":5691,"line":5832},[5689,15900,13550],{"class":7765},[5689,15902,15903],{"class":5691,"line":5838},[5689,15904,6330],{"class":7765},[5689,15906,15907],{"class":5691,"line":5843},[5689,15908,15909],{"class":8259},"    \u002F\u002F Без автентифікації (auth = nil)\n",[5689,15911,15912,15914,15916,15918,15920,15922,15924,15926,15928,15930,15932,15934,15936,15938,15940,15942,15944,15946,15948,15950],{"class":5691,"line":5848},[5689,15913,13610],{"class":8275},[5689,15915,8357],{"class":7765},[5689,15917,13569],{"class":8275},[5689,15919,5261],{"class":7765},[5689,15921,13619],{"class":8268},[5689,15923,8272],{"class":7765},[5689,15925,13594],{"class":8275},[5689,15927,12598],{"class":7765},[5689,15929,13631],{"class":7829},[5689,15931,12598],{"class":7765},[5689,15933,13636],{"class":8275},[5689,15935,5225],{"class":7765},[5689,15937,8886],{"class":7769},[5689,15939,5225],{"class":7765},[5689,15941,13463],{"class":8275},[5689,15943,5225],{"class":7765},[5689,15945,13484],{"class":8275},[5689,15947,5225],{"class":7765},[5689,15949,14833],{"class":8275},[5689,15951,8250],{"class":7765},[5689,15953,15954,15956,15958,15960,15962],{"class":5691,"line":5854},[5689,15955,8877],{"class":7761},[5689,15957,8880],{"class":8275},[5689,15959,8883],{"class":7765},[5689,15961,8886],{"class":7769},[5689,15963,8303],{"class":7765},[5689,15965,15966,15968,15970,15972,15974,15977,15979,15981,15983,15985],{"class":5691,"line":5860},[5689,15967,8893],{"class":8275},[5689,15969,5261],{"class":7765},[5689,15971,8898],{"class":8268},[5689,15973,8272],{"class":7765},[5689,15975,15976],{"class":7829},"\"Помилка: ",[5689,15978,8911],{"class":8275},[5689,15980,8914],{"class":7829},[5689,15982,5225],{"class":7765},[5689,15984,8850],{"class":8275},[5689,15986,8250],{"class":7765},[5689,15988,15989],{"class":5691,"line":5866},[5689,15990,6325],{"class":7765},[5689,15992,15993],{"class":5691,"line":5871},[5689,15994,6330],{"class":7765},[5689,15996,15997,15999,16001,16003,16005,16008],{"class":5691,"line":5877},[5689,15998,8937],{"class":8275},[5689,16000,5261],{"class":7765},[5689,16002,13726],{"class":8268},[5689,16004,8272],{"class":7765},[5689,16006,16007],{"class":7829},"\"✅ Лист надіслано в MailHog!\"",[5689,16009,8250],{"class":7765},[5689,16011,16012,16014,16016,16018,16020,16023],{"class":5691,"line":5883},[5689,16013,8937],{"class":8275},[5689,16015,5261],{"class":7765},[5689,16017,13726],{"class":8268},[5689,16019,8272],{"class":7765},[5689,16021,16022],{"class":7829},"\"🌐 Переглянути: http:\u002F\u002Flocalhost:8025\"",[5689,16024,8250],{"class":7765},[5689,16026,16027],{"class":5691,"line":5889},[5689,16028,5750],{"class":7765},[5373,16030,16031,16032,16035],{},"Після запуску програми відкрийте браузер на адресі ",[5258,16033,16034],{},"http:\u002F\u002Flocalhost:8025"," — ви побачите отриманий лист у красивому інтерфейсі з можливістю перегляду вихідного коду (включно з усіма MIME-заголовками), що надзвичайно зручно для налагодження.",[5373,16037,16038],{},[5669,16039],{"alt":16040,"className":16041,"src":16042},"Вебінтерфейс поштового сервера MailHog із перехопленими повідомленнями",[5673],"\u002Fimages\u002Fclient-server-architecture\u002Fdns-smtp-application-protocols\u002F04.png",[5444,16044,16046],{"id":16045},"mailpit-як-сучасна-заміна-mailhog","Mailpit як сучасна заміна MailHog",[5373,16048,16049,16050,16053],{},"Для більш вимогливих проєктів, інтеграційного тестування та щоденної розробки індустріальним стандартом став ",[5205,16051,16052],{},"Mailpit"," — сучасний, швидкий та легковаговий емулятор електронної пошти на Go, створений як пряма заміна застарілому MailHog. Mailpit активно розвивається, зберігає історію листів у вбудованій базі даних SQLite, підтримує перевірку спам-рейтингу (SpamAssassin), має темну тему, повноцінне REST API та потужний веб-інтерфейс із вкладками перегляду HTML-розмітки, текстової версії, аналізу сирого MIME та попереднього перегляду вкладень (зображення, PDF тощо).",[5373,16055,16056],{},[5205,16057,16058],{},"Запуск Mailpit через Docker:",[5680,16060,16062],{"className":14976,"code":16061,"language":14978,"meta":5685,"style":5685},"docker run -d \\\n  --name mailpit \\\n  -p 1025:1025 \\\n  -p 8025:8025 \\\n  axllent\u002Fmailpit\n",[5258,16063,16064,16074,16083,16091,16099],{"__ignoreMap":5685},[5689,16065,16066,16068,16070,16072],{"class":5691,"line":5692},[5689,16067,15635],{"class":8268},[5689,16069,15638],{"class":7829},[5689,16071,15641],{"class":7769},[5689,16073,15644],{"class":8954},[5689,16075,16076,16078,16081],{"class":5691,"line":5698},[5689,16077,15649],{"class":7769},[5689,16079,16080],{"class":7829}," mailpit",[5689,16082,15644],{"class":8954},[5689,16084,16085,16087,16089],{"class":5691,"line":5704},[5689,16086,15659],{"class":7769},[5689,16088,15662],{"class":7829},[5689,16090,15644],{"class":8954},[5689,16092,16093,16095,16097],{"class":5691,"line":5710},[5689,16094,15659],{"class":7769},[5689,16096,15671],{"class":7829},[5689,16098,15644],{"class":8954},[5689,16100,16101],{"class":5691,"line":5716},[5689,16102,16103],{"class":7829},"  axllent\u002Fmailpit\n",[5373,16105,16106],{},[5669,16107],{"alt":16108,"className":16109,"src":16110},"Сучасний вебінтерфейс тестування електронної пошти Mailpit",[5673],"\u002Fimages\u002Fclient-server-architecture\u002Fdns-smtp-application-protocols\u002F05.png",[5365,16112],{},[5368,16114,16116],{"id":16115},"інтеграція-dns-та-smtp-у-клієнт-серверній-архітектурі","Інтеграція DNS та SMTP у клієнт-серверній архітектурі",[5373,16118,16119,16120,16123],{},"Тепер, коли ми детально розібрали обидва протоколи окремо, важливо усвідомити, як вони ",[5205,16121,16122],{},"взаємодіють у реальних клієнт-серверних системах",". Розглянемо типовий сценарій: мобільний застосунок на React Native дозволяє користувачеві скинути пароль через електронну пошту.",[5444,16125,16127],{"id":16126},"архітектура-системи-скидання-пароля","Архітектура системи скидання пароля",[5676,16129,16131],{"alt":16130},"Повний цикл DNS + SMTP для відправки листа скидання пароля",[5680,16132,16134],{"className":5682,"code":16133,"language":5684,"meta":5685,"style":5685},"@startuml\nskinparam style plain\nskinparam backgroundColor #FFFFFF\nautonumber\n\nactor \"Користувач\\n(мобільний додаток)\" as User #DBEAFE\nparticipant \"Go Backend API\\napi.company.com\" as API #DCFCE7\nparticipant \"DNS Resolver\" as DNS #FEF3C7\nparticipant \"SMTP Server\\nsmtp.gmail.com\" as SMTP #E2E8F0\nparticipant \"Gmail MTA\" as Gmail #FEE2E2\nparticipant \"Поштова скринька\\nuser@gmail.com\" as Mailbox #DBEAFE\n\nUser -> API : POST \u002Fapi\u002Fv1\u002Fauth\u002Freset-password\\n{\"email\": \"user@gmail.com\"}\n\nAPI -> API : Генерує токен скидання пароля\\nзберігає в Redis із TTL 15 хвилин\n\nAPI -> DNS : LookupMX(\"gmail.com\")\nDNS -> API : MX: smtp.gmail.com (пріоритет 10)\n\nAPI -> DNS : LookupHost(\"smtp.gmail.com\")\nDNS -> API : A: 142.250.185.108\n\nAPI -> SMTP : TCP-з'єднання на 142.250.185.108:587\nSMTP -> API : 220 smtp.gmail.com готовий\n\nAPI -> SMTP : EHLO api.company.com\nSMTP -> API : 250-Hello, 250 STARTTLS\n\nAPI -> SMTP : STARTTLS\nnote over API, SMTP #FEF3C7\n  TLS-рукостискання, канал зашифрований 🔒\nend note\n\nAPI -> SMTP : MAIL FROM:\u003Cnoreply@company.com>\nSMTP -> API : 250 OK\n\nAPI -> SMTP : RCPT TO:\u003Cuser@gmail.com>\nSMTP -> API : 250 Accepted\n\nAPI -> SMTP : DATA\nSMTP -> API : 354 Start mail input\n\nAPI -> SMTP : Subject: Скидання пароля\\n...\\nПосилання: https:\u002F\u002Fcompany.com\u002Freset?token=xyz\\n.\nSMTP -> API : 250 Message queued (ID: abc123)\n\nAPI -> User : HTTP 200 OK\\n{\"message\": \"Лист надіслано\"}\n\nSMTP -> Gmail : Передача листа через SMTP-relay\nGmail -> Mailbox : Доставка в поштову скриньку\n\nnote over User, Mailbox #DCFCE7\n  Користувач отримує лист із посиланням\n  для скидання пароля\nend note\n@enduml\n",[5258,16135,16136,16140,16144,16148,16152,16156,16161,16166,16171,16176,16181,16186,16190,16195,16199,16204,16208,16213,16218,16222,16227,16232,16236,16241,16246,16250,16255,16260,16264,16269,16274,16279,16283,16287,16292,16297,16301,16306,16311,16315,16320,16325,16329,16334,16339,16343,16348,16352,16357,16362,16366,16371,16376,16381,16385],{"__ignoreMap":5685},[5689,16137,16138],{"class":5691,"line":5692},[5689,16139,5695],{},[5689,16141,16142],{"class":5691,"line":5698},[5689,16143,5701],{},[5689,16145,16146],{"class":5691,"line":5704},[5689,16147,5707],{},[5689,16149,16150],{"class":5691,"line":5710},[5689,16151,7495],{},[5689,16153,16154],{"class":5691,"line":5716},[5689,16155,5720],{"emptyLinePlaceholder":5719},[5689,16157,16158],{"class":5691,"line":5723},[5689,16159,16160],{},"actor \"Користувач\\n(мобільний додаток)\" as User #DBEAFE\n",[5689,16162,16163],{"class":5691,"line":5729},[5689,16164,16165],{},"participant \"Go Backend API\\napi.company.com\" as API #DCFCE7\n",[5689,16167,16168],{"class":5691,"line":5735},[5689,16169,16170],{},"participant \"DNS Resolver\" as DNS #FEF3C7\n",[5689,16172,16173],{"class":5691,"line":5741},[5689,16174,16175],{},"participant \"SMTP Server\\nsmtp.gmail.com\" as SMTP #E2E8F0\n",[5689,16177,16178],{"class":5691,"line":5747},[5689,16179,16180],{},"participant \"Gmail MTA\" as Gmail #FEE2E2\n",[5689,16182,16183],{"class":5691,"line":5753},[5689,16184,16185],{},"participant \"Поштова скринька\\nuser@gmail.com\" as Mailbox #DBEAFE\n",[5689,16187,16188],{"class":5691,"line":5758},[5689,16189,5720],{"emptyLinePlaceholder":5719},[5689,16191,16192],{"class":5691,"line":5764},[5689,16193,16194],{},"User -> API : POST \u002Fapi\u002Fv1\u002Fauth\u002Freset-password\\n{\"email\": \"user@gmail.com\"}\n",[5689,16196,16197],{"class":5691,"line":5770},[5689,16198,5720],{"emptyLinePlaceholder":5719},[5689,16200,16201],{"class":5691,"line":5776},[5689,16202,16203],{},"API -> API : Генерує токен скидання пароля\\nзберігає в Redis із TTL 15 хвилин\n",[5689,16205,16206],{"class":5691,"line":5781},[5689,16207,5720],{"emptyLinePlaceholder":5719},[5689,16209,16210],{"class":5691,"line":5786},[5689,16211,16212],{},"API -> DNS : LookupMX(\"gmail.com\")\n",[5689,16214,16215],{"class":5691,"line":5792},[5689,16216,16217],{},"DNS -> API : MX: smtp.gmail.com (пріоритет 10)\n",[5689,16219,16220],{"class":5691,"line":5798},[5689,16221,5720],{"emptyLinePlaceholder":5719},[5689,16223,16224],{"class":5691,"line":5804},[5689,16225,16226],{},"API -> DNS : LookupHost(\"smtp.gmail.com\")\n",[5689,16228,16229],{"class":5691,"line":5809},[5689,16230,16231],{},"DNS -> API : A: 142.250.185.108\n",[5689,16233,16234],{"class":5691,"line":5814},[5689,16235,5720],{"emptyLinePlaceholder":5719},[5689,16237,16238],{"class":5691,"line":5820},[5689,16239,16240],{},"API -> SMTP : TCP-з'єднання на 142.250.185.108:587\n",[5689,16242,16243],{"class":5691,"line":5826},[5689,16244,16245],{},"SMTP -> API : 220 smtp.gmail.com готовий\n",[5689,16247,16248],{"class":5691,"line":5832},[5689,16249,5720],{"emptyLinePlaceholder":5719},[5689,16251,16252],{"class":5691,"line":5838},[5689,16253,16254],{},"API -> SMTP : EHLO api.company.com\n",[5689,16256,16257],{"class":5691,"line":5843},[5689,16258,16259],{},"SMTP -> API : 250-Hello, 250 STARTTLS\n",[5689,16261,16262],{"class":5691,"line":5848},[5689,16263,5720],{"emptyLinePlaceholder":5719},[5689,16265,16266],{"class":5691,"line":5854},[5689,16267,16268],{},"API -> SMTP : STARTTLS\n",[5689,16270,16271],{"class":5691,"line":5860},[5689,16272,16273],{},"note over API, SMTP #FEF3C7\n",[5689,16275,16276],{"class":5691,"line":5866},[5689,16277,16278],{},"  TLS-рукостискання, канал зашифрований 🔒\n",[5689,16280,16281],{"class":5691,"line":5871},[5689,16282,5892],{},[5689,16284,16285],{"class":5691,"line":5877},[5689,16286,5720],{"emptyLinePlaceholder":5719},[5689,16288,16289],{"class":5691,"line":5883},[5689,16290,16291],{},"API -> SMTP : MAIL FROM:\u003Cnoreply@company.com>\n",[5689,16293,16294],{"class":5691,"line":5889},[5689,16295,16296],{},"SMTP -> API : 250 OK\n",[5689,16298,16299],{"class":5691,"line":5895},[5689,16300,5720],{"emptyLinePlaceholder":5719},[5689,16302,16303],{"class":5691,"line":9945},[5689,16304,16305],{},"API -> SMTP : RCPT TO:\u003Cuser@gmail.com>\n",[5689,16307,16308],{"class":5691,"line":10427},[5689,16309,16310],{},"SMTP -> API : 250 Accepted\n",[5689,16312,16313],{"class":5691,"line":10452},[5689,16314,5720],{"emptyLinePlaceholder":5719},[5689,16316,16317],{"class":5691,"line":10461},[5689,16318,16319],{},"API -> SMTP : DATA\n",[5689,16321,16322],{"class":5691,"line":10485},[5689,16323,16324],{},"SMTP -> API : 354 Start mail input\n",[5689,16326,16327],{"class":5691,"line":10490},[5689,16328,5720],{"emptyLinePlaceholder":5719},[5689,16330,16331],{"class":5691,"line":10496},[5689,16332,16333],{},"API -> SMTP : Subject: Скидання пароля\\n...\\nПосилання: https:\u002F\u002Fcompany.com\u002Freset?token=xyz\\n.\n",[5689,16335,16336],{"class":5691,"line":10501},[5689,16337,16338],{},"SMTP -> API : 250 Message queued (ID: abc123)\n",[5689,16340,16341],{"class":5691,"line":10506},[5689,16342,5720],{"emptyLinePlaceholder":5719},[5689,16344,16345],{"class":5691,"line":10533},[5689,16346,16347],{},"API -> User : HTTP 200 OK\\n{\"message\": \"Лист надіслано\"}\n",[5689,16349,16350],{"class":5691,"line":11097},[5689,16351,5720],{"emptyLinePlaceholder":5719},[5689,16353,16354],{"class":5691,"line":11103},[5689,16355,16356],{},"SMTP -> Gmail : Передача листа через SMTP-relay\n",[5689,16358,16359],{"class":5691,"line":11119},[5689,16360,16361],{},"Gmail -> Mailbox : Доставка в поштову скриньку\n",[5689,16363,16364],{"class":5691,"line":11139},[5689,16365,5720],{"emptyLinePlaceholder":5719},[5689,16367,16368],{"class":5691,"line":11152},[5689,16369,16370],{},"note over User, Mailbox #DCFCE7\n",[5689,16372,16373],{"class":5691,"line":11177},[5689,16374,16375],{},"  Користувач отримує лист із посиланням\n",[5689,16377,16378],{"class":5691,"line":11182},[5689,16379,16380],{},"  для скидання пароля\n",[5689,16382,16383],{"class":5691,"line":11198},[5689,16384,5892],{},[5689,16386,16387],{"class":5691,"line":11203},[5689,16388,5898],{},[5444,16390,16392],{"id":16391},"ключові-моменти-інтеграції","Ключові моменти інтеграції",[5552,16394,16395,16401,16407,16413],{},[5201,16396,16397,16400],{},[5205,16398,16399],{},"DNS є обов'язковим кроком перед SMTP:"," Go-бекенд не може просто «надіслати лист на gmail.com» — спочатку він виконує MX-запит, щоб дізнатися, який поштовий сервер відповідає за цей домен, потім виконує A\u002FAAAA-запит для отримання IP-адреси цього сервера.",[5201,16402,16403,16406],{},[5205,16404,16405],{},"Кешування DNS-відповідей:"," якщо ваш сервіс надсилає тисячі листів на день, критично важливо кешувати DNS-відповіді (як ми обговорювали раніше), щоб не виконувати окремий MX-запит для кожного листа.",[5201,16408,16409,16412],{},[5205,16410,16411],{},"Обробка помилок на кожному рівні:"," DNS може повернути NXDOMAIN (домен не існує), SMTP-сервер може повернути 550 (поштова скринька не існує) або 421 (тимчасово недоступний). Ваш Go-бекенд повинен коректно інтерпретувати ці помилки та відповідно інформувати клієнтський застосунок.",[5201,16414,16415,16418,16419,16422],{},[5205,16416,16417],{},"Асинхронна обробка:"," надсилання електронної пошти — це відносно повільна операція (встановлення TCP-з'єднання, TLS-рукостискання, передача даних), яка може зайняти кілька секунд. У production-системах листи зазвичай ставляться в ",[5205,16420,16421],{},"чергу фонових завдань"," (наприклад, Redis Queue або RabbitMQ), а фоновий воркер обробляє їх асинхронно, не блокуючи HTTP-запит від клієнта.",[6869,16424,16425,16429],{},[6872,16426,16428],{"icon":6874,"label":16427},"❓ Чому не можна просто використовувати жорстко прописану IP-адресу SMTP-сервера замість DNS-резолвінгу?","IP-адреси серверів можуть змінюватися (особливо у хмарних інфраструктурах на кшталт AWS, Azure, Google Cloud), а домени можуть мати кілька MX-записів із різними пріоритетами для забезпечення відмовостійкості. Якщо основний поштовий сервер недоступний, ви повинні автоматично звернутися до резервного. Крім того, DNS-кешування (як на рівні ОС, так і на рівні застосунку) робить резолвінг надзвичайно швидким — зазвичай менше мілісекунди для закешованих записів.",[6872,16430,16432,16435,16453],{"icon":6874,"label":16431},"❓ Що робити, якщо користувач вказав неіснуючу поштову адресу при реєстрації?",[5373,16433,16434],{},"Існує два підходи:",[5552,16436,16437,16443],{},[5201,16438,16439,16442],{},[5205,16440,16441],{},"Оптимістична верифікація:"," відправити лист із посиланням для підтвердження та дозволити користувачу користуватися сервісом обмежено до підтвердження. Якщо SMTP-сервер поверне 550 (поштова скринька не існує), записати це у лог і позначити облік ування як непідтверджений.",[5201,16444,16445,16448,16449,16452],{},[5205,16446,16447],{},"Попередня перевірка через SMTP VRFY:"," деякі SMTP-сервери підтримують команду ",[5258,16450,16451],{},"VRFY",", яка дозволяє перевірити існування поштової скриньки без фактичного надсилання листа. Проте багато сучасних серверів (включно з Gmail) відключили цю команду через ризики збору адрес спамерами, тому цей підхід не завжди працює.",[5373,16454,16455],{},"Найкраща практика — комбінувати оптимістичну відправку з моніторингом bounce-повідомлень (листів про невдалу доставку), які надсилають SMTP-сервери у разі помилок.",[5365,16457],{},[5368,16459,16461],{"id":16460},"підсумки-ключові-висновки-та-практичні-рекомендації","Підсумки: ключові висновки та практичні рекомендації",[5373,16463,16464,16465,5430,16468,16470],{},"У цій лекції ми детально розібрали два фундаментальні протоколи прикладного рівня — ",[5205,16466,16467],{},"DNS",[5205,16469,5278],{},", які є невід'ємною частиною будь-якої сучасної клієнт-серверної архітектури. Підсумуємо найважливіші концепції та практичні поради для розробників.",[5444,16472,16474],{"id":16473},"dns-критична-інфраструктура-про-яку-легко-забути","DNS — критична інфраструктура, про яку легко забути",[5198,16476,16477,16483,16489,16495],{},[5201,16478,16479,16482],{},[5205,16480,16481],{},"DNS є набагато більшим, ніж просто «телефонна книга інтернету»:"," це розподілена база даних, яка зберігає метаінформацію про мережеві сервіси (MX-записи для пошти, SRV-записи для виявлення сервісів, TXT-записи для верифікації та політик безпеки).",[5201,16484,16485,16488],{},[5205,16486,16487],{},"Завжди обробляйте DNS-помилки коректно:"," розрізняйте постійні помилки (NXDOMAIN — домен не існує) і тимчасові (SERVFAIL, таймаут). Використовуйте експоненційну затримку для повторних спроб у разі тимчасових збоїв.",[5201,16490,16491,16494],{},[5205,16492,16493],{},"Кешуйте DNS-відповіді відповідально:"," поважайте TTL, встановлені адміністраторами доменів, але реалізуйте власний кеш на рівні застосунку для високонавантажених сценаріїв.",[5201,16496,16497,16500],{},[5205,16498,16499],{},"Підтримуйте dual-stack (IPv4 + IPv6):"," сучасні застосунки повинні виконувати паралельні запити A та AAAA та намагатися підключитися через обидва протоколи (Happy Eyeballs).",[5444,16502,16504],{"id":16503},"smtp-більше-ніж-просто-надсилання-текстових-повідомлень","SMTP — більше, ніж просто надсилання текстових повідомлень",[5198,16506,16507,16513,16519,16525,16531],{},[5201,16508,16509,16512],{},[5205,16510,16511],{},"Розуміння архітектури пошти критично важливе:"," знання різниці між MSA (submission), MTA (relay) та MDA (delivery) допомагає діагностувати проблеми доставки та правильно налаштовувати інфраструктуру.",[5201,16514,16515,16518],{},[5205,16516,16517],{},"Завжди використовуйте STARTTLS для захисту даних:"," передача паролів автентифікації та вмісту листів через незашифроване з'єднання є неприпустимою практикою в сучасних системах.",[5201,16520,16521,16524],{},[5205,16522,16523],{},"Впроваджуйте SPF, DKIM та DMARC:"," без цих механізмів захисту ваші листи з високою ймовірністю потраплятимуть у спам або відхилятимуться поштовими серверами отримувачів.",[5201,16526,16527,16530],{},[5205,16528,16529],{},"Формуйте MIME-повідомлення коректно:"," неправильна структура багатокомпонентних листів (відсутність boundary, некоректне кодування Base64, відсутність заголовків Content-Type) призводить до того, що листи відображаються як нечитабельний текст або вкладення не відкриваються.",[5201,16532,16533,16536],{},[5205,16534,16535],{},"Тестуйте локально через MailHog\u002FMailpit:"," ніколи не налагоджуйте функціональність пошти безпосередньо на production-серверах або через реальні поштові скриньки.",[5444,16538,16540],{"id":16539},"інтеграція-в-go-застосунках","Інтеграція в Go-застосунках",[5373,16542,16543],{},"Стандартна бібліотека Go надає потужні та мінімалістичні інструменти для роботи з обома протоколами:",[5198,16545,16546,16553],{},[5201,16547,16548,16552],{},[5205,16549,16550],{},[5258,16551,5267],{}," для DNS-резолвінгу з підтримкою кастомних серверів, таймаутів та контекстів скасування.",[5201,16554,16555,16559],{},[5205,16556,16557],{},[5258,16558,5305],{}," для надсилання листів із підтримкою автентифікації та TLS.",[5373,16561,16562,16563,16566],{},"Для production-систем зазвичай використовуються ",[5205,16564,16565],{},"асинхронні черги завдань"," (Redis Queue, RabbitMQ) для обробки надсилання листів у фоновому режимі, щоб не блокувати HTTP-запити від клієнтів. Розгорнутий приклад такої архітектури ми розглянемо в наступних лекціях, присвячених асинхронному обміну повідомленнями.",[5421,16568,16569,16572],{},[5205,16570,16571],{},"Зв'язок із наступними темами:"," у лекціях 10–12 ми вивчатимо шарувату архітектуру бекенд-систем, фреймворк Gin та автоматичну валідацію даних — ці знання дозволять побудувати повноцінний REST API для керування користувачами з функціональністю реєстрації, автентифікації JWT та відправки листів підтвердження. У лекціях 16–17 ми розглянемо черги повідомлень (RabbitMQ, MQTT) для організації надійної асинхронної обробки фонових завдань, включно з масовою розсилкою листів та обробкою bounce-повідомлень.",[5365,16574],{},[5368,16576,16578],{"id":16577},"контрольні-запитання-для-самоперевірки","Контрольні запитання для самоперевірки",[6869,16580,16581,16596,16600,16608,16632],{},[6872,16582,16584,16590],{"icon":6874,"label":16583},"❓ Яка різниця між рекурсивним та ітеративним DNS-резолвінгом?",[5373,16585,16586,16589],{},[5205,16587,16588],{},"Рекурсивний резолвінг:"," клієнт надсилає один запит до рекурсивного DNS-сервера (зазвичай сервер інтернет-провайдера або публічний резолвер на кшталт 8.8.8.8), який бере на себе відповідальність за виконання всього ланцюжка запитів (до кореневих серверів, TLD-серверів, авторитетних серверів) та повертає клієнту готову відповідь — IP-адресу або помилку.",[5373,16591,16592,16595],{},[5205,16593,16594],{},"Ітеративний резолвінг:"," клієнт сам виконує кожен крок: спочатку запитує кореневий сервер, який повертає адреси TLD-серверів; потім запитує TLD-сервер, який повертає адреси авторитетних серверів зони; нарешті запитує авторитетний сервер і отримує кінцеву відповідь. Цей підхід рідко використовується звичайними клієнтами через складність, але саме так працюють рекурсивні резолвери «під капотом».",[6872,16597,16599],{"icon":6874,"label":16598},"❓ Чому CNAME-записи не можуть співіснувати з іншими типами записів для того самого імені?","Згідно зі специфікацією RFC 1034, якщо доменне ім'я є CNAME (аліасом), усі запити до цього імені повинні бути перенаправлені на канонічне ім'я, і будь-які інші типи записів (A, MX, TXT) для цього імені втрачають сенс. Наявність CNAME і, наприклад, A-запису для одного імені створювала б неоднозначність: який запис вважати правильним? Саме тому стандарт забороняє таке змішування. Для кореневих доменів, де потрібні як CNAME-подібна поведінка, так і інші записи (наприклад, MX для пошти), деякі DNS-провайдери пропонують нестандартні розширення на кшталт ALIAS або ANAME, які працюють на рівні DNS-сервера, а не на рівні протоколу.",[6872,16601,16603,16604,16607],{"icon":6874,"label":16602},"❓ Що станеться, якщо SMTP-клієнт надішле команду DATA без попередніх MAIL FROM і RCPT TO?","SMTP-сервер відхилить команду DATA з кодом помилки ",[5205,16605,16606],{},"503 Bad sequence of commands"," або подібним. Протокол SMTP вимагає чіткої послідовності команд: спочатку HELO\u002FEHLO (представлення), потім MAIL FROM (адреса відправника), потім щонайменше один RCPT TO (адреса отримувача), і лише після цього DATA (передача вмісту). Порушення цієї послідовності призводить до відхилення транзакції. Це частина захисту від неправильно реалізованих клієнтів і автоматизованих систем спаму.",[6872,16609,16611,16622],{"icon":6874,"label":16610},"❓ Чому Base64-кодування збільшує розмір файлів на ~33%, і чи можна це якось оптимізувати?",[5373,16612,16613,16614,16617,16618,16621],{},"Base64 перетворює кожні ",[5205,16615,16616],{},"3 байти"," бінарних даних у ",[5205,16619,16620],{},"4 символи"," ASCII (оскільки 2^6 = 64 можливих символів, а кожен символ Base64 кодує 6 біт інформації). Отже, 3 байти = 24 біти перетворюються на 4 × 6 = 24 біти у вигляді 4 символів ASCII. Але кожен ASCII-символ займає 1 байт (8 біт) при передачі, тому 3 байти вихідних даних перетворюються на 4 байти закодованих даних: (4 \u002F 3 - 1) × 100% ≈ 33% збільшення.",[5373,16623,16624,16627,16628,16631],{},[5205,16625,16626],{},"Чи можна оптимізувати?"," Ні, якщо ви обмежені текстовим протоколом SMTP. Але існують альтернативи: наприклад, замість вкладення великих файлів у лист можна надіслати ",[5205,16629,16630],{},"посилання для завантаження"," (file upload link) на хмарне сховище (AWS S3, Google Cloud Storage), де файл зберігається в оригінальному бінарному форматі без зайвих накладних витрат.",[6872,16633,16635,16638],{"icon":6874,"label":16634},"❓ Як захистити SMTP-сервер від використання його для масового розсилання спаму?",[5373,16636,16637],{},"Основні механізми захисту:",[5552,16639,16640,16646,16652,16658,16664,16670],{},[5201,16641,16642,16645],{},[5205,16643,16644],{},"Автентифікація на порту 587 (MSA):"," вимагати логін\u002Fпароль перед прийняттям листів від клієнтів.",[5201,16647,16648,16651],{},[5205,16649,16650],{},"Rate Limiting:"," обмежувати кількість листів, які один користувач може надіслати за одиницю часу (наприклад, не більше 100 листів на годину).",[5201,16653,16654,16657],{},[5205,16655,16656],{},"SPF, DKIM, DMARC:"," перевіряти вхідні листи на відповідність цим стандартам і відхиляти підозрілі.",[5201,16659,16660,16663],{},[5205,16661,16662],{},"IP-репутація та чорні списки (DNSBL):"," автоматично перевіряти IP-адреси відправників за базами відомих джерел спаму (Spamhaus, Barracuda).",[5201,16665,16666,16669],{},[5205,16667,16668],{},"Greylisting:"," тимчасово відхиляти листи від невідомих відправників (код 4xx) і приймати їх лише при повторній спробі через кілька хвилин (легітимні сервери повторюють спробу, спамери зазвичай ні).",[5201,16671,16672,16675],{},[5205,16673,16674],{},"Контент-фільтри:"," аналізувати текст та заголовки листів за допомогою систем на кшталт SpamAssassin або навчених ML-моделей.",[5365,16677],{},[5368,16679,16681],{"id":16680},"рекомендована-література-та-джерела-для-поглибленого-вивчення","Рекомендована література та джерела для поглибленого вивчення",[5444,16683,16685],{"id":16684},"специфікації-rfc-офіційні-стандарти-ietf","Специфікації RFC (офіційні стандарти IETF)",[5198,16687,16688,16694,16700,16706,16712,16718,16724,16730,16736],{},[5201,16689,16690,16693],{},[5205,16691,16692],{},"RFC 1034, RFC 1035:"," Domain Names — Concepts and Facilities; Implementation and Specification (оригінальні специфікації DNS, 1987).",[5201,16695,16696,16699],{},[5205,16697,16698],{},"RFC 8499:"," DNS Terminology (сучасний глосарій термінів DNS, 2019).",[5201,16701,16702,16705],{},[5205,16703,16704],{},"RFC 5321:"," Simple Mail Transfer Protocol (оновлена специфікація SMTP, 2008).",[5201,16707,16708,16711],{},[5205,16709,16710],{},"RFC 5322:"," Internet Message Format (формат заголовків електронної пошти).",[5201,16713,16714,16717],{},[5205,16715,16716],{},"RFC 2045–2049:"," Multipurpose Internet Mail Extensions (MIME) (п'ять документів, що визначають структуру MIME-повідомлень).",[5201,16719,16720,16723],{},[5205,16721,16722],{},"RFC 7208:"," Sender Policy Framework (SPF) for Authorizing Use of Domains in Email.",[5201,16725,16726,16729],{},[5205,16727,16728],{},"RFC 6376:"," DomainKeys Identified Mail (DKIM) Signatures.",[5201,16731,16732,16735],{},[5205,16733,16734],{},"RFC 7489:"," Domain-based Message Authentication, Reporting, and Conformance (DMARC).",[5201,16737,16738,16741],{},[5205,16739,16740],{},"RFC 3207:"," SMTP Service Extension for Secure SMTP over TLS (STARTTLS).",[5444,16743,16745],{"id":16744},"книги-та-навчальні-ресурси","Книги та навчальні ресурси",[5198,16747,16748,16757,16766],{},[5201,16749,16750,5323,16753,16756],{},[5205,16751,16752],{},"Kurose J. F., Ross K. W.",[5408,16754,16755],{},"Computer Networking: A Top-Down Approach."," 8th Edition. Pearson, 2021. (Розділи 2.4–2.5: DNS та електронна пошта).",[5201,16758,16759,5323,16762,16765],{},[5205,16760,16761],{},"Liu C., Albitz P.",[5408,16763,16764],{},"DNS and BIND."," 5th Edition. O'Reilly Media, 2006. (Поглиблене вивчення адміністрування DNS-серверів).",[5201,16767,16768,5323,16771,16777,16778,5225,16780,5225,16782,5225,16784,5980],{},[5205,16769,16770],{},"Офіційна документація Go:",[16772,16773,16774],"a",{"href":16774,"rel":16775},"https:\u002F\u002Fpkg.go.dev\u002Fnet",[16776],"nofollow"," (пакети ",[5258,16779,5326],{},[5258,16781,5305],{},[5258,16783,5331],{},[5258,16785,5334],{},[5444,16787,16789],{"id":16788},"інструменти-діагностики-та-тестування","Інструменти діагностики та тестування",[5198,16791,16792,16801,16807,16816,16825],{},[5201,16793,16794,5346,16796,5346,16798,16800],{},[5205,16795,5345],{},[5205,16797,5349],{},[5205,16799,5352],{}," — консольні утиліти для виконання DNS-запитів вручну.",[5201,16802,16803,16806],{},[5205,16804,16805],{},"Wireshark:"," аналіз DNS та SMTP-трафіку на рівні пакетів.",[5201,16808,16809,5323,16812],{},[5205,16810,16811],{},"MailHog:",[16772,16813,16814],{"href":16814,"rel":16815},"https:\u002F\u002Fgithub.com\u002Fmailhog\u002FMailHog",[16776],[5201,16817,16818,5323,16821],{},[5205,16819,16820],{},"Mailpit:",[16772,16822,16823],{"href":16823,"rel":16824},"https:\u002F\u002Fgithub.com\u002Faxllent\u002Fmailpit",[16776],[5201,16826,16827,5323,16830,16834],{},[5205,16828,16829],{},"MXToolbox:",[16772,16831,16832],{"href":16832,"rel":16833},"https:\u002F\u002Fmxtoolbox.com",[16776]," — онлайн-інструменти для перевірки MX-записів, SPF, DKIM, DMARC та репутації поштових серверів.",[5365,16836],{},[5190,16838,16839,16877],{},[5193,16840,16843,16846],{"icon":16841,"title":16842},"i-lucide-check-circle","✅ Результати навчання",[5373,16844,16845],{},"Після опрацювання цієї лекції ви здатні:",[5198,16847,16848,16851,16856,16859,16862,16865,16868,16871],{},[5201,16849,16850],{},"Пояснити ієрархічну структуру DNS та процес рекурсивного резолвінгу від кореневих серверів до авторитетних.",[5201,16852,16853,16854,5261],{},"Програмно виконувати DNS-запити різних типів (A, AAAA, MX, TXT, SRV) через Go-пакет ",[5258,16855,5267],{},[5201,16857,16858],{},"Розбирати формат DNS-повідомлень та інтерпретувати коди відповідей.",[5201,16860,16861],{},"Розуміти архітектуру електронної пошти та роль компонентів MSA, MTA, MDA.",[5201,16863,16864],{},"Створювати SMTP-з'єднання, виконувати рукостискання та коректно обробляти коди відповідей сервера.",[5201,16866,16867],{},"Формувати багатокомпонентні MIME-повідомлення з HTML-вмістом і Base64-вкладеннями.",[5201,16869,16870],{},"Налаштовувати механізми захисту пошти (SPF, DKIM, DMARC, STARTTLS).",[5201,16872,16873,16874,16876],{},"Надсилати електронні листи через Go-пакет ",[5258,16875,5305],{}," з автентифікацією та шифруванням.",[5193,16878,16881],{"icon":16879,"title":16880},"i-lucide-link","🔗 Зв'язок із наступними темами",[5198,16882,16883,16889,16895,16901],{},[5201,16884,16885,16888],{},[5205,16886,16887],{},"Лекція 8:"," Протокол HTTP та стандартний вебсервер Go — розглянемо, як HTTP-клієнти спираються на DNS для резолвінгу доменних імен API-серверів.",[5201,16890,16891,16894],{},[5205,16892,16893],{},"Лекція 10:"," Шарувата архітектура та конвеєри обробки запитів — інтеграція функціональності надсилання листів у Clean Architecture.",[5201,16896,16897,16900],{},[5205,16898,16899],{},"Лекція 12:"," Валідація даних та документування у Gin — реалізація ендпоінтів реєстрації та скидання пароля з відправкою верифікаційних листів.",[5201,16902,16903,16906],{},[5205,16904,16905],{},"Лекція 16:"," Асинхронний обмін повідомленнями та черги — організація фонової обробки надсилання листів через RabbitMQ для масштабованості.",[16908,16909,16910],"style",{},"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 .s8xlr, html code.shiki .s8xlr{--shiki-light:#AF00DB;--shiki-default:#C586C0;--shiki-dark:#C586C0}html pre.shiki code .sHH4Y, html code.shiki .sHH4Y{--shiki-light:#000000;--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .su1O8, html code.shiki .su1O8{--shiki-light:#0000FF;--shiki-default:#569CD6;--shiki-dark:#569CD6}html pre.shiki code .sJj4R, html code.shiki .sJj4R{--shiki-light:#098658;--shiki-default:#B5CEA8;--shiki-dark:#B5CEA8}html pre.shiki code .sKtos, html code.shiki .sKtos{--shiki-light:#800000;--shiki-default:#569CD6;--shiki-dark:#569CD6}html pre.shiki code .sbdoH, html code.shiki .sbdoH{--shiki-light:#A31515;--shiki-default:#CE9178;--shiki-dark:#CE9178}html pre.shiki code .sN1BT, html code.shiki .sN1BT{--shiki-light:#267F99;--shiki-default:#4EC9B0;--shiki-dark:#4EC9B0}html pre.shiki code .spJ8K, html code.shiki .spJ8K{--shiki-light:#008000;--shiki-default:#6A9955;--shiki-dark:#6A9955}html pre.shiki code .s8Opu, html code.shiki .s8Opu{--shiki-light:#795E26;--shiki-default:#DCDCAA;--shiki-dark:#DCDCAA}html pre.shiki code .siwwj, html code.shiki .siwwj{--shiki-light:#001080;--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}html pre.shiki code .sjcCO, html code.shiki .sjcCO{--shiki-light:#EE0000;--shiki-default:#D7BA7D;--shiki-dark:#D7BA7D}",{"title":5685,"searchDepth":5698,"depth":5698,"links":16912},[16913,16916,16926,16930,16938,16951,16958,16962,16967,16972,16978,16983,16987,16991,16996,16997],{"id":5370,"depth":5698,"text":5371,"children":16914},[16915],{"id":5446,"depth":5704,"text":5447},{"id":5509,"depth":5698,"text":5510,"children":16917},[16918,16919,16920,16921,16922,16923,16924,16925],{"id":5542,"depth":5704,"text":5543},{"id":5901,"depth":5704,"text":5902},{"id":5922,"depth":5704,"text":5923},{"id":5941,"depth":5704,"text":5942},{"id":5960,"depth":5704,"text":5961},{"id":5983,"depth":5704,"text":5984},{"id":5997,"depth":5704,"text":5998},{"id":6033,"depth":5704,"text":6034},{"id":6059,"depth":5698,"text":6060,"children":16927},[16928,16929],{"id":6077,"depth":5704,"text":6078},{"id":6422,"depth":5704,"text":6423},{"id":6489,"depth":5698,"text":6490,"children":16931},[16932,16933,16934,16935,16936,16937],{"id":6545,"depth":5704,"text":6546},{"id":6589,"depth":5704,"text":6590},{"id":6637,"depth":5704,"text":6638},{"id":6705,"depth":5704,"text":6706},{"id":6761,"depth":5704,"text":6762},{"id":6824,"depth":5704,"text":6825},{"id":6889,"depth":5698,"text":6890,"children":16939},[16940,16941,16942,16943,16944,16945,16946,16947,16948,16949,16950],{"id":6922,"depth":5704,"text":6923},{"id":7051,"depth":5704,"text":7052},{"id":7289,"depth":5704,"text":7290},{"id":7380,"depth":5704,"text":7381},{"id":7406,"depth":5704,"text":7407},{"id":7423,"depth":5704,"text":7424},{"id":7440,"depth":5704,"text":7441},{"id":7461,"depth":5704,"text":7462},{"id":7619,"depth":5704,"text":7620},{"id":7738,"depth":5704,"text":7739},{"id":7880,"depth":5704,"text":7881},{"id":8640,"depth":5698,"text":8641,"children":16952},[16953,16954,16955,16956,16957],{"id":8664,"depth":5704,"text":8665},{"id":9044,"depth":5704,"text":9045},{"id":9506,"depth":5704,"text":9507},{"id":9961,"depth":5704,"text":9962},{"id":10556,"depth":5704,"text":10557},{"id":11560,"depth":5698,"text":11561,"children":16959},[16960,16961],{"id":11599,"depth":5704,"text":11600},{"id":11829,"depth":5704,"text":11830},{"id":11874,"depth":5698,"text":11875,"children":16963},[16964,16965,16966],{"id":11902,"depth":5704,"text":11903},{"id":11993,"depth":5704,"text":11994},{"id":12098,"depth":5704,"text":12099},{"id":12368,"depth":5698,"text":12369,"children":16968},[16969,16970,16971],{"id":12385,"depth":5704,"text":12386},{"id":12501,"depth":5704,"text":12502},{"id":12578,"depth":5704,"text":12579},{"id":12939,"depth":5698,"text":12940,"children":16973},[16974,16975,16976,16977],{"id":13083,"depth":5704,"text":13084},{"id":13144,"depth":5704,"text":13145},{"id":13189,"depth":5704,"text":13190},{"id":13237,"depth":5704,"text":13238},{"id":13263,"depth":5698,"text":13264,"children":16979},[16980,16981,16982],{"id":13275,"depth":5704,"text":13276},{"id":13754,"depth":5704,"text":13755},{"id":14906,"depth":5704,"text":14907},{"id":15602,"depth":5698,"text":15603,"children":16984},[16985,16986],{"id":15613,"depth":5704,"text":15614},{"id":16045,"depth":5704,"text":16046},{"id":16115,"depth":5698,"text":16116,"children":16988},[16989,16990],{"id":16126,"depth":5704,"text":16127},{"id":16391,"depth":5704,"text":16392},{"id":16460,"depth":5698,"text":16461,"children":16992},[16993,16994,16995],{"id":16473,"depth":5704,"text":16474},{"id":16503,"depth":5704,"text":16504},{"id":16539,"depth":5704,"text":16540},{"id":16577,"depth":5698,"text":16578},{"id":16680,"depth":5698,"text":16681,"children":16998},[16999,17000,17001],{"id":16684,"depth":5704,"text":16685},{"id":16744,"depth":5704,"text":16745},{"id":16788,"depth":5704,"text":16789},"Детальний розгляд фундаментальних протоколів прикладного рівня: DNS як основа інфраструктури імен в інтернеті (ієрархія доменів, формат DNS-повідомлень, типи записів A\u002FAAAA\u002FCNAME\u002FMX\u002FTXT\u002FSRV, проблема CNAME на Zone Apex, механізми CNAME Flattening та RFC 9460 HTTPS\u002FSVCB для роботи без www, резолвінг у Go через net.Resolver) та SMTP як стандарт електронної пошти (архітектура поштових систем, команди та коди відповідей, формат MIME, багатокомпонентні листи Multipart, вкладення файлів Base64, захист пошти STARTTLS\u002FSPF\u002FDKIM\u002FDMARC, надсилання через пакет net\u002Fsmtp).","md",null,{},{"title":4013,"description":17002},"ldBUUikmdx9QBRMIxXa2-ffpUItpWhAgzF_-7dhZAB0",[17009,17011],{"title":4009,"path":4010,"stem":4011,"description":17010,"children":-1},"Повний розгляд криптографічних основ захисту мережевих комунікацій мовою Go: доступне пояснення симетричного та асиметричного шифрування на прикладі листування, хеш-функції та цифрові підписи, протокол TLS 1.3 із детальним розбором фаз рукостискання та захисту від атак Man-in-the-Middle, інфраструктура відкритих ключів (PKI) та сертифікати X.509, центри сертифікації (CA), пакет crypto\u002Ftls для створення захищених серверів і клієнтів, взаємна автентифікація (mTLS) та модель Zero Trust на прикладі корпоративного мікросервісу.",{"title":4017,"path":4018,"stem":4019,"description":17012,"children":-1},"Еволюція протоколу HTTP від версії 1.0 до HTTP\u002F3 з транспортом QUIC, детальний розбір анатомії HTTP-запитів та відповідей (методи, статус-коди, заголовки, тіло), принципи ідемпотентності та безпеки методів, стандартний пакет net\u002Fhttp у Go (інтерфейс http.Handler, роутер http.ServeMux, кастомний http.Server), налаштування таймаутів, TLS та обробка потокових даних.",1791986743033]