[{"data":1,"prerenderedAt":14710},["ShallowReactive",2],{"navigation_docs":3,"-client-server-architecture-streaming-data-and-websockets":5180,"-client-server-architecture-streaming-data-and-websockets-surround":14705},[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":4041,"body":5182,"description":14699,"extension":14700,"links":14701,"meta":14702,"navigation":5487,"path":4042,"seo":14703,"stem":4043,"__hash__":14704},"docs\u002F17.client-server-architecture\u002F14.streaming-data-and-websockets.md",{"type":5183,"value":5184,"toc":14653},"minimark",[5185,5189,5265,5268,5273,5278,5293,5300,5311,5321,5328,5332,5342,5351,5361,5371,5375,5377,5381,5385,5396,5407,5428,5438,5441,5650,5654,5661,6673,6678,6694,6712,6730,6740,6758,6772,6780,6788,6792,6795,6809,6815,6824,6830,6835,6861,6865,6868,7020,7027,7029,7033,7037,7048,7055,7058,7077,7283,7287,7293,7298,7382,7387,7414,7419,7425,7471,7489,7495,7500,7503,7507,7520,7526,7531,7638,7645,7649,7652,7658,7664,7673,7690,7695,7706,7713,7715,7719,7723,7739,7742,7769,7773,7779,8197,8204,8215,8236,8321,8343,8347,8364,8668,8673,8698,8703,8728,8742,8746,8753,9231,9236,9248,9262,9270,9277,9281,9287,9896,9901,9934,9937,9939,9943,9947,9964,9971,9975,9978,10009,10191,10195,11810,11815,11828,11847,11856,11871,11893,11908,11924,11937,11941,11950,13004,13009,13114,13117,13119,13123,13127,13140,13559,13563,13570,13576,13955,13959,13964,14215,14217,14221,14224,14321,14323,14327,14399,14401,14405,14482,14484,14488,14536,14649],[5186,5187,4041],"h1",{"id":5188},"потокова-передача-даних-та-протокол-websocket",[5190,5191,5192,5221],"card-group",{},[5193,5194,5197],"card",{"icon":5195,"title":5196},"i-lucide-target","🎯 Мета лекції",[5198,5199,5200,5204,5207,5210,5218],"ul",{},[5201,5202,5203],"li",{},"Зрозуміти фундаментальну потребу у двосторонній комунікації між клієнтом та сервером у реальному часі.",[5201,5205,5206],{},"Опанувати технологію Server-Sent Events (SSE) як однонапрямлений канал потокової доставки подій.",[5201,5208,5209],{},"Вивчити протокол WebSocket (RFC 6455), його архітектуру, процедуру встановлення з'єднання та структуру фреймів.",[5201,5211,5212,5213,5217],{},"Навчитися реалізовувати WebSocket-сервери у Go із використанням бібліотеки ",[5214,5215,5216],"code",{},"gorilla\u002Fwebsocket",".",[5201,5219,5220],{},"Впровадити архітектурні патерни Hub, Broadcasting та Room Management для масштабованої обробки з'єднань.",[5193,5222,5224],{"icon":4618,"title":5223},"🔑 Ключові терміни",[5198,5225,5226,5233,5239,5245,5256],{},[5201,5227,5228,5232],{},[5229,5230,5231],"strong",{},"Server-Sent Events (SSE):"," однонапрямлена технологія потокової доставки подій від сервера до клієнта через довготривале HTTP-з'єднання.",[5201,5234,5235,5238],{},[5229,5236,5237],{},"WebSocket:"," повнодуплексний протокол обміну даними поверх одного TCP-з'єднання, що забезпечує низьку затримку та мінімальні накладні витрати.",[5201,5240,5241,5244],{},[5229,5242,5243],{},"Upgrade Handshake:"," процедура переведення звичайного HTTP-з'єднання у WebSocket-режим через обмін спеціальними заголовками.",[5201,5246,5247,5250,5251,5255],{},[5229,5248,5249],{},"Frame:"," атомарна одиниця передачі даних у протоколі WebSocket, що містить метадані (тип, маскування) та корисне навантаження (",[5252,5253,5254],"em",{},"payload",").",[5201,5257,5258,5261,5262,5255],{},[5229,5259,5260],{},"Hub Pattern:"," централізований диспетчер, що координує реєстрацію, відключення клієнтів та широкомовну розсилку повідомлень (",[5252,5263,5264],{},"broadcast",[5266,5267],"hr",{},[5269,5270,5272],"h2",{"id":5271},"архітектурний-контекст-та-еволюція-комунікаційних-підходів","Архітектурний контекст та еволюція комунікаційних підходів",[5274,5275,5277],"h3",{"id":5276},"обмеження-класичної-моделі-запит-відповідь","Обмеження класичної моделі «запит-відповідь»",[5279,5280,5281,5282,5285,5286,5289,5290,5217],"p",{},"Традиційна архітектура вебзастосунків побудована навколо моделі ",[5229,5283,5284],{},"HTTP запит-відповідь"," (",[5252,5287,5288],{},"request-response","). Клієнт ініціює комунікацію, надсилаючи HTTP-запит до сервера, після чого сервер формує відповідь і закриває з'єднання. Ця модель є ідемпотентною, простою у розумінні та підтримці, однак вона має фундаментальне обмеження: ",[5229,5291,5292],{},"сервер не може самостійно ініціювати передачу даних до клієнта",[5279,5294,5295,5296,5299],{},"У типовому REST API клієнт повинен періодично опитувати сервер (",[5252,5297,5298],{},"polling","), надсилаючи запити через фіксовані інтервали часу, щоб перевірити наявність нових даних. Наприклад, для відображення оновлень чату, цін на біржі або статусу обробки завдання, клієнт може виконувати запит кожні 3–5 секунд. Такий підхід призводить до кількох критичних проблем.",[5279,5301,5302,5303,5306,5307,5310],{},"По-перше, ",[5229,5304,5305],{},"неефективне використання мережевих ресурсів та обчислювальних потужностей",". Кожен опитуючий запит вимагає встановлення TCP-з'єднання (якщо не використовується HTTP\u002F2 або постійні з'єднання ",[5252,5308,5309],{},"keep-alive","), обробки на сервері, серіалізації відповіді та передачі через мережу — навіть якщо нових даних немає. При зростанні кількості підключених клієнтів навантаження на сервер зростає лінійно, незалежно від наявності подій, що вимагають доставки.",[5279,5312,5313,5314,5285,5317,5320],{},"По-друге, ",[5229,5315,5316],{},"висока затримка доставки інформації",[5252,5318,5319],{},"latency","). Якщо подія відбулася на сервері одразу після чергового опитування, клієнт дізнається про неї лише через проміжок часу, що дорівнює інтервалу опитування. Зменшення інтервалу до 1–2 секунд різко збільшує навантаження на інфраструктуру, але все одно не гарантує миттєвого отримання даних.",[5279,5322,5323,5324,5327],{},"По-третє, ",[5229,5325,5326],{},"складність масштабування та моніторингу",". У сценарії тисяч одночасних клієнтів, кожен із яких виконує опитування кожні 3 секунди, сервер отримує сотні тисяч порожніх запитів на годину. Відстеження реального трафіку та діагностика проблем стають значно складнішими.",[5274,5329,5331],{"id":5330},"класифікація-технологій-реального-часу","Класифікація технологій реального часу",[5279,5333,5334,5335,5285,5338,5341],{},"Для розв'язання цих проблем інженери створили кілька підходів до організації ",[5229,5336,5337],{},"комунікації у реальному часі",[5252,5339,5340],{},"real-time communication","). Розглянемо еволюцію цих технологій.",[5279,5343,5344,5347,5348,5350],{},[5229,5345,5346],{},"1. Long Polling (Довге опитування)."," Клієнт надсилає HTTP-запит, але сервер не закриває з'єднання одразу, а тримає його відкритим до появи нових даних або спливу таймауту (наприклад, 30–60 секунд). Після отримання відповіді клієнт негайно надсилає новий запит. Цей підхід зменшує затримку порівняно з класичним ",[5252,5349,5298],{},", але збільшує складність обробки на сервері, оскільки потрібно керувати тисячами відкритих з'єднань, які фактично чекають події.",[5279,5352,5353,5356,5357,5360],{},[5229,5354,5355],{},"2. Server-Sent Events (SSE)."," Стандарт HTML5, що дозволяє серверу надсилати потік текстових повідомлень клієнту через єдине довготривале HTTP-з'єднання. SSE є ",[5229,5358,5359],{},"однонапрямленим каналом"," (сервер → клієнт), що робить його простим у реалізації та придатним для сценаріїв, де клієнт лише споживає оновлення без необхідності відправляти дані назад у тому ж каналі. Приклади використання: стрічки новин, фінансові котирування, системні логи.",[5279,5362,5363,5366,5367,5370],{},[5229,5364,5365],{},"3. WebSocket."," Повнодуплексний протокол, що забезпечує ",[5229,5368,5369],{},"двосторонній обмін даними"," між клієнтом та сервером через одне TCP-з'єднання. На відміну від SSE, WebSocket дозволяє як клієнту, так і серверу надсилати повідомлення у будь-який момент без обмежень. Протокол має надзвичайно низькі накладні витрати (фрейм лише 2–14 байтів метаданих) та підтримує передачу як текстових, так і бінарних даних. WebSocket є оптимальним рішенням для інтерактивних застосунків: чати, онлайн-ігри, спільна робота над документами, відеоконференції.",[5372,5373,5374],"note",{},"Вибір між SSE та WebSocket залежить від вимог до напрямку комунікації. Якщо клієнту потрібно лише отримувати оновлення, SSE є простішим та ефективнішим рішенням. Якщо потрібна інтерактивна двостороння взаємодія з мінімальною затримкою, WebSocket є єдиною адекватною альтернативою.",[5266,5376],{},[5269,5378,5380],{"id":5379},"технологія-server-sent-events-sse-однонапрямлений-потік-подій","Технологія Server-Sent Events (SSE): однонапрямлений потік подій",[5274,5382,5384],{"id":5383},"архітектура-протоколу-sse","Архітектура протоколу SSE",[5279,5386,5387,5388,5391,5392,5395],{},"Server-Sent Events (",[5252,5389,5390],{},"SSE",") представляє собою стандарт HTML5, що визначає формат передачі потоку подій від сервера до клієнта через звичайне HTTP-з'єднання. Фізично SSE є довготривалим HTTP-відповіддю (",[5252,5393,5394],{},"long-lived HTTP response","), у якій сервер періодично надсилає нові дані без закриття з'єднання.",[5279,5397,5398,5399,5402,5403,5406],{},"Ключовою особливістю SSE є те, що з'єднання встановлюється за допомогою звичайного HTTP-запиту методом ",[5214,5400,5401],{},"GET",", тому воно легко проходить через проксі-сервери, балансувальники навантаження та корпоративні брандмауери, які можуть блокувати нестандартні протоколи. Браузери підтримують SSE нативно через JavaScript API ",[5214,5404,5405],{},"EventSource",", що автоматично обробляє повторне підключення у разі розриву з'єднання.",[5279,5408,5409,5410,5413,5414,5413,5417,5413,5420,5423,5424,5427],{},"Формат повідомлень SSE є текстовим та регламентований специфікацією. Кожна подія складається з одного або кількох рядків, що починаються з ключових слів ",[5214,5411,5412],{},"data:",", ",[5214,5415,5416],{},"event:",[5214,5418,5419],{},"id:",[5214,5421,5422],{},"retry:",". Повідомлення відокремлюються подвійним символом нового рядка (",[5214,5425,5426],{},"\\n\\n","). Наприклад:",[5429,5430,5435],"pre",{"className":5431,"code":5433,"language":5434},[5432],"language-text","data: {\"user\": \"alice\", \"message\": \"Hello, world!\"}\n\nevent: priceUpdate\ndata: {\"symbol\": \"BTC\u002FUSD\", \"price\": 64250.30}\nid: 42\n\n","text",[5214,5436,5433],{"__ignoreMap":5437},"",[5279,5439,5440],{},"Клієнтський код у браузері виглядає надзвичайно просто:",[5429,5442,5446],{"className":5443,"code":5444,"language":5445,"meta":5437,"style":5437},"language-javascript shiki shiki-themes light-plus dark-plus dark-plus","const eventSource = new EventSource('\u002Fapi\u002Fv1\u002Fevents');\n\neventSource.onmessage = (event) => {\n    const data = JSON.parse(event.data);\n    console.log('Received:', data);\n};\n\neventSource.addEventListener('priceUpdate', (event) => {\n    const price = JSON.parse(event.data);\n    updatePriceOnUI(price);\n});\n","javascript",[5214,5447,5448,5482,5489,5516,5546,5568,5574,5579,5605,5631,5644],{"__ignoreMap":5437},[5449,5450,5453,5457,5461,5465,5468,5472,5475,5479],"span",{"class":5451,"line":5452},"line",1,[5449,5454,5456],{"class":5455},"su1O8","const",[5449,5458,5460],{"class":5459},"s-QsJ"," eventSource",[5449,5462,5464],{"class":5463},"sHH4Y"," = ",[5449,5466,5467],{"class":5455},"new",[5449,5469,5471],{"class":5470},"s8Opu"," EventSource",[5449,5473,5474],{"class":5463},"(",[5449,5476,5478],{"class":5477},"sbdoH","'\u002Fapi\u002Fv1\u002Fevents'",[5449,5480,5481],{"class":5463},");\n",[5449,5483,5485],{"class":5451,"line":5484},2,[5449,5486,5488],{"emptyLinePlaceholder":5487},true,"\n",[5449,5490,5492,5496,5498,5501,5504,5507,5510,5513],{"class":5451,"line":5491},3,[5449,5493,5495],{"class":5494},"siwwj","eventSource",[5449,5497,5217],{"class":5463},[5449,5499,5500],{"class":5470},"onmessage",[5449,5502,5503],{"class":5463}," = (",[5449,5505,5506],{"class":5494},"event",[5449,5508,5509],{"class":5463},") ",[5449,5511,5512],{"class":5455},"=>",[5449,5514,5515],{"class":5463}," {\n",[5449,5517,5519,5522,5525,5527,5530,5532,5535,5537,5539,5541,5544],{"class":5451,"line":5518},4,[5449,5520,5521],{"class":5455},"    const",[5449,5523,5524],{"class":5459}," data",[5449,5526,5464],{"class":5463},[5449,5528,5529],{"class":5459},"JSON",[5449,5531,5217],{"class":5463},[5449,5533,5534],{"class":5470},"parse",[5449,5536,5474],{"class":5463},[5449,5538,5506],{"class":5494},[5449,5540,5217],{"class":5463},[5449,5542,5543],{"class":5494},"data",[5449,5545,5481],{"class":5463},[5449,5547,5549,5552,5554,5557,5559,5562,5564,5566],{"class":5451,"line":5548},5,[5449,5550,5551],{"class":5494},"    console",[5449,5553,5217],{"class":5463},[5449,5555,5556],{"class":5470},"log",[5449,5558,5474],{"class":5463},[5449,5560,5561],{"class":5477},"'Received:'",[5449,5563,5413],{"class":5463},[5449,5565,5543],{"class":5494},[5449,5567,5481],{"class":5463},[5449,5569,5571],{"class":5451,"line":5570},6,[5449,5572,5573],{"class":5463},"};\n",[5449,5575,5577],{"class":5451,"line":5576},7,[5449,5578,5488],{"emptyLinePlaceholder":5487},[5449,5580,5582,5584,5586,5589,5591,5594,5597,5599,5601,5603],{"class":5451,"line":5581},8,[5449,5583,5495],{"class":5494},[5449,5585,5217],{"class":5463},[5449,5587,5588],{"class":5470},"addEventListener",[5449,5590,5474],{"class":5463},[5449,5592,5593],{"class":5477},"'priceUpdate'",[5449,5595,5596],{"class":5463},", (",[5449,5598,5506],{"class":5494},[5449,5600,5509],{"class":5463},[5449,5602,5512],{"class":5455},[5449,5604,5515],{"class":5463},[5449,5606,5608,5610,5613,5615,5617,5619,5621,5623,5625,5627,5629],{"class":5451,"line":5607},9,[5449,5609,5521],{"class":5455},[5449,5611,5612],{"class":5459}," price",[5449,5614,5464],{"class":5463},[5449,5616,5529],{"class":5459},[5449,5618,5217],{"class":5463},[5449,5620,5534],{"class":5470},[5449,5622,5474],{"class":5463},[5449,5624,5506],{"class":5494},[5449,5626,5217],{"class":5463},[5449,5628,5543],{"class":5494},[5449,5630,5481],{"class":5463},[5449,5632,5634,5637,5639,5642],{"class":5451,"line":5633},10,[5449,5635,5636],{"class":5470},"    updatePriceOnUI",[5449,5638,5474],{"class":5463},[5449,5640,5641],{"class":5494},"price",[5449,5643,5481],{"class":5463},[5449,5645,5647],{"class":5451,"line":5646},11,[5449,5648,5649],{"class":5463},"});\n",[5274,5651,5653],{"id":5652},"реалізація-sse-ендпоінту-у-go","Реалізація SSE-ендпоінту у Go",[5279,5655,5656,5657,5660],{},"Для реалізації SSE-сервера в Go необхідно використати інтерфейс ",[5214,5658,5659],{},"http.Flusher",", що дозволяє примусово скидати дані з буферів запису в клієнтське з'єднання без закриття відповіді. Розглянемо повну реалізацію ендпоінту, що транслює системні метрики кожні 2 секунди.",[5429,5662,5666],{"className":5663,"code":5664,"language":5665,"meta":5437,"style":5437},"language-go shiki shiki-themes light-plus dark-plus dark-plus","package main\n\nimport (\n    \"encoding\u002Fjson\"\n    \"fmt\"\n    \"log\"\n    \"net\u002Fhttp\"\n    \"runtime\"\n    \"time\"\n)\n\ntype SystemMetric struct {\n    Timestamp   int64  `json:\"timestamp\"`\n    Goroutines  int    `json:\"goroutines\"`\n    MemoryUsage uint64 `json:\"memory_mb\"`\n}\n\nfunc sseMetricsHandler(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F Перевіряємо підтримку Flusher (критично для SSE)\n    flusher, ok := w.(http.Flusher)\n    if !ok {\n        http.Error(w, \"SSE not supported\", http.StatusInternalServerError)\n        return\n    }\n\n    \u002F\u002F Встановлюємо заголовки для SSE-потоку\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    w.Header().Set(\"Access-Control-Allow-Origin\", \"*\")\n\n    log.Printf(\"SSE client connected: %s\", r.RemoteAddr)\n\n    \u002F\u002F Канал для сигналу завершення (розрив з'єднання клієнтом)\n    ctx := r.Context()\n    ticker := time.NewTicker(2 * time.Second)\n    defer ticker.Stop()\n\n    for {\n        select {\n        case \u003C-ctx.Done():\n            \u002F\u002F Клієнт закрив з'єднання\n            log.Printf(\"SSE client disconnected: %s\", r.RemoteAddr)\n            return\n\n        case \u003C-ticker.C:\n            \u002F\u002F Збираємо поточні метрики системи\n            var memStats runtime.MemStats\n            runtime.ReadMemStats(&memStats)\n\n            metric := SystemMetric{\n                Timestamp:   time.Now().Unix(),\n                Goroutines:  runtime.NumGoroutine(),\n                MemoryUsage: memStats.Alloc \u002F 1024 \u002F 1024, \u002F\u002F Конвертуємо у МБ\n            }\n\n            data, _ := json.Marshal(metric)\n\n            \u002F\u002F Форматуємо повідомлення згідно зі специфікацією SSE\n            _, err := fmt.Fprintf(w, \"data: %s\\n\\n\", data)\n            if err != nil {\n                log.Printf(\"Failed to write SSE data: %v\", err)\n                return\n            }\n\n            \u002F\u002F Примусово скидаємо буфер у мережу\n            flusher.Flush()\n        }\n    }\n}\n\nfunc main() {\n    http.HandleFunc(\"\u002Fmetrics\u002Fstream\", sseMetricsHandler)\n    log.Println(\"SSE server listening on :8080\")\n    log.Fatal(http.ListenAndServe(\":8080\", nil))\n}\n","go",[5214,5667,5668,5677,5681,5690,5695,5700,5705,5710,5715,5720,5725,5729,5743,5755,5767,5779,5785,5790,5831,5838,5866,5879,5910,5916,5922,5927,5933,5962,5987,6012,6037,6042,6075,6080,6086,6104,6138,6154,6159,6167,6175,6195,6201,6230,6236,6241,6259,6265,6282,6301,6306,6320,6344,6363,6394,6400,6405,6433,6438,6444,6487,6504,6530,6536,6541,6546,6552,6565,6571,6576,6581,6586,6597,6620,6637,6668],{"__ignoreMap":5437},[5449,5669,5670,5673],{"class":5451,"line":5452},[5449,5671,5672],{"class":5455},"package",[5449,5674,5676],{"class":5675},"sN1BT"," main\n",[5449,5678,5679],{"class":5451,"line":5484},[5449,5680,5488],{"emptyLinePlaceholder":5487},[5449,5682,5683,5687],{"class":5451,"line":5491},[5449,5684,5686],{"class":5685},"s8xlr","import",[5449,5688,5689],{"class":5463}," (\n",[5449,5691,5692],{"class":5451,"line":5518},[5449,5693,5694],{"class":5477},"    \"encoding\u002Fjson\"\n",[5449,5696,5697],{"class":5451,"line":5548},[5449,5698,5699],{"class":5477},"    \"fmt\"\n",[5449,5701,5702],{"class":5451,"line":5570},[5449,5703,5704],{"class":5477},"    \"log\"\n",[5449,5706,5707],{"class":5451,"line":5576},[5449,5708,5709],{"class":5477},"    \"net\u002Fhttp\"\n",[5449,5711,5712],{"class":5451,"line":5581},[5449,5713,5714],{"class":5477},"    \"runtime\"\n",[5449,5716,5717],{"class":5451,"line":5607},[5449,5718,5719],{"class":5477},"    \"time\"\n",[5449,5721,5722],{"class":5451,"line":5633},[5449,5723,5724],{"class":5463},")\n",[5449,5726,5727],{"class":5451,"line":5646},[5449,5728,5488],{"emptyLinePlaceholder":5487},[5449,5730,5732,5735,5738,5741],{"class":5451,"line":5731},12,[5449,5733,5734],{"class":5455},"type",[5449,5736,5737],{"class":5675}," SystemMetric",[5449,5739,5740],{"class":5455}," struct",[5449,5742,5515],{"class":5463},[5449,5744,5746,5749,5752],{"class":5451,"line":5745},13,[5449,5747,5748],{"class":5494},"    Timestamp",[5449,5750,5751],{"class":5675},"   int64",[5449,5753,5754],{"class":5477},"  `json:\"timestamp\"`\n",[5449,5756,5758,5761,5764],{"class":5451,"line":5757},14,[5449,5759,5760],{"class":5494},"    Goroutines",[5449,5762,5763],{"class":5675},"  int",[5449,5765,5766],{"class":5477},"    `json:\"goroutines\"`\n",[5449,5768,5770,5773,5776],{"class":5451,"line":5769},15,[5449,5771,5772],{"class":5494},"    MemoryUsage",[5449,5774,5775],{"class":5675}," uint64",[5449,5777,5778],{"class":5477}," `json:\"memory_mb\"`\n",[5449,5780,5782],{"class":5451,"line":5781},16,[5449,5783,5784],{"class":5463},"}\n",[5449,5786,5788],{"class":5451,"line":5787},17,[5449,5789,5488],{"emptyLinePlaceholder":5487},[5449,5791,5793,5796,5799,5801,5804,5807,5809,5812,5814,5817,5820,5823,5825,5828],{"class":5451,"line":5792},18,[5449,5794,5795],{"class":5455},"func",[5449,5797,5798],{"class":5470}," sseMetricsHandler",[5449,5800,5474],{"class":5463},[5449,5802,5803],{"class":5494},"w",[5449,5805,5806],{"class":5675}," http",[5449,5808,5217],{"class":5463},[5449,5810,5811],{"class":5675},"ResponseWriter",[5449,5813,5413],{"class":5463},[5449,5815,5816],{"class":5494},"r",[5449,5818,5819],{"class":5463}," *",[5449,5821,5822],{"class":5675},"http",[5449,5824,5217],{"class":5463},[5449,5826,5827],{"class":5675},"Request",[5449,5829,5830],{"class":5463},") {\n",[5449,5832,5834],{"class":5451,"line":5833},19,[5449,5835,5837],{"class":5836},"spJ8K","    \u002F\u002F Перевіряємо підтримку Flusher (критично для SSE)\n",[5449,5839,5841,5844,5846,5849,5852,5854,5857,5859,5861,5864],{"class":5451,"line":5840},20,[5449,5842,5843],{"class":5494},"    flusher",[5449,5845,5413],{"class":5463},[5449,5847,5848],{"class":5494},"ok",[5449,5850,5851],{"class":5463}," := ",[5449,5853,5803],{"class":5494},[5449,5855,5856],{"class":5463},".(",[5449,5858,5822],{"class":5675},[5449,5860,5217],{"class":5463},[5449,5862,5863],{"class":5675},"Flusher",[5449,5865,5724],{"class":5463},[5449,5867,5869,5872,5875,5877],{"class":5451,"line":5868},21,[5449,5870,5871],{"class":5685},"    if",[5449,5873,5874],{"class":5463}," !",[5449,5876,5848],{"class":5494},[5449,5878,5515],{"class":5463},[5449,5880,5882,5885,5887,5890,5892,5894,5896,5899,5901,5903,5905,5908],{"class":5451,"line":5881},22,[5449,5883,5884],{"class":5494},"        http",[5449,5886,5217],{"class":5463},[5449,5888,5889],{"class":5470},"Error",[5449,5891,5474],{"class":5463},[5449,5893,5803],{"class":5494},[5449,5895,5413],{"class":5463},[5449,5897,5898],{"class":5477},"\"SSE not supported\"",[5449,5900,5413],{"class":5463},[5449,5902,5822],{"class":5494},[5449,5904,5217],{"class":5463},[5449,5906,5907],{"class":5494},"StatusInternalServerError",[5449,5909,5724],{"class":5463},[5449,5911,5913],{"class":5451,"line":5912},23,[5449,5914,5915],{"class":5685},"        return\n",[5449,5917,5919],{"class":5451,"line":5918},24,[5449,5920,5921],{"class":5463},"    }\n",[5449,5923,5925],{"class":5451,"line":5924},25,[5449,5926,5488],{"emptyLinePlaceholder":5487},[5449,5928,5930],{"class":5451,"line":5929},26,[5449,5931,5932],{"class":5836},"    \u002F\u002F Встановлюємо заголовки для SSE-потоку\n",[5449,5934,5936,5939,5941,5944,5947,5950,5952,5955,5957,5960],{"class":5451,"line":5935},27,[5449,5937,5938],{"class":5494},"    w",[5449,5940,5217],{"class":5463},[5449,5942,5943],{"class":5470},"Header",[5449,5945,5946],{"class":5463},"().",[5449,5948,5949],{"class":5470},"Set",[5449,5951,5474],{"class":5463},[5449,5953,5954],{"class":5477},"\"Content-Type\"",[5449,5956,5413],{"class":5463},[5449,5958,5959],{"class":5477},"\"text\u002Fevent-stream\"",[5449,5961,5724],{"class":5463},[5449,5963,5965,5967,5969,5971,5973,5975,5977,5980,5982,5985],{"class":5451,"line":5964},28,[5449,5966,5938],{"class":5494},[5449,5968,5217],{"class":5463},[5449,5970,5943],{"class":5470},[5449,5972,5946],{"class":5463},[5449,5974,5949],{"class":5470},[5449,5976,5474],{"class":5463},[5449,5978,5979],{"class":5477},"\"Cache-Control\"",[5449,5981,5413],{"class":5463},[5449,5983,5984],{"class":5477},"\"no-cache\"",[5449,5986,5724],{"class":5463},[5449,5988,5990,5992,5994,5996,5998,6000,6002,6005,6007,6010],{"class":5451,"line":5989},29,[5449,5991,5938],{"class":5494},[5449,5993,5217],{"class":5463},[5449,5995,5943],{"class":5470},[5449,5997,5946],{"class":5463},[5449,5999,5949],{"class":5470},[5449,6001,5474],{"class":5463},[5449,6003,6004],{"class":5477},"\"Connection\"",[5449,6006,5413],{"class":5463},[5449,6008,6009],{"class":5477},"\"keep-alive\"",[5449,6011,5724],{"class":5463},[5449,6013,6015,6017,6019,6021,6023,6025,6027,6030,6032,6035],{"class":5451,"line":6014},30,[5449,6016,5938],{"class":5494},[5449,6018,5217],{"class":5463},[5449,6020,5943],{"class":5470},[5449,6022,5946],{"class":5463},[5449,6024,5949],{"class":5470},[5449,6026,5474],{"class":5463},[5449,6028,6029],{"class":5477},"\"Access-Control-Allow-Origin\"",[5449,6031,5413],{"class":5463},[5449,6033,6034],{"class":5477},"\"*\"",[5449,6036,5724],{"class":5463},[5449,6038,6040],{"class":5451,"line":6039},31,[5449,6041,5488],{"emptyLinePlaceholder":5487},[5449,6043,6045,6048,6050,6053,6055,6058,6061,6064,6066,6068,6070,6073],{"class":5451,"line":6044},32,[5449,6046,6047],{"class":5494},"    log",[5449,6049,5217],{"class":5463},[5449,6051,6052],{"class":5470},"Printf",[5449,6054,5474],{"class":5463},[5449,6056,6057],{"class":5477},"\"SSE client connected: ",[5449,6059,6060],{"class":5494},"%s",[5449,6062,6063],{"class":5477},"\"",[5449,6065,5413],{"class":5463},[5449,6067,5816],{"class":5494},[5449,6069,5217],{"class":5463},[5449,6071,6072],{"class":5494},"RemoteAddr",[5449,6074,5724],{"class":5463},[5449,6076,6078],{"class":5451,"line":6077},33,[5449,6079,5488],{"emptyLinePlaceholder":5487},[5449,6081,6083],{"class":5451,"line":6082},34,[5449,6084,6085],{"class":5836},"    \u002F\u002F Канал для сигналу завершення (розрив з'єднання клієнтом)\n",[5449,6087,6089,6092,6094,6096,6098,6101],{"class":5451,"line":6088},35,[5449,6090,6091],{"class":5494},"    ctx",[5449,6093,5851],{"class":5463},[5449,6095,5816],{"class":5494},[5449,6097,5217],{"class":5463},[5449,6099,6100],{"class":5470},"Context",[5449,6102,6103],{"class":5463},"()\n",[5449,6105,6107,6110,6112,6115,6117,6120,6122,6126,6129,6131,6133,6136],{"class":5451,"line":6106},36,[5449,6108,6109],{"class":5494},"    ticker",[5449,6111,5851],{"class":5463},[5449,6113,6114],{"class":5494},"time",[5449,6116,5217],{"class":5463},[5449,6118,6119],{"class":5470},"NewTicker",[5449,6121,5474],{"class":5463},[5449,6123,6125],{"class":6124},"sJj4R","2",[5449,6127,6128],{"class":5463}," * ",[5449,6130,6114],{"class":5494},[5449,6132,5217],{"class":5463},[5449,6134,6135],{"class":5494},"Second",[5449,6137,5724],{"class":5463},[5449,6139,6141,6144,6147,6149,6152],{"class":5451,"line":6140},37,[5449,6142,6143],{"class":5685},"    defer",[5449,6145,6146],{"class":5494}," ticker",[5449,6148,5217],{"class":5463},[5449,6150,6151],{"class":5470},"Stop",[5449,6153,6103],{"class":5463},[5449,6155,6157],{"class":5451,"line":6156},38,[5449,6158,5488],{"emptyLinePlaceholder":5487},[5449,6160,6162,6165],{"class":5451,"line":6161},39,[5449,6163,6164],{"class":5685},"    for",[5449,6166,5515],{"class":5463},[5449,6168,6170,6173],{"class":5451,"line":6169},40,[5449,6171,6172],{"class":5685},"        select",[5449,6174,5515],{"class":5463},[5449,6176,6178,6181,6184,6187,6189,6192],{"class":5451,"line":6177},41,[5449,6179,6180],{"class":5685},"        case",[5449,6182,6183],{"class":5463}," \u003C-",[5449,6185,6186],{"class":5494},"ctx",[5449,6188,5217],{"class":5463},[5449,6190,6191],{"class":5470},"Done",[5449,6193,6194],{"class":5463},"():\n",[5449,6196,6198],{"class":5451,"line":6197},42,[5449,6199,6200],{"class":5836},"            \u002F\u002F Клієнт закрив з'єднання\n",[5449,6202,6204,6207,6209,6211,6213,6216,6218,6220,6222,6224,6226,6228],{"class":5451,"line":6203},43,[5449,6205,6206],{"class":5494},"            log",[5449,6208,5217],{"class":5463},[5449,6210,6052],{"class":5470},[5449,6212,5474],{"class":5463},[5449,6214,6215],{"class":5477},"\"SSE client disconnected: ",[5449,6217,6060],{"class":5494},[5449,6219,6063],{"class":5477},[5449,6221,5413],{"class":5463},[5449,6223,5816],{"class":5494},[5449,6225,5217],{"class":5463},[5449,6227,6072],{"class":5494},[5449,6229,5724],{"class":5463},[5449,6231,6233],{"class":5451,"line":6232},44,[5449,6234,6235],{"class":5685},"            return\n",[5449,6237,6239],{"class":5451,"line":6238},45,[5449,6240,5488],{"emptyLinePlaceholder":5487},[5449,6242,6244,6246,6248,6251,6253,6256],{"class":5451,"line":6243},46,[5449,6245,6180],{"class":5685},[5449,6247,6183],{"class":5463},[5449,6249,6250],{"class":5494},"ticker",[5449,6252,5217],{"class":5463},[5449,6254,6255],{"class":5494},"C",[5449,6257,6258],{"class":5463},":\n",[5449,6260,6262],{"class":5451,"line":6261},47,[5449,6263,6264],{"class":5836},"            \u002F\u002F Збираємо поточні метрики системи\n",[5449,6266,6268,6271,6274,6277,6279],{"class":5451,"line":6267},48,[5449,6269,6270],{"class":5455},"            var",[5449,6272,6273],{"class":5494}," memStats",[5449,6275,6276],{"class":5675}," runtime",[5449,6278,5217],{"class":5463},[5449,6280,6281],{"class":5675},"MemStats\n",[5449,6283,6285,6288,6290,6293,6296,6299],{"class":5451,"line":6284},49,[5449,6286,6287],{"class":5494},"            runtime",[5449,6289,5217],{"class":5463},[5449,6291,6292],{"class":5470},"ReadMemStats",[5449,6294,6295],{"class":5463},"(&",[5449,6297,6298],{"class":5494},"memStats",[5449,6300,5724],{"class":5463},[5449,6302,6304],{"class":5451,"line":6303},50,[5449,6305,5488],{"emptyLinePlaceholder":5487},[5449,6307,6309,6312,6314,6317],{"class":5451,"line":6308},51,[5449,6310,6311],{"class":5494},"            metric",[5449,6313,5851],{"class":5463},[5449,6315,6316],{"class":5675},"SystemMetric",[5449,6318,6319],{"class":5463},"{\n",[5449,6321,6323,6326,6329,6331,6333,6336,6338,6341],{"class":5451,"line":6322},52,[5449,6324,6325],{"class":5494},"                Timestamp",[5449,6327,6328],{"class":5463},":   ",[5449,6330,6114],{"class":5494},[5449,6332,5217],{"class":5463},[5449,6334,6335],{"class":5470},"Now",[5449,6337,5946],{"class":5463},[5449,6339,6340],{"class":5470},"Unix",[5449,6342,6343],{"class":5463},"(),\n",[5449,6345,6347,6350,6353,6356,6358,6361],{"class":5451,"line":6346},53,[5449,6348,6349],{"class":5494},"                Goroutines",[5449,6351,6352],{"class":5463},":  ",[5449,6354,6355],{"class":5494},"runtime",[5449,6357,5217],{"class":5463},[5449,6359,6360],{"class":5470},"NumGoroutine",[5449,6362,6343],{"class":5463},[5449,6364,6366,6369,6372,6374,6376,6379,6382,6385,6387,6389,6391],{"class":5451,"line":6365},54,[5449,6367,6368],{"class":5494},"                MemoryUsage",[5449,6370,6371],{"class":5463},": ",[5449,6373,6298],{"class":5494},[5449,6375,5217],{"class":5463},[5449,6377,6378],{"class":5494},"Alloc",[5449,6380,6381],{"class":5463}," \u002F ",[5449,6383,6384],{"class":6124},"1024",[5449,6386,6381],{"class":5463},[5449,6388,6384],{"class":6124},[5449,6390,5413],{"class":5463},[5449,6392,6393],{"class":5836},"\u002F\u002F Конвертуємо у МБ\n",[5449,6395,6397],{"class":5451,"line":6396},55,[5449,6398,6399],{"class":5463},"            }\n",[5449,6401,6403],{"class":5451,"line":6402},56,[5449,6404,5488],{"emptyLinePlaceholder":5487},[5449,6406,6408,6411,6413,6416,6418,6421,6423,6426,6428,6431],{"class":5451,"line":6407},57,[5449,6409,6410],{"class":5494},"            data",[5449,6412,5413],{"class":5463},[5449,6414,6415],{"class":5494},"_",[5449,6417,5851],{"class":5463},[5449,6419,6420],{"class":5494},"json",[5449,6422,5217],{"class":5463},[5449,6424,6425],{"class":5470},"Marshal",[5449,6427,5474],{"class":5463},[5449,6429,6430],{"class":5494},"metric",[5449,6432,5724],{"class":5463},[5449,6434,6436],{"class":5451,"line":6435},58,[5449,6437,5488],{"emptyLinePlaceholder":5487},[5449,6439,6441],{"class":5451,"line":6440},59,[5449,6442,6443],{"class":5836},"            \u002F\u002F Форматуємо повідомлення згідно зі специфікацією SSE\n",[5449,6445,6447,6450,6452,6455,6457,6460,6462,6465,6467,6469,6471,6474,6476,6479,6481,6483,6485],{"class":5451,"line":6446},60,[5449,6448,6449],{"class":5494},"            _",[5449,6451,5413],{"class":5463},[5449,6453,6454],{"class":5494},"err",[5449,6456,5851],{"class":5463},[5449,6458,6459],{"class":5494},"fmt",[5449,6461,5217],{"class":5463},[5449,6463,6464],{"class":5470},"Fprintf",[5449,6466,5474],{"class":5463},[5449,6468,5803],{"class":5494},[5449,6470,5413],{"class":5463},[5449,6472,6473],{"class":5477},"\"data: ",[5449,6475,6060],{"class":5494},[5449,6477,5426],{"class":6478},"sjcCO",[5449,6480,6063],{"class":5477},[5449,6482,5413],{"class":5463},[5449,6484,5543],{"class":5494},[5449,6486,5724],{"class":5463},[5449,6488,6490,6493,6496,6499,6502],{"class":5451,"line":6489},61,[5449,6491,6492],{"class":5685},"            if",[5449,6494,6495],{"class":5494}," err",[5449,6497,6498],{"class":5463}," != ",[5449,6500,6501],{"class":5455},"nil",[5449,6503,5515],{"class":5463},[5449,6505,6507,6510,6512,6514,6516,6519,6522,6524,6526,6528],{"class":5451,"line":6506},62,[5449,6508,6509],{"class":5494},"                log",[5449,6511,5217],{"class":5463},[5449,6513,6052],{"class":5470},[5449,6515,5474],{"class":5463},[5449,6517,6518],{"class":5477},"\"Failed to write SSE data: ",[5449,6520,6521],{"class":5494},"%v",[5449,6523,6063],{"class":5477},[5449,6525,5413],{"class":5463},[5449,6527,6454],{"class":5494},[5449,6529,5724],{"class":5463},[5449,6531,6533],{"class":5451,"line":6532},63,[5449,6534,6535],{"class":5685},"                return\n",[5449,6537,6539],{"class":5451,"line":6538},64,[5449,6540,6399],{"class":5463},[5449,6542,6544],{"class":5451,"line":6543},65,[5449,6545,5488],{"emptyLinePlaceholder":5487},[5449,6547,6549],{"class":5451,"line":6548},66,[5449,6550,6551],{"class":5836},"            \u002F\u002F Примусово скидаємо буфер у мережу\n",[5449,6553,6555,6558,6560,6563],{"class":5451,"line":6554},67,[5449,6556,6557],{"class":5494},"            flusher",[5449,6559,5217],{"class":5463},[5449,6561,6562],{"class":5470},"Flush",[5449,6564,6103],{"class":5463},[5449,6566,6568],{"class":5451,"line":6567},68,[5449,6569,6570],{"class":5463},"        }\n",[5449,6572,6574],{"class":5451,"line":6573},69,[5449,6575,5921],{"class":5463},[5449,6577,6579],{"class":5451,"line":6578},70,[5449,6580,5784],{"class":5463},[5449,6582,6584],{"class":5451,"line":6583},71,[5449,6585,5488],{"emptyLinePlaceholder":5487},[5449,6587,6589,6591,6594],{"class":5451,"line":6588},72,[5449,6590,5795],{"class":5455},[5449,6592,6593],{"class":5470}," main",[5449,6595,6596],{"class":5463},"() {\n",[5449,6598,6600,6603,6605,6608,6610,6613,6615,6618],{"class":5451,"line":6599},73,[5449,6601,6602],{"class":5494},"    http",[5449,6604,5217],{"class":5463},[5449,6606,6607],{"class":5470},"HandleFunc",[5449,6609,5474],{"class":5463},[5449,6611,6612],{"class":5477},"\"\u002Fmetrics\u002Fstream\"",[5449,6614,5413],{"class":5463},[5449,6616,6617],{"class":5494},"sseMetricsHandler",[5449,6619,5724],{"class":5463},[5449,6621,6623,6625,6627,6630,6632,6635],{"class":5451,"line":6622},74,[5449,6624,6047],{"class":5494},[5449,6626,5217],{"class":5463},[5449,6628,6629],{"class":5470},"Println",[5449,6631,5474],{"class":5463},[5449,6633,6634],{"class":5477},"\"SSE server listening on :8080\"",[5449,6636,5724],{"class":5463},[5449,6638,6640,6642,6644,6647,6649,6651,6653,6656,6658,6661,6663,6665],{"class":5451,"line":6639},75,[5449,6641,6047],{"class":5494},[5449,6643,5217],{"class":5463},[5449,6645,6646],{"class":5470},"Fatal",[5449,6648,5474],{"class":5463},[5449,6650,5822],{"class":5494},[5449,6652,5217],{"class":5463},[5449,6654,6655],{"class":5470},"ListenAndServe",[5449,6657,5474],{"class":5463},[5449,6659,6660],{"class":5477},"\":8080\"",[5449,6662,5413],{"class":5463},[5449,6664,6501],{"class":5455},[5449,6666,6667],{"class":5463},"))\n",[5449,6669,6671],{"class":5451,"line":6670},76,[5449,6672,5784],{"class":5463},[5279,6674,6675],{},[5229,6676,6677],{},"Покрокове пояснення реалізації:",[5279,6679,6680,6683,6684,6687,6688,6690,6691,6693],{},[5229,6681,6682],{},"Рядки 15–19:"," Перевіряємо, чи базовий ",[5214,6685,6686],{},"http.ResponseWriter"," реалізує інтерфейс ",[5214,6689,5659],{},". Більшість стандартних HTTP-серверів підтримують цей інтерфейс, але у разі використання спеціальних проксі-адаптерів ця перевірка є критичною. Якщо ",[5214,6692,5863],{}," недоступний, потокова передача неможлива — дані буферизуються до закриття відповіді.",[5279,6695,6696,6699,6700,6703,6704,6707,6708,6711],{},[5229,6697,6698],{},"Рядки 21–24:"," Встановлюємо обов'язкові заголовки SSE. ",[5214,6701,6702],{},"Content-Type: text\u002Fevent-stream"," сигналізує клієнту про початок потоку подій. ",[5214,6705,6706],{},"Cache-Control: no-cache"," вимикає кешування проксі-серверами та CDN, що є критичним для даних реального часу. ",[5214,6709,6710],{},"Connection: keep-alive"," інструктує проміжні вузли зберігати з'єднання відкритим.",[5279,6713,6714,6717,6718,6721,6722,6725,6726,6729],{},[5229,6715,6716],{},"Рядки 28–30:"," Отримуємо об'єкт ",[5214,6719,6720],{},"context.Context"," із запиту. Цей контекст автоматично скасовується (",[5252,6723,6724],{},"canceled","), коли клієнт закриває з'єднання або браузер закривається. Створюємо періодичний таймер ",[5214,6727,6728],{},"time.Ticker",", що генерує подію кожні 2 секунди.",[5279,6731,6732,6735,6736,6739],{},[5229,6733,6734],{},"Рядок 34:"," Канал ",[5214,6737,6738],{},"ctx.Done()"," закривається у момент, коли клієнт розриває з'єднання. У цьому випадку обробник завершує роботу, звільняючи горутину та пов'язані ресурси.",[5279,6741,6742,6745,6746,6749,6750,6753,6754,6757],{},[5229,6743,6744],{},"Рядки 39–45:"," Формуємо об'єкт метрики із поточною кількістю горутин та використаної пам'яті. Функція ",[5214,6747,6748],{},"runtime.NumGoroutine()"," повертає кількість активних горутин у процесі, а ",[5214,6751,6752],{},"runtime.ReadMemStats()"," заповнює структуру детальною інформацією про стан купи (",[5252,6755,6756],{},"heap","). Ці дані корисні для моніторингу стану серверного застосунку в реальному часі.",[5279,6759,6760,6763,6764,6767,6768,6771],{},[5229,6761,6762],{},"Рядки 49–55:"," Серіалізуємо метрику у JSON та записуємо у відповідь у форматі SSE: ",[5214,6765,6766],{},"data: {...}\\n\\n",". Символ подвійного перенесення рядка є обов'язковим роздільником повідомлень. Після запису викликаємо ",[5214,6769,6770],{},"flusher.Flush()",", що гарантує негайну відправку даних без затримки у буферах ОС чи мережевого стека.",[6773,6774,6775,6776,6779],"tip",{},"Завжди викликайте ",[5214,6777,6778],{},"Flush()"," після запису кожного SSE-повідомлення. Без цього виклику дані можуть затримуватися у буферах ядра TCP на секунди або навіть хвилини, що робить комунікацію у «реальному часі» марною.",[6781,6782,6783,6784,6787],"warning",{},"SSE використовує звичайні HTTP-з'єднання, тому кількість одночасних SSE-потоків обмежена ресурсами операційної системи (дескриптори файлів, обмеження планувальника). На типовому Linux-сервері можна підтримувати десятки тисяч одночасних SSE-з'єднань, але для екстремального масштабування слід розглянути використання спеціалізованих серверів на базі ",[5214,6785,6786],{},"epoll"," або WebSocket.",[5274,6789,6791],{"id":6790},"обмеження-sse-та-сценарії-застосування","Обмеження SSE та сценарії застосування",[5279,6793,6794],{},"Попри простоту та ефективність, SSE має кілька архітектурних обмежень, які визначають його придатність для конкретних завдань.",[5279,6796,6797,6800,6801,6804,6805,6808],{},[5229,6798,6799],{},"Обмеження 1: Однонапрямлена комунікація."," SSE є виключно каналом «сервер → клієнт». Якщо клієнту потрібно надіслати дані серверу (наприклад, відповісти на подію або надіслати команду), він повинен виконати окремий HTTP-запит методом ",[5214,6802,6803],{},"POST"," або ",[5214,6806,6807],{},"PUT",". У сценаріях, де передача даних є двосторонньою та інтенсивною (чат, онлайн-гра, спільне редагування), це призводить до ускладнення архітектури та збільшення затримки.",[5279,6810,6811,6814],{},[5229,6812,6813],{},"Обмеження 2: Лише текстові дані."," Специфікація SSE передбачає передачу лише UTF-8 текстових повідомлень. Бінарні дані (зображення, відео, закодовані структури Protocol Buffers) необхідно кодувати у Base64, що збільшує обсяг трафіку на 33% та додає накладні витрати на кодування\u002Fдекодування.",[5279,6816,6817,6820,6821,5255],{},[5229,6818,6819],{},"Обмеження 3: Підтримка браузерами."," Більшість сучасних браузерів підтримують SSE, однак Internet Explorer та старі версії Edge не мають нативної підтримки. Для сумісності потрібно використовувати поліфіли (",[5252,6822,6823],{},"polyfills",[5279,6825,6826,6829],{},[5229,6827,6828],{},"Обмеження 4: Ліміт одночасних з'єднань у браузерах."," Браузери обмежують кількість одночасних HTTP-з'єднань до одного домену (зазвичай 6 з'єднань). Якщо застосунок відкриває кілька SSE-потоків до одного сервера, це може заблокувати інші HTTP-запити. WebSocket рахується як одне з'єднання незалежно від кількості повідомлень.",[5279,6831,6832],{},[5229,6833,6834],{},"Сценарії оптимального застосування SSE:",[5198,6836,6837,6843,6849,6855],{},[5201,6838,6839,6842],{},[5229,6840,6841],{},"Стрічки оновлень та сповіщень:"," Соціальні мережі, системи моніторингу, панелі адміністрування.",[5201,6844,6845,6848],{},[5229,6846,6847],{},"Фінансові котирування:"," Біржові ціни, курси валют, статистика торгів.",[5201,6850,6851,6854],{},[5229,6852,6853],{},"Системні логи та телеметрія:"," Потокові логи контейнерів Docker, Kubernetes Events, метрики Prometheus.",[5201,6856,6857,6860],{},[5229,6858,6859],{},"Прогрес довготривалих операцій:"," Завантаження файлів, обробка відео, виконання скриптів міграції баз даних.",[5274,6862,6864],{"id":6863},"порівняльна-таблиця-sse-vs-websocket","Порівняльна таблиця: SSE vs WebSocket",[5279,6866,6867],{},"Розуміння відмінностей між технологіями є критичним для вибору правильного рішення на етапі проєктування системи.",[6869,6870,6871,6886],"table",{},[6872,6873,6874],"thead",{},[6875,6876,6877,6881,6883],"tr",{},[6878,6879,6880],"th",{},"Критерій",[6878,6882,4722],{},[6878,6884,6885],{},"WebSocket",[6887,6888,6889,6903,6916,6929,6942,6955,6968,6981,6994,7007],"tbody",{},[6875,6890,6891,6897,6900],{},[6892,6893,6894],"td",{},[5229,6895,6896],{},"Напрямок комунікації",[6892,6898,6899],{},"Однонапрямлений (сервер → клієнт)",[6892,6901,6902],{},"Повнодуплексний (сервер ↔ клієнт)",[6875,6904,6905,6910,6913],{},[6892,6906,6907],{},[5229,6908,6909],{},"Транспортний протокол",[6892,6911,6912],{},"HTTP\u002F1.1, HTTP\u002F2",[6892,6914,6915],{},"TCP (з HTTP Upgrade)",[6875,6917,6918,6923,6926],{},[6892,6919,6920],{},[5229,6921,6922],{},"Формат даних",[6892,6924,6925],{},"Тільки текст (UTF-8)",[6892,6927,6928],{},"Текст та бінарні дані",[6875,6930,6931,6936,6939],{},[6892,6932,6933],{},[5229,6934,6935],{},"Накладні витрати на фрейм",[6892,6937,6938],{},"~100–200 байтів (HTTP заголовки)",[6892,6940,6941],{},"2–14 байтів",[6875,6943,6944,6949,6952],{},[6892,6945,6946],{},[5229,6947,6948],{},"Автоматичне перепідключення",[6892,6950,6951],{},"Так (вбудовано у EventSource API)",[6892,6953,6954],{},"Ні (потрібна ручна реалізація)",[6875,6956,6957,6962,6965],{},[6892,6958,6959],{},[5229,6960,6961],{},"Підтримка проксі\u002Fбрандмауерів",[6892,6963,6964],{},"Відмінна (звичайний HTTP)",[6892,6966,6967],{},"Може бути заблокований",[6875,6969,6970,6975,6978],{},[6892,6971,6972],{},[5229,6973,6974],{},"Підтримка браузерами",[6892,6976,6977],{},"Всі крім IE\u002Fстарий Edge",[6892,6979,6980],{},"Універсальна",[6875,6982,6983,6988,6991],{},[6892,6984,6985],{},[5229,6986,6987],{},"Складність реалізації",[6892,6989,6990],{},"Дуже проста",[6892,6992,6993],{},"Середня",[6875,6995,6996,7001,7004],{},[6892,6997,6998],{},[5229,6999,7000],{},"Ліміт з'єднань у браузері",[6892,7002,7003],{},"Враховується у HTTP-ліміт (6)",[6892,7005,7006],{},"Окреме з'єднання",[6875,7008,7009,7014,7017],{},[6892,7010,7011],{},[5229,7012,7013],{},"Ідеальний use-case",[6892,7015,7016],{},"Стрічки новин, котирування, логи",[6892,7018,7019],{},"Чати, ігри, спільне редагування",[6773,7021,7022,7023,7026],{},"Якщо ваш застосунок потребує лише доставки оновлень від сервера без інтенсивної зворотної комунікації, ",[5229,7024,7025],{},"віддайте перевагу SSE",". Він простіший у реалізації, легше проходить через корпоративну інфраструктуру та має вбудоване автоматичне перепідключення. WebSocket слід обирати лише тоді, коли дійсно потрібна двостороння комунікація з низькою затримкою.",[5266,7028],{},[5269,7030,7032],{"id":7031},"протокол-websocket-повнодуплексна-комунікація-з-мінімальними-накладними-витратами","Протокол WebSocket: повнодуплексна комунікація з мінімальними накладними витратами",[5274,7034,7036],{"id":7035},"фундаментальна-архітектура-websocket","Фундаментальна архітектура WebSocket",[5279,7038,7039,7040,7043,7044,7047],{},"Протокол WebSocket визначений специфікацією ",[5229,7041,7042],{},"RFC 6455"," та є стандартом повнодуплексної (",[5252,7045,7046],{},"full-duplex",") комунікації між клієнтом та сервером поверх одного TCP-з'єднання. На відміну від HTTP, де кожен запит є ізольованою транзакцією із заголовками, тілом повідомлення та відповіддю, WebSocket дозволяє обом сторонам надсилати повідомлення у будь-який момент без зайвих метаданих.",[5279,7049,7050,7051,7054],{},"Ключовою перевагою WebSocket є ",[5229,7052,7053],{},"низькі накладні витрати на фреймінг",". Мінімальний фрейм WebSocket містить лише 2 байти метаданих, тоді як типовий HTTP-запит включає сотні байтів заголовків. Для застосунків, що надсилають тисячі коротких повідомлень на секунду (онлайн-ігри, фінансові терміна ли), ця різниця є критичною.",[5279,7056,7057],{},"Протокол WebSocket проходить дві стадії життєвого циклу:",[7059,7060,7061,7071],"ol",{},[5201,7062,7063,7066,7067,7070],{},[5229,7064,7065],{},"Встановлення з'єднання через HTTP Upgrade Handshake:"," Клієнт надсилає спеціальний HTTP-запит із заголовками ",[5214,7068,7069],{},"Upgrade: websocket",", після чого сервер погоджується на перехід, і з'єднання переключається у режим WebSocket.",[5201,7072,7073,7076],{},[5229,7074,7075],{},"Обмін повідомленнями через фрейми:"," Після успішного встановлення з'єднання обидві сторони обмінюються бінарними фреймами, що містять текстові або бінарні дані, керуючі команди (Ping, Pong, Close).",[7078,7079,7081],"plant-uml",{"alt":7080},"Життєвий цикл WebSocket з'єднання",[5429,7082,7086],{"className":7083,"code":7084,"language":7085,"meta":5437,"style":5437},"language-plantuml shiki shiki-themes light-plus dark-plus dark-plus","@startuml\nskinparam style plain\nskinparam backgroundColor #FFFFFF\nautonumber\n\nactor \"Клієнт (Browser\u002FMobile)\" as Client #DBEAFE\nparticipant \"HTTP Сервер Go\" as Server #E2E8F0\nparticipant \"WebSocket Handler\" as WS #DCFCE7\n\nClient -> Server : GET \u002Fws HTTP\u002F1.1\\nUpgrade: websocket\\nConnection: Upgrade\nnote over Client, Server #FEF3C7\n  Клієнт ініціює процедуру апгрейду\n  звичайного HTTP до WebSocket\nend note\n\nServer -> Server : Перевірка Sec-WebSocket-Key\nServer -> Client : HTTP\u002F1.1 101 Switching Protocols\\nUpgrade: websocket\n\nnote over Client, Server #DCFCE7\n  З'єднання переведено у режим WebSocket.\n  HTTP-семантика більше не застосовується.\nend note\n\nClient -> WS : [TEXT FRAME] {\"action\": \"subscribe\", \"channel\": \"chat\"}\nWS -> Client : [TEXT FRAME] {\"status\": \"subscribed\"}\n\nloop Двосторонній обмін повідомленнями\n    Client -> WS : [TEXT\u002FBINARY FRAME] message\n    WS -> Client : [TEXT\u002FBINARY FRAME] response\nend\n\nClient -> WS : [PING FRAME]\nWS -> Client : [PONG FRAME]\n\nClient -> WS : [CLOSE FRAME]\nWS -> Client : [CLOSE FRAME]\nnote over Client, WS #FEF3C7\n  Плавне завершення з'єднання через\n  обмін фреймами закриття\nend note\n@enduml\n","plantuml",[5214,7087,7088,7093,7098,7103,7108,7112,7117,7122,7127,7131,7136,7141,7146,7151,7156,7160,7165,7170,7174,7179,7184,7189,7193,7197,7202,7207,7211,7216,7221,7226,7231,7235,7240,7245,7249,7254,7259,7264,7269,7274,7278],{"__ignoreMap":5437},[5449,7089,7090],{"class":5451,"line":5452},[5449,7091,7092],{},"@startuml\n",[5449,7094,7095],{"class":5451,"line":5484},[5449,7096,7097],{},"skinparam style plain\n",[5449,7099,7100],{"class":5451,"line":5491},[5449,7101,7102],{},"skinparam backgroundColor #FFFFFF\n",[5449,7104,7105],{"class":5451,"line":5518},[5449,7106,7107],{},"autonumber\n",[5449,7109,7110],{"class":5451,"line":5548},[5449,7111,5488],{"emptyLinePlaceholder":5487},[5449,7113,7114],{"class":5451,"line":5570},[5449,7115,7116],{},"actor \"Клієнт (Browser\u002FMobile)\" as Client #DBEAFE\n",[5449,7118,7119],{"class":5451,"line":5576},[5449,7120,7121],{},"participant \"HTTP Сервер Go\" as Server #E2E8F0\n",[5449,7123,7124],{"class":5451,"line":5581},[5449,7125,7126],{},"participant \"WebSocket Handler\" as WS #DCFCE7\n",[5449,7128,7129],{"class":5451,"line":5607},[5449,7130,5488],{"emptyLinePlaceholder":5487},[5449,7132,7133],{"class":5451,"line":5633},[5449,7134,7135],{},"Client -> Server : GET \u002Fws HTTP\u002F1.1\\nUpgrade: websocket\\nConnection: Upgrade\n",[5449,7137,7138],{"class":5451,"line":5646},[5449,7139,7140],{},"note over Client, Server #FEF3C7\n",[5449,7142,7143],{"class":5451,"line":5731},[5449,7144,7145],{},"  Клієнт ініціює процедуру апгрейду\n",[5449,7147,7148],{"class":5451,"line":5745},[5449,7149,7150],{},"  звичайного HTTP до WebSocket\n",[5449,7152,7153],{"class":5451,"line":5757},[5449,7154,7155],{},"end note\n",[5449,7157,7158],{"class":5451,"line":5769},[5449,7159,5488],{"emptyLinePlaceholder":5487},[5449,7161,7162],{"class":5451,"line":5781},[5449,7163,7164],{},"Server -> Server : Перевірка Sec-WebSocket-Key\n",[5449,7166,7167],{"class":5451,"line":5787},[5449,7168,7169],{},"Server -> Client : HTTP\u002F1.1 101 Switching Protocols\\nUpgrade: websocket\n",[5449,7171,7172],{"class":5451,"line":5792},[5449,7173,5488],{"emptyLinePlaceholder":5487},[5449,7175,7176],{"class":5451,"line":5833},[5449,7177,7178],{},"note over Client, Server #DCFCE7\n",[5449,7180,7181],{"class":5451,"line":5840},[5449,7182,7183],{},"  З'єднання переведено у режим WebSocket.\n",[5449,7185,7186],{"class":5451,"line":5868},[5449,7187,7188],{},"  HTTP-семантика більше не застосовується.\n",[5449,7190,7191],{"class":5451,"line":5881},[5449,7192,7155],{},[5449,7194,7195],{"class":5451,"line":5912},[5449,7196,5488],{"emptyLinePlaceholder":5487},[5449,7198,7199],{"class":5451,"line":5918},[5449,7200,7201],{},"Client -> WS : [TEXT FRAME] {\"action\": \"subscribe\", \"channel\": \"chat\"}\n",[5449,7203,7204],{"class":5451,"line":5924},[5449,7205,7206],{},"WS -> Client : [TEXT FRAME] {\"status\": \"subscribed\"}\n",[5449,7208,7209],{"class":5451,"line":5929},[5449,7210,5488],{"emptyLinePlaceholder":5487},[5449,7212,7213],{"class":5451,"line":5935},[5449,7214,7215],{},"loop Двосторонній обмін повідомленнями\n",[5449,7217,7218],{"class":5451,"line":5964},[5449,7219,7220],{},"    Client -> WS : [TEXT\u002FBINARY FRAME] message\n",[5449,7222,7223],{"class":5451,"line":5989},[5449,7224,7225],{},"    WS -> Client : [TEXT\u002FBINARY FRAME] response\n",[5449,7227,7228],{"class":5451,"line":6014},[5449,7229,7230],{},"end\n",[5449,7232,7233],{"class":5451,"line":6039},[5449,7234,5488],{"emptyLinePlaceholder":5487},[5449,7236,7237],{"class":5451,"line":6044},[5449,7238,7239],{},"Client -> WS : [PING FRAME]\n",[5449,7241,7242],{"class":5451,"line":6077},[5449,7243,7244],{},"WS -> Client : [PONG FRAME]\n",[5449,7246,7247],{"class":5451,"line":6082},[5449,7248,5488],{"emptyLinePlaceholder":5487},[5449,7250,7251],{"class":5451,"line":6088},[5449,7252,7253],{},"Client -> WS : [CLOSE FRAME]\n",[5449,7255,7256],{"class":5451,"line":6106},[5449,7257,7258],{},"WS -> Client : [CLOSE FRAME]\n",[5449,7260,7261],{"class":5451,"line":6140},[5449,7262,7263],{},"note over Client, WS #FEF3C7\n",[5449,7265,7266],{"class":5451,"line":6156},[5449,7267,7268],{},"  Плавне завершення з'єднання через\n",[5449,7270,7271],{"class":5451,"line":6161},[5449,7272,7273],{},"  обмін фреймами закриття\n",[5449,7275,7276],{"class":5451,"line":6169},[5449,7277,7155],{},[5449,7279,7280],{"class":5451,"line":6177},[5449,7281,7282],{},"@enduml\n",[5274,7284,7286],{"id":7285},"процедура-встановлення-зєднання-http-upgrade-handshake","Процедура встановлення з'єднання: HTTP Upgrade Handshake",[5279,7288,7289,7290,7292],{},"Встановлення WebSocket-з'єднання починається із звичайного HTTP-запиту методом ",[5214,7291,5401],{},", що містить набір спеціальних заголовків. Розглянемо повну процедуру обміну повідомленнями.",[5279,7294,7295],{},[5229,7296,7297],{},"Крок 1: Клієнт надсилає HTTP-запит на апгрейд",[5429,7299,7302],{"className":7300,"code":7301,"language":5822,"meta":5437,"style":5437},"language-http shiki shiki-themes light-plus dark-plus dark-plus","GET \u002Fws HTTP\u002F1.1\nHost: example.com\nUpgrade: websocket\nConnection: Upgrade\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\nSec-WebSocket-Version: 13\nOrigin: https:\u002F\u002Fexample.com\n",[5214,7303,7304,7320,7332,7342,7352,7362,7372],{"__ignoreMap":5437},[5449,7305,7306,7308,7311,7314,7317],{"class":5451,"line":5452},[5449,7307,5401],{"class":5685},[5449,7309,7310],{"class":5463}," \u002Fws ",[5449,7312,7313],{"class":5455},"HTTP",[5449,7315,7316],{"class":5463},"\u002F",[5449,7318,7319],{"class":6124},"1.1\n",[5449,7321,7322,7326,7329],{"class":5451,"line":5484},[5449,7323,7325],{"class":7324},"sKtos","Host",[5449,7327,7328],{"class":5455},":",[5449,7330,7331],{"class":5477}," example.com\n",[5449,7333,7334,7337,7339],{"class":5451,"line":5491},[5449,7335,7336],{"class":7324},"Upgrade",[5449,7338,7328],{"class":5455},[5449,7340,7341],{"class":5477}," websocket\n",[5449,7343,7344,7347,7349],{"class":5451,"line":5518},[5449,7345,7346],{"class":7324},"Connection",[5449,7348,7328],{"class":5455},[5449,7350,7351],{"class":5477}," Upgrade\n",[5449,7353,7354,7357,7359],{"class":5451,"line":5548},[5449,7355,7356],{"class":7324},"Sec-WebSocket-Key",[5449,7358,7328],{"class":5455},[5449,7360,7361],{"class":5477}," dGhlIHNhbXBsZSBub25jZQ==\n",[5449,7363,7364,7367,7369],{"class":5451,"line":5570},[5449,7365,7366],{"class":7324},"Sec-WebSocket-Version",[5449,7368,7328],{"class":5455},[5449,7370,7371],{"class":5477}," 13\n",[5449,7373,7374,7377,7379],{"class":5451,"line":5576},[5449,7375,7376],{"class":7324},"Origin",[5449,7378,7328],{"class":5455},[5449,7380,7381],{"class":5477}," https:\u002F\u002Fexample.com\n",[5279,7383,7384],{},[5229,7385,7386],{},"Аналіз заголовків:",[5198,7388,7389,7398,7403,7409],{},[5201,7390,7391,7393,7394,7397],{},[5214,7392,7069],{}," та ",[5214,7395,7396],{},"Connection: Upgrade"," сигналізують серверу про бажання переключити протокол з HTTP на WebSocket.",[5201,7399,7400,7402],{},[5214,7401,7356],{}," містить випадково згенерований 16-байтовий ключ, закодований у Base64. Цей ключ використовується для криптографічного підтвердження того, що сервер дійсно підтримує WebSocket (запобігає помилковим з'єднанням через проксі-сервери, що не розуміють протокол).",[5201,7404,7405,7408],{},[5214,7406,7407],{},"Sec-WebSocket-Version: 13"," вказує версію протоколу WebSocket (версія 13 є фінальною згідно з RFC 6455).",[5201,7410,7411,7413],{},[5214,7412,7376],{}," повідомляє серверу, з якого джерела (домену) надходить запит. Сервер може перевірити це значення та відхилити з'єднання, якщо джерело не є довіреним.",[5279,7415,7416],{},[5229,7417,7418],{},"Крок 2: Сервер приймає апгрейд та відправляє підтвердження",[5279,7420,7421,7422,7328],{},"Якщо сервер підтримує WebSocket та погоджується на встановлення з'єднання, він відповідає статус-кодом ",[5214,7423,7424],{},"101 Switching Protocols",[5429,7426,7428],{"className":7300,"code":7427,"language":5822,"meta":5437,"style":5437},"HTTP\u002F1.1 101 Switching Protocols\nUpgrade: websocket\nConnection: Upgrade\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\n",[5214,7429,7430,7445,7453,7461],{"__ignoreMap":5437},[5449,7431,7432,7434,7436,7439,7442],{"class":5451,"line":5452},[5449,7433,7313],{"class":5455},[5449,7435,7316],{"class":5463},[5449,7437,7438],{"class":6124},"1.1",[5449,7440,7441],{"class":6124}," 101",[5449,7443,7444],{"class":5477}," Switching Protocols\n",[5449,7446,7447,7449,7451],{"class":5451,"line":5484},[5449,7448,7336],{"class":7324},[5449,7450,7328],{"class":5455},[5449,7452,7341],{"class":5477},[5449,7454,7455,7457,7459],{"class":5451,"line":5491},[5449,7456,7346],{"class":7324},[5449,7458,7328],{"class":5455},[5449,7460,7351],{"class":5477},[5449,7462,7463,7466,7468],{"class":5451,"line":5518},[5449,7464,7465],{"class":7324},"Sec-WebSocket-Accept",[5449,7467,7328],{"class":5455},[5449,7469,7470],{"class":5477}," s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\n",[5279,7472,7473,7478,7479,7481,7482,5509,7485,7488],{},[5229,7474,7475,7476,7328],{},"Заголовок ",[5214,7477,7465],{}," Сервер обчислює це значення шляхом конкатенації клієнтського ",[5214,7480,7356],{}," із магічною константою (",[5252,7483,7484],{},"magic string",[5214,7486,7487],{},"258EAFA5-E914-47DA-95CA-C5AB0DC85B11",", після чого застосовує геш-функцію SHA-1 та кодує результат у Base64. Цей механізм гарантує, що сервер справді розуміє протокол WebSocket, а не просто відправляє статус 101 без відповідної логіки.",[5372,7490,7491,7492,7494],{},"Магічна константа ",[5214,7493,7487],{}," є частиною специфікації RFC 6455 та служить ідентифікатором версії протоколу. Її використання запобігає колізіям між різними версіями протоколів апгрейду.",[5279,7496,7497],{},[5229,7498,7499],{},"Крок 3: Перехід у режим обміну фреймами",[5279,7501,7502],{},"Після успішного обміну заголовками TCP-з'єднання залишається відкритим, але HTTP-семантика більше не застосовується. Обидві сторони можуть починати надсилати WebSocket-фрейми без додаткових заголовків або підтверджень. З'єднання є повнодуплексним: клієнт та сервер можуть надсилати дані одночасно, без блокування один одного.",[5274,7504,7506],{"id":7505},"анатомія-websocket-фрейму","Анатомія WebSocket-фрейму",[5279,7508,7509,7510,5285,7513,7516,7517,7519],{},"Кожне повідомлення у протоколі WebSocket передається у вигляді одного або кількох ",[5229,7511,7512],{},"фреймів",[5252,7514,7515],{},"frames","). Фрейм — це атомарна одиниця передачі, що складається з невеликого заголовка (2–14 байтів) та корисного навантаження (",[5252,7518,5254],{},"). Розглянемо структуру базового фрейму.",[5429,7521,7524],{"className":7522,"code":7523,"language":5434},[5432]," 0                   1                   2                   3\n 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\n+-+-+-+-+-------+-+-------------+-------------------------------+\n|F|R|R|R| opcode|M| Payload len |    Extended payload length    |\n|I|S|S|S|  (4)  |A|     (7)     |            (16\u002F64)            |\n|N|V|V|V|       |S|             |   (if payload len==126\u002F127)   |\n| |1|2|3|       |K|             |                               |\n+-+-+-+-+-------+-+-------------+-------------------------------+\n|     Extended payload length continued, if payload len == 127  |\n+---------------------------------------------------------------+\n|                     Masking-key (if MASK=1)                   |\n+---------------------------------------------------------------+\n|                       Payload Data                            |\n+---------------------------------------------------------------+\n",[5214,7525,7523],{"__ignoreMap":5437},[5279,7527,7528],{},[5229,7529,7530],{},"Пояснення полів:",[5198,7532,7533,7550,7560,7607,7620,7626,7632],{},[5201,7534,7535,7538,7539,7542,7543,7546,7547,5255],{},[5229,7536,7537],{},"FIN (1 біт):"," Прапорець, що вказує, чи є поточний фрейм останнім у повідомленні. Якщо ",[5214,7540,7541],{},"FIN = 1",", повідомлення завершено. Якщо ",[5214,7544,7545],{},"FIN = 0",", наступні фрейми продовжують це ж повідомлення (",[5252,7548,7549],{},"fragmentation",[5201,7551,7552,7555,7556,7559],{},[5229,7553,7554],{},"RSV1, RSV2, RSV3 (по 1 біту кожен):"," Зарезервовані для розширень протоколу. Зазвичай встановлені у ",[5214,7557,7558],{},"0",". Якщо сервер отримує фрейм із встановленими RSV-бітами без узгодження розширення, з'єднання має бути закрите.",[5201,7561,7562,7565,7566],{},[5229,7563,7564],{},"Opcode (4 біти):"," Визначає тип фрейму:\n",[5198,7567,7568,7574,7580,7586,7595,7601],{},[5201,7569,7570,7573],{},[5214,7571,7572],{},"0x0"," — продовження попереднього фрагментованого повідомлення.",[5201,7575,7576,7579],{},[5214,7577,7578],{},"0x1"," — текстовий фрейм (UTF-8 дані).",[5201,7581,7582,7585],{},[5214,7583,7584],{},"0x2"," — бінарний фрейм (довільні байти).",[5201,7587,7588,7591,7592,5255],{},[5214,7589,7590],{},"0x8"," — фрейм закриття з'єднання (",[5252,7593,7594],{},"Close",[5201,7596,7597,7600],{},[5214,7598,7599],{},"0x9"," — Ping (запит перевірки живості).",[5201,7602,7603,7606],{},[5214,7604,7605],{},"0xA"," — Pong (відповідь на Ping).",[5201,7608,7609,7612,7613,7616,7617,5255],{},[5229,7610,7611],{},"MASK (1 біт):"," Вказує, чи замасковане корисне навантаження. ",[5229,7614,7615],{},"Відповідно до RFC 6455, всі фрейми, відправлені клієнтом, повинні бути замасковані."," Сервер не маскує свої фрейми. Маскування використовується для запобігання атакам на проміжні проксі-сервери (",[5252,7618,7619],{},"cache poisoning",[5201,7621,7622,7625],{},[5229,7623,7624],{},"Payload Length (7 біт + додаткові байти):"," Довжина корисного навантаження у байтах. Якщо значення ≤ 125, воно безпосередньо вказує довжину. Якщо 126, наступні 2 байти містять 16-бітову довжину. Якщо 127, наступні 8 байтів містять 64-бітову довжину.",[5201,7627,7628,7631],{},[5229,7629,7630],{},"Masking Key (4 байти, якщо MASK = 1):"," Випадковий 32-бітний ключ, що використовується для маскування даних. Кожен байт корисного навантаження XOR-иться з відповідним байтом ключа (циклічно).",[5201,7633,7634,7637],{},[5229,7635,7636],{},"Payload Data:"," Власне корисне навантаження — текст або бінарні дані.",[6781,7639,7640,7641,7644],{},"Маскування фреймів клієнта є обов'язковою вимогою специфікації. Якщо сервер отримує немаскований фрейм від клієнта, він зобов'язаний негайно закрити з'єднання із кодом помилки ",[5214,7642,7643],{},"1002"," (Protocol Error). Це правило захищає інфраструктуру від атак типу кеш-отруєння через проксі-сервери.",[5274,7646,7648],{"id":7647},"типи-фреймів-та-керуючі-команди","Типи фреймів та керуючі команди",[5279,7650,7651],{},"WebSocket визначає кілька типів фреймів для різних цілей комунікації.",[5279,7653,7654,7657],{},[5229,7655,7656],{},"1. Текстові фрейми (opcode = 0x1)."," Передають UTF-8 закодований текст. Це найпоширеніший тип фреймів для передачі JSON-повідомлень, команд та серіалізованих структур даних.",[5279,7659,7660,7663],{},[5229,7661,7662],{},"2. Бінарні фрейми (opcode = 0x2)."," Передають довільні байти без інтерпретації. Використовуються для передачі зображень, відео, закодованих Protocol Buffers структур, архівів тощо.",[5279,7665,7666,7669,7670,7672],{},[5229,7667,7668],{},"3. Ping-фрейми (opcode = 0x9) та Pong-фрейми (opcode = 0xA)."," Механізм перевірки живості з'єднання (",[5252,7671,5309],{},"). Одна сторона надсилає Ping, інша повинна відповісти Pong із тим самим корисним навантаженням. Якщо протягом певного таймауту відповіді не надходить, з'єднання вважається мертвим та закривається. Це критично важливо для визначення розриву з'єднання у мережах із нестабільним зв'язком або NAT-маршрутизаторами, що закривають неактивні з'єднання.",[5279,7674,7675,7678,7679,7682,7683,7686,7687,7689],{},[5229,7676,7677],{},"4. Close-фрейми (opcode = 0x8)."," Ініціюють плавне завершення з'єднання. Фрейм закриття може містити 2-байтовий статус-код (наприклад, ",[5214,7680,7681],{},"1000"," — нормальне закриття, ",[5214,7684,7685],{},"1001"," — сервер йде у режим обслуговування, ",[5214,7688,7643],{}," — помилка протоколу) та опціональну текстову причину у UTF-8.",[5279,7691,7692],{},[5229,7693,7694],{},"Процедура коректного закриття з'єднання:",[7059,7696,7697,7700,7703],{},[5201,7698,7699],{},"Одна сторона (клієнт або сервер) надсилає Close-фрейм.",[5201,7701,7702],{},"Протилежна сторона відповідає власним Close-фреймом.",[5201,7704,7705],{},"Обидві сторони закривають базове TCP-з'єднання.",[6773,7707,7708,7709,7712],{},"Завжди реалізуйте обробку Close-фреймів у серверній логіці. Якщо клієнт надсилає Close, а сервер не відповідає, з'єднання залишається у напіввідкритому стані (",[5252,7710,7711],{},"half-closed","), що призводить до витоку дескрипторів сокетів та порушення ліміту відкритих файлів операційної системи.",[5266,7714],{},[5269,7716,7718],{"id":7717},"реалізація-websocket-сервера-у-go-з-використанням-gorillawebsocket","Реалізація WebSocket-сервера у Go з використанням gorilla\u002Fwebsocket",[5274,7720,7722],{"id":7721},"бібліотека-gorillawebsocket-промисловий-стандарт-для-go","Бібліотека gorilla\u002Fwebsocket: промисловий стандарт для Go",[5279,7724,7725,7726,7729,7730,7734,7735,7738],{},"Стандартна бібліотека Go не містить повноцінної підтримки протоколу WebSocket на рівні пакета ",[5214,7727,7728],{},"net",". Замість цього спільнота Go створила бібліотеку ",[5229,7731,7732],{},[5214,7733,5216],{},", що є де-факто стандартом для серверної та клієнтської WebSocket-комунікації. Ця бібліотека підтримує всі вимоги RFC 6455, включаючи фрагментацію повідомлень, стиснення (",[5252,7736,7737],{},"permessage-deflate extension","), коректну обробку Ping\u002FPong та плавне закриття з'єднань.",[5279,7740,7741],{},"Встановлення бібліотеки виконується стандартною командою Go Modules:",[7743,7744,7745],"tabs",{},[7746,7747,7749],"tabs-item",{"label":7748},"Go Modules",[5429,7750,7754],{"className":7751,"code":7752,"language":7753,"meta":5437,"style":5437},"language-bash shiki shiki-themes light-plus dark-plus dark-plus","go get -u github.com\u002Fgorilla\u002Fwebsocket\n","bash",[5214,7755,7756],{"__ignoreMap":5437},[5449,7757,7758,7760,7763,7766],{"class":5451,"line":5452},[5449,7759,5665],{"class":5470},[5449,7761,7762],{"class":5477}," get",[5449,7764,7765],{"class":5455}," -u",[5449,7767,7768],{"class":5477}," github.com\u002Fgorilla\u002Fwebsocket\n",[5274,7770,7772],{"id":7771},"апгрейд-http-зєднання-до-websocket","Апгрейд HTTP-з'єднання до WebSocket",[5279,7774,7775,7776,5217],{},"Першим кроком у створенні WebSocket-сервера є реалізація ендпоінту, що виконує процедуру апгрейду HTTP-запиту до WebSocket-з'єднання. Для цього використовується об'єкт ",[5214,7777,7778],{},"websocket.Upgrader",[5429,7780,7782],{"className":5663,"code":7781,"language":5665,"meta":5437,"style":5437},"package main\n\nimport (\n    \"log\"\n    \"net\u002Fhttp\"\n    \"github.com\u002Fgorilla\u002Fwebsocket\"\n)\n\n\u002F\u002F Конфігурація Upgrader для перетворення HTTP → WebSocket\nvar upgrader = websocket.Upgrader{\n    \u002F\u002F Розмір буфера читання (за замовчуванням 4096 байтів)\n    ReadBufferSize:  1024,\n    \u002F\u002F Розмір буфера запису\n    WriteBufferSize: 1024,\n    \u002F\u002F Функція перевірки джерела запиту (Origin header)\n    CheckOrigin: func(r *http.Request) bool {\n        \u002F\u002F У продакшені тут має бути перевірка списку дозволених доменів\n        return true\n    },\n}\n\nfunc wsHandler(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F Виконуємо апгрейд HTTP → WebSocket\n    conn, err := upgrader.Upgrade(w, r, nil)\n    if err != nil {\n        log.Printf(\"WebSocket upgrade failed: %v\", err)\n        return\n    }\n    defer conn.Close()\n\n    log.Printf(\"Client connected: %s\", conn.RemoteAddr())\n\n    \u002F\u002F Запускаємо обробку повідомлень від клієнта\n    handleWebSocketConnection(conn)\n}\n\nfunc main() {\n    http.HandleFunc(\"\u002Fws\", wsHandler)\n    log.Println(\"WebSocket server listening on :8080\")\n    log.Fatal(http.ListenAndServe(\":8080\", nil))\n}\n",[5214,7783,7784,7790,7794,7800,7804,7808,7813,7817,7821,7826,7846,7851,7863,7868,7879,7884,7912,7917,7925,7930,7934,7938,7969,7974,8006,8018,8042,8046,8050,8063,8067,8096,8100,8105,8116,8120,8124,8132,8152,8167,8193],{"__ignoreMap":5437},[5449,7785,7786,7788],{"class":5451,"line":5452},[5449,7787,5672],{"class":5455},[5449,7789,5676],{"class":5675},[5449,7791,7792],{"class":5451,"line":5484},[5449,7793,5488],{"emptyLinePlaceholder":5487},[5449,7795,7796,7798],{"class":5451,"line":5491},[5449,7797,5686],{"class":5685},[5449,7799,5689],{"class":5463},[5449,7801,7802],{"class":5451,"line":5518},[5449,7803,5704],{"class":5477},[5449,7805,7806],{"class":5451,"line":5548},[5449,7807,5709],{"class":5477},[5449,7809,7810],{"class":5451,"line":5570},[5449,7811,7812],{"class":5477},"    \"github.com\u002Fgorilla\u002Fwebsocket\"\n",[5449,7814,7815],{"class":5451,"line":5576},[5449,7816,5724],{"class":5463},[5449,7818,7819],{"class":5451,"line":5581},[5449,7820,5488],{"emptyLinePlaceholder":5487},[5449,7822,7823],{"class":5451,"line":5607},[5449,7824,7825],{"class":5836},"\u002F\u002F Конфігурація Upgrader для перетворення HTTP → WebSocket\n",[5449,7827,7828,7831,7834,7836,7839,7841,7844],{"class":5451,"line":5633},[5449,7829,7830],{"class":5455},"var",[5449,7832,7833],{"class":5494}," upgrader",[5449,7835,5464],{"class":5463},[5449,7837,7838],{"class":5675},"websocket",[5449,7840,5217],{"class":5463},[5449,7842,7843],{"class":5675},"Upgrader",[5449,7845,6319],{"class":5463},[5449,7847,7848],{"class":5451,"line":5646},[5449,7849,7850],{"class":5836},"    \u002F\u002F Розмір буфера читання (за замовчуванням 4096 байтів)\n",[5449,7852,7853,7856,7858,7860],{"class":5451,"line":5731},[5449,7854,7855],{"class":5494},"    ReadBufferSize",[5449,7857,6352],{"class":5463},[5449,7859,6384],{"class":6124},[5449,7861,7862],{"class":5463},",\n",[5449,7864,7865],{"class":5451,"line":5745},[5449,7866,7867],{"class":5836},"    \u002F\u002F Розмір буфера запису\n",[5449,7869,7870,7873,7875,7877],{"class":5451,"line":5757},[5449,7871,7872],{"class":5494},"    WriteBufferSize",[5449,7874,6371],{"class":5463},[5449,7876,6384],{"class":6124},[5449,7878,7862],{"class":5463},[5449,7880,7881],{"class":5451,"line":5769},[5449,7882,7883],{"class":5836},"    \u002F\u002F Функція перевірки джерела запиту (Origin header)\n",[5449,7885,7886,7889,7891,7893,7895,7897,7899,7901,7903,7905,7907,7910],{"class":5451,"line":5781},[5449,7887,7888],{"class":5494},"    CheckOrigin",[5449,7890,6371],{"class":5463},[5449,7892,5795],{"class":5455},[5449,7894,5474],{"class":5463},[5449,7896,5816],{"class":5494},[5449,7898,5819],{"class":5463},[5449,7900,5822],{"class":5675},[5449,7902,5217],{"class":5463},[5449,7904,5827],{"class":5675},[5449,7906,5509],{"class":5463},[5449,7908,7909],{"class":5675},"bool",[5449,7911,5515],{"class":5463},[5449,7913,7914],{"class":5451,"line":5787},[5449,7915,7916],{"class":5836},"        \u002F\u002F У продакшені тут має бути перевірка списку дозволених доменів\n",[5449,7918,7919,7922],{"class":5451,"line":5792},[5449,7920,7921],{"class":5685},"        return",[5449,7923,7924],{"class":5455}," true\n",[5449,7926,7927],{"class":5451,"line":5833},[5449,7928,7929],{"class":5463},"    },\n",[5449,7931,7932],{"class":5451,"line":5840},[5449,7933,5784],{"class":5463},[5449,7935,7936],{"class":5451,"line":5868},[5449,7937,5488],{"emptyLinePlaceholder":5487},[5449,7939,7940,7942,7945,7947,7949,7951,7953,7955,7957,7959,7961,7963,7965,7967],{"class":5451,"line":5881},[5449,7941,5795],{"class":5455},[5449,7943,7944],{"class":5470}," wsHandler",[5449,7946,5474],{"class":5463},[5449,7948,5803],{"class":5494},[5449,7950,5806],{"class":5675},[5449,7952,5217],{"class":5463},[5449,7954,5811],{"class":5675},[5449,7956,5413],{"class":5463},[5449,7958,5816],{"class":5494},[5449,7960,5819],{"class":5463},[5449,7962,5822],{"class":5675},[5449,7964,5217],{"class":5463},[5449,7966,5827],{"class":5675},[5449,7968,5830],{"class":5463},[5449,7970,7971],{"class":5451,"line":5912},[5449,7972,7973],{"class":5836},"    \u002F\u002F Виконуємо апгрейд HTTP → WebSocket\n",[5449,7975,7976,7979,7981,7983,7985,7988,7990,7992,7994,7996,7998,8000,8002,8004],{"class":5451,"line":5918},[5449,7977,7978],{"class":5494},"    conn",[5449,7980,5413],{"class":5463},[5449,7982,6454],{"class":5494},[5449,7984,5851],{"class":5463},[5449,7986,7987],{"class":5494},"upgrader",[5449,7989,5217],{"class":5463},[5449,7991,7336],{"class":5470},[5449,7993,5474],{"class":5463},[5449,7995,5803],{"class":5494},[5449,7997,5413],{"class":5463},[5449,7999,5816],{"class":5494},[5449,8001,5413],{"class":5463},[5449,8003,6501],{"class":5455},[5449,8005,5724],{"class":5463},[5449,8007,8008,8010,8012,8014,8016],{"class":5451,"line":5924},[5449,8009,5871],{"class":5685},[5449,8011,6495],{"class":5494},[5449,8013,6498],{"class":5463},[5449,8015,6501],{"class":5455},[5449,8017,5515],{"class":5463},[5449,8019,8020,8023,8025,8027,8029,8032,8034,8036,8038,8040],{"class":5451,"line":5929},[5449,8021,8022],{"class":5494},"        log",[5449,8024,5217],{"class":5463},[5449,8026,6052],{"class":5470},[5449,8028,5474],{"class":5463},[5449,8030,8031],{"class":5477},"\"WebSocket upgrade failed: ",[5449,8033,6521],{"class":5494},[5449,8035,6063],{"class":5477},[5449,8037,5413],{"class":5463},[5449,8039,6454],{"class":5494},[5449,8041,5724],{"class":5463},[5449,8043,8044],{"class":5451,"line":5935},[5449,8045,5915],{"class":5685},[5449,8047,8048],{"class":5451,"line":5964},[5449,8049,5921],{"class":5463},[5449,8051,8052,8054,8057,8059,8061],{"class":5451,"line":5989},[5449,8053,6143],{"class":5685},[5449,8055,8056],{"class":5494}," conn",[5449,8058,5217],{"class":5463},[5449,8060,7594],{"class":5470},[5449,8062,6103],{"class":5463},[5449,8064,8065],{"class":5451,"line":6014},[5449,8066,5488],{"emptyLinePlaceholder":5487},[5449,8068,8069,8071,8073,8075,8077,8080,8082,8084,8086,8089,8091,8093],{"class":5451,"line":6039},[5449,8070,6047],{"class":5494},[5449,8072,5217],{"class":5463},[5449,8074,6052],{"class":5470},[5449,8076,5474],{"class":5463},[5449,8078,8079],{"class":5477},"\"Client connected: ",[5449,8081,6060],{"class":5494},[5449,8083,6063],{"class":5477},[5449,8085,5413],{"class":5463},[5449,8087,8088],{"class":5494},"conn",[5449,8090,5217],{"class":5463},[5449,8092,6072],{"class":5470},[5449,8094,8095],{"class":5463},"())\n",[5449,8097,8098],{"class":5451,"line":6044},[5449,8099,5488],{"emptyLinePlaceholder":5487},[5449,8101,8102],{"class":5451,"line":6077},[5449,8103,8104],{"class":5836},"    \u002F\u002F Запускаємо обробку повідомлень від клієнта\n",[5449,8106,8107,8110,8112,8114],{"class":5451,"line":6082},[5449,8108,8109],{"class":5470},"    handleWebSocketConnection",[5449,8111,5474],{"class":5463},[5449,8113,8088],{"class":5494},[5449,8115,5724],{"class":5463},[5449,8117,8118],{"class":5451,"line":6088},[5449,8119,5784],{"class":5463},[5449,8121,8122],{"class":5451,"line":6106},[5449,8123,5488],{"emptyLinePlaceholder":5487},[5449,8125,8126,8128,8130],{"class":5451,"line":6140},[5449,8127,5795],{"class":5455},[5449,8129,6593],{"class":5470},[5449,8131,6596],{"class":5463},[5449,8133,8134,8136,8138,8140,8142,8145,8147,8150],{"class":5451,"line":6156},[5449,8135,6602],{"class":5494},[5449,8137,5217],{"class":5463},[5449,8139,6607],{"class":5470},[5449,8141,5474],{"class":5463},[5449,8143,8144],{"class":5477},"\"\u002Fws\"",[5449,8146,5413],{"class":5463},[5449,8148,8149],{"class":5494},"wsHandler",[5449,8151,5724],{"class":5463},[5449,8153,8154,8156,8158,8160,8162,8165],{"class":5451,"line":6161},[5449,8155,6047],{"class":5494},[5449,8157,5217],{"class":5463},[5449,8159,6629],{"class":5470},[5449,8161,5474],{"class":5463},[5449,8163,8164],{"class":5477},"\"WebSocket server listening on :8080\"",[5449,8166,5724],{"class":5463},[5449,8168,8169,8171,8173,8175,8177,8179,8181,8183,8185,8187,8189,8191],{"class":5451,"line":6169},[5449,8170,6047],{"class":5494},[5449,8172,5217],{"class":5463},[5449,8174,6646],{"class":5470},[5449,8176,5474],{"class":5463},[5449,8178,5822],{"class":5494},[5449,8180,5217],{"class":5463},[5449,8182,6655],{"class":5470},[5449,8184,5474],{"class":5463},[5449,8186,6660],{"class":5477},[5449,8188,5413],{"class":5463},[5449,8190,6501],{"class":5455},[5449,8192,6667],{"class":5463},[5449,8194,8195],{"class":5451,"line":6177},[5449,8196,5784],{"class":5463},[5279,8198,8199],{},[5229,8200,8201,8202,7328],{},"Пояснення конфігурації ",[5214,8203,7778],{},[5279,8205,8206,8214],{},[5229,8207,8208,7393,8211,7328],{},[5214,8209,8210],{},"ReadBufferSize",[5214,8212,8213],{},"WriteBufferSize"," Визначають розмір внутрішніх буферів для операцій читання та запису. Більші буфери зменшують кількість системних викликів при передачі великих повідомлень, але збільшують використання пам'яті на кожне з'єднання. Типові значення — 1024 або 4096 байтів.",[5279,8216,8217,8222,8223,8225,8226,8228,8229,8231,8232,8235],{},[5229,8218,8219,7328],{},[5214,8220,8221],{},"CheckOrigin"," Функція валідації заголовка ",[5214,8224,7376],{}," для захисту від Cross-Site WebSocket Hijacking атак. За замовчуванням ",[5214,8227,5216],{}," відхиляє з'єднання, якщо ",[5214,8230,7376],{}," не збігається з хостом сервера. У прикладі вище функція завжди повертає ",[5214,8233,8234],{},"true"," для спрощення, але у продакшені необхідно перевіряти список дозволених доменів:",[5429,8237,8239],{"className":5663,"code":8238,"language":5665,"meta":5437,"style":5437},"CheckOrigin: func(r *http.Request) bool {\n    origin := r.Header.Get(\"Origin\")\n    return origin == \"https:\u002F\u002Fexample.com\" || origin == \"https:\u002F\u002Fapp.example.com\"\n}\n",[5214,8240,8241,8267,8292,8317],{"__ignoreMap":5437},[5449,8242,8243,8245,8247,8249,8251,8253,8255,8257,8259,8261,8263,8265],{"class":5451,"line":5452},[5449,8244,8221],{"class":5494},[5449,8246,6371],{"class":5463},[5449,8248,5795],{"class":5455},[5449,8250,5474],{"class":5463},[5449,8252,5816],{"class":5494},[5449,8254,5819],{"class":5463},[5449,8256,5822],{"class":5675},[5449,8258,5217],{"class":5463},[5449,8260,5827],{"class":5675},[5449,8262,5509],{"class":5463},[5449,8264,7909],{"class":5675},[5449,8266,5515],{"class":5463},[5449,8268,8269,8272,8274,8276,8278,8280,8282,8285,8287,8290],{"class":5451,"line":5484},[5449,8270,8271],{"class":5494},"    origin",[5449,8273,5851],{"class":5463},[5449,8275,5816],{"class":5494},[5449,8277,5217],{"class":5463},[5449,8279,5943],{"class":5494},[5449,8281,5217],{"class":5463},[5449,8283,8284],{"class":5470},"Get",[5449,8286,5474],{"class":5463},[5449,8288,8289],{"class":5477},"\"Origin\"",[5449,8291,5724],{"class":5463},[5449,8293,8294,8297,8300,8303,8306,8309,8312,8314],{"class":5451,"line":5491},[5449,8295,8296],{"class":5685},"    return",[5449,8298,8299],{"class":5494}," origin",[5449,8301,8302],{"class":5463}," == ",[5449,8304,8305],{"class":5477},"\"https:\u002F\u002Fexample.com\"",[5449,8307,8308],{"class":5463}," || ",[5449,8310,8311],{"class":5494},"origin",[5449,8313,8302],{"class":5463},[5449,8315,8316],{"class":5477},"\"https:\u002F\u002Fapp.example.com\"\n",[5449,8318,8319],{"class":5451,"line":5518},[5449,8320,5784],{"class":5463},[5279,8322,8323,8329,8330,8332,8333,8335,8336,8339,8340,8342],{},[5229,8324,8325,8326,7328],{},"Метод ",[5214,8327,8328],{},"Upgrade()"," Виконує повний цикл WebSocket Handshake: перевіряє заголовки запиту, обчислює ",[5214,8331,7465],{},", відправляє відповідь ",[5214,8334,7424],{}," та повертає об'єкт ",[5214,8337,8338],{},"*websocket.Conn",", що представляє встановлене з'єднання. Третій параметр (",[5214,8341,6501],{}," у прикладі) дозволяє додати додаткові HTTP-заголовки до відповіді 101.",[5274,8344,8346],{"id":8345},"читання-та-запис-повідомлень","Читання та запис повідомлень",[5279,8348,8349,8350,8352,8353,5285,8356,8359,8360,8363],{},"Об'єкт ",[5214,8351,8338],{}," надає методи для читання та запису текстових і бінарних повідомлень. Критично важливо розуміти, що методи читання є ",[5229,8354,8355],{},"блокуючими",[5252,8357,8358],{},"blocking",") — виклик ",[5214,8361,8362],{},"ReadMessage()"," зупиняє горутину до отримання повного повідомлення або помилки.",[5429,8365,8367],{"className":5663,"code":8366,"language":5665,"meta":5437,"style":5437},"func handleWebSocketConnection(conn *websocket.Conn) {\n    for {\n        \u002F\u002F Блокуючий виклик: чекаємо на повідомлення від клієнта\n        messageType, payload, err := conn.ReadMessage()\n        if err != nil {\n            \u002F\u002F Клієнт закрив з'єднання або відбулася помилка читання\n            if websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseGoingAway) {\n                log.Println(\"Client closed connection gracefully\")\n            } else {\n                log.Printf(\"Read error: %v\", err)\n            }\n            break\n        }\n\n        log.Printf(\"Received [type=%d]: %s\", messageType, string(payload))\n\n        \u002F\u002F Відправляємо відповідь клієнту (ехо-сервер)\n        err = conn.WriteMessage(messageType, payload)\n        if err != nil {\n            log.Printf(\"Write error: %v\", err)\n            break\n        }\n    }\n}\n",[5214,8368,8369,8391,8397,8402,8426,8439,8444,8480,8495,8505,8528,8532,8537,8541,8545,8584,8588,8593,8617,8629,8652,8656,8660,8664],{"__ignoreMap":5437},[5449,8370,8371,8373,8376,8378,8380,8382,8384,8386,8389],{"class":5451,"line":5452},[5449,8372,5795],{"class":5455},[5449,8374,8375],{"class":5470}," handleWebSocketConnection",[5449,8377,5474],{"class":5463},[5449,8379,8088],{"class":5494},[5449,8381,5819],{"class":5463},[5449,8383,7838],{"class":5675},[5449,8385,5217],{"class":5463},[5449,8387,8388],{"class":5675},"Conn",[5449,8390,5830],{"class":5463},[5449,8392,8393,8395],{"class":5451,"line":5484},[5449,8394,6164],{"class":5685},[5449,8396,5515],{"class":5463},[5449,8398,8399],{"class":5451,"line":5491},[5449,8400,8401],{"class":5836},"        \u002F\u002F Блокуючий виклик: чекаємо на повідомлення від клієнта\n",[5449,8403,8404,8407,8409,8411,8413,8415,8417,8419,8421,8424],{"class":5451,"line":5518},[5449,8405,8406],{"class":5494},"        messageType",[5449,8408,5413],{"class":5463},[5449,8410,5254],{"class":5494},[5449,8412,5413],{"class":5463},[5449,8414,6454],{"class":5494},[5449,8416,5851],{"class":5463},[5449,8418,8088],{"class":5494},[5449,8420,5217],{"class":5463},[5449,8422,8423],{"class":5470},"ReadMessage",[5449,8425,6103],{"class":5463},[5449,8427,8428,8431,8433,8435,8437],{"class":5451,"line":5548},[5449,8429,8430],{"class":5685},"        if",[5449,8432,6495],{"class":5494},[5449,8434,6498],{"class":5463},[5449,8436,6501],{"class":5455},[5449,8438,5515],{"class":5463},[5449,8440,8441],{"class":5451,"line":5570},[5449,8442,8443],{"class":5836},"            \u002F\u002F Клієнт закрив з'єднання або відбулася помилка читання\n",[5449,8445,8446,8448,8451,8453,8456,8458,8460,8462,8464,8466,8469,8471,8473,8475,8478],{"class":5451,"line":5576},[5449,8447,6492],{"class":5685},[5449,8449,8450],{"class":5494}," websocket",[5449,8452,5217],{"class":5463},[5449,8454,8455],{"class":5470},"IsCloseError",[5449,8457,5474],{"class":5463},[5449,8459,6454],{"class":5494},[5449,8461,5413],{"class":5463},[5449,8463,7838],{"class":5494},[5449,8465,5217],{"class":5463},[5449,8467,8468],{"class":5494},"CloseNormalClosure",[5449,8470,5413],{"class":5463},[5449,8472,7838],{"class":5494},[5449,8474,5217],{"class":5463},[5449,8476,8477],{"class":5494},"CloseGoingAway",[5449,8479,5830],{"class":5463},[5449,8481,8482,8484,8486,8488,8490,8493],{"class":5451,"line":5581},[5449,8483,6509],{"class":5494},[5449,8485,5217],{"class":5463},[5449,8487,6629],{"class":5470},[5449,8489,5474],{"class":5463},[5449,8491,8492],{"class":5477},"\"Client closed connection gracefully\"",[5449,8494,5724],{"class":5463},[5449,8496,8497,8500,8503],{"class":5451,"line":5607},[5449,8498,8499],{"class":5463},"            } ",[5449,8501,8502],{"class":5685},"else",[5449,8504,5515],{"class":5463},[5449,8506,8507,8509,8511,8513,8515,8518,8520,8522,8524,8526],{"class":5451,"line":5633},[5449,8508,6509],{"class":5494},[5449,8510,5217],{"class":5463},[5449,8512,6052],{"class":5470},[5449,8514,5474],{"class":5463},[5449,8516,8517],{"class":5477},"\"Read error: ",[5449,8519,6521],{"class":5494},[5449,8521,6063],{"class":5477},[5449,8523,5413],{"class":5463},[5449,8525,6454],{"class":5494},[5449,8527,5724],{"class":5463},[5449,8529,8530],{"class":5451,"line":5646},[5449,8531,6399],{"class":5463},[5449,8533,8534],{"class":5451,"line":5731},[5449,8535,8536],{"class":5685},"            break\n",[5449,8538,8539],{"class":5451,"line":5745},[5449,8540,6570],{"class":5463},[5449,8542,8543],{"class":5451,"line":5757},[5449,8544,5488],{"emptyLinePlaceholder":5487},[5449,8546,8547,8549,8551,8553,8555,8558,8561,8564,8566,8568,8570,8573,8575,8578,8580,8582],{"class":5451,"line":5769},[5449,8548,8022],{"class":5494},[5449,8550,5217],{"class":5463},[5449,8552,6052],{"class":5470},[5449,8554,5474],{"class":5463},[5449,8556,8557],{"class":5477},"\"Received [type=",[5449,8559,8560],{"class":5494},"%d",[5449,8562,8563],{"class":5477},"]: ",[5449,8565,6060],{"class":5494},[5449,8567,6063],{"class":5477},[5449,8569,5413],{"class":5463},[5449,8571,8572],{"class":5494},"messageType",[5449,8574,5413],{"class":5463},[5449,8576,8577],{"class":5675},"string",[5449,8579,5474],{"class":5463},[5449,8581,5254],{"class":5494},[5449,8583,6667],{"class":5463},[5449,8585,8586],{"class":5451,"line":5781},[5449,8587,5488],{"emptyLinePlaceholder":5487},[5449,8589,8590],{"class":5451,"line":5787},[5449,8591,8592],{"class":5836},"        \u002F\u002F Відправляємо відповідь клієнту (ехо-сервер)\n",[5449,8594,8595,8598,8600,8602,8604,8607,8609,8611,8613,8615],{"class":5451,"line":5792},[5449,8596,8597],{"class":5494},"        err",[5449,8599,5464],{"class":5463},[5449,8601,8088],{"class":5494},[5449,8603,5217],{"class":5463},[5449,8605,8606],{"class":5470},"WriteMessage",[5449,8608,5474],{"class":5463},[5449,8610,8572],{"class":5494},[5449,8612,5413],{"class":5463},[5449,8614,5254],{"class":5494},[5449,8616,5724],{"class":5463},[5449,8618,8619,8621,8623,8625,8627],{"class":5451,"line":5833},[5449,8620,8430],{"class":5685},[5449,8622,6495],{"class":5494},[5449,8624,6498],{"class":5463},[5449,8626,6501],{"class":5455},[5449,8628,5515],{"class":5463},[5449,8630,8631,8633,8635,8637,8639,8642,8644,8646,8648,8650],{"class":5451,"line":5840},[5449,8632,6206],{"class":5494},[5449,8634,5217],{"class":5463},[5449,8636,6052],{"class":5470},[5449,8638,5474],{"class":5463},[5449,8640,8641],{"class":5477},"\"Write error: ",[5449,8643,6521],{"class":5494},[5449,8645,6063],{"class":5477},[5449,8647,5413],{"class":5463},[5449,8649,6454],{"class":5494},[5449,8651,5724],{"class":5463},[5449,8653,8654],{"class":5451,"line":5868},[5449,8655,8536],{"class":5685},[5449,8657,8658],{"class":5451,"line":5881},[5449,8659,6570],{"class":5463},[5449,8661,8662],{"class":5451,"line":5912},[5449,8663,5921],{"class":5463},[5449,8665,8666],{"class":5451,"line":5918},[5449,8667,5784],{"class":5463},[5279,8669,8670],{},[5229,8671,8672],{},"Методи читання:",[5198,8674,8675,8688],{},[5201,8676,8677,8680,8681,6804,8684,8687],{},[5214,8678,8679],{},"ReadMessage() (messageType int, p []byte, err error)"," — читає наступне повідомлення цілком, блокуючись до його отримання. Повертає тип повідомлення (",[5214,8682,8683],{},"websocket.TextMessage",[5214,8685,8686],{},"websocket.BinaryMessage",") та корисне навантаження.",[5201,8689,8690,8693,8694,8697],{},[5214,8691,8692],{},"NextReader() (messageType int, r io.Reader, err error)"," — надає потоковий доступ до повідомлення через ",[5214,8695,8696],{},"io.Reader",", корисно для обробки великих повідомлень без завантаження всього у пам'ять.",[5279,8699,8700],{},[5229,8701,8702],{},"Методи запису:",[5198,8704,8705,8718],{},[5201,8706,8707,8710,8711,5285,8714,8717],{},[5214,8708,8709],{},"WriteMessage(messageType int, data []byte) error"," — надсилає повідомлення одним фреймом. Цей метод ",[5229,8712,8713],{},"не є потокобезпечним",[5252,8715,8716],{},"not goroutine-safe",") — одночасний виклик з кількох горутин призведе до невизначеної поведінки та пошкодження фреймів.",[5201,8719,8720,8723,8724,8727],{},[5214,8721,8722],{},"NextWriter(messageType int) (io.WriteCloser, error)"," — повертає потоковий ",[5214,8725,8726],{},"io.Writer"," для формування великих повідомлень частинами.",[8729,8730,8349,8731,8733,8734,8737,8738,8741],"caution",{},[5214,8732,8338],{}," не є потокобезпечним для операцій запису. Якщо кілька горутин одночасно викликають ",[5214,8735,8736],{},"WriteMessage()",", фрейми можуть перемішатися, що призведе до порушення протоколу та розриву з'єднання. Завжди синхронізуйте доступ до запису через ",[5214,8739,8740],{},"sync.Mutex"," або використовуйте окрему горутину-письменник.",[5274,8743,8745],{"id":8744},"архітектурний-патерн-горутини-читання-та-запису","Архітектурний патерн: горутини читання та запису",[5279,8747,8748,8749,8752],{},"Типова архітектура WebSocket-обробника передбачає ",[5229,8750,8751],{},"розділення логіки читання та запису у дві незалежні горутини",". Це дозволяє одночасно обробляювати вхідні повідомлення та надсилати вихідні без блокування.",[5429,8754,8756],{"className":5663,"code":8755,"language":5665,"meta":5437,"style":5437},"type Client struct {\n    conn *websocket.Conn\n    send chan []byte \u002F\u002F Канал для передачі повідомлень від логіки до writer-горутини\n}\n\nfunc (c *Client) readPump() {\n    defer c.conn.Close()\n    \n    for {\n        _, message, err := c.conn.ReadMessage()\n        if err != nil {\n            break\n        }\n        \n        \u002F\u002F Обробка отриманого повідомлення\n        log.Printf(\"Received: %s\", string(message))\n        \n        \u002F\u002F Надсилаємо відповідь через канал (не напряму!)\n        c.send \u003C- []byte(\"Echo: \" + string(message))\n    }\n}\n\nfunc (c *Client) writePump() {\n    defer c.conn.Close()\n    \n    for message := range c.send {\n        err := c.conn.WriteMessage(websocket.TextMessage, message)\n        if err != nil {\n            break\n        }\n    }\n}\n\nfunc handleClient(conn *websocket.Conn) {\n    client := &Client{\n        conn: conn,\n        send: make(chan []byte, 256), \u002F\u002F Буферизований канал для згладжування пікових навантажень\n    }\n    \n    go client.writePump()\n    client.readPump() \u002F\u002F Блокує поточну горутину до закриття з'єднання\n}\n",[5214,8757,8758,8769,8782,8799,8803,8807,8829,8846,8851,8857,8886,8898,8902,8906,8911,8916,8943,8947,8952,8983,8987,8991,8995,9014,9030,9034,9054,9085,9097,9101,9105,9109,9113,9117,9138,9150,9161,9191,9195,9199,9213,9227],{"__ignoreMap":5437},[5449,8759,8760,8762,8765,8767],{"class":5451,"line":5452},[5449,8761,5734],{"class":5455},[5449,8763,8764],{"class":5675}," Client",[5449,8766,5740],{"class":5455},[5449,8768,5515],{"class":5463},[5449,8770,8771,8773,8775,8777,8779],{"class":5451,"line":5484},[5449,8772,7978],{"class":5494},[5449,8774,5819],{"class":5463},[5449,8776,7838],{"class":5675},[5449,8778,5217],{"class":5463},[5449,8780,8781],{"class":5675},"Conn\n",[5449,8783,8784,8787,8790,8793,8796],{"class":5451,"line":5491},[5449,8785,8786],{"class":5494},"    send",[5449,8788,8789],{"class":5455}," chan",[5449,8791,8792],{"class":5463}," []",[5449,8794,8795],{"class":5675},"byte",[5449,8797,8798],{"class":5836}," \u002F\u002F Канал для передачі повідомлень від логіки до writer-горутини\n",[5449,8800,8801],{"class":5451,"line":5518},[5449,8802,5784],{"class":5463},[5449,8804,8805],{"class":5451,"line":5548},[5449,8806,5488],{"emptyLinePlaceholder":5487},[5449,8808,8809,8811,8813,8816,8819,8822,8824,8827],{"class":5451,"line":5570},[5449,8810,5795],{"class":5455},[5449,8812,5285],{"class":5463},[5449,8814,8815],{"class":5494},"c ",[5449,8817,8818],{"class":5463},"*",[5449,8820,8821],{"class":5675},"Client",[5449,8823,5509],{"class":5463},[5449,8825,8826],{"class":5470},"readPump",[5449,8828,6596],{"class":5463},[5449,8830,8831,8833,8836,8838,8840,8842,8844],{"class":5451,"line":5576},[5449,8832,6143],{"class":5685},[5449,8834,8835],{"class":5494}," c",[5449,8837,5217],{"class":5463},[5449,8839,8088],{"class":5494},[5449,8841,5217],{"class":5463},[5449,8843,7594],{"class":5470},[5449,8845,6103],{"class":5463},[5449,8847,8848],{"class":5451,"line":5581},[5449,8849,8850],{"class":5463},"    \n",[5449,8852,8853,8855],{"class":5451,"line":5607},[5449,8854,6164],{"class":5685},[5449,8856,5515],{"class":5463},[5449,8858,8859,8862,8864,8867,8869,8871,8873,8876,8878,8880,8882,8884],{"class":5451,"line":5633},[5449,8860,8861],{"class":5494},"        _",[5449,8863,5413],{"class":5463},[5449,8865,8866],{"class":5494},"message",[5449,8868,5413],{"class":5463},[5449,8870,6454],{"class":5494},[5449,8872,5851],{"class":5463},[5449,8874,8875],{"class":5494},"c",[5449,8877,5217],{"class":5463},[5449,8879,8088],{"class":5494},[5449,8881,5217],{"class":5463},[5449,8883,8423],{"class":5470},[5449,8885,6103],{"class":5463},[5449,8887,8888,8890,8892,8894,8896],{"class":5451,"line":5646},[5449,8889,8430],{"class":5685},[5449,8891,6495],{"class":5494},[5449,8893,6498],{"class":5463},[5449,8895,6501],{"class":5455},[5449,8897,5515],{"class":5463},[5449,8899,8900],{"class":5451,"line":5731},[5449,8901,8536],{"class":5685},[5449,8903,8904],{"class":5451,"line":5745},[5449,8905,6570],{"class":5463},[5449,8907,8908],{"class":5451,"line":5757},[5449,8909,8910],{"class":5463},"        \n",[5449,8912,8913],{"class":5451,"line":5769},[5449,8914,8915],{"class":5836},"        \u002F\u002F Обробка отриманого повідомлення\n",[5449,8917,8918,8920,8922,8924,8926,8929,8931,8933,8935,8937,8939,8941],{"class":5451,"line":5781},[5449,8919,8022],{"class":5494},[5449,8921,5217],{"class":5463},[5449,8923,6052],{"class":5470},[5449,8925,5474],{"class":5463},[5449,8927,8928],{"class":5477},"\"Received: ",[5449,8930,6060],{"class":5494},[5449,8932,6063],{"class":5477},[5449,8934,5413],{"class":5463},[5449,8936,8577],{"class":5675},[5449,8938,5474],{"class":5463},[5449,8940,8866],{"class":5494},[5449,8942,6667],{"class":5463},[5449,8944,8945],{"class":5451,"line":5787},[5449,8946,8910],{"class":5463},[5449,8948,8949],{"class":5451,"line":5792},[5449,8950,8951],{"class":5836},"        \u002F\u002F Надсилаємо відповідь через канал (не напряму!)\n",[5449,8953,8954,8957,8959,8962,8965,8967,8969,8972,8975,8977,8979,8981],{"class":5451,"line":5833},[5449,8955,8956],{"class":5494},"        c",[5449,8958,5217],{"class":5463},[5449,8960,8961],{"class":5494},"send",[5449,8963,8964],{"class":5463}," \u003C- []",[5449,8966,8795],{"class":5675},[5449,8968,5474],{"class":5463},[5449,8970,8971],{"class":5477},"\"Echo: \"",[5449,8973,8974],{"class":5463}," + ",[5449,8976,8577],{"class":5675},[5449,8978,5474],{"class":5463},[5449,8980,8866],{"class":5494},[5449,8982,6667],{"class":5463},[5449,8984,8985],{"class":5451,"line":5840},[5449,8986,5921],{"class":5463},[5449,8988,8989],{"class":5451,"line":5868},[5449,8990,5784],{"class":5463},[5449,8992,8993],{"class":5451,"line":5881},[5449,8994,5488],{"emptyLinePlaceholder":5487},[5449,8996,8997,8999,9001,9003,9005,9007,9009,9012],{"class":5451,"line":5912},[5449,8998,5795],{"class":5455},[5449,9000,5285],{"class":5463},[5449,9002,8815],{"class":5494},[5449,9004,8818],{"class":5463},[5449,9006,8821],{"class":5675},[5449,9008,5509],{"class":5463},[5449,9010,9011],{"class":5470},"writePump",[5449,9013,6596],{"class":5463},[5449,9015,9016,9018,9020,9022,9024,9026,9028],{"class":5451,"line":5918},[5449,9017,6143],{"class":5685},[5449,9019,8835],{"class":5494},[5449,9021,5217],{"class":5463},[5449,9023,8088],{"class":5494},[5449,9025,5217],{"class":5463},[5449,9027,7594],{"class":5470},[5449,9029,6103],{"class":5463},[5449,9031,9032],{"class":5451,"line":5924},[5449,9033,8850],{"class":5463},[5449,9035,9036,9038,9041,9043,9046,9048,9050,9052],{"class":5451,"line":5929},[5449,9037,6164],{"class":5685},[5449,9039,9040],{"class":5494}," message",[5449,9042,5851],{"class":5463},[5449,9044,9045],{"class":5685},"range",[5449,9047,8835],{"class":5494},[5449,9049,5217],{"class":5463},[5449,9051,8961],{"class":5494},[5449,9053,5515],{"class":5463},[5449,9055,9056,9058,9060,9062,9064,9066,9068,9070,9072,9074,9076,9079,9081,9083],{"class":5451,"line":5935},[5449,9057,8597],{"class":5494},[5449,9059,5851],{"class":5463},[5449,9061,8875],{"class":5494},[5449,9063,5217],{"class":5463},[5449,9065,8088],{"class":5494},[5449,9067,5217],{"class":5463},[5449,9069,8606],{"class":5470},[5449,9071,5474],{"class":5463},[5449,9073,7838],{"class":5494},[5449,9075,5217],{"class":5463},[5449,9077,9078],{"class":5494},"TextMessage",[5449,9080,5413],{"class":5463},[5449,9082,8866],{"class":5494},[5449,9084,5724],{"class":5463},[5449,9086,9087,9089,9091,9093,9095],{"class":5451,"line":5964},[5449,9088,8430],{"class":5685},[5449,9090,6495],{"class":5494},[5449,9092,6498],{"class":5463},[5449,9094,6501],{"class":5455},[5449,9096,5515],{"class":5463},[5449,9098,9099],{"class":5451,"line":5989},[5449,9100,8536],{"class":5685},[5449,9102,9103],{"class":5451,"line":6014},[5449,9104,6570],{"class":5463},[5449,9106,9107],{"class":5451,"line":6039},[5449,9108,5921],{"class":5463},[5449,9110,9111],{"class":5451,"line":6044},[5449,9112,5784],{"class":5463},[5449,9114,9115],{"class":5451,"line":6077},[5449,9116,5488],{"emptyLinePlaceholder":5487},[5449,9118,9119,9121,9124,9126,9128,9130,9132,9134,9136],{"class":5451,"line":6082},[5449,9120,5795],{"class":5455},[5449,9122,9123],{"class":5470}," handleClient",[5449,9125,5474],{"class":5463},[5449,9127,8088],{"class":5494},[5449,9129,5819],{"class":5463},[5449,9131,7838],{"class":5675},[5449,9133,5217],{"class":5463},[5449,9135,8388],{"class":5675},[5449,9137,5830],{"class":5463},[5449,9139,9140,9143,9146,9148],{"class":5451,"line":6088},[5449,9141,9142],{"class":5494},"    client",[5449,9144,9145],{"class":5463}," := &",[5449,9147,8821],{"class":5675},[5449,9149,6319],{"class":5463},[5449,9151,9152,9155,9157,9159],{"class":5451,"line":6106},[5449,9153,9154],{"class":5494},"        conn",[5449,9156,6371],{"class":5463},[5449,9158,8088],{"class":5494},[5449,9160,7862],{"class":5463},[5449,9162,9163,9166,9168,9171,9173,9176,9178,9180,9182,9185,9188],{"class":5451,"line":6140},[5449,9164,9165],{"class":5494},"        send",[5449,9167,6371],{"class":5463},[5449,9169,9170],{"class":5470},"make",[5449,9172,5474],{"class":5463},[5449,9174,9175],{"class":5455},"chan",[5449,9177,8792],{"class":5463},[5449,9179,8795],{"class":5675},[5449,9181,5413],{"class":5463},[5449,9183,9184],{"class":6124},"256",[5449,9186,9187],{"class":5463},"), ",[5449,9189,9190],{"class":5836},"\u002F\u002F Буферизований канал для згладжування пікових навантажень\n",[5449,9192,9193],{"class":5451,"line":6156},[5449,9194,5921],{"class":5463},[5449,9196,9197],{"class":5451,"line":6161},[5449,9198,8850],{"class":5463},[5449,9200,9201,9204,9207,9209,9211],{"class":5451,"line":6169},[5449,9202,9203],{"class":5685},"    go",[5449,9205,9206],{"class":5494}," client",[5449,9208,5217],{"class":5463},[5449,9210,9011],{"class":5470},[5449,9212,6103],{"class":5463},[5449,9214,9215,9217,9219,9221,9224],{"class":5451,"line":6177},[5449,9216,9142],{"class":5494},[5449,9218,5217],{"class":5463},[5449,9220,8826],{"class":5470},[5449,9222,9223],{"class":5463},"() ",[5449,9225,9226],{"class":5836},"\u002F\u002F Блокує поточну горутину до закриття з'єднання\n",[5449,9228,9229],{"class":5451,"line":6197},[5449,9230,5784],{"class":5463},[5279,9232,9233],{},[5229,9234,9235],{},"Пояснення архітектури:",[5279,9237,9238,9244,9245,9247],{},[5229,9239,9240,9241,7328],{},"Горутина ",[5214,9242,9243],{},"readPump()"," Виконує блокуюче читання повідомлень від клієнта у нескінченному циклі. При отриманні повідомлення воно обробляється (парситься, валідується, передається у бізнес-логіку) та результат відправляється у канал ",[5214,9246,8961],{}," для подальшої передачі клієнту.",[5279,9249,9250,9255,9256,9258,9259,9261],{},[5229,9251,9240,9252,7328],{},[5214,9253,9254],{},"writePump()"," Чекає на повідомлення з каналу ",[5214,9257,8961],{}," та відправляє їх клієнту через ",[5214,9260,8736],{},". Оскільки ця горутина є єдиним місцем виклику методів запису, гарантується потокобезпечність без використання м'ютексів.",[5279,9263,9264,9269],{},[5229,9265,9266,9267,7328],{},"Буферизований канал ",[5214,9268,8961],{}," Ємність каналу 256 дозволяє згладжувати короткочасні сплески навантаження, коли повідомлення генеруються швидше, ніж мережа може їх відправити. Якщо канал заповнюється повністю, відправник блокується, що запобігає необмеженому росту черги у пам'яті.",[5372,9271,9272,9273,9276],{},"Використання окремих горутин для читання та запису є класичним патерном у мережевому програмуванні. Це дозволяє уникнути ",[5252,9274,9275],{},"head-of-line blocking"," — ситуації, коли затримка запису повністю блокує читання нових повідомлень.",[5274,9278,9280],{"id":9279},"обробка-pingpong-для-визначення-живості-зєднання","Обробка Ping\u002FPong для визначення живості з'єднання",[5279,9282,9283,9284,9286],{},"Протокол WebSocket включає механізм керуючих фреймів Ping\u002FPong для перевірки доступності протилежної сторони. Бібліотека ",[5214,9285,5216],{}," автоматично відповідає на Ping-фрейми, але для активної перевірки живості сервер повинен періодично надсилати власні Ping-и.",[5429,9288,9290],{"className":5663,"code":9289,"language":5665,"meta":5437,"style":5437},"import \"time\"\n\nconst (\n    \u002F\u002F Максимальний час очікування на Pong-відповідь\n    pongWait = 60 * time.Second\n    \u002F\u002F Інтервал надсилання Ping (має бути менше pongWait)\n    pingPeriod = (pongWait * 9) \u002F 10\n)\n\nfunc (c *Client) writePump() {\n    ticker := time.NewTicker(pingPeriod)\n    defer func() {\n        ticker.Stop()\n        c.conn.Close()\n    }()\n    \n    for {\n        select {\n        case message, ok := \u003C-c.send:\n            if !ok {\n                \u002F\u002F Канал закритий, завершуємо з'єднання\n                c.conn.WriteMessage(websocket.CloseMessage, []byte{})\n                return\n            }\n            \n            c.conn.WriteMessage(websocket.TextMessage, message)\n            \n        case \u003C-ticker.C:\n            \u002F\u002F Надсилаємо Ping клієнту\n            if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil {\n                return\n            }\n        }\n    }\n}\n\nfunc (c *Client) readPump() {\n    defer c.conn.Close()\n    \n    \u002F\u002F Встановлюємо дедлайн для Pong-відповіді\n    c.conn.SetReadDeadline(time.Now().Add(pongWait))\n    \n    \u002F\u002F Реєструємо обробник Pong, що оновлює дедлайн\n    c.conn.SetPongHandler(func(string) error {\n        c.conn.SetReadDeadline(time.Now().Add(pongWait))\n        return nil\n    })\n    \n    for {\n        _, message, err := c.conn.ReadMessage()\n        if err != nil {\n            break\n        }\n        \n        \u002F\u002F Обробка повідомлення...\n        c.send \u003C- message\n    }\n}\n",[5214,9291,9292,9299,9303,9309,9314,9333,9338,9359,9363,9367,9385,9404,9413,9424,9438,9443,9447,9453,9459,9480,9490,9495,9525,9529,9533,9538,9565,9569,9583,9588,9630,9634,9638,9642,9646,9650,9654,9672,9688,9692,9697,9730,9734,9739,9767,9797,9804,9809,9813,9819,9845,9857,9861,9865,9869,9874,9888,9892],{"__ignoreMap":5437},[5449,9293,9294,9296],{"class":5451,"line":5452},[5449,9295,5686],{"class":5685},[5449,9297,9298],{"class":5477}," \"time\"\n",[5449,9300,9301],{"class":5451,"line":5484},[5449,9302,5488],{"emptyLinePlaceholder":5487},[5449,9304,9305,9307],{"class":5451,"line":5491},[5449,9306,5456],{"class":5455},[5449,9308,5689],{"class":5463},[5449,9310,9311],{"class":5451,"line":5518},[5449,9312,9313],{"class":5836},"    \u002F\u002F Максимальний час очікування на Pong-відповідь\n",[5449,9315,9316,9319,9321,9324,9326,9328,9330],{"class":5451,"line":5548},[5449,9317,9318],{"class":5459},"    pongWait",[5449,9320,5464],{"class":5463},[5449,9322,9323],{"class":6124},"60",[5449,9325,6128],{"class":5463},[5449,9327,6114],{"class":5494},[5449,9329,5217],{"class":5463},[5449,9331,9332],{"class":5494},"Second\n",[5449,9334,9335],{"class":5451,"line":5570},[5449,9336,9337],{"class":5836},"    \u002F\u002F Інтервал надсилання Ping (має бути менше pongWait)\n",[5449,9339,9340,9343,9345,9348,9350,9353,9356],{"class":5451,"line":5576},[5449,9341,9342],{"class":5459},"    pingPeriod",[5449,9344,5503],{"class":5463},[5449,9346,9347],{"class":5494},"pongWait",[5449,9349,6128],{"class":5463},[5449,9351,9352],{"class":6124},"9",[5449,9354,9355],{"class":5463},") \u002F ",[5449,9357,9358],{"class":6124},"10\n",[5449,9360,9361],{"class":5451,"line":5581},[5449,9362,5724],{"class":5463},[5449,9364,9365],{"class":5451,"line":5607},[5449,9366,5488],{"emptyLinePlaceholder":5487},[5449,9368,9369,9371,9373,9375,9377,9379,9381,9383],{"class":5451,"line":5633},[5449,9370,5795],{"class":5455},[5449,9372,5285],{"class":5463},[5449,9374,8815],{"class":5494},[5449,9376,8818],{"class":5463},[5449,9378,8821],{"class":5675},[5449,9380,5509],{"class":5463},[5449,9382,9011],{"class":5470},[5449,9384,6596],{"class":5463},[5449,9386,9387,9389,9391,9393,9395,9397,9399,9402],{"class":5451,"line":5646},[5449,9388,6109],{"class":5494},[5449,9390,5851],{"class":5463},[5449,9392,6114],{"class":5494},[5449,9394,5217],{"class":5463},[5449,9396,6119],{"class":5470},[5449,9398,5474],{"class":5463},[5449,9400,9401],{"class":5494},"pingPeriod",[5449,9403,5724],{"class":5463},[5449,9405,9406,9408,9411],{"class":5451,"line":5731},[5449,9407,6143],{"class":5685},[5449,9409,9410],{"class":5455}," func",[5449,9412,6596],{"class":5463},[5449,9414,9415,9418,9420,9422],{"class":5451,"line":5745},[5449,9416,9417],{"class":5494},"        ticker",[5449,9419,5217],{"class":5463},[5449,9421,6151],{"class":5470},[5449,9423,6103],{"class":5463},[5449,9425,9426,9428,9430,9432,9434,9436],{"class":5451,"line":5757},[5449,9427,8956],{"class":5494},[5449,9429,5217],{"class":5463},[5449,9431,8088],{"class":5494},[5449,9433,5217],{"class":5463},[5449,9435,7594],{"class":5470},[5449,9437,6103],{"class":5463},[5449,9439,9440],{"class":5451,"line":5769},[5449,9441,9442],{"class":5463},"    }()\n",[5449,9444,9445],{"class":5451,"line":5781},[5449,9446,8850],{"class":5463},[5449,9448,9449,9451],{"class":5451,"line":5787},[5449,9450,6164],{"class":5685},[5449,9452,5515],{"class":5463},[5449,9454,9455,9457],{"class":5451,"line":5792},[5449,9456,6172],{"class":5685},[5449,9458,5515],{"class":5463},[5449,9460,9461,9463,9465,9467,9469,9472,9474,9476,9478],{"class":5451,"line":5833},[5449,9462,6180],{"class":5685},[5449,9464,9040],{"class":5494},[5449,9466,5413],{"class":5463},[5449,9468,5848],{"class":5494},[5449,9470,9471],{"class":5463}," := \u003C-",[5449,9473,8875],{"class":5494},[5449,9475,5217],{"class":5463},[5449,9477,8961],{"class":5494},[5449,9479,6258],{"class":5463},[5449,9481,9482,9484,9486,9488],{"class":5451,"line":5840},[5449,9483,6492],{"class":5685},[5449,9485,5874],{"class":5463},[5449,9487,5848],{"class":5494},[5449,9489,5515],{"class":5463},[5449,9491,9492],{"class":5451,"line":5868},[5449,9493,9494],{"class":5836},"                \u002F\u002F Канал закритий, завершуємо з'єднання\n",[5449,9496,9497,9500,9502,9504,9506,9508,9510,9512,9514,9517,9520,9522],{"class":5451,"line":5881},[5449,9498,9499],{"class":5494},"                c",[5449,9501,5217],{"class":5463},[5449,9503,8088],{"class":5494},[5449,9505,5217],{"class":5463},[5449,9507,8606],{"class":5470},[5449,9509,5474],{"class":5463},[5449,9511,7838],{"class":5494},[5449,9513,5217],{"class":5463},[5449,9515,9516],{"class":5494},"CloseMessage",[5449,9518,9519],{"class":5463},", []",[5449,9521,8795],{"class":5675},[5449,9523,9524],{"class":5463},"{})\n",[5449,9526,9527],{"class":5451,"line":5912},[5449,9528,6535],{"class":5685},[5449,9530,9531],{"class":5451,"line":5918},[5449,9532,6399],{"class":5463},[5449,9534,9535],{"class":5451,"line":5924},[5449,9536,9537],{"class":5463},"            \n",[5449,9539,9540,9543,9545,9547,9549,9551,9553,9555,9557,9559,9561,9563],{"class":5451,"line":5929},[5449,9541,9542],{"class":5494},"            c",[5449,9544,5217],{"class":5463},[5449,9546,8088],{"class":5494},[5449,9548,5217],{"class":5463},[5449,9550,8606],{"class":5470},[5449,9552,5474],{"class":5463},[5449,9554,7838],{"class":5494},[5449,9556,5217],{"class":5463},[5449,9558,9078],{"class":5494},[5449,9560,5413],{"class":5463},[5449,9562,8866],{"class":5494},[5449,9564,5724],{"class":5463},[5449,9566,9567],{"class":5451,"line":5935},[5449,9568,9537],{"class":5463},[5449,9570,9571,9573,9575,9577,9579,9581],{"class":5451,"line":5964},[5449,9572,6180],{"class":5685},[5449,9574,6183],{"class":5463},[5449,9576,6250],{"class":5494},[5449,9578,5217],{"class":5463},[5449,9580,6255],{"class":5494},[5449,9582,6258],{"class":5463},[5449,9584,9585],{"class":5451,"line":5989},[5449,9586,9587],{"class":5836},"            \u002F\u002F Надсилаємо Ping клієнту\n",[5449,9589,9590,9592,9594,9596,9598,9600,9602,9604,9606,9608,9610,9612,9615,9617,9619,9622,9624,9626,9628],{"class":5451,"line":6014},[5449,9591,6492],{"class":5685},[5449,9593,6495],{"class":5494},[5449,9595,5851],{"class":5463},[5449,9597,8875],{"class":5494},[5449,9599,5217],{"class":5463},[5449,9601,8088],{"class":5494},[5449,9603,5217],{"class":5463},[5449,9605,8606],{"class":5470},[5449,9607,5474],{"class":5463},[5449,9609,7838],{"class":5494},[5449,9611,5217],{"class":5463},[5449,9613,9614],{"class":5494},"PingMessage",[5449,9616,5413],{"class":5463},[5449,9618,6501],{"class":5455},[5449,9620,9621],{"class":5463},"); ",[5449,9623,6454],{"class":5494},[5449,9625,6498],{"class":5463},[5449,9627,6501],{"class":5455},[5449,9629,5515],{"class":5463},[5449,9631,9632],{"class":5451,"line":6039},[5449,9633,6535],{"class":5685},[5449,9635,9636],{"class":5451,"line":6044},[5449,9637,6399],{"class":5463},[5449,9639,9640],{"class":5451,"line":6077},[5449,9641,6570],{"class":5463},[5449,9643,9644],{"class":5451,"line":6082},[5449,9645,5921],{"class":5463},[5449,9647,9648],{"class":5451,"line":6088},[5449,9649,5784],{"class":5463},[5449,9651,9652],{"class":5451,"line":6106},[5449,9653,5488],{"emptyLinePlaceholder":5487},[5449,9655,9656,9658,9660,9662,9664,9666,9668,9670],{"class":5451,"line":6140},[5449,9657,5795],{"class":5455},[5449,9659,5285],{"class":5463},[5449,9661,8815],{"class":5494},[5449,9663,8818],{"class":5463},[5449,9665,8821],{"class":5675},[5449,9667,5509],{"class":5463},[5449,9669,8826],{"class":5470},[5449,9671,6596],{"class":5463},[5449,9673,9674,9676,9678,9680,9682,9684,9686],{"class":5451,"line":6156},[5449,9675,6143],{"class":5685},[5449,9677,8835],{"class":5494},[5449,9679,5217],{"class":5463},[5449,9681,8088],{"class":5494},[5449,9683,5217],{"class":5463},[5449,9685,7594],{"class":5470},[5449,9687,6103],{"class":5463},[5449,9689,9690],{"class":5451,"line":6161},[5449,9691,8850],{"class":5463},[5449,9693,9694],{"class":5451,"line":6169},[5449,9695,9696],{"class":5836},"    \u002F\u002F Встановлюємо дедлайн для Pong-відповіді\n",[5449,9698,9699,9702,9704,9706,9708,9711,9713,9715,9717,9719,9721,9724,9726,9728],{"class":5451,"line":6177},[5449,9700,9701],{"class":5494},"    c",[5449,9703,5217],{"class":5463},[5449,9705,8088],{"class":5494},[5449,9707,5217],{"class":5463},[5449,9709,9710],{"class":5470},"SetReadDeadline",[5449,9712,5474],{"class":5463},[5449,9714,6114],{"class":5494},[5449,9716,5217],{"class":5463},[5449,9718,6335],{"class":5470},[5449,9720,5946],{"class":5463},[5449,9722,9723],{"class":5470},"Add",[5449,9725,5474],{"class":5463},[5449,9727,9347],{"class":5494},[5449,9729,6667],{"class":5463},[5449,9731,9732],{"class":5451,"line":6197},[5449,9733,8850],{"class":5463},[5449,9735,9736],{"class":5451,"line":6203},[5449,9737,9738],{"class":5836},"    \u002F\u002F Реєструємо обробник Pong, що оновлює дедлайн\n",[5449,9740,9741,9743,9745,9747,9749,9752,9754,9756,9758,9760,9762,9765],{"class":5451,"line":6232},[5449,9742,9701],{"class":5494},[5449,9744,5217],{"class":5463},[5449,9746,8088],{"class":5494},[5449,9748,5217],{"class":5463},[5449,9750,9751],{"class":5470},"SetPongHandler",[5449,9753,5474],{"class":5463},[5449,9755,5795],{"class":5455},[5449,9757,5474],{"class":5463},[5449,9759,8577],{"class":5675},[5449,9761,5509],{"class":5463},[5449,9763,9764],{"class":5675},"error",[5449,9766,5515],{"class":5463},[5449,9768,9769,9771,9773,9775,9777,9779,9781,9783,9785,9787,9789,9791,9793,9795],{"class":5451,"line":6238},[5449,9770,8956],{"class":5494},[5449,9772,5217],{"class":5463},[5449,9774,8088],{"class":5494},[5449,9776,5217],{"class":5463},[5449,9778,9710],{"class":5470},[5449,9780,5474],{"class":5463},[5449,9782,6114],{"class":5494},[5449,9784,5217],{"class":5463},[5449,9786,6335],{"class":5470},[5449,9788,5946],{"class":5463},[5449,9790,9723],{"class":5470},[5449,9792,5474],{"class":5463},[5449,9794,9347],{"class":5494},[5449,9796,6667],{"class":5463},[5449,9798,9799,9801],{"class":5451,"line":6243},[5449,9800,7921],{"class":5685},[5449,9802,9803],{"class":5455}," nil\n",[5449,9805,9806],{"class":5451,"line":6261},[5449,9807,9808],{"class":5463},"    })\n",[5449,9810,9811],{"class":5451,"line":6267},[5449,9812,8850],{"class":5463},[5449,9814,9815,9817],{"class":5451,"line":6284},[5449,9816,6164],{"class":5685},[5449,9818,5515],{"class":5463},[5449,9820,9821,9823,9825,9827,9829,9831,9833,9835,9837,9839,9841,9843],{"class":5451,"line":6303},[5449,9822,8861],{"class":5494},[5449,9824,5413],{"class":5463},[5449,9826,8866],{"class":5494},[5449,9828,5413],{"class":5463},[5449,9830,6454],{"class":5494},[5449,9832,5851],{"class":5463},[5449,9834,8875],{"class":5494},[5449,9836,5217],{"class":5463},[5449,9838,8088],{"class":5494},[5449,9840,5217],{"class":5463},[5449,9842,8423],{"class":5470},[5449,9844,6103],{"class":5463},[5449,9846,9847,9849,9851,9853,9855],{"class":5451,"line":6308},[5449,9848,8430],{"class":5685},[5449,9850,6495],{"class":5494},[5449,9852,6498],{"class":5463},[5449,9854,6501],{"class":5455},[5449,9856,5515],{"class":5463},[5449,9858,9859],{"class":5451,"line":6322},[5449,9860,8536],{"class":5685},[5449,9862,9863],{"class":5451,"line":6346},[5449,9864,6570],{"class":5463},[5449,9866,9867],{"class":5451,"line":6365},[5449,9868,8910],{"class":5463},[5449,9870,9871],{"class":5451,"line":6396},[5449,9872,9873],{"class":5836},"        \u002F\u002F Обробка повідомлення...\n",[5449,9875,9876,9878,9880,9882,9885],{"class":5451,"line":6402},[5449,9877,8956],{"class":5494},[5449,9879,5217],{"class":5463},[5449,9881,8961],{"class":5494},[5449,9883,9884],{"class":5463}," \u003C- ",[5449,9886,9887],{"class":5494},"message\n",[5449,9889,9890],{"class":5451,"line":6407},[5449,9891,5921],{"class":5463},[5449,9893,9894],{"class":5451,"line":6435},[5449,9895,5784],{"class":5463},[5279,9897,9898],{},[5229,9899,9900],{},"Механізм роботи:",[7059,9902,9903,9913,9916,9919,9928],{},[5201,9904,9240,9905,9907,9908,9910,9911,5255],{},[5214,9906,9254],{}," запускає таймер ",[5214,9909,6250],{},", що спрацьовує кожні ~54 секунди (90% від ",[5214,9912,9347],{},[5201,9914,9915],{},"При спрацюванні таймера сервер надсилає клієнту Ping-фрейм.",[5201,9917,9918],{},"Клієнт (якщо він справний та підключений) автоматично відповідає Pong-фреймом.",[5201,9920,9240,9921,9923,9924,9927],{},[5214,9922,9243],{}," через ",[5214,9925,9926],{},"SetPongHandler()"," реєструє обробник, що оновлює дедлайн читання при отриманні Pong.",[5201,9929,9930,9931,9933],{},"Якщо протягом 60 секунд сервер не отримує жодних даних (включаючи Pong), виклик ",[5214,9932,8362],{}," повертає помилку таймауту, і з'єднання закривається.",[6773,9935,9936],{},"Завжди встановлюйте період Ping менше таймауту Pong (зазвичай 80–90%). Це гарантує, що сервер встигне отримати відповідь навіть при невеликій затримці мережі.",[5266,9938],{},[5269,9940,9942],{"id":9941},"патерн-hub-централізоване-керування-клієнтами-та-броадкастинг","Патерн Hub: централізоване керування клієнтами та броадкастинг",[5274,9944,9946],{"id":9945},"проблема-масштабування-прямої-комунікації","Проблема масштабування прямої комунікації",[5279,9948,9949,9950,9953,9954,9956,9957,9959,9960,9963],{},"Коли кількість одночасних WebSocket-з'єднань зростає до сотень або тисяч, виникає потреба у ",[5229,9951,9952],{},"централізованому координаторі",", що керує реєстрацією клієнтів, їх відключенням та широкомовною розсилкою повідомлень (",[5252,9955,5264],{},"). Якщо кожна горутина ",[5214,9958,9243],{}," безпосередньо взаємодіє із колекцією активних клієнтів, необхідно синхронізувати доступ до цієї колекції через м'ютекси, що створює точку контенції (",[5252,9961,9962],{},"contention",") та обмежує пропускну здатність системи.",[5279,9965,9966,9967,9970],{},"Патерн ",[5229,9968,9969],{},"Hub"," розв'язує цю проблему шляхом створення окремої горутини-диспетчера, що володіє монопольним доступом до списку клієнтів та комунікує з іншими горутинами через канали. Завдяки цьому всі операції з колекцією клієнтів виконуються послідовно у єдиній горутині, що усуває необхідність у м'ютексах та забезпечує лінійну масштабованість.",[5274,9972,9974],{"id":9973},"архітектура-hub","Архітектура Hub",[5279,9976,9977],{},"Hub представляє собою централізовану структуру, що керує трьома основними операціями:",[7059,9979,9980,9989,9998],{},[5201,9981,9982,5285,9985,9988],{},[5229,9983,9984],{},"Реєстрація нових клієнтів",[5214,9986,9987],{},"register","): додавання нового з'єднання до активної колекції.",[5201,9990,9991,5285,9994,9997],{},[5229,9992,9993],{},"Відключення клієнтів",[5214,9995,9996],{},"unregister","): видалення закритих з'єднань із колекції.",[5201,9999,10000,5285,10003,10005,10006,5255],{},[5229,10001,10002],{},"Широкомовна розсилка повідомлень",[5214,10004,5264],{},"): надсилання одного повідомлення всім підключеним клієнтам або клієнтам у певній кімнаті (",[5252,10007,10008],{},"room",[7078,10010,10012],{"alt":10011},"Архітектура патерну Hub",[5429,10013,10015],{"className":7083,"code":10014,"language":7085,"meta":5437,"style":5437},"@startuml\nskinparam style plain\nskinparam backgroundColor #FFFFFF\n\npackage \"Hub (центральна горутина)\" #E2E8F0 {\n    rectangle Hub {\n        map \"clients\" #DBEAFE {\n            *Client1 => true\n            *Client2 => true\n            *ClientN => true\n        }\n        queue \"register chan\" #DCFCE7\n        queue \"unregister chan\" #FEF3C7\n        queue \"broadcast chan\" #E0E7FF\n    }\n}\n\nrectangle \"Client 1 Goroutines\" #F1F5F9 {\n    component readPump1\n    component writePump1\n}\n\nrectangle \"Client 2 Goroutines\" #F1F5F9 {\n    component readPump2\n    component writePump2\n}\n\nreadPump1 --> Hub : register\u002Funregister\nreadPump2 --> Hub : register\u002Funregister\n\nHub --> writePump1 : send chan\nHub --> writePump2 : send chan\n\nnote right of Hub\n  Hub виконується у єдиній горутині\n  та обробляє події через select\nend note\n@enduml\n",[5214,10016,10017,10021,10025,10029,10033,10038,10043,10048,10053,10058,10063,10067,10072,10077,10082,10086,10090,10094,10099,10104,10109,10113,10117,10122,10127,10132,10136,10140,10145,10150,10154,10159,10164,10168,10173,10178,10183,10187],{"__ignoreMap":5437},[5449,10018,10019],{"class":5451,"line":5452},[5449,10020,7092],{},[5449,10022,10023],{"class":5451,"line":5484},[5449,10024,7097],{},[5449,10026,10027],{"class":5451,"line":5491},[5449,10028,7102],{},[5449,10030,10031],{"class":5451,"line":5518},[5449,10032,5488],{"emptyLinePlaceholder":5487},[5449,10034,10035],{"class":5451,"line":5548},[5449,10036,10037],{},"package \"Hub (центральна горутина)\" #E2E8F0 {\n",[5449,10039,10040],{"class":5451,"line":5570},[5449,10041,10042],{},"    rectangle Hub {\n",[5449,10044,10045],{"class":5451,"line":5576},[5449,10046,10047],{},"        map \"clients\" #DBEAFE {\n",[5449,10049,10050],{"class":5451,"line":5581},[5449,10051,10052],{},"            *Client1 => true\n",[5449,10054,10055],{"class":5451,"line":5607},[5449,10056,10057],{},"            *Client2 => true\n",[5449,10059,10060],{"class":5451,"line":5633},[5449,10061,10062],{},"            *ClientN => true\n",[5449,10064,10065],{"class":5451,"line":5646},[5449,10066,6570],{},[5449,10068,10069],{"class":5451,"line":5731},[5449,10070,10071],{},"        queue \"register chan\" #DCFCE7\n",[5449,10073,10074],{"class":5451,"line":5745},[5449,10075,10076],{},"        queue \"unregister chan\" #FEF3C7\n",[5449,10078,10079],{"class":5451,"line":5757},[5449,10080,10081],{},"        queue \"broadcast chan\" #E0E7FF\n",[5449,10083,10084],{"class":5451,"line":5769},[5449,10085,5921],{},[5449,10087,10088],{"class":5451,"line":5781},[5449,10089,5784],{},[5449,10091,10092],{"class":5451,"line":5787},[5449,10093,5488],{"emptyLinePlaceholder":5487},[5449,10095,10096],{"class":5451,"line":5792},[5449,10097,10098],{},"rectangle \"Client 1 Goroutines\" #F1F5F9 {\n",[5449,10100,10101],{"class":5451,"line":5833},[5449,10102,10103],{},"    component readPump1\n",[5449,10105,10106],{"class":5451,"line":5840},[5449,10107,10108],{},"    component writePump1\n",[5449,10110,10111],{"class":5451,"line":5868},[5449,10112,5784],{},[5449,10114,10115],{"class":5451,"line":5881},[5449,10116,5488],{"emptyLinePlaceholder":5487},[5449,10118,10119],{"class":5451,"line":5912},[5449,10120,10121],{},"rectangle \"Client 2 Goroutines\" #F1F5F9 {\n",[5449,10123,10124],{"class":5451,"line":5918},[5449,10125,10126],{},"    component readPump2\n",[5449,10128,10129],{"class":5451,"line":5924},[5449,10130,10131],{},"    component writePump2\n",[5449,10133,10134],{"class":5451,"line":5929},[5449,10135,5784],{},[5449,10137,10138],{"class":5451,"line":5935},[5449,10139,5488],{"emptyLinePlaceholder":5487},[5449,10141,10142],{"class":5451,"line":5964},[5449,10143,10144],{},"readPump1 --> Hub : register\u002Funregister\n",[5449,10146,10147],{"class":5451,"line":5989},[5449,10148,10149],{},"readPump2 --> Hub : register\u002Funregister\n",[5449,10151,10152],{"class":5451,"line":6014},[5449,10153,5488],{"emptyLinePlaceholder":5487},[5449,10155,10156],{"class":5451,"line":6039},[5449,10157,10158],{},"Hub --> writePump1 : send chan\n",[5449,10160,10161],{"class":5451,"line":6044},[5449,10162,10163],{},"Hub --> writePump2 : send chan\n",[5449,10165,10166],{"class":5451,"line":6077},[5449,10167,5488],{"emptyLinePlaceholder":5487},[5449,10169,10170],{"class":5451,"line":6082},[5449,10171,10172],{},"note right of Hub\n",[5449,10174,10175],{"class":5451,"line":6088},[5449,10176,10177],{},"  Hub виконується у єдиній горутині\n",[5449,10179,10180],{"class":5451,"line":6106},[5449,10181,10182],{},"  та обробляє події через select\n",[5449,10184,10185],{"class":5451,"line":6140},[5449,10186,7155],{},[5449,10188,10189],{"class":5451,"line":6156},[5449,10190,7282],{},[5274,10192,10194],{"id":10193},"повна-реалізація-hub-патерна","Повна реалізація Hub-патерна",[5429,10196,10198],{"className":5663,"code":10197,"language":5665,"meta":5437,"style":5437},"package main\n\nimport (\n    \"log\"\n    \"net\u002Fhttp\"\n    \"github.com\u002Fgorilla\u002Fwebsocket\"\n)\n\n\u002F\u002F Client представляє одне WebSocket-з'єднання\ntype Client struct {\n    hub  *Hub\n    conn *websocket.Conn\n    send chan []byte\n}\n\n\u002F\u002F Hub керує множиною клієнтів та координує розсилку\ntype Hub struct {\n    \u002F\u002F Карта активних клієнтів\n    clients map[*Client]bool\n    \n    \u002F\u002F Канал для широкомовної розсилки повідомлень\n    broadcast chan []byte\n    \n    \u002F\u002F Канал для реєстрації нових клієнтів\n    register chan *Client\n    \n    \u002F\u002F Канал для відключення клієнтів\n    unregister chan *Client\n}\n\n\u002F\u002F NewHub створює новий екземпляр Hub\nfunc NewHub() *Hub {\n    return &Hub{\n        clients:    make(map[*Client]bool),\n        broadcast:  make(chan []byte),\n        register:   make(chan *Client),\n        unregister: make(chan *Client),\n    }\n}\n\n\u002F\u002F Run запускає головний цикл Hub у окремій горутині\nfunc (h *Hub) Run() {\n    for {\n        select {\n        case client := \u003C-h.register:\n            \u002F\u002F Додаємо нового клієнта до карти\n            h.clients[client] = true\n            log.Printf(\"Client registered. Total: %d\", len(h.clients))\n            \n        case client := \u003C-h.unregister:\n            \u002F\u002F Видаляємо клієнта та закриваємо його канал відправки\n            if _, ok := h.clients[client]; ok {\n                delete(h.clients, client)\n                close(client.send)\n                log.Printf(\"Client unregistered. Total: %d\", len(h.clients))\n            }\n            \n        case message := \u003C-h.broadcast:\n            \u002F\u002F Розсилаємо повідомлення всім активним клієнтам\n            for client := range h.clients {\n                select {\n                case client.send \u003C- message:\n                    \u002F\u002F Повідомлення успішно поставлено у чергу\n                case default:\n                    \u002F\u002F Канал клієнта переповнений, відключаємо його\n                    close(client.send)\n                    delete(h.clients, client)\n                    log.Println(\"Client disconnected due to slow consumer\")\n                }\n            }\n        }\n    }\n}\n\n\u002F\u002F readPump обробляє вхідні повідомлення від клієнта\nfunc (c *Client) readPump() {\n    defer func() {\n        c.hub.unregister \u003C- c\n        c.conn.Close()\n    }()\n    \n    for {\n        _, message, err := c.conn.ReadMessage()\n        if err != nil {\n            if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {\n                log.Printf(\"Read error: %v\", err)\n            }\n            break\n        }\n        \n        \u002F\u002F Розсилаємо отримане повідомлення всім клієнтам\n        c.hub.broadcast \u003C- message\n    }\n}\n\n\u002F\u002F writePump відправляє повідомлення клієнту з каналу send\nfunc (c *Client) writePump() {\n    defer c.conn.Close()\n    \n    for message := range c.send {\n        err := c.conn.WriteMessage(websocket.TextMessage, message)\n        if err != nil {\n            break\n        }\n    }\n}\n\nvar upgrader = websocket.Upgrader{\n    ReadBufferSize:  1024,\n    WriteBufferSize: 1024,\n    CheckOrigin: func(r *http.Request) bool {\n        return true\n    },\n}\n\nfunc serveWs(hub *Hub, w http.ResponseWriter, r *http.Request) {\n    conn, err := upgrader.Upgrade(w, r, nil)\n    if err != nil {\n        log.Printf(\"Upgrade error: %v\", err)\n        return\n    }\n    \n    client := &Client{\n        hub:  hub,\n        conn: conn,\n        send: make(chan []byte, 256),\n    }\n    \n    \u002F\u002F Реєструємо клієнта у Hub\n    client.hub.register \u003C- client\n    \n    \u002F\u002F Запускаємо горутини читання та запису\n    go client.writePump()\n    client.readPump() \u002F\u002F Блокуємо HTTP-handler до закриття з'єднання\n}\n\nfunc main() {\n    hub := NewHub()\n    go hub.Run()\n    \n    http.HandleFunc(\"\u002Fws\", func(w http.ResponseWriter, r *http.Request) {\n        serveWs(hub, w, r)\n    })\n    \n    log.Println(\"WebSocket Hub server listening on :8080\")\n    log.Fatal(http.ListenAndServe(\":8080\", nil))\n}\n",[5214,10199,10200,10206,10210,10216,10220,10224,10228,10232,10236,10241,10251,10262,10274,10285,10289,10293,10298,10309,10314,10333,10337,10342,10353,10357,10362,10374,10378,10383,10394,10398,10402,10407,10421,10432,10458,10477,10496,10515,10519,10523,10527,10532,10552,10558,10564,10581,10586,10608,10640,10644,10660,10665,10695,10714,10729,10760,10764,10768,10784,10789,10809,10816,10833,10838,10847,10852,10867,10886,10902,10907,10911,10915,10919,10923,10927,10932,10950,10959,10978,10993,10998,11003,11010,11037,11050,11085,11108,11113,11118,11123,11128,11134,11151,11156,11161,11166,11172,11191,11208,11213,11232,11263,11276,11281,11286,11291,11296,11301,11318,11329,11340,11367,11374,11379,11384,11389,11429,11460,11473,11497,11502,11507,11512,11523,11535,11546,11569,11574,11579,11585,11603,11608,11614,11627,11641,11646,11651,11660,11672,11686,11691,11732,11752,11757,11762,11778,11805],{"__ignoreMap":5437},[5449,10201,10202,10204],{"class":5451,"line":5452},[5449,10203,5672],{"class":5455},[5449,10205,5676],{"class":5675},[5449,10207,10208],{"class":5451,"line":5484},[5449,10209,5488],{"emptyLinePlaceholder":5487},[5449,10211,10212,10214],{"class":5451,"line":5491},[5449,10213,5686],{"class":5685},[5449,10215,5689],{"class":5463},[5449,10217,10218],{"class":5451,"line":5518},[5449,10219,5704],{"class":5477},[5449,10221,10222],{"class":5451,"line":5548},[5449,10223,5709],{"class":5477},[5449,10225,10226],{"class":5451,"line":5570},[5449,10227,7812],{"class":5477},[5449,10229,10230],{"class":5451,"line":5576},[5449,10231,5724],{"class":5463},[5449,10233,10234],{"class":5451,"line":5581},[5449,10235,5488],{"emptyLinePlaceholder":5487},[5449,10237,10238],{"class":5451,"line":5607},[5449,10239,10240],{"class":5836},"\u002F\u002F Client представляє одне WebSocket-з'єднання\n",[5449,10242,10243,10245,10247,10249],{"class":5451,"line":5633},[5449,10244,5734],{"class":5455},[5449,10246,8764],{"class":5675},[5449,10248,5740],{"class":5455},[5449,10250,5515],{"class":5463},[5449,10252,10253,10256,10259],{"class":5451,"line":5646},[5449,10254,10255],{"class":5494},"    hub",[5449,10257,10258],{"class":5463},"  *",[5449,10260,10261],{"class":5675},"Hub\n",[5449,10263,10264,10266,10268,10270,10272],{"class":5451,"line":5731},[5449,10265,7978],{"class":5494},[5449,10267,5819],{"class":5463},[5449,10269,7838],{"class":5675},[5449,10271,5217],{"class":5463},[5449,10273,8781],{"class":5675},[5449,10275,10276,10278,10280,10282],{"class":5451,"line":5745},[5449,10277,8786],{"class":5494},[5449,10279,8789],{"class":5455},[5449,10281,8792],{"class":5463},[5449,10283,10284],{"class":5675},"byte\n",[5449,10286,10287],{"class":5451,"line":5757},[5449,10288,5784],{"class":5463},[5449,10290,10291],{"class":5451,"line":5769},[5449,10292,5488],{"emptyLinePlaceholder":5487},[5449,10294,10295],{"class":5451,"line":5781},[5449,10296,10297],{"class":5836},"\u002F\u002F Hub керує множиною клієнтів та координує розсилку\n",[5449,10299,10300,10302,10305,10307],{"class":5451,"line":5787},[5449,10301,5734],{"class":5455},[5449,10303,10304],{"class":5675}," Hub",[5449,10306,5740],{"class":5455},[5449,10308,5515],{"class":5463},[5449,10310,10311],{"class":5451,"line":5792},[5449,10312,10313],{"class":5836},"    \u002F\u002F Карта активних клієнтів\n",[5449,10315,10316,10319,10322,10325,10327,10330],{"class":5451,"line":5833},[5449,10317,10318],{"class":5494},"    clients",[5449,10320,10321],{"class":5455}," map",[5449,10323,10324],{"class":5463},"[*",[5449,10326,8821],{"class":5675},[5449,10328,10329],{"class":5463},"]",[5449,10331,10332],{"class":5675},"bool\n",[5449,10334,10335],{"class":5451,"line":5840},[5449,10336,8850],{"class":5463},[5449,10338,10339],{"class":5451,"line":5868},[5449,10340,10341],{"class":5836},"    \u002F\u002F Канал для широкомовної розсилки повідомлень\n",[5449,10343,10344,10347,10349,10351],{"class":5451,"line":5881},[5449,10345,10346],{"class":5494},"    broadcast",[5449,10348,8789],{"class":5455},[5449,10350,8792],{"class":5463},[5449,10352,10284],{"class":5675},[5449,10354,10355],{"class":5451,"line":5912},[5449,10356,8850],{"class":5463},[5449,10358,10359],{"class":5451,"line":5918},[5449,10360,10361],{"class":5836},"    \u002F\u002F Канал для реєстрації нових клієнтів\n",[5449,10363,10364,10367,10369,10371],{"class":5451,"line":5924},[5449,10365,10366],{"class":5494},"    register",[5449,10368,8789],{"class":5455},[5449,10370,5819],{"class":5463},[5449,10372,10373],{"class":5675},"Client\n",[5449,10375,10376],{"class":5451,"line":5929},[5449,10377,8850],{"class":5463},[5449,10379,10380],{"class":5451,"line":5935},[5449,10381,10382],{"class":5836},"    \u002F\u002F Канал для відключення клієнтів\n",[5449,10384,10385,10388,10390,10392],{"class":5451,"line":5964},[5449,10386,10387],{"class":5494},"    unregister",[5449,10389,8789],{"class":5455},[5449,10391,5819],{"class":5463},[5449,10393,10373],{"class":5675},[5449,10395,10396],{"class":5451,"line":5989},[5449,10397,5784],{"class":5463},[5449,10399,10400],{"class":5451,"line":6014},[5449,10401,5488],{"emptyLinePlaceholder":5487},[5449,10403,10404],{"class":5451,"line":6039},[5449,10405,10406],{"class":5836},"\u002F\u002F NewHub створює новий екземпляр Hub\n",[5449,10408,10409,10411,10414,10417,10419],{"class":5451,"line":6044},[5449,10410,5795],{"class":5455},[5449,10412,10413],{"class":5470}," NewHub",[5449,10415,10416],{"class":5463},"() *",[5449,10418,9969],{"class":5675},[5449,10420,5515],{"class":5463},[5449,10422,10423,10425,10428,10430],{"class":5451,"line":6077},[5449,10424,8296],{"class":5685},[5449,10426,10427],{"class":5463}," &",[5449,10429,9969],{"class":5675},[5449,10431,6319],{"class":5463},[5449,10433,10434,10437,10440,10442,10444,10447,10449,10451,10453,10455],{"class":5451,"line":6082},[5449,10435,10436],{"class":5494},"        clients",[5449,10438,10439],{"class":5463},":    ",[5449,10441,9170],{"class":5470},[5449,10443,5474],{"class":5463},[5449,10445,10446],{"class":5455},"map",[5449,10448,10324],{"class":5463},[5449,10450,8821],{"class":5675},[5449,10452,10329],{"class":5463},[5449,10454,7909],{"class":5675},[5449,10456,10457],{"class":5463},"),\n",[5449,10459,10460,10463,10465,10467,10469,10471,10473,10475],{"class":5451,"line":6088},[5449,10461,10462],{"class":5494},"        broadcast",[5449,10464,6352],{"class":5463},[5449,10466,9170],{"class":5470},[5449,10468,5474],{"class":5463},[5449,10470,9175],{"class":5455},[5449,10472,8792],{"class":5463},[5449,10474,8795],{"class":5675},[5449,10476,10457],{"class":5463},[5449,10478,10479,10482,10484,10486,10488,10490,10492,10494],{"class":5451,"line":6106},[5449,10480,10481],{"class":5494},"        register",[5449,10483,6328],{"class":5463},[5449,10485,9170],{"class":5470},[5449,10487,5474],{"class":5463},[5449,10489,9175],{"class":5455},[5449,10491,5819],{"class":5463},[5449,10493,8821],{"class":5675},[5449,10495,10457],{"class":5463},[5449,10497,10498,10501,10503,10505,10507,10509,10511,10513],{"class":5451,"line":6140},[5449,10499,10500],{"class":5494},"        unregister",[5449,10502,6371],{"class":5463},[5449,10504,9170],{"class":5470},[5449,10506,5474],{"class":5463},[5449,10508,9175],{"class":5455},[5449,10510,5819],{"class":5463},[5449,10512,8821],{"class":5675},[5449,10514,10457],{"class":5463},[5449,10516,10517],{"class":5451,"line":6156},[5449,10518,5921],{"class":5463},[5449,10520,10521],{"class":5451,"line":6161},[5449,10522,5784],{"class":5463},[5449,10524,10525],{"class":5451,"line":6169},[5449,10526,5488],{"emptyLinePlaceholder":5487},[5449,10528,10529],{"class":5451,"line":6177},[5449,10530,10531],{"class":5836},"\u002F\u002F Run запускає головний цикл Hub у окремій горутині\n",[5449,10533,10534,10536,10538,10541,10543,10545,10547,10550],{"class":5451,"line":6197},[5449,10535,5795],{"class":5455},[5449,10537,5285],{"class":5463},[5449,10539,10540],{"class":5494},"h ",[5449,10542,8818],{"class":5463},[5449,10544,9969],{"class":5675},[5449,10546,5509],{"class":5463},[5449,10548,10549],{"class":5470},"Run",[5449,10551,6596],{"class":5463},[5449,10553,10554,10556],{"class":5451,"line":6203},[5449,10555,6164],{"class":5685},[5449,10557,5515],{"class":5463},[5449,10559,10560,10562],{"class":5451,"line":6232},[5449,10561,6172],{"class":5685},[5449,10563,5515],{"class":5463},[5449,10565,10566,10568,10570,10572,10575,10577,10579],{"class":5451,"line":6238},[5449,10567,6180],{"class":5685},[5449,10569,9206],{"class":5494},[5449,10571,9471],{"class":5463},[5449,10573,10574],{"class":5494},"h",[5449,10576,5217],{"class":5463},[5449,10578,9987],{"class":5494},[5449,10580,6258],{"class":5463},[5449,10582,10583],{"class":5451,"line":6243},[5449,10584,10585],{"class":5836},"            \u002F\u002F Додаємо нового клієнта до карти\n",[5449,10587,10588,10591,10593,10596,10599,10602,10605],{"class":5451,"line":6261},[5449,10589,10590],{"class":5494},"            h",[5449,10592,5217],{"class":5463},[5449,10594,10595],{"class":5494},"clients",[5449,10597,10598],{"class":5463},"[",[5449,10600,10601],{"class":5494},"client",[5449,10603,10604],{"class":5463},"] = ",[5449,10606,10607],{"class":5455},"true\n",[5449,10609,10610,10612,10614,10616,10618,10621,10623,10625,10627,10630,10632,10634,10636,10638],{"class":5451,"line":6267},[5449,10611,6206],{"class":5494},[5449,10613,5217],{"class":5463},[5449,10615,6052],{"class":5470},[5449,10617,5474],{"class":5463},[5449,10619,10620],{"class":5477},"\"Client registered. Total: ",[5449,10622,8560],{"class":5494},[5449,10624,6063],{"class":5477},[5449,10626,5413],{"class":5463},[5449,10628,10629],{"class":5470},"len",[5449,10631,5474],{"class":5463},[5449,10633,10574],{"class":5494},[5449,10635,5217],{"class":5463},[5449,10637,10595],{"class":5494},[5449,10639,6667],{"class":5463},[5449,10641,10642],{"class":5451,"line":6284},[5449,10643,9537],{"class":5463},[5449,10645,10646,10648,10650,10652,10654,10656,10658],{"class":5451,"line":6303},[5449,10647,6180],{"class":5685},[5449,10649,9206],{"class":5494},[5449,10651,9471],{"class":5463},[5449,10653,10574],{"class":5494},[5449,10655,5217],{"class":5463},[5449,10657,9996],{"class":5494},[5449,10659,6258],{"class":5463},[5449,10661,10662],{"class":5451,"line":6308},[5449,10663,10664],{"class":5836},"            \u002F\u002F Видаляємо клієнта та закриваємо його канал відправки\n",[5449,10666,10667,10669,10672,10674,10676,10678,10680,10682,10684,10686,10688,10691,10693],{"class":5451,"line":6322},[5449,10668,6492],{"class":5685},[5449,10670,10671],{"class":5494}," _",[5449,10673,5413],{"class":5463},[5449,10675,5848],{"class":5494},[5449,10677,5851],{"class":5463},[5449,10679,10574],{"class":5494},[5449,10681,5217],{"class":5463},[5449,10683,10595],{"class":5494},[5449,10685,10598],{"class":5463},[5449,10687,10601],{"class":5494},[5449,10689,10690],{"class":5463},"]; ",[5449,10692,5848],{"class":5494},[5449,10694,5515],{"class":5463},[5449,10696,10697,10700,10702,10704,10706,10708,10710,10712],{"class":5451,"line":6346},[5449,10698,10699],{"class":5470},"                delete",[5449,10701,5474],{"class":5463},[5449,10703,10574],{"class":5494},[5449,10705,5217],{"class":5463},[5449,10707,10595],{"class":5494},[5449,10709,5413],{"class":5463},[5449,10711,10601],{"class":5494},[5449,10713,5724],{"class":5463},[5449,10715,10716,10719,10721,10723,10725,10727],{"class":5451,"line":6365},[5449,10717,10718],{"class":5470},"                close",[5449,10720,5474],{"class":5463},[5449,10722,10601],{"class":5494},[5449,10724,5217],{"class":5463},[5449,10726,8961],{"class":5494},[5449,10728,5724],{"class":5463},[5449,10730,10731,10733,10735,10737,10739,10742,10744,10746,10748,10750,10752,10754,10756,10758],{"class":5451,"line":6396},[5449,10732,6509],{"class":5494},[5449,10734,5217],{"class":5463},[5449,10736,6052],{"class":5470},[5449,10738,5474],{"class":5463},[5449,10740,10741],{"class":5477},"\"Client unregistered. Total: ",[5449,10743,8560],{"class":5494},[5449,10745,6063],{"class":5477},[5449,10747,5413],{"class":5463},[5449,10749,10629],{"class":5470},[5449,10751,5474],{"class":5463},[5449,10753,10574],{"class":5494},[5449,10755,5217],{"class":5463},[5449,10757,10595],{"class":5494},[5449,10759,6667],{"class":5463},[5449,10761,10762],{"class":5451,"line":6402},[5449,10763,6399],{"class":5463},[5449,10765,10766],{"class":5451,"line":6407},[5449,10767,9537],{"class":5463},[5449,10769,10770,10772,10774,10776,10778,10780,10782],{"class":5451,"line":6435},[5449,10771,6180],{"class":5685},[5449,10773,9040],{"class":5494},[5449,10775,9471],{"class":5463},[5449,10777,10574],{"class":5494},[5449,10779,5217],{"class":5463},[5449,10781,5264],{"class":5494},[5449,10783,6258],{"class":5463},[5449,10785,10786],{"class":5451,"line":6440},[5449,10787,10788],{"class":5836},"            \u002F\u002F Розсилаємо повідомлення всім активним клієнтам\n",[5449,10790,10791,10794,10796,10798,10800,10803,10805,10807],{"class":5451,"line":6446},[5449,10792,10793],{"class":5685},"            for",[5449,10795,9206],{"class":5494},[5449,10797,5851],{"class":5463},[5449,10799,9045],{"class":5685},[5449,10801,10802],{"class":5494}," h",[5449,10804,5217],{"class":5463},[5449,10806,10595],{"class":5494},[5449,10808,5515],{"class":5463},[5449,10810,10811,10814],{"class":5451,"line":6489},[5449,10812,10813],{"class":5685},"                select",[5449,10815,5515],{"class":5463},[5449,10817,10818,10821,10823,10825,10827,10829,10831],{"class":5451,"line":6506},[5449,10819,10820],{"class":5685},"                case",[5449,10822,9206],{"class":5494},[5449,10824,5217],{"class":5463},[5449,10826,8961],{"class":5494},[5449,10828,9884],{"class":5463},[5449,10830,8866],{"class":5494},[5449,10832,6258],{"class":5463},[5449,10834,10835],{"class":5451,"line":6532},[5449,10836,10837],{"class":5836},"                    \u002F\u002F Повідомлення успішно поставлено у чергу\n",[5449,10839,10840,10842,10845],{"class":5451,"line":6538},[5449,10841,10820],{"class":5685},[5449,10843,10844],{"class":5685}," default",[5449,10846,6258],{"class":5463},[5449,10848,10849],{"class":5451,"line":6543},[5449,10850,10851],{"class":5836},"                    \u002F\u002F Канал клієнта переповнений, відключаємо його\n",[5449,10853,10854,10857,10859,10861,10863,10865],{"class":5451,"line":6548},[5449,10855,10856],{"class":5470},"                    close",[5449,10858,5474],{"class":5463},[5449,10860,10601],{"class":5494},[5449,10862,5217],{"class":5463},[5449,10864,8961],{"class":5494},[5449,10866,5724],{"class":5463},[5449,10868,10869,10872,10874,10876,10878,10880,10882,10884],{"class":5451,"line":6554},[5449,10870,10871],{"class":5470},"                    delete",[5449,10873,5474],{"class":5463},[5449,10875,10574],{"class":5494},[5449,10877,5217],{"class":5463},[5449,10879,10595],{"class":5494},[5449,10881,5413],{"class":5463},[5449,10883,10601],{"class":5494},[5449,10885,5724],{"class":5463},[5449,10887,10888,10891,10893,10895,10897,10900],{"class":5451,"line":6567},[5449,10889,10890],{"class":5494},"                    log",[5449,10892,5217],{"class":5463},[5449,10894,6629],{"class":5470},[5449,10896,5474],{"class":5463},[5449,10898,10899],{"class":5477},"\"Client disconnected due to slow consumer\"",[5449,10901,5724],{"class":5463},[5449,10903,10904],{"class":5451,"line":6573},[5449,10905,10906],{"class":5463},"                }\n",[5449,10908,10909],{"class":5451,"line":6578},[5449,10910,6399],{"class":5463},[5449,10912,10913],{"class":5451,"line":6583},[5449,10914,6570],{"class":5463},[5449,10916,10917],{"class":5451,"line":6588},[5449,10918,5921],{"class":5463},[5449,10920,10921],{"class":5451,"line":6599},[5449,10922,5784],{"class":5463},[5449,10924,10925],{"class":5451,"line":6622},[5449,10926,5488],{"emptyLinePlaceholder":5487},[5449,10928,10929],{"class":5451,"line":6639},[5449,10930,10931],{"class":5836},"\u002F\u002F readPump обробляє вхідні повідомлення від клієнта\n",[5449,10933,10934,10936,10938,10940,10942,10944,10946,10948],{"class":5451,"line":6670},[5449,10935,5795],{"class":5455},[5449,10937,5285],{"class":5463},[5449,10939,8815],{"class":5494},[5449,10941,8818],{"class":5463},[5449,10943,8821],{"class":5675},[5449,10945,5509],{"class":5463},[5449,10947,8826],{"class":5470},[5449,10949,6596],{"class":5463},[5449,10951,10953,10955,10957],{"class":5451,"line":10952},77,[5449,10954,6143],{"class":5685},[5449,10956,9410],{"class":5455},[5449,10958,6596],{"class":5463},[5449,10960,10962,10964,10966,10969,10971,10973,10975],{"class":5451,"line":10961},78,[5449,10963,8956],{"class":5494},[5449,10965,5217],{"class":5463},[5449,10967,10968],{"class":5494},"hub",[5449,10970,5217],{"class":5463},[5449,10972,9996],{"class":5494},[5449,10974,9884],{"class":5463},[5449,10976,10977],{"class":5494},"c\n",[5449,10979,10981,10983,10985,10987,10989,10991],{"class":5451,"line":10980},79,[5449,10982,8956],{"class":5494},[5449,10984,5217],{"class":5463},[5449,10986,8088],{"class":5494},[5449,10988,5217],{"class":5463},[5449,10990,7594],{"class":5470},[5449,10992,6103],{"class":5463},[5449,10994,10996],{"class":5451,"line":10995},80,[5449,10997,9442],{"class":5463},[5449,10999,11001],{"class":5451,"line":11000},81,[5449,11002,8850],{"class":5463},[5449,11004,11006,11008],{"class":5451,"line":11005},82,[5449,11007,6164],{"class":5685},[5449,11009,5515],{"class":5463},[5449,11011,11013,11015,11017,11019,11021,11023,11025,11027,11029,11031,11033,11035],{"class":5451,"line":11012},83,[5449,11014,8861],{"class":5494},[5449,11016,5413],{"class":5463},[5449,11018,8866],{"class":5494},[5449,11020,5413],{"class":5463},[5449,11022,6454],{"class":5494},[5449,11024,5851],{"class":5463},[5449,11026,8875],{"class":5494},[5449,11028,5217],{"class":5463},[5449,11030,8088],{"class":5494},[5449,11032,5217],{"class":5463},[5449,11034,8423],{"class":5470},[5449,11036,6103],{"class":5463},[5449,11038,11040,11042,11044,11046,11048],{"class":5451,"line":11039},84,[5449,11041,8430],{"class":5685},[5449,11043,6495],{"class":5494},[5449,11045,6498],{"class":5463},[5449,11047,6501],{"class":5455},[5449,11049,5515],{"class":5463},[5449,11051,11053,11055,11057,11059,11062,11064,11066,11068,11070,11072,11074,11076,11078,11080,11083],{"class":5451,"line":11052},85,[5449,11054,6492],{"class":5685},[5449,11056,8450],{"class":5494},[5449,11058,5217],{"class":5463},[5449,11060,11061],{"class":5470},"IsUnexpectedCloseError",[5449,11063,5474],{"class":5463},[5449,11065,6454],{"class":5494},[5449,11067,5413],{"class":5463},[5449,11069,7838],{"class":5494},[5449,11071,5217],{"class":5463},[5449,11073,8477],{"class":5494},[5449,11075,5413],{"class":5463},[5449,11077,7838],{"class":5494},[5449,11079,5217],{"class":5463},[5449,11081,11082],{"class":5494},"CloseAbnormalClosure",[5449,11084,5830],{"class":5463},[5449,11086,11088,11090,11092,11094,11096,11098,11100,11102,11104,11106],{"class":5451,"line":11087},86,[5449,11089,6509],{"class":5494},[5449,11091,5217],{"class":5463},[5449,11093,6052],{"class":5470},[5449,11095,5474],{"class":5463},[5449,11097,8517],{"class":5477},[5449,11099,6521],{"class":5494},[5449,11101,6063],{"class":5477},[5449,11103,5413],{"class":5463},[5449,11105,6454],{"class":5494},[5449,11107,5724],{"class":5463},[5449,11109,11111],{"class":5451,"line":11110},87,[5449,11112,6399],{"class":5463},[5449,11114,11116],{"class":5451,"line":11115},88,[5449,11117,8536],{"class":5685},[5449,11119,11121],{"class":5451,"line":11120},89,[5449,11122,6570],{"class":5463},[5449,11124,11126],{"class":5451,"line":11125},90,[5449,11127,8910],{"class":5463},[5449,11129,11131],{"class":5451,"line":11130},91,[5449,11132,11133],{"class":5836},"        \u002F\u002F Розсилаємо отримане повідомлення всім клієнтам\n",[5449,11135,11137,11139,11141,11143,11145,11147,11149],{"class":5451,"line":11136},92,[5449,11138,8956],{"class":5494},[5449,11140,5217],{"class":5463},[5449,11142,10968],{"class":5494},[5449,11144,5217],{"class":5463},[5449,11146,5264],{"class":5494},[5449,11148,9884],{"class":5463},[5449,11150,9887],{"class":5494},[5449,11152,11154],{"class":5451,"line":11153},93,[5449,11155,5921],{"class":5463},[5449,11157,11159],{"class":5451,"line":11158},94,[5449,11160,5784],{"class":5463},[5449,11162,11164],{"class":5451,"line":11163},95,[5449,11165,5488],{"emptyLinePlaceholder":5487},[5449,11167,11169],{"class":5451,"line":11168},96,[5449,11170,11171],{"class":5836},"\u002F\u002F writePump відправляє повідомлення клієнту з каналу send\n",[5449,11173,11175,11177,11179,11181,11183,11185,11187,11189],{"class":5451,"line":11174},97,[5449,11176,5795],{"class":5455},[5449,11178,5285],{"class":5463},[5449,11180,8815],{"class":5494},[5449,11182,8818],{"class":5463},[5449,11184,8821],{"class":5675},[5449,11186,5509],{"class":5463},[5449,11188,9011],{"class":5470},[5449,11190,6596],{"class":5463},[5449,11192,11194,11196,11198,11200,11202,11204,11206],{"class":5451,"line":11193},98,[5449,11195,6143],{"class":5685},[5449,11197,8835],{"class":5494},[5449,11199,5217],{"class":5463},[5449,11201,8088],{"class":5494},[5449,11203,5217],{"class":5463},[5449,11205,7594],{"class":5470},[5449,11207,6103],{"class":5463},[5449,11209,11211],{"class":5451,"line":11210},99,[5449,11212,8850],{"class":5463},[5449,11214,11216,11218,11220,11222,11224,11226,11228,11230],{"class":5451,"line":11215},100,[5449,11217,6164],{"class":5685},[5449,11219,9040],{"class":5494},[5449,11221,5851],{"class":5463},[5449,11223,9045],{"class":5685},[5449,11225,8835],{"class":5494},[5449,11227,5217],{"class":5463},[5449,11229,8961],{"class":5494},[5449,11231,5515],{"class":5463},[5449,11233,11235,11237,11239,11241,11243,11245,11247,11249,11251,11253,11255,11257,11259,11261],{"class":5451,"line":11234},101,[5449,11236,8597],{"class":5494},[5449,11238,5851],{"class":5463},[5449,11240,8875],{"class":5494},[5449,11242,5217],{"class":5463},[5449,11244,8088],{"class":5494},[5449,11246,5217],{"class":5463},[5449,11248,8606],{"class":5470},[5449,11250,5474],{"class":5463},[5449,11252,7838],{"class":5494},[5449,11254,5217],{"class":5463},[5449,11256,9078],{"class":5494},[5449,11258,5413],{"class":5463},[5449,11260,8866],{"class":5494},[5449,11262,5724],{"class":5463},[5449,11264,11266,11268,11270,11272,11274],{"class":5451,"line":11265},102,[5449,11267,8430],{"class":5685},[5449,11269,6495],{"class":5494},[5449,11271,6498],{"class":5463},[5449,11273,6501],{"class":5455},[5449,11275,5515],{"class":5463},[5449,11277,11279],{"class":5451,"line":11278},103,[5449,11280,8536],{"class":5685},[5449,11282,11284],{"class":5451,"line":11283},104,[5449,11285,6570],{"class":5463},[5449,11287,11289],{"class":5451,"line":11288},105,[5449,11290,5921],{"class":5463},[5449,11292,11294],{"class":5451,"line":11293},106,[5449,11295,5784],{"class":5463},[5449,11297,11299],{"class":5451,"line":11298},107,[5449,11300,5488],{"emptyLinePlaceholder":5487},[5449,11302,11304,11306,11308,11310,11312,11314,11316],{"class":5451,"line":11303},108,[5449,11305,7830],{"class":5455},[5449,11307,7833],{"class":5494},[5449,11309,5464],{"class":5463},[5449,11311,7838],{"class":5675},[5449,11313,5217],{"class":5463},[5449,11315,7843],{"class":5675},[5449,11317,6319],{"class":5463},[5449,11319,11321,11323,11325,11327],{"class":5451,"line":11320},109,[5449,11322,7855],{"class":5494},[5449,11324,6352],{"class":5463},[5449,11326,6384],{"class":6124},[5449,11328,7862],{"class":5463},[5449,11330,11332,11334,11336,11338],{"class":5451,"line":11331},110,[5449,11333,7872],{"class":5494},[5449,11335,6371],{"class":5463},[5449,11337,6384],{"class":6124},[5449,11339,7862],{"class":5463},[5449,11341,11343,11345,11347,11349,11351,11353,11355,11357,11359,11361,11363,11365],{"class":5451,"line":11342},111,[5449,11344,7888],{"class":5494},[5449,11346,6371],{"class":5463},[5449,11348,5795],{"class":5455},[5449,11350,5474],{"class":5463},[5449,11352,5816],{"class":5494},[5449,11354,5819],{"class":5463},[5449,11356,5822],{"class":5675},[5449,11358,5217],{"class":5463},[5449,11360,5827],{"class":5675},[5449,11362,5509],{"class":5463},[5449,11364,7909],{"class":5675},[5449,11366,5515],{"class":5463},[5449,11368,11370,11372],{"class":5451,"line":11369},112,[5449,11371,7921],{"class":5685},[5449,11373,7924],{"class":5455},[5449,11375,11377],{"class":5451,"line":11376},113,[5449,11378,7929],{"class":5463},[5449,11380,11382],{"class":5451,"line":11381},114,[5449,11383,5784],{"class":5463},[5449,11385,11387],{"class":5451,"line":11386},115,[5449,11388,5488],{"emptyLinePlaceholder":5487},[5449,11390,11392,11394,11397,11399,11401,11403,11405,11407,11409,11411,11413,11415,11417,11419,11421,11423,11425,11427],{"class":5451,"line":11391},116,[5449,11393,5795],{"class":5455},[5449,11395,11396],{"class":5470}," serveWs",[5449,11398,5474],{"class":5463},[5449,11400,10968],{"class":5494},[5449,11402,5819],{"class":5463},[5449,11404,9969],{"class":5675},[5449,11406,5413],{"class":5463},[5449,11408,5803],{"class":5494},[5449,11410,5806],{"class":5675},[5449,11412,5217],{"class":5463},[5449,11414,5811],{"class":5675},[5449,11416,5413],{"class":5463},[5449,11418,5816],{"class":5494},[5449,11420,5819],{"class":5463},[5449,11422,5822],{"class":5675},[5449,11424,5217],{"class":5463},[5449,11426,5827],{"class":5675},[5449,11428,5830],{"class":5463},[5449,11430,11432,11434,11436,11438,11440,11442,11444,11446,11448,11450,11452,11454,11456,11458],{"class":5451,"line":11431},117,[5449,11433,7978],{"class":5494},[5449,11435,5413],{"class":5463},[5449,11437,6454],{"class":5494},[5449,11439,5851],{"class":5463},[5449,11441,7987],{"class":5494},[5449,11443,5217],{"class":5463},[5449,11445,7336],{"class":5470},[5449,11447,5474],{"class":5463},[5449,11449,5803],{"class":5494},[5449,11451,5413],{"class":5463},[5449,11453,5816],{"class":5494},[5449,11455,5413],{"class":5463},[5449,11457,6501],{"class":5455},[5449,11459,5724],{"class":5463},[5449,11461,11463,11465,11467,11469,11471],{"class":5451,"line":11462},118,[5449,11464,5871],{"class":5685},[5449,11466,6495],{"class":5494},[5449,11468,6498],{"class":5463},[5449,11470,6501],{"class":5455},[5449,11472,5515],{"class":5463},[5449,11474,11476,11478,11480,11482,11484,11487,11489,11491,11493,11495],{"class":5451,"line":11475},119,[5449,11477,8022],{"class":5494},[5449,11479,5217],{"class":5463},[5449,11481,6052],{"class":5470},[5449,11483,5474],{"class":5463},[5449,11485,11486],{"class":5477},"\"Upgrade error: ",[5449,11488,6521],{"class":5494},[5449,11490,6063],{"class":5477},[5449,11492,5413],{"class":5463},[5449,11494,6454],{"class":5494},[5449,11496,5724],{"class":5463},[5449,11498,11500],{"class":5451,"line":11499},120,[5449,11501,5915],{"class":5685},[5449,11503,11505],{"class":5451,"line":11504},121,[5449,11506,5921],{"class":5463},[5449,11508,11510],{"class":5451,"line":11509},122,[5449,11511,8850],{"class":5463},[5449,11513,11515,11517,11519,11521],{"class":5451,"line":11514},123,[5449,11516,9142],{"class":5494},[5449,11518,9145],{"class":5463},[5449,11520,8821],{"class":5675},[5449,11522,6319],{"class":5463},[5449,11524,11526,11529,11531,11533],{"class":5451,"line":11525},124,[5449,11527,11528],{"class":5494},"        hub",[5449,11530,6352],{"class":5463},[5449,11532,10968],{"class":5494},[5449,11534,7862],{"class":5463},[5449,11536,11538,11540,11542,11544],{"class":5451,"line":11537},125,[5449,11539,9154],{"class":5494},[5449,11541,6371],{"class":5463},[5449,11543,8088],{"class":5494},[5449,11545,7862],{"class":5463},[5449,11547,11549,11551,11553,11555,11557,11559,11561,11563,11565,11567],{"class":5451,"line":11548},126,[5449,11550,9165],{"class":5494},[5449,11552,6371],{"class":5463},[5449,11554,9170],{"class":5470},[5449,11556,5474],{"class":5463},[5449,11558,9175],{"class":5455},[5449,11560,8792],{"class":5463},[5449,11562,8795],{"class":5675},[5449,11564,5413],{"class":5463},[5449,11566,9184],{"class":6124},[5449,11568,10457],{"class":5463},[5449,11570,11572],{"class":5451,"line":11571},127,[5449,11573,5921],{"class":5463},[5449,11575,11577],{"class":5451,"line":11576},128,[5449,11578,8850],{"class":5463},[5449,11580,11582],{"class":5451,"line":11581},129,[5449,11583,11584],{"class":5836},"    \u002F\u002F Реєструємо клієнта у Hub\n",[5449,11586,11588,11590,11592,11594,11596,11598,11600],{"class":5451,"line":11587},130,[5449,11589,9142],{"class":5494},[5449,11591,5217],{"class":5463},[5449,11593,10968],{"class":5494},[5449,11595,5217],{"class":5463},[5449,11597,9987],{"class":5494},[5449,11599,9884],{"class":5463},[5449,11601,11602],{"class":5494},"client\n",[5449,11604,11606],{"class":5451,"line":11605},131,[5449,11607,8850],{"class":5463},[5449,11609,11611],{"class":5451,"line":11610},132,[5449,11612,11613],{"class":5836},"    \u002F\u002F Запускаємо горутини читання та запису\n",[5449,11615,11617,11619,11621,11623,11625],{"class":5451,"line":11616},133,[5449,11618,9203],{"class":5685},[5449,11620,9206],{"class":5494},[5449,11622,5217],{"class":5463},[5449,11624,9011],{"class":5470},[5449,11626,6103],{"class":5463},[5449,11628,11630,11632,11634,11636,11638],{"class":5451,"line":11629},134,[5449,11631,9142],{"class":5494},[5449,11633,5217],{"class":5463},[5449,11635,8826],{"class":5470},[5449,11637,9223],{"class":5463},[5449,11639,11640],{"class":5836},"\u002F\u002F Блокуємо HTTP-handler до закриття з'єднання\n",[5449,11642,11644],{"class":5451,"line":11643},135,[5449,11645,5784],{"class":5463},[5449,11647,11649],{"class":5451,"line":11648},136,[5449,11650,5488],{"emptyLinePlaceholder":5487},[5449,11652,11654,11656,11658],{"class":5451,"line":11653},137,[5449,11655,5795],{"class":5455},[5449,11657,6593],{"class":5470},[5449,11659,6596],{"class":5463},[5449,11661,11663,11665,11667,11670],{"class":5451,"line":11662},138,[5449,11664,10255],{"class":5494},[5449,11666,5851],{"class":5463},[5449,11668,11669],{"class":5470},"NewHub",[5449,11671,6103],{"class":5463},[5449,11673,11675,11677,11680,11682,11684],{"class":5451,"line":11674},139,[5449,11676,9203],{"class":5685},[5449,11678,11679],{"class":5494}," hub",[5449,11681,5217],{"class":5463},[5449,11683,10549],{"class":5470},[5449,11685,6103],{"class":5463},[5449,11687,11689],{"class":5451,"line":11688},140,[5449,11690,8850],{"class":5463},[5449,11692,11694,11696,11698,11700,11702,11704,11706,11708,11710,11712,11714,11716,11718,11720,11722,11724,11726,11728,11730],{"class":5451,"line":11693},141,[5449,11695,6602],{"class":5494},[5449,11697,5217],{"class":5463},[5449,11699,6607],{"class":5470},[5449,11701,5474],{"class":5463},[5449,11703,8144],{"class":5477},[5449,11705,5413],{"class":5463},[5449,11707,5795],{"class":5455},[5449,11709,5474],{"class":5463},[5449,11711,5803],{"class":5494},[5449,11713,5806],{"class":5675},[5449,11715,5217],{"class":5463},[5449,11717,5811],{"class":5675},[5449,11719,5413],{"class":5463},[5449,11721,5816],{"class":5494},[5449,11723,5819],{"class":5463},[5449,11725,5822],{"class":5675},[5449,11727,5217],{"class":5463},[5449,11729,5827],{"class":5675},[5449,11731,5830],{"class":5463},[5449,11733,11735,11738,11740,11742,11744,11746,11748,11750],{"class":5451,"line":11734},142,[5449,11736,11737],{"class":5470},"        serveWs",[5449,11739,5474],{"class":5463},[5449,11741,10968],{"class":5494},[5449,11743,5413],{"class":5463},[5449,11745,5803],{"class":5494},[5449,11747,5413],{"class":5463},[5449,11749,5816],{"class":5494},[5449,11751,5724],{"class":5463},[5449,11753,11755],{"class":5451,"line":11754},143,[5449,11756,9808],{"class":5463},[5449,11758,11760],{"class":5451,"line":11759},144,[5449,11761,8850],{"class":5463},[5449,11763,11765,11767,11769,11771,11773,11776],{"class":5451,"line":11764},145,[5449,11766,6047],{"class":5494},[5449,11768,5217],{"class":5463},[5449,11770,6629],{"class":5470},[5449,11772,5474],{"class":5463},[5449,11774,11775],{"class":5477},"\"WebSocket Hub server listening on :8080\"",[5449,11777,5724],{"class":5463},[5449,11779,11781,11783,11785,11787,11789,11791,11793,11795,11797,11799,11801,11803],{"class":5451,"line":11780},146,[5449,11782,6047],{"class":5494},[5449,11784,5217],{"class":5463},[5449,11786,6646],{"class":5470},[5449,11788,5474],{"class":5463},[5449,11790,5822],{"class":5494},[5449,11792,5217],{"class":5463},[5449,11794,6655],{"class":5470},[5449,11796,5474],{"class":5463},[5449,11798,6660],{"class":5477},[5449,11800,5413],{"class":5463},[5449,11802,6501],{"class":5455},[5449,11804,6667],{"class":5463},[5449,11806,11808],{"class":5451,"line":11807},147,[5449,11809,5784],{"class":5463},[5279,11811,11812],{},[5229,11813,11814],{},"Детальний аналіз реалізації:",[5279,11816,11817,11823,11824,11827],{},[5229,11818,11819,11820,11822],{},"Структура ",[5214,11821,9969],{}," (рядки 17–25):"," Містить карту активних клієнтів (",[5214,11825,11826],{},"map[*Client]bool",") та три канали для асинхронної комунікації. Використання карти замість зрізу дозволяє виконувати операції додавання та видалення за константний час O(1).",[5279,11829,11830,11836,11837,11840,11841,11843,11844,11846],{},[5229,11831,8325,11832,11835],{},[5214,11833,11834],{},"Hub.Run()"," (рядки 33–56):"," Нескінченний цикл обробки подій через ",[5214,11838,11839],{},"select",". Оскільки цей метод виконується у єдиній горутині, всі операції з картою ",[5214,11842,10595],{}," є потокобезпечними без використання м'ютексів. Горутина блокується на ",[5214,11845,11839],{}," до надходження події з одного з каналів.",[5279,11848,11849,11852,11853,11855],{},[5229,11850,11851],{},"Реєстрація клієнта (рядки 35–37):"," При надходженні нового клієнта через канал ",[5214,11854,9987],{},", він додається до карти. Логування кількості підключених клієнтів корисне для моніторингу навантаження системи.",[5279,11857,11858,11861,11862,11864,11865,11867,11868,11870],{},[5229,11859,11860],{},"Відключення клієнта (рядки 39–45):"," При отриманні події ",[5214,11863,9996],{},", клієнт видаляється з карти, а його канал ",[5214,11866,8961],{}," закривається. Закриття каналу сигналізує горутині ",[5214,11869,9254],{}," про необхідність завершення роботи.",[5279,11872,11873,11876,11877,11879,11880,11882,11883,11885,11886,11889,11890,5255],{},[5229,11874,11875],{},"Широкомовна розсилка (рядки 47–56):"," Повідомлення з каналу ",[5214,11878,5264],{}," надсилається у канал ",[5214,11881,8961],{}," кожного підключеного клієнта. Використання вкладеного ",[5214,11884,11839],{}," із ",[5214,11887,11888],{},"default","-гілкою критично важливе: якщо канал клієнта переповнений (клієнт не встигає обробляти повідомлення через повільне мережеве з'єднання), він негайно відключається замість блокування розсилки для інших клієнтів. Це запобігає ситуації «повільний споживач блокує всіх» (",[5252,11891,11892],{},"slow consumer blocking",[5279,11894,11895,11900,11901,11904,11905,11907],{},[5229,11896,9240,11897,11899],{},[5214,11898,9243],{}," (рядки 59–75):"," Читає повідомлення від клієнта та розсилає їх через ",[5214,11902,11903],{},"hub.broadcast",". При закритті з'єднання або помилці читання клієнт відправляє сигнал у канал ",[5214,11906,9996],{}," та закриває сокет.",[5279,11909,11910,9255,11915,11917,11918,11921,11922,5217],{},[5229,11911,9240,11912,11914],{},[5214,11913,9254],{}," (рядки 78–86):",[5214,11916,8961],{}," та відправляє їх через WebSocket. Цикл ",[5214,11919,11920],{},"for range"," автоматично завершується, коли канал закривається у методі ",[5214,11923,11834],{},[5372,11925,11926,11927,5285,11930,11933,11934,5255],{},"Патерн Hub є прикладом парадигми ",[5229,11928,11929],{},"CSP",[5252,11931,11932],{},"Communicating Sequential Processes","), де горутини координуються через канали замість спільної пам'яті. Цей підхід спрощує розуміння коду та усуває класи помилок, пов'язаних із гонками даних (",[5252,11935,11936],{},"data races",[5274,11938,11940],{"id":11939},"розширення-hub-кімнати-та-таргетована-розсилка","Розширення Hub: кімнати та таргетована розсилка",[5279,11942,11943,11944,5285,11947,5255],{},"Для складних застосунків (чат із кімнатами, багатокористувацькі ігри, групові дзвінки) часто потрібна можливість надсилати повідомлення не всім клієнтам, а лише певній підмножині. Реалізуємо систему ",[5229,11945,11946],{},"кімнат",[5252,11948,11949],{},"rooms",[5429,11951,11953],{"className":5663,"code":11952,"language":5665,"meta":5437,"style":5437},"type Hub struct {\n    clients    map[*Client]bool\n    rooms      map[string]map[*Client]bool \u002F\u002F roomID -> clients\n    broadcast  chan []byte\n    roomcast   chan *RoomMessage\n    register   chan *Client\n    unregister chan *Client\n    joinRoom   chan *JoinRoomMsg\n    leaveRoom  chan *LeaveRoomMsg\n}\n\ntype RoomMessage struct {\n    RoomID  string\n    Message []byte\n}\n\ntype JoinRoomMsg struct {\n    Client *Client\n    RoomID string\n}\n\ntype LeaveRoomMsg struct {\n    Client *Client\n    RoomID string\n}\n\nfunc (h *Hub) Run() {\n    for {\n        select {\n        case client := \u003C-h.register:\n            h.clients[client] = true\n            \n        case client := \u003C-h.unregister:\n            if _, ok := h.clients[client]; ok {\n                delete(h.clients, client)\n                \u002F\u002F Видаляємо клієнта з усіх кімнат\n                for roomID, room := range h.rooms {\n                    delete(room, client)\n                    if len(room) == 0 {\n                        delete(h.rooms, roomID)\n                    }\n                }\n                close(client.send)\n            }\n            \n        case msg := \u003C-h.joinRoom:\n            if h.rooms[msg.RoomID] == nil {\n                h.rooms[msg.RoomID] = make(map[*Client]bool)\n            }\n            h.rooms[msg.RoomID][msg.Client] = true\n            log.Printf(\"Client joined room %s. Room size: %d\", msg.RoomID, len(h.rooms[msg.RoomID]))\n            \n        case msg := \u003C-h.leaveRoom:\n            if room, ok := h.rooms[msg.RoomID]; ok {\n                delete(room, msg.Client)\n                if len(room) == 0 {\n                    delete(h.rooms, msg.RoomID)\n                }\n            }\n            \n        case msg := \u003C-h.roomcast:\n            \u002F\u002F Розсилаємо лише клієнтам у конкретній кімнаті\n            if room, ok := h.rooms[msg.RoomID]; ok {\n                for client := range room {\n                    select {\n                    case client.send \u003C- msg.Message:\n                    default:\n                        close(client.send)\n                        delete(h.clients, client)\n                        delete(room, client)\n                    }\n                }\n            }\n            \n        case message := \u003C-h.broadcast:\n            \u002F\u002F Глобальна розсилка залишається без змін\n            for client := range h.clients {\n                select {\n                case client.send \u003C- message:\n                default:\n                    close(client.send)\n                    delete(h.clients, client)\n                }\n            }\n        }\n    }\n}\n",[5214,11954,11955,11965,11980,12007,12018,12031,12041,12051,12063,12075,12079,12083,12094,12102,12111,12115,12119,12130,12139,12146,12150,12154,12165,12173,12179,12183,12187,12205,12211,12217,12233,12249,12253,12269,12297,12315,12320,12344,12358,12377,12397,12402,12406,12420,12424,12428,12446,12473,12508,12512,12541,12594,12598,12615,12648,12666,12683,12705,12709,12713,12717,12734,12739,12771,12785,12792,12814,12821,12836,12854,12868,12872,12876,12880,12884,12900,12905,12923,12929,12945,12952,12966,12984,12988,12992,12996,13000],{"__ignoreMap":5437},[5449,11956,11957,11959,11961,11963],{"class":5451,"line":5452},[5449,11958,5734],{"class":5455},[5449,11960,10304],{"class":5675},[5449,11962,5740],{"class":5455},[5449,11964,5515],{"class":5463},[5449,11966,11967,11969,11972,11974,11976,11978],{"class":5451,"line":5484},[5449,11968,10318],{"class":5494},[5449,11970,11971],{"class":5455},"    map",[5449,11973,10324],{"class":5463},[5449,11975,8821],{"class":5675},[5449,11977,10329],{"class":5463},[5449,11979,10332],{"class":5675},[5449,11981,11982,11985,11988,11990,11992,11994,11996,11998,12000,12002,12004],{"class":5451,"line":5491},[5449,11983,11984],{"class":5494},"    rooms",[5449,11986,11987],{"class":5455},"      map",[5449,11989,10598],{"class":5463},[5449,11991,8577],{"class":5675},[5449,11993,10329],{"class":5463},[5449,11995,10446],{"class":5455},[5449,11997,10324],{"class":5463},[5449,11999,8821],{"class":5675},[5449,12001,10329],{"class":5463},[5449,12003,7909],{"class":5675},[5449,12005,12006],{"class":5836}," \u002F\u002F roomID -> clients\n",[5449,12008,12009,12011,12014,12016],{"class":5451,"line":5518},[5449,12010,10346],{"class":5494},[5449,12012,12013],{"class":5455},"  chan",[5449,12015,8792],{"class":5463},[5449,12017,10284],{"class":5675},[5449,12019,12020,12023,12026,12028],{"class":5451,"line":5548},[5449,12021,12022],{"class":5494},"    roomcast",[5449,12024,12025],{"class":5455},"   chan",[5449,12027,5819],{"class":5463},[5449,12029,12030],{"class":5675},"RoomMessage\n",[5449,12032,12033,12035,12037,12039],{"class":5451,"line":5570},[5449,12034,10366],{"class":5494},[5449,12036,12025],{"class":5455},[5449,12038,5819],{"class":5463},[5449,12040,10373],{"class":5675},[5449,12042,12043,12045,12047,12049],{"class":5451,"line":5576},[5449,12044,10387],{"class":5494},[5449,12046,8789],{"class":5455},[5449,12048,5819],{"class":5463},[5449,12050,10373],{"class":5675},[5449,12052,12053,12056,12058,12060],{"class":5451,"line":5581},[5449,12054,12055],{"class":5494},"    joinRoom",[5449,12057,12025],{"class":5455},[5449,12059,5819],{"class":5463},[5449,12061,12062],{"class":5675},"JoinRoomMsg\n",[5449,12064,12065,12068,12070,12072],{"class":5451,"line":5607},[5449,12066,12067],{"class":5494},"    leaveRoom",[5449,12069,12013],{"class":5455},[5449,12071,5819],{"class":5463},[5449,12073,12074],{"class":5675},"LeaveRoomMsg\n",[5449,12076,12077],{"class":5451,"line":5633},[5449,12078,5784],{"class":5463},[5449,12080,12081],{"class":5451,"line":5646},[5449,12082,5488],{"emptyLinePlaceholder":5487},[5449,12084,12085,12087,12090,12092],{"class":5451,"line":5731},[5449,12086,5734],{"class":5455},[5449,12088,12089],{"class":5675}," RoomMessage",[5449,12091,5740],{"class":5455},[5449,12093,5515],{"class":5463},[5449,12095,12096,12099],{"class":5451,"line":5745},[5449,12097,12098],{"class":5494},"    RoomID",[5449,12100,12101],{"class":5675},"  string\n",[5449,12103,12104,12107,12109],{"class":5451,"line":5757},[5449,12105,12106],{"class":5494},"    Message",[5449,12108,8792],{"class":5463},[5449,12110,10284],{"class":5675},[5449,12112,12113],{"class":5451,"line":5769},[5449,12114,5784],{"class":5463},[5449,12116,12117],{"class":5451,"line":5781},[5449,12118,5488],{"emptyLinePlaceholder":5487},[5449,12120,12121,12123,12126,12128],{"class":5451,"line":5787},[5449,12122,5734],{"class":5455},[5449,12124,12125],{"class":5675}," JoinRoomMsg",[5449,12127,5740],{"class":5455},[5449,12129,5515],{"class":5463},[5449,12131,12132,12135,12137],{"class":5451,"line":5792},[5449,12133,12134],{"class":5494},"    Client",[5449,12136,5819],{"class":5463},[5449,12138,10373],{"class":5675},[5449,12140,12141,12143],{"class":5451,"line":5833},[5449,12142,12098],{"class":5494},[5449,12144,12145],{"class":5675}," string\n",[5449,12147,12148],{"class":5451,"line":5840},[5449,12149,5784],{"class":5463},[5449,12151,12152],{"class":5451,"line":5868},[5449,12153,5488],{"emptyLinePlaceholder":5487},[5449,12155,12156,12158,12161,12163],{"class":5451,"line":5881},[5449,12157,5734],{"class":5455},[5449,12159,12160],{"class":5675}," LeaveRoomMsg",[5449,12162,5740],{"class":5455},[5449,12164,5515],{"class":5463},[5449,12166,12167,12169,12171],{"class":5451,"line":5912},[5449,12168,12134],{"class":5494},[5449,12170,5819],{"class":5463},[5449,12172,10373],{"class":5675},[5449,12174,12175,12177],{"class":5451,"line":5918},[5449,12176,12098],{"class":5494},[5449,12178,12145],{"class":5675},[5449,12180,12181],{"class":5451,"line":5924},[5449,12182,5784],{"class":5463},[5449,12184,12185],{"class":5451,"line":5929},[5449,12186,5488],{"emptyLinePlaceholder":5487},[5449,12188,12189,12191,12193,12195,12197,12199,12201,12203],{"class":5451,"line":5935},[5449,12190,5795],{"class":5455},[5449,12192,5285],{"class":5463},[5449,12194,10540],{"class":5494},[5449,12196,8818],{"class":5463},[5449,12198,9969],{"class":5675},[5449,12200,5509],{"class":5463},[5449,12202,10549],{"class":5470},[5449,12204,6596],{"class":5463},[5449,12206,12207,12209],{"class":5451,"line":5964},[5449,12208,6164],{"class":5685},[5449,12210,5515],{"class":5463},[5449,12212,12213,12215],{"class":5451,"line":5989},[5449,12214,6172],{"class":5685},[5449,12216,5515],{"class":5463},[5449,12218,12219,12221,12223,12225,12227,12229,12231],{"class":5451,"line":6014},[5449,12220,6180],{"class":5685},[5449,12222,9206],{"class":5494},[5449,12224,9471],{"class":5463},[5449,12226,10574],{"class":5494},[5449,12228,5217],{"class":5463},[5449,12230,9987],{"class":5494},[5449,12232,6258],{"class":5463},[5449,12234,12235,12237,12239,12241,12243,12245,12247],{"class":5451,"line":6039},[5449,12236,10590],{"class":5494},[5449,12238,5217],{"class":5463},[5449,12240,10595],{"class":5494},[5449,12242,10598],{"class":5463},[5449,12244,10601],{"class":5494},[5449,12246,10604],{"class":5463},[5449,12248,10607],{"class":5455},[5449,12250,12251],{"class":5451,"line":6044},[5449,12252,9537],{"class":5463},[5449,12254,12255,12257,12259,12261,12263,12265,12267],{"class":5451,"line":6077},[5449,12256,6180],{"class":5685},[5449,12258,9206],{"class":5494},[5449,12260,9471],{"class":5463},[5449,12262,10574],{"class":5494},[5449,12264,5217],{"class":5463},[5449,12266,9996],{"class":5494},[5449,12268,6258],{"class":5463},[5449,12270,12271,12273,12275,12277,12279,12281,12283,12285,12287,12289,12291,12293,12295],{"class":5451,"line":6082},[5449,12272,6492],{"class":5685},[5449,12274,10671],{"class":5494},[5449,12276,5413],{"class":5463},[5449,12278,5848],{"class":5494},[5449,12280,5851],{"class":5463},[5449,12282,10574],{"class":5494},[5449,12284,5217],{"class":5463},[5449,12286,10595],{"class":5494},[5449,12288,10598],{"class":5463},[5449,12290,10601],{"class":5494},[5449,12292,10690],{"class":5463},[5449,12294,5848],{"class":5494},[5449,12296,5515],{"class":5463},[5449,12298,12299,12301,12303,12305,12307,12309,12311,12313],{"class":5451,"line":6088},[5449,12300,10699],{"class":5470},[5449,12302,5474],{"class":5463},[5449,12304,10574],{"class":5494},[5449,12306,5217],{"class":5463},[5449,12308,10595],{"class":5494},[5449,12310,5413],{"class":5463},[5449,12312,10601],{"class":5494},[5449,12314,5724],{"class":5463},[5449,12316,12317],{"class":5451,"line":6106},[5449,12318,12319],{"class":5836},"                \u002F\u002F Видаляємо клієнта з усіх кімнат\n",[5449,12321,12322,12325,12328,12330,12332,12334,12336,12338,12340,12342],{"class":5451,"line":6140},[5449,12323,12324],{"class":5685},"                for",[5449,12326,12327],{"class":5494}," roomID",[5449,12329,5413],{"class":5463},[5449,12331,10008],{"class":5494},[5449,12333,5851],{"class":5463},[5449,12335,9045],{"class":5685},[5449,12337,10802],{"class":5494},[5449,12339,5217],{"class":5463},[5449,12341,11949],{"class":5494},[5449,12343,5515],{"class":5463},[5449,12345,12346,12348,12350,12352,12354,12356],{"class":5451,"line":6156},[5449,12347,10871],{"class":5470},[5449,12349,5474],{"class":5463},[5449,12351,10008],{"class":5494},[5449,12353,5413],{"class":5463},[5449,12355,10601],{"class":5494},[5449,12357,5724],{"class":5463},[5449,12359,12360,12363,12366,12368,12370,12373,12375],{"class":5451,"line":6161},[5449,12361,12362],{"class":5685},"                    if",[5449,12364,12365],{"class":5470}," len",[5449,12367,5474],{"class":5463},[5449,12369,10008],{"class":5494},[5449,12371,12372],{"class":5463},") == ",[5449,12374,7558],{"class":6124},[5449,12376,5515],{"class":5463},[5449,12378,12379,12382,12384,12386,12388,12390,12392,12395],{"class":5451,"line":6169},[5449,12380,12381],{"class":5470},"                        delete",[5449,12383,5474],{"class":5463},[5449,12385,10574],{"class":5494},[5449,12387,5217],{"class":5463},[5449,12389,11949],{"class":5494},[5449,12391,5413],{"class":5463},[5449,12393,12394],{"class":5494},"roomID",[5449,12396,5724],{"class":5463},[5449,12398,12399],{"class":5451,"line":6177},[5449,12400,12401],{"class":5463},"                    }\n",[5449,12403,12404],{"class":5451,"line":6197},[5449,12405,10906],{"class":5463},[5449,12407,12408,12410,12412,12414,12416,12418],{"class":5451,"line":6203},[5449,12409,10718],{"class":5470},[5449,12411,5474],{"class":5463},[5449,12413,10601],{"class":5494},[5449,12415,5217],{"class":5463},[5449,12417,8961],{"class":5494},[5449,12419,5724],{"class":5463},[5449,12421,12422],{"class":5451,"line":6232},[5449,12423,6399],{"class":5463},[5449,12425,12426],{"class":5451,"line":6238},[5449,12427,9537],{"class":5463},[5449,12429,12430,12432,12435,12437,12439,12441,12444],{"class":5451,"line":6243},[5449,12431,6180],{"class":5685},[5449,12433,12434],{"class":5494}," msg",[5449,12436,9471],{"class":5463},[5449,12438,10574],{"class":5494},[5449,12440,5217],{"class":5463},[5449,12442,12443],{"class":5494},"joinRoom",[5449,12445,6258],{"class":5463},[5449,12447,12448,12450,12452,12454,12456,12458,12461,12463,12466,12469,12471],{"class":5451,"line":6261},[5449,12449,6492],{"class":5685},[5449,12451,10802],{"class":5494},[5449,12453,5217],{"class":5463},[5449,12455,11949],{"class":5494},[5449,12457,10598],{"class":5463},[5449,12459,12460],{"class":5494},"msg",[5449,12462,5217],{"class":5463},[5449,12464,12465],{"class":5494},"RoomID",[5449,12467,12468],{"class":5463},"] == ",[5449,12470,6501],{"class":5455},[5449,12472,5515],{"class":5463},[5449,12474,12475,12478,12480,12482,12484,12486,12488,12490,12492,12494,12496,12498,12500,12502,12504,12506],{"class":5451,"line":6267},[5449,12476,12477],{"class":5494},"                h",[5449,12479,5217],{"class":5463},[5449,12481,11949],{"class":5494},[5449,12483,10598],{"class":5463},[5449,12485,12460],{"class":5494},[5449,12487,5217],{"class":5463},[5449,12489,12465],{"class":5494},[5449,12491,10604],{"class":5463},[5449,12493,9170],{"class":5470},[5449,12495,5474],{"class":5463},[5449,12497,10446],{"class":5455},[5449,12499,10324],{"class":5463},[5449,12501,8821],{"class":5675},[5449,12503,10329],{"class":5463},[5449,12505,7909],{"class":5675},[5449,12507,5724],{"class":5463},[5449,12509,12510],{"class":5451,"line":6284},[5449,12511,6399],{"class":5463},[5449,12513,12514,12516,12518,12520,12522,12524,12526,12528,12531,12533,12535,12537,12539],{"class":5451,"line":6303},[5449,12515,10590],{"class":5494},[5449,12517,5217],{"class":5463},[5449,12519,11949],{"class":5494},[5449,12521,10598],{"class":5463},[5449,12523,12460],{"class":5494},[5449,12525,5217],{"class":5463},[5449,12527,12465],{"class":5494},[5449,12529,12530],{"class":5463},"][",[5449,12532,12460],{"class":5494},[5449,12534,5217],{"class":5463},[5449,12536,8821],{"class":5494},[5449,12538,10604],{"class":5463},[5449,12540,10607],{"class":5455},[5449,12542,12543,12545,12547,12549,12551,12554,12556,12559,12561,12563,12565,12567,12569,12571,12573,12575,12577,12579,12581,12583,12585,12587,12589,12591],{"class":5451,"line":6308},[5449,12544,6206],{"class":5494},[5449,12546,5217],{"class":5463},[5449,12548,6052],{"class":5470},[5449,12550,5474],{"class":5463},[5449,12552,12553],{"class":5477},"\"Client joined room ",[5449,12555,6060],{"class":5494},[5449,12557,12558],{"class":5477},". Room size: ",[5449,12560,8560],{"class":5494},[5449,12562,6063],{"class":5477},[5449,12564,5413],{"class":5463},[5449,12566,12460],{"class":5494},[5449,12568,5217],{"class":5463},[5449,12570,12465],{"class":5494},[5449,12572,5413],{"class":5463},[5449,12574,10629],{"class":5470},[5449,12576,5474],{"class":5463},[5449,12578,10574],{"class":5494},[5449,12580,5217],{"class":5463},[5449,12582,11949],{"class":5494},[5449,12584,10598],{"class":5463},[5449,12586,12460],{"class":5494},[5449,12588,5217],{"class":5463},[5449,12590,12465],{"class":5494},[5449,12592,12593],{"class":5463},"]))\n",[5449,12595,12596],{"class":5451,"line":6322},[5449,12597,9537],{"class":5463},[5449,12599,12600,12602,12604,12606,12608,12610,12613],{"class":5451,"line":6346},[5449,12601,6180],{"class":5685},[5449,12603,12434],{"class":5494},[5449,12605,9471],{"class":5463},[5449,12607,10574],{"class":5494},[5449,12609,5217],{"class":5463},[5449,12611,12612],{"class":5494},"leaveRoom",[5449,12614,6258],{"class":5463},[5449,12616,12617,12619,12622,12624,12626,12628,12630,12632,12634,12636,12638,12640,12642,12644,12646],{"class":5451,"line":6365},[5449,12618,6492],{"class":5685},[5449,12620,12621],{"class":5494}," room",[5449,12623,5413],{"class":5463},[5449,12625,5848],{"class":5494},[5449,12627,5851],{"class":5463},[5449,12629,10574],{"class":5494},[5449,12631,5217],{"class":5463},[5449,12633,11949],{"class":5494},[5449,12635,10598],{"class":5463},[5449,12637,12460],{"class":5494},[5449,12639,5217],{"class":5463},[5449,12641,12465],{"class":5494},[5449,12643,10690],{"class":5463},[5449,12645,5848],{"class":5494},[5449,12647,5515],{"class":5463},[5449,12649,12650,12652,12654,12656,12658,12660,12662,12664],{"class":5451,"line":6396},[5449,12651,10699],{"class":5470},[5449,12653,5474],{"class":5463},[5449,12655,10008],{"class":5494},[5449,12657,5413],{"class":5463},[5449,12659,12460],{"class":5494},[5449,12661,5217],{"class":5463},[5449,12663,8821],{"class":5494},[5449,12665,5724],{"class":5463},[5449,12667,12668,12671,12673,12675,12677,12679,12681],{"class":5451,"line":6402},[5449,12669,12670],{"class":5685},"                if",[5449,12672,12365],{"class":5470},[5449,12674,5474],{"class":5463},[5449,12676,10008],{"class":5494},[5449,12678,12372],{"class":5463},[5449,12680,7558],{"class":6124},[5449,12682,5515],{"class":5463},[5449,12684,12685,12687,12689,12691,12693,12695,12697,12699,12701,12703],{"class":5451,"line":6407},[5449,12686,10871],{"class":5470},[5449,12688,5474],{"class":5463},[5449,12690,10574],{"class":5494},[5449,12692,5217],{"class":5463},[5449,12694,11949],{"class":5494},[5449,12696,5413],{"class":5463},[5449,12698,12460],{"class":5494},[5449,12700,5217],{"class":5463},[5449,12702,12465],{"class":5494},[5449,12704,5724],{"class":5463},[5449,12706,12707],{"class":5451,"line":6435},[5449,12708,10906],{"class":5463},[5449,12710,12711],{"class":5451,"line":6440},[5449,12712,6399],{"class":5463},[5449,12714,12715],{"class":5451,"line":6446},[5449,12716,9537],{"class":5463},[5449,12718,12719,12721,12723,12725,12727,12729,12732],{"class":5451,"line":6489},[5449,12720,6180],{"class":5685},[5449,12722,12434],{"class":5494},[5449,12724,9471],{"class":5463},[5449,12726,10574],{"class":5494},[5449,12728,5217],{"class":5463},[5449,12730,12731],{"class":5494},"roomcast",[5449,12733,6258],{"class":5463},[5449,12735,12736],{"class":5451,"line":6506},[5449,12737,12738],{"class":5836},"            \u002F\u002F Розсилаємо лише клієнтам у конкретній кімнаті\n",[5449,12740,12741,12743,12745,12747,12749,12751,12753,12755,12757,12759,12761,12763,12765,12767,12769],{"class":5451,"line":6532},[5449,12742,6492],{"class":5685},[5449,12744,12621],{"class":5494},[5449,12746,5413],{"class":5463},[5449,12748,5848],{"class":5494},[5449,12750,5851],{"class":5463},[5449,12752,10574],{"class":5494},[5449,12754,5217],{"class":5463},[5449,12756,11949],{"class":5494},[5449,12758,10598],{"class":5463},[5449,12760,12460],{"class":5494},[5449,12762,5217],{"class":5463},[5449,12764,12465],{"class":5494},[5449,12766,10690],{"class":5463},[5449,12768,5848],{"class":5494},[5449,12770,5515],{"class":5463},[5449,12772,12773,12775,12777,12779,12781,12783],{"class":5451,"line":6538},[5449,12774,12324],{"class":5685},[5449,12776,9206],{"class":5494},[5449,12778,5851],{"class":5463},[5449,12780,9045],{"class":5685},[5449,12782,12621],{"class":5494},[5449,12784,5515],{"class":5463},[5449,12786,12787,12790],{"class":5451,"line":6543},[5449,12788,12789],{"class":5685},"                    select",[5449,12791,5515],{"class":5463},[5449,12793,12794,12797,12799,12801,12803,12805,12807,12809,12812],{"class":5451,"line":6548},[5449,12795,12796],{"class":5685},"                    case",[5449,12798,9206],{"class":5494},[5449,12800,5217],{"class":5463},[5449,12802,8961],{"class":5494},[5449,12804,9884],{"class":5463},[5449,12806,12460],{"class":5494},[5449,12808,5217],{"class":5463},[5449,12810,12811],{"class":5494},"Message",[5449,12813,6258],{"class":5463},[5449,12815,12816,12819],{"class":5451,"line":6554},[5449,12817,12818],{"class":5685},"                    default",[5449,12820,6258],{"class":5463},[5449,12822,12823,12826,12828,12830,12832,12834],{"class":5451,"line":6567},[5449,12824,12825],{"class":5470},"                        close",[5449,12827,5474],{"class":5463},[5449,12829,10601],{"class":5494},[5449,12831,5217],{"class":5463},[5449,12833,8961],{"class":5494},[5449,12835,5724],{"class":5463},[5449,12837,12838,12840,12842,12844,12846,12848,12850,12852],{"class":5451,"line":6573},[5449,12839,12381],{"class":5470},[5449,12841,5474],{"class":5463},[5449,12843,10574],{"class":5494},[5449,12845,5217],{"class":5463},[5449,12847,10595],{"class":5494},[5449,12849,5413],{"class":5463},[5449,12851,10601],{"class":5494},[5449,12853,5724],{"class":5463},[5449,12855,12856,12858,12860,12862,12864,12866],{"class":5451,"line":6578},[5449,12857,12381],{"class":5470},[5449,12859,5474],{"class":5463},[5449,12861,10008],{"class":5494},[5449,12863,5413],{"class":5463},[5449,12865,10601],{"class":5494},[5449,12867,5724],{"class":5463},[5449,12869,12870],{"class":5451,"line":6583},[5449,12871,12401],{"class":5463},[5449,12873,12874],{"class":5451,"line":6588},[5449,12875,10906],{"class":5463},[5449,12877,12878],{"class":5451,"line":6599},[5449,12879,6399],{"class":5463},[5449,12881,12882],{"class":5451,"line":6622},[5449,12883,9537],{"class":5463},[5449,12885,12886,12888,12890,12892,12894,12896,12898],{"class":5451,"line":6639},[5449,12887,6180],{"class":5685},[5449,12889,9040],{"class":5494},[5449,12891,9471],{"class":5463},[5449,12893,10574],{"class":5494},[5449,12895,5217],{"class":5463},[5449,12897,5264],{"class":5494},[5449,12899,6258],{"class":5463},[5449,12901,12902],{"class":5451,"line":6670},[5449,12903,12904],{"class":5836},"            \u002F\u002F Глобальна розсилка залишається без змін\n",[5449,12906,12907,12909,12911,12913,12915,12917,12919,12921],{"class":5451,"line":10952},[5449,12908,10793],{"class":5685},[5449,12910,9206],{"class":5494},[5449,12912,5851],{"class":5463},[5449,12914,9045],{"class":5685},[5449,12916,10802],{"class":5494},[5449,12918,5217],{"class":5463},[5449,12920,10595],{"class":5494},[5449,12922,5515],{"class":5463},[5449,12924,12925,12927],{"class":5451,"line":10961},[5449,12926,10813],{"class":5685},[5449,12928,5515],{"class":5463},[5449,12930,12931,12933,12935,12937,12939,12941,12943],{"class":5451,"line":10980},[5449,12932,10820],{"class":5685},[5449,12934,9206],{"class":5494},[5449,12936,5217],{"class":5463},[5449,12938,8961],{"class":5494},[5449,12940,9884],{"class":5463},[5449,12942,8866],{"class":5494},[5449,12944,6258],{"class":5463},[5449,12946,12947,12950],{"class":5451,"line":10995},[5449,12948,12949],{"class":5685},"                default",[5449,12951,6258],{"class":5463},[5449,12953,12954,12956,12958,12960,12962,12964],{"class":5451,"line":11000},[5449,12955,10856],{"class":5470},[5449,12957,5474],{"class":5463},[5449,12959,10601],{"class":5494},[5449,12961,5217],{"class":5463},[5449,12963,8961],{"class":5494},[5449,12965,5724],{"class":5463},[5449,12967,12968,12970,12972,12974,12976,12978,12980,12982],{"class":5451,"line":11005},[5449,12969,10871],{"class":5470},[5449,12971,5474],{"class":5463},[5449,12973,10574],{"class":5494},[5449,12975,5217],{"class":5463},[5449,12977,10595],{"class":5494},[5449,12979,5413],{"class":5463},[5449,12981,10601],{"class":5494},[5449,12983,5724],{"class":5463},[5449,12985,12986],{"class":5451,"line":11012},[5449,12987,10906],{"class":5463},[5449,12989,12990],{"class":5451,"line":11039},[5449,12991,6399],{"class":5463},[5449,12993,12994],{"class":5451,"line":11052},[5449,12995,6570],{"class":5463},[5449,12997,12998],{"class":5451,"line":11087},[5449,12999,5921],{"class":5463},[5449,13001,13002],{"class":5451,"line":11110},[5449,13003,5784],{"class":5463},[5279,13005,13006],{},[5229,13007,13008],{},"Використання кімнат у клієнтському коді:",[5429,13010,13012],{"className":5663,"code":13011,"language":5665,"meta":5437,"style":5437},"\u002F\u002F Клієнт приєднується до кімнати \"chat-room-42\"\nhub.joinRoom \u003C- &JoinRoomMsg{\n    Client: client,\n    RoomID: \"chat-room-42\",\n}\n\n\u002F\u002F Розсилка повідомлення лише учасникам кімнати\nhub.roomcast \u003C- &RoomMessage{\n    RoomID:  \"chat-room-42\",\n    Message: []byte(`{\"user\": \"alice\", \"text\": \"Hello room!\"}`),\n}\n",[5214,13013,13014,13019,13035,13045,13056,13060,13064,13069,13084,13094,13110],{"__ignoreMap":5437},[5449,13015,13016],{"class":5451,"line":5452},[5449,13017,13018],{"class":5836},"\u002F\u002F Клієнт приєднується до кімнати \"chat-room-42\"\n",[5449,13020,13021,13023,13025,13027,13030,13033],{"class":5451,"line":5484},[5449,13022,10968],{"class":5494},[5449,13024,5217],{"class":5463},[5449,13026,12443],{"class":5494},[5449,13028,13029],{"class":5463}," \u003C- &",[5449,13031,13032],{"class":5675},"JoinRoomMsg",[5449,13034,6319],{"class":5463},[5449,13036,13037,13039,13041,13043],{"class":5451,"line":5491},[5449,13038,12134],{"class":5494},[5449,13040,6371],{"class":5463},[5449,13042,10601],{"class":5494},[5449,13044,7862],{"class":5463},[5449,13046,13047,13049,13051,13054],{"class":5451,"line":5518},[5449,13048,12098],{"class":5494},[5449,13050,6371],{"class":5463},[5449,13052,13053],{"class":5477},"\"chat-room-42\"",[5449,13055,7862],{"class":5463},[5449,13057,13058],{"class":5451,"line":5548},[5449,13059,5784],{"class":5463},[5449,13061,13062],{"class":5451,"line":5570},[5449,13063,5488],{"emptyLinePlaceholder":5487},[5449,13065,13066],{"class":5451,"line":5576},[5449,13067,13068],{"class":5836},"\u002F\u002F Розсилка повідомлення лише учасникам кімнати\n",[5449,13070,13071,13073,13075,13077,13079,13082],{"class":5451,"line":5581},[5449,13072,10968],{"class":5494},[5449,13074,5217],{"class":5463},[5449,13076,12731],{"class":5494},[5449,13078,13029],{"class":5463},[5449,13080,13081],{"class":5675},"RoomMessage",[5449,13083,6319],{"class":5463},[5449,13085,13086,13088,13090,13092],{"class":5451,"line":5607},[5449,13087,12098],{"class":5494},[5449,13089,6352],{"class":5463},[5449,13091,13053],{"class":5477},[5449,13093,7862],{"class":5463},[5449,13095,13096,13098,13101,13103,13105,13108],{"class":5451,"line":5633},[5449,13097,12106],{"class":5494},[5449,13099,13100],{"class":5463},": []",[5449,13102,8795],{"class":5675},[5449,13104,5474],{"class":5463},[5449,13106,13107],{"class":5477},"`{\"user\": \"alice\", \"text\": \"Hello room!\"}`",[5449,13109,10457],{"class":5463},[5449,13111,13112],{"class":5451,"line":5646},[5449,13113,5784],{"class":5463},[5279,13115,13116],{},"Ця архітектура забезпечує масштабовану ізоляцію комунікаційних потоків без необхідності створення окремих Hub-ів для кожної кімнати.",[5266,13118],{},[5269,13120,13122],{"id":13121},"інтеграція-websocket-із-десктопними-та-мобільними-клієнтами","Інтеграція WebSocket із десктопними та мобільними клієнтами",[5274,13124,13126],{"id":13125},"клієнт-на-javafx-java","Клієнт на JavaFX (Java)",[5279,13128,13129,13130,13133,13134,5413,13137,5255],{},"Для з'єднання з WebSocket-сервером у Java-застосунках використовується стандартний API ",[5214,13131,13132],{},"javax.websocket"," або сторонні бібліотеки (",[5214,13135,13136],{},"Tyrus",[5214,13138,13139],{},"Java-WebSocket",[5429,13141,13145],{"className":13142,"code":13143,"language":13144,"meta":5437,"style":5437},"language-java shiki shiki-themes light-plus dark-plus dark-plus","import javax.websocket.*;\nimport java.net.URI;\n\n@ClientEndpoint\npublic class WebSocketClient {\n\n    @OnOpen\n    public void onOpen(Session session) {\n        System.out.println(\"Connected to server\");\n        try {\n            session.getBasicRemote().sendText(\"{\\\"action\\\": \\\"subscribe\\\"}\");\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    @OnMessage\n    public void onMessage(String message) {\n        System.out.println(\"Received: \" + message);\n        \u002F\u002F Оновлюємо UI через Platform.runLater()\n    }\n\n    @OnClose\n    public void onClose(Session session, CloseReason reason) {\n        System.out.println(\"Disconnected: \" + reason.getReasonPhrase());\n    }\n\n    public static void main(String[] args) throws Exception {\n        WebSocketContainer container = ContainerProvider.getWebSocketContainer();\n        container.connectToServer(WebSocketClient.class, \n            new URI(\"ws:\u002F\u002Flocalhost:8080\u002Fws\"));\n    }\n}\n","java",[5214,13146,13147,13154,13161,13165,13173,13186,13190,13198,13219,13241,13248,13290,13308,13321,13325,13329,13333,13340,13358,13378,13383,13387,13391,13398,13423,13453,13457,13461,13492,13512,13535,13551,13555],{"__ignoreMap":5437},[5449,13148,13149,13151],{"class":5451,"line":5452},[5449,13150,5686],{"class":5455},[5449,13152,13153],{"class":5463}," javax.websocket.*;\n",[5449,13155,13156,13158],{"class":5451,"line":5484},[5449,13157,5686],{"class":5455},[5449,13159,13160],{"class":5463}," java.net.URI;\n",[5449,13162,13163],{"class":5451,"line":5491},[5449,13164,5488],{"emptyLinePlaceholder":5487},[5449,13166,13167,13170],{"class":5451,"line":5518},[5449,13168,13169],{"class":5463},"@",[5449,13171,13172],{"class":5675},"ClientEndpoint\n",[5449,13174,13175,13178,13181,13184],{"class":5451,"line":5548},[5449,13176,13177],{"class":5455},"public",[5449,13179,13180],{"class":5455}," class",[5449,13182,13183],{"class":5675}," WebSocketClient",[5449,13185,5515],{"class":5463},[5449,13187,13188],{"class":5451,"line":5570},[5449,13189,5488],{"emptyLinePlaceholder":5487},[5449,13191,13192,13195],{"class":5451,"line":5576},[5449,13193,13194],{"class":5463},"    @",[5449,13196,13197],{"class":5675},"OnOpen\n",[5449,13199,13200,13203,13206,13209,13211,13214,13217],{"class":5451,"line":5581},[5449,13201,13202],{"class":5455},"    public",[5449,13204,13205],{"class":5675}," void",[5449,13207,13208],{"class":5470}," onOpen",[5449,13210,5474],{"class":5463},[5449,13212,13213],{"class":5675},"Session",[5449,13215,13216],{"class":5494}," session",[5449,13218,5830],{"class":5463},[5449,13220,13221,13224,13226,13229,13231,13234,13236,13239],{"class":5451,"line":5607},[5449,13222,13223],{"class":5494},"        System",[5449,13225,5217],{"class":5463},[5449,13227,13228],{"class":5494},"out",[5449,13230,5217],{"class":5463},[5449,13232,13233],{"class":5470},"println",[5449,13235,5474],{"class":5463},[5449,13237,13238],{"class":5477},"\"Connected to server\"",[5449,13240,5481],{"class":5463},[5449,13242,13243,13246],{"class":5451,"line":5633},[5449,13244,13245],{"class":5685},"        try",[5449,13247,5515],{"class":5463},[5449,13249,13250,13253,13255,13258,13260,13263,13265,13268,13271,13274,13276,13278,13280,13283,13285,13288],{"class":5451,"line":5646},[5449,13251,13252],{"class":5494},"            session",[5449,13254,5217],{"class":5463},[5449,13256,13257],{"class":5470},"getBasicRemote",[5449,13259,5946],{"class":5463},[5449,13261,13262],{"class":5470},"sendText",[5449,13264,5474],{"class":5463},[5449,13266,13267],{"class":5477},"\"{",[5449,13269,13270],{"class":6478},"\\\"",[5449,13272,13273],{"class":5477},"action",[5449,13275,13270],{"class":6478},[5449,13277,6371],{"class":5477},[5449,13279,13270],{"class":6478},[5449,13281,13282],{"class":5477},"subscribe",[5449,13284,13270],{"class":6478},[5449,13286,13287],{"class":5477},"}\"",[5449,13289,5481],{"class":5463},[5449,13291,13292,13295,13298,13300,13303,13306],{"class":5451,"line":5731},[5449,13293,13294],{"class":5463},"        } ",[5449,13296,13297],{"class":5685},"catch",[5449,13299,5285],{"class":5463},[5449,13301,13302],{"class":5675},"Exception",[5449,13304,13305],{"class":5494}," e",[5449,13307,5830],{"class":5463},[5449,13309,13310,13313,13315,13318],{"class":5451,"line":5745},[5449,13311,13312],{"class":5494},"            e",[5449,13314,5217],{"class":5463},[5449,13316,13317],{"class":5470},"printStackTrace",[5449,13319,13320],{"class":5463},"();\n",[5449,13322,13323],{"class":5451,"line":5757},[5449,13324,6570],{"class":5463},[5449,13326,13327],{"class":5451,"line":5769},[5449,13328,5921],{"class":5463},[5449,13330,13331],{"class":5451,"line":5781},[5449,13332,5488],{"emptyLinePlaceholder":5487},[5449,13334,13335,13337],{"class":5451,"line":5787},[5449,13336,13194],{"class":5463},[5449,13338,13339],{"class":5675},"OnMessage\n",[5449,13341,13342,13344,13346,13349,13351,13354,13356],{"class":5451,"line":5792},[5449,13343,13202],{"class":5455},[5449,13345,13205],{"class":5675},[5449,13347,13348],{"class":5470}," onMessage",[5449,13350,5474],{"class":5463},[5449,13352,13353],{"class":5675},"String",[5449,13355,9040],{"class":5494},[5449,13357,5830],{"class":5463},[5449,13359,13360,13362,13364,13366,13368,13370,13372,13375],{"class":5451,"line":5833},[5449,13361,13223],{"class":5494},[5449,13363,5217],{"class":5463},[5449,13365,13228],{"class":5494},[5449,13367,5217],{"class":5463},[5449,13369,13233],{"class":5470},[5449,13371,5474],{"class":5463},[5449,13373,13374],{"class":5477},"\"Received: \"",[5449,13376,13377],{"class":5463}," + message);\n",[5449,13379,13380],{"class":5451,"line":5840},[5449,13381,13382],{"class":5836},"        \u002F\u002F Оновлюємо UI через Platform.runLater()\n",[5449,13384,13385],{"class":5451,"line":5868},[5449,13386,5921],{"class":5463},[5449,13388,13389],{"class":5451,"line":5881},[5449,13390,5488],{"emptyLinePlaceholder":5487},[5449,13392,13393,13395],{"class":5451,"line":5912},[5449,13394,13194],{"class":5463},[5449,13396,13397],{"class":5675},"OnClose\n",[5449,13399,13400,13402,13404,13407,13409,13411,13413,13415,13418,13421],{"class":5451,"line":5918},[5449,13401,13202],{"class":5455},[5449,13403,13205],{"class":5675},[5449,13405,13406],{"class":5470}," onClose",[5449,13408,5474],{"class":5463},[5449,13410,13213],{"class":5675},[5449,13412,13216],{"class":5494},[5449,13414,5413],{"class":5463},[5449,13416,13417],{"class":5675},"CloseReason",[5449,13419,13420],{"class":5494}," reason",[5449,13422,5830],{"class":5463},[5449,13424,13425,13427,13429,13431,13433,13435,13437,13440,13442,13445,13447,13450],{"class":5451,"line":5924},[5449,13426,13223],{"class":5494},[5449,13428,5217],{"class":5463},[5449,13430,13228],{"class":5494},[5449,13432,5217],{"class":5463},[5449,13434,13233],{"class":5470},[5449,13436,5474],{"class":5463},[5449,13438,13439],{"class":5477},"\"Disconnected: \"",[5449,13441,8974],{"class":5463},[5449,13443,13444],{"class":5494},"reason",[5449,13446,5217],{"class":5463},[5449,13448,13449],{"class":5470},"getReasonPhrase",[5449,13451,13452],{"class":5463},"());\n",[5449,13454,13455],{"class":5451,"line":5929},[5449,13456,5921],{"class":5463},[5449,13458,13459],{"class":5451,"line":5935},[5449,13460,5488],{"emptyLinePlaceholder":5487},[5449,13462,13463,13465,13468,13470,13472,13474,13476,13479,13482,13484,13487,13490],{"class":5451,"line":5964},[5449,13464,13202],{"class":5455},[5449,13466,13467],{"class":5455}," static",[5449,13469,13205],{"class":5675},[5449,13471,6593],{"class":5470},[5449,13473,5474],{"class":5463},[5449,13475,13353],{"class":5675},[5449,13477,13478],{"class":5463},"[] ",[5449,13480,13481],{"class":5494},"args",[5449,13483,5509],{"class":5463},[5449,13485,13486],{"class":5455},"throws",[5449,13488,13489],{"class":5675}," Exception",[5449,13491,5515],{"class":5463},[5449,13493,13494,13497,13500,13502,13505,13507,13510],{"class":5451,"line":5989},[5449,13495,13496],{"class":5675},"        WebSocketContainer",[5449,13498,13499],{"class":5494}," container",[5449,13501,5464],{"class":5463},[5449,13503,13504],{"class":5494},"ContainerProvider",[5449,13506,5217],{"class":5463},[5449,13508,13509],{"class":5470},"getWebSocketContainer",[5449,13511,13320],{"class":5463},[5449,13513,13514,13517,13519,13522,13524,13527,13529,13532],{"class":5451,"line":6014},[5449,13515,13516],{"class":5494},"        container",[5449,13518,5217],{"class":5463},[5449,13520,13521],{"class":5470},"connectToServer",[5449,13523,5474],{"class":5463},[5449,13525,13526],{"class":5494},"WebSocketClient",[5449,13528,5217],{"class":5463},[5449,13530,13531],{"class":5494},"class",[5449,13533,13534],{"class":5463},", \n",[5449,13536,13537,13540,13543,13545,13548],{"class":5451,"line":6039},[5449,13538,13539],{"class":5685},"            new",[5449,13541,13542],{"class":5470}," URI",[5449,13544,5474],{"class":5463},[5449,13546,13547],{"class":5477},"\"ws:\u002F\u002Flocalhost:8080\u002Fws\"",[5449,13549,13550],{"class":5463},"));\n",[5449,13552,13553],{"class":5451,"line":6044},[5449,13554,5921],{"class":5463},[5449,13556,13557],{"class":5451,"line":6077},[5449,13558,5784],{"class":5463},[5274,13560,13562],{"id":13561},"клієнт-на-c-avalonia-wpf","Клієнт на C# (Avalonia \u002F WPF)",[5279,13564,13565,13566,13569],{},"У .NET 6+ використовується клас ",[5214,13567,13568],{},"ClientWebSocket"," з простран",[5279,13571,13572,13573,5217],{},"ства імен ",[5214,13574,13575],{},"System.Net.WebSockets",[5429,13577,13581],{"className":13578,"code":13579,"language":13580,"meta":5437,"style":5437},"language-csharp shiki shiki-themes light-plus dark-plus dark-plus","using System.Net.WebSockets;\nusing System.Text;\n\nvar ws = new ClientWebSocket();\nawait ws.ConnectAsync(new Uri(\"ws:\u002F\u002Flocalhost:8080\u002Fws\"), CancellationToken.None);\n\n\u002F\u002F Відправка повідомлення\nvar message = Encoding.UTF8.GetBytes(\"{\\\"action\\\": \\\"subscribe\\\"}\");\nawait ws.SendAsync(new ArraySegment\u003Cbyte>(message), \n    WebSocketMessageType.Text, true, CancellationToken.None);\n\n\u002F\u002F Читання у циклі\nvar buffer = new byte[1024];\nwhile (ws.State == WebSocketState.Open)\n{\n    var result = await ws.ReceiveAsync(new ArraySegment\u003Cbyte>(buffer), CancellationToken.None);\n    var text = Encoding.UTF8.GetString(buffer, 0, result.Count);\n    Console.WriteLine($\"Received: {text}\");\n}\n","csharp",[5214,13582,13583,13604,13617,13621,13637,13672,13676,13681,13724,13755,13778,13782,13787,13808,13835,13839,13883,13923,13951],{"__ignoreMap":5437},[5449,13584,13585,13588,13591,13593,13596,13598,13601],{"class":5451,"line":5452},[5449,13586,13587],{"class":5685},"using",[5449,13589,13590],{"class":5675}," System",[5449,13592,5217],{"class":5463},[5449,13594,13595],{"class":5675},"Net",[5449,13597,5217],{"class":5463},[5449,13599,13600],{"class":5675},"WebSockets",[5449,13602,13603],{"class":5463},";\n",[5449,13605,13606,13608,13610,13612,13615],{"class":5451,"line":5484},[5449,13607,13587],{"class":5685},[5449,13609,13590],{"class":5675},[5449,13611,5217],{"class":5463},[5449,13613,13614],{"class":5675},"Text",[5449,13616,13603],{"class":5463},[5449,13618,13619],{"class":5451,"line":5491},[5449,13620,5488],{"emptyLinePlaceholder":5487},[5449,13622,13623,13625,13628,13630,13632,13635],{"class":5451,"line":5518},[5449,13624,7830],{"class":5455},[5449,13626,13627],{"class":5494}," ws",[5449,13629,5464],{"class":5463},[5449,13631,5467],{"class":5455},[5449,13633,13634],{"class":5675}," ClientWebSocket",[5449,13636,13320],{"class":5463},[5449,13638,13639,13642,13644,13646,13649,13651,13653,13656,13658,13660,13662,13665,13667,13670],{"class":5451,"line":5548},[5449,13640,13641],{"class":5455},"await",[5449,13643,13627],{"class":5494},[5449,13645,5217],{"class":5463},[5449,13647,13648],{"class":5470},"ConnectAsync",[5449,13650,5474],{"class":5463},[5449,13652,5467],{"class":5455},[5449,13654,13655],{"class":5675}," Uri",[5449,13657,5474],{"class":5463},[5449,13659,13547],{"class":5477},[5449,13661,9187],{"class":5463},[5449,13663,13664],{"class":5494},"CancellationToken",[5449,13666,5217],{"class":5463},[5449,13668,13669],{"class":5494},"None",[5449,13671,5481],{"class":5463},[5449,13673,13674],{"class":5451,"line":5570},[5449,13675,5488],{"emptyLinePlaceholder":5487},[5449,13677,13678],{"class":5451,"line":5576},[5449,13679,13680],{"class":5836},"\u002F\u002F Відправка повідомлення\n",[5449,13682,13683,13685,13687,13689,13692,13694,13697,13699,13702,13704,13706,13708,13710,13712,13714,13716,13718,13720,13722],{"class":5451,"line":5581},[5449,13684,7830],{"class":5455},[5449,13686,9040],{"class":5494},[5449,13688,5464],{"class":5463},[5449,13690,13691],{"class":5494},"Encoding",[5449,13693,5217],{"class":5463},[5449,13695,13696],{"class":5494},"UTF8",[5449,13698,5217],{"class":5463},[5449,13700,13701],{"class":5470},"GetBytes",[5449,13703,5474],{"class":5463},[5449,13705,13267],{"class":5477},[5449,13707,13270],{"class":6478},[5449,13709,13273],{"class":5477},[5449,13711,13270],{"class":6478},[5449,13713,6371],{"class":5477},[5449,13715,13270],{"class":6478},[5449,13717,13282],{"class":5477},[5449,13719,13270],{"class":6478},[5449,13721,13287],{"class":5477},[5449,13723,5481],{"class":5463},[5449,13725,13726,13728,13730,13732,13735,13737,13739,13742,13745,13747,13750,13752],{"class":5451,"line":5607},[5449,13727,13641],{"class":5455},[5449,13729,13627],{"class":5494},[5449,13731,5217],{"class":5463},[5449,13733,13734],{"class":5470},"SendAsync",[5449,13736,5474],{"class":5463},[5449,13738,5467],{"class":5455},[5449,13740,13741],{"class":5675}," ArraySegment",[5449,13743,13744],{"class":5463},"\u003C",[5449,13746,8795],{"class":5455},[5449,13748,13749],{"class":5463},">(",[5449,13751,8866],{"class":5494},[5449,13753,13754],{"class":5463},"), \n",[5449,13756,13757,13760,13762,13764,13766,13768,13770,13772,13774,13776],{"class":5451,"line":5633},[5449,13758,13759],{"class":5494},"    WebSocketMessageType",[5449,13761,5217],{"class":5463},[5449,13763,13614],{"class":5494},[5449,13765,5413],{"class":5463},[5449,13767,8234],{"class":5455},[5449,13769,5413],{"class":5463},[5449,13771,13664],{"class":5494},[5449,13773,5217],{"class":5463},[5449,13775,13669],{"class":5494},[5449,13777,5481],{"class":5463},[5449,13779,13780],{"class":5451,"line":5646},[5449,13781,5488],{"emptyLinePlaceholder":5487},[5449,13783,13784],{"class":5451,"line":5731},[5449,13785,13786],{"class":5836},"\u002F\u002F Читання у циклі\n",[5449,13788,13789,13791,13794,13796,13798,13801,13803,13805],{"class":5451,"line":5745},[5449,13790,7830],{"class":5455},[5449,13792,13793],{"class":5494}," buffer",[5449,13795,5464],{"class":5463},[5449,13797,5467],{"class":5455},[5449,13799,13800],{"class":5455}," byte",[5449,13802,10598],{"class":5463},[5449,13804,6384],{"class":6124},[5449,13806,13807],{"class":5463},"];\n",[5449,13809,13810,13813,13815,13818,13820,13823,13825,13828,13830,13833],{"class":5451,"line":5757},[5449,13811,13812],{"class":5685},"while",[5449,13814,5285],{"class":5463},[5449,13816,13817],{"class":5494},"ws",[5449,13819,5217],{"class":5463},[5449,13821,13822],{"class":5494},"State",[5449,13824,8302],{"class":5463},[5449,13826,13827],{"class":5494},"WebSocketState",[5449,13829,5217],{"class":5463},[5449,13831,13832],{"class":5494},"Open",[5449,13834,5724],{"class":5463},[5449,13836,13837],{"class":5451,"line":5769},[5449,13838,6319],{"class":5463},[5449,13840,13841,13844,13847,13849,13851,13853,13855,13858,13860,13862,13864,13866,13868,13870,13873,13875,13877,13879,13881],{"class":5451,"line":5781},[5449,13842,13843],{"class":5455},"    var",[5449,13845,13846],{"class":5494}," result",[5449,13848,5464],{"class":5463},[5449,13850,13641],{"class":5455},[5449,13852,13627],{"class":5494},[5449,13854,5217],{"class":5463},[5449,13856,13857],{"class":5470},"ReceiveAsync",[5449,13859,5474],{"class":5463},[5449,13861,5467],{"class":5455},[5449,13863,13741],{"class":5675},[5449,13865,13744],{"class":5463},[5449,13867,8795],{"class":5455},[5449,13869,13749],{"class":5463},[5449,13871,13872],{"class":5494},"buffer",[5449,13874,9187],{"class":5463},[5449,13876,13664],{"class":5494},[5449,13878,5217],{"class":5463},[5449,13880,13669],{"class":5494},[5449,13882,5481],{"class":5463},[5449,13884,13885,13887,13890,13892,13894,13896,13898,13900,13903,13905,13907,13909,13911,13913,13916,13918,13921],{"class":5451,"line":5787},[5449,13886,13843],{"class":5455},[5449,13888,13889],{"class":5494}," text",[5449,13891,5464],{"class":5463},[5449,13893,13691],{"class":5494},[5449,13895,5217],{"class":5463},[5449,13897,13696],{"class":5494},[5449,13899,5217],{"class":5463},[5449,13901,13902],{"class":5470},"GetString",[5449,13904,5474],{"class":5463},[5449,13906,13872],{"class":5494},[5449,13908,5413],{"class":5463},[5449,13910,7558],{"class":6124},[5449,13912,5413],{"class":5463},[5449,13914,13915],{"class":5494},"result",[5449,13917,5217],{"class":5463},[5449,13919,13920],{"class":5494},"Count",[5449,13922,5481],{"class":5463},[5449,13924,13925,13928,13930,13933,13935,13938,13942,13944,13947,13949],{"class":5451,"line":5792},[5449,13926,13927],{"class":5494},"    Console",[5449,13929,5217],{"class":5463},[5449,13931,13932],{"class":5470},"WriteLine",[5449,13934,5474],{"class":5463},[5449,13936,13937],{"class":5477},"$\"Received: ",[5449,13939,13941],{"class":13940},"sD7JJ","{",[5449,13943,5434],{"class":5494},[5449,13945,13946],{"class":13940},"}",[5449,13948,6063],{"class":5477},[5449,13950,5481],{"class":5463},[5449,13952,13953],{"class":5451,"line":5833},[5449,13954,5784],{"class":5463},[5274,13956,13958],{"id":13957},"клієнт-на-react-native-javascripttypescript","Клієнт на React Native (JavaScript\u002FTypeScript)",[5279,13960,13961,13962,5217],{},"React Native підтримує WebSocket нативно через глобальний об'єкт ",[5214,13963,6885],{},[5429,13965,13967],{"className":5443,"code":13966,"language":5445,"meta":5437,"style":5437},"const ws = new WebSocket('ws:\u002F\u002F192.168.1.10:8080\u002Fws');\n\nws.onopen = () => {\n    console.log('Connected');\n    ws.send(JSON.stringify({ action: 'subscribe' }));\n};\n\nws.onmessage = (event) => {\n    const data = JSON.parse(event.data);\n    console.log('Received:', data);\n    \u002F\u002F Оновлюємо стан React компонента\n};\n\nws.onerror = (error) => {\n    console.error('WebSocket error:', error);\n};\n\nws.onclose = () => {\n    console.log('Connection closed');\n};\n",[5214,13968,13969,13989,13993,14009,14024,14054,14058,14062,14080,14104,14122,14127,14131,14135,14154,14173,14177,14181,14196,14211],{"__ignoreMap":5437},[5449,13970,13971,13973,13975,13977,13979,13982,13984,13987],{"class":5451,"line":5452},[5449,13972,5456],{"class":5455},[5449,13974,13627],{"class":5459},[5449,13976,5464],{"class":5463},[5449,13978,5467],{"class":5455},[5449,13980,13981],{"class":5470}," WebSocket",[5449,13983,5474],{"class":5463},[5449,13985,13986],{"class":5477},"'ws:\u002F\u002F192.168.1.10:8080\u002Fws'",[5449,13988,5481],{"class":5463},[5449,13990,13991],{"class":5451,"line":5484},[5449,13992,5488],{"emptyLinePlaceholder":5487},[5449,13994,13995,13997,13999,14002,14005,14007],{"class":5451,"line":5491},[5449,13996,13817],{"class":5494},[5449,13998,5217],{"class":5463},[5449,14000,14001],{"class":5470},"onopen",[5449,14003,14004],{"class":5463}," = () ",[5449,14006,5512],{"class":5455},[5449,14008,5515],{"class":5463},[5449,14010,14011,14013,14015,14017,14019,14022],{"class":5451,"line":5518},[5449,14012,5551],{"class":5494},[5449,14014,5217],{"class":5463},[5449,14016,5556],{"class":5470},[5449,14018,5474],{"class":5463},[5449,14020,14021],{"class":5477},"'Connected'",[5449,14023,5481],{"class":5463},[5449,14025,14026,14029,14031,14033,14035,14037,14039,14042,14045,14048,14051],{"class":5451,"line":5548},[5449,14027,14028],{"class":5494},"    ws",[5449,14030,5217],{"class":5463},[5449,14032,8961],{"class":5470},[5449,14034,5474],{"class":5463},[5449,14036,5529],{"class":5459},[5449,14038,5217],{"class":5463},[5449,14040,14041],{"class":5470},"stringify",[5449,14043,14044],{"class":5463},"({ ",[5449,14046,14047],{"class":5494},"action:",[5449,14049,14050],{"class":5477}," 'subscribe'",[5449,14052,14053],{"class":5463}," }));\n",[5449,14055,14056],{"class":5451,"line":5570},[5449,14057,5573],{"class":5463},[5449,14059,14060],{"class":5451,"line":5576},[5449,14061,5488],{"emptyLinePlaceholder":5487},[5449,14063,14064,14066,14068,14070,14072,14074,14076,14078],{"class":5451,"line":5581},[5449,14065,13817],{"class":5494},[5449,14067,5217],{"class":5463},[5449,14069,5500],{"class":5470},[5449,14071,5503],{"class":5463},[5449,14073,5506],{"class":5494},[5449,14075,5509],{"class":5463},[5449,14077,5512],{"class":5455},[5449,14079,5515],{"class":5463},[5449,14081,14082,14084,14086,14088,14090,14092,14094,14096,14098,14100,14102],{"class":5451,"line":5607},[5449,14083,5521],{"class":5455},[5449,14085,5524],{"class":5459},[5449,14087,5464],{"class":5463},[5449,14089,5529],{"class":5459},[5449,14091,5217],{"class":5463},[5449,14093,5534],{"class":5470},[5449,14095,5474],{"class":5463},[5449,14097,5506],{"class":5494},[5449,14099,5217],{"class":5463},[5449,14101,5543],{"class":5494},[5449,14103,5481],{"class":5463},[5449,14105,14106,14108,14110,14112,14114,14116,14118,14120],{"class":5451,"line":5633},[5449,14107,5551],{"class":5494},[5449,14109,5217],{"class":5463},[5449,14111,5556],{"class":5470},[5449,14113,5474],{"class":5463},[5449,14115,5561],{"class":5477},[5449,14117,5413],{"class":5463},[5449,14119,5543],{"class":5494},[5449,14121,5481],{"class":5463},[5449,14123,14124],{"class":5451,"line":5646},[5449,14125,14126],{"class":5836},"    \u002F\u002F Оновлюємо стан React компонента\n",[5449,14128,14129],{"class":5451,"line":5731},[5449,14130,5573],{"class":5463},[5449,14132,14133],{"class":5451,"line":5745},[5449,14134,5488],{"emptyLinePlaceholder":5487},[5449,14136,14137,14139,14141,14144,14146,14148,14150,14152],{"class":5451,"line":5757},[5449,14138,13817],{"class":5494},[5449,14140,5217],{"class":5463},[5449,14142,14143],{"class":5470},"onerror",[5449,14145,5503],{"class":5463},[5449,14147,9764],{"class":5494},[5449,14149,5509],{"class":5463},[5449,14151,5512],{"class":5455},[5449,14153,5515],{"class":5463},[5449,14155,14156,14158,14160,14162,14164,14167,14169,14171],{"class":5451,"line":5769},[5449,14157,5551],{"class":5494},[5449,14159,5217],{"class":5463},[5449,14161,9764],{"class":5470},[5449,14163,5474],{"class":5463},[5449,14165,14166],{"class":5477},"'WebSocket error:'",[5449,14168,5413],{"class":5463},[5449,14170,9764],{"class":5494},[5449,14172,5481],{"class":5463},[5449,14174,14175],{"class":5451,"line":5781},[5449,14176,5573],{"class":5463},[5449,14178,14179],{"class":5451,"line":5787},[5449,14180,5488],{"emptyLinePlaceholder":5487},[5449,14182,14183,14185,14187,14190,14192,14194],{"class":5451,"line":5792},[5449,14184,13817],{"class":5494},[5449,14186,5217],{"class":5463},[5449,14188,14189],{"class":5470},"onclose",[5449,14191,14004],{"class":5463},[5449,14193,5512],{"class":5455},[5449,14195,5515],{"class":5463},[5449,14197,14198,14200,14202,14204,14206,14209],{"class":5451,"line":5833},[5449,14199,5551],{"class":5494},[5449,14201,5217],{"class":5463},[5449,14203,5556],{"class":5470},[5449,14205,5474],{"class":5463},[5449,14207,14208],{"class":5477},"'Connection closed'",[5449,14210,5481],{"class":5463},[5449,14212,14213],{"class":5451,"line":5840},[5449,14214,5573],{"class":5463},[5266,14216],{},[5269,14218,14220],{"id":14219},"підсумок-та","Підсумок та",[5279,14222,14223],{},"рекомендації",[5190,14225,14226,14271],{},[5193,14227,14230,14235,14241,14249,14258],{"icon":14228,"title":14229},"i-lucide-check-circle","✅ Ключові висновки",[5279,14231,14232,14234],{},[5229,14233,4722],{}," є простою та ефективною технологією для однонапрямленої доставки подій від сервера до клієнта. SSE працює поверх звичайного HTTP, легко проходить через проксі та підтримується браузерами нативно. Оптимальний вибір для стрічок оновлень, фінансових котирувань, системних логів та прогресу виконання задач.",[5279,14236,14237,14240],{},[5229,14238,14239],{},"Протокол WebSocket (RFC 6455)"," забезпечує повнодуплексну комунікацію з мінімальними накладними витратами (2–14 байтів на фрейм). Процедура встановлення з'єднання відбувається через HTTP Upgrade Handshake, після чого обидві сторони обмінюються текстовими або бінарними фреймами без повторного встановлення з'єднання.",[5279,14242,14243,14248],{},[5229,14244,14245,14246],{},"Бібліотека ",[5214,14247,5216],{}," є промисловим стандартом для реалізації WebSocket-серверів у Go. Вона підтримує всі вимоги RFC 6455, включаючи фрагментацію, Ping\u002FPong механізм та коректне закриття з'єднань.",[5279,14250,14251,14254,14255,14257],{},[5229,14252,14253],{},"Патерн Hub"," дозволяє централізовано керувати тисячами одночасних WebSocket-з'єднань без м'ютексів завдяки використанню каналів та єдиної горутини-диспетчера. Розширення Hub кімнатами (",[5252,14256,11949],{},") забезпечує масштабовану таргетовану розсилку повідомлень.",[5279,14259,14260,14263,14264,7393,14266,14268,14269,5217],{},[5229,14261,14262],{},"Архітектура читання\u002Fзапису:"," розділення логіки на дві незалежні горутини (",[5214,14265,8826],{},[5214,14267,9011],{},") є стандартною практикою, що запобігає блокуванню читання під час повільного запису та гарантує потокобезпечність операцій з ",[5214,14270,8338],{},[5193,14272,14275],{"icon":14273,"title":14274},"i-lucide-lightbulb","🎓 Практичні рекомендації",[5198,14276,14277,14280,14290,14296,14308,14314],{},[5201,14278,14279],{},"Завжди використовуйте механізм Ping\u002FPong для визначення мертвих з'єднань та своєчасного звільнення ресурсів.",[5201,14281,14282,14283,7393,14286,14289],{},"Встановлюйте ",[5214,14284,14285],{},"ReadDeadline",[5214,14287,14288],{},"WriteDeadline"," для запобігання нескінченного блокування у разі мережевих збоїв.",[5201,14291,14292,14293,14295],{},"Використовуйте буферизовані канали ",[5214,14294,8961],{}," для згладжування короткочасних сплесків навантаження.",[5201,14297,14298,14299,14301,14302,14304,14305,5255],{},"Реалізуйте обробку ",[5214,14300,11888],{},"-гілки у ",[5214,14303,11839],{}," при широкомовній розсилці для відключення повільних споживачів (",[5252,14306,14307],{},"slow consumers",[5201,14309,14310,14311,14313],{},"Валідуйте заголовок ",[5214,14312,7376],{}," у продакшені для захисту від Cross-Site WebSocket Hijacking атак.",[5201,14315,14316,14317,14320],{},"Для критичних застосунків розгляньте використання TLS (",[5214,14318,14319],{},"wss:\u002F\u002F",") для шифрування трафіку WebSocket.",[5266,14322],{},[5269,14324,14326],{"id":14325},"запитання-для-самоконтролю","Запитання для самоконтролю",[14328,14329,14330,14336,14346,14358,14369,14391],"accordion",{},[14331,14332,14335],"accordion-item",{"icon":14333,"label":14334},"i-lucide-help-circle","❓ Чому SSE не підходить для інтерактивних застосунків типу чату?","SSE є однонапрямленим каналом комунікації (сервер → клієнт). Якщо клієнту потрібно надіслати повідомлення серверу, він повинен виконати окремий HTTP-запит методом POST. У застосунках із високою частотою двосторонньої взаємодії (чат, онлайн-гра) це призводить до збільшення затримки, дублювання з'єднань та ускладнення архітектури. WebSocket є оптимальним рішенням для таких сценаріїв, оскільки забезпечує повнодуплексну комунікацію через одне з'єднання.",[14331,14337,14339,14340,14342,14343,14345],{"icon":14333,"label":14338},"❓ Яку роль відіграє магічна константа 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 у WebSocket Handshake?","Ця константа є унікальним ідентифікатором версії протоколу WebSocket згідно з RFC 6455. Сервер конкатенує її з клієнтським ",[5214,14341,7356],{},", застосовує SHA-1 хеш та кодує результат у Base64, після чого відправляє у заголовку ",[5214,14344,7465],{},". Цей механізм гарантує, що сервер дійсно підтримує протокол WebSocket, а не просто відповідає статус-кодом 101 без відповідної логіки. Це запобігає помилковим апгрейдам через проксі-сервери, що не розуміють протокол.",[14331,14347,14349,14350,14352,14353,14355,14356,5217],{"icon":14333,"label":14348},"❓ Чому методи запису `*websocket.Conn` не є потокобезпечними?","Протокол WebSocket вимагає, щоб фрейми надсилалися атомарно та послідовно. Якщо дві горутини одночасно викликають ",[5214,14351,8736],{},", їхні фрейми можуть перемішатися на рівні байтів: заголовок першого фрейму, частина корисного навантаження другого, закінчення першого тощо. Це призводить до порушення структури протоколу, неможливості розпарсити дані на протилежній стороні та закриття з'єднання із кодом помилки ",[5214,14354,7643],{}," (Protocol Error). Для забезпечення потокобезпечності слід використовувати окрему горутину-письменник або синхронізувати доступ через ",[5214,14357,8740],{},[14331,14359,14361,14362,14365,14366,14368],{"icon":14333,"label":14360},"❓ Яка різниця між Close Frame та просто закриттям TCP-сокета?","Close Frame є ",[5229,14363,14364],{},"плавним завершенням з'єднання на рівні протоколу WebSocket",". Сторона, що ініціює закриття, надсилає Close Frame із статус-кодом (наприклад, ",[5214,14367,7681],{}," — нормальне закриття) та опціональною текстовою причиною. Протилежна сторона повинна відповісти власним Close Frame, після чого обидві сторони закривають базове TCP-з'єднання. Це дозволяє коректно завершити обробку останніх повідомлень, звільнити ресурси та записати метрики. Якщо просто закрити TCP-сокет без Close Frame, протилежна сторона отримає помилку читання без контексту причини розриву, що ускладнює діагностику та може призвести до витоку ресурсів.",[14331,14370,14372,14373,14376,14377,14379,14380,14383,14384,14387,14388,14390],{"icon":14333,"label":14371},"❓ Навіщо потрібен `default`-кейс у select при широкомовній розсилці у патерні Hub?","Канал ",[5214,14374,14375],{},"client.send"," має фіксовану ємність (наприклад, 256 повідомлень). Якщо клієнт має повільне мережеве з'єднання або завис, його канал може заповнитися повністю. Без ",[5214,14378,11888],{},"-гілки спроба надіслати повідомлення у повний канал ",[5229,14381,14382],{},"заблокує горутину Hub",", що зупинить розсилку для всіх інших клієнтів (",[5252,14385,14386],{},"slow consumer blocking all","). ",[5214,14389,11888],{},"-кейс виконується негайно, якщо канал зайнятий, дозволяючи Hub відключити проблемного клієнта та продовжити розсилку для решти. Це критично важливо для високонавантажених систем із тисячами підключених користувачів.",[14331,14392,14394,14395,14398],{"icon":14333,"label":14393},"❓ Чому інтервал надсилання Ping має бути менше таймауту Pong?","Ping\u002FPong механізм використовується для визначення мертвих з'єднань у мережах із нестабільним зв'язком або за NAT. Якщо інтервал Ping дорівнює або перевищує таймаут Pong, існує ризик хибнопозитивного визначення розриву: сервер надсилає Ping у момент T, але через мережеву затримку або втрату пакета Pong надходить через T + ε, що перевищує дедлайн. Встановлення інтервалу у 80–90% від таймауту (наприклад, Ping кожні 54 секунди при таймауті 60 секунд) забезпечує буфер для мережевої варіативності (",[5252,14396,14397],{},"jitter",") та гарантує, що справні з'єднання не закриваються передчасно.",[5266,14400],{},[5269,14402,14404],{"id":14403},"практичне-завдання","Практичне завдання",[14406,14407,14408,14412,14418,14422,14428,14432,14435,14439,14449,14453,14456,14479],"steps",{},[5274,14409,14411],{"id":14410},"крок-1-створення-базового-websocket-сервера","Крок 1. Створення базового WebSocket-сервера",[5279,14413,14414,14415,14417],{},"Реалізуйте WebSocket-сервер на базі ",[5214,14416,5216],{},", що виконує функції ехо-сервера: отримує текстові повідомлення від клієнтів та відправляє їх назад. Додайте логування адреси клієнта при підключенні та відключенні.",[5274,14419,14421],{"id":14420},"крок-2-впровадження-патерну-hub","Крок 2. Впровадження патерну Hub",[5279,14423,14424,14425,14427],{},"Модифікуйте сервер, додавши структуру ",[5214,14426,9969],{}," для централізованого керування клієнтами. Реалізуйте широкомовну розсилку: коли один клієнт надсилає повідомлення, воно має доставлятися всім підключеним клієнтам.",[5274,14429,14431],{"id":14430},"крок-3-механізм-pingpong","Крок 3. Механізм Ping\u002FPong",[5279,14433,14434],{},"Додайте періодичну відправку Ping-фреймів клієнтам (інтервал 30 секунд) та встановіть таймаут Pong-відповіді (40 секунд). Логуйте відключення клієнтів через таймаут.",[5274,14436,14438],{"id":14437},"крок-4-система-кімнат","Крок 4. Система кімнат",[5279,14440,14441,14442,7393,14445,14448],{},"Розширте Hub системою кімнат. Реалізуйте команди ",[5214,14443,14444],{},"JOIN room_id",[5214,14446,14447],{},"LEAVE room_id",", що дозволяють клієнтам приєднуватися до кімнат та виходити з них. Повідомлення мають розсилатися лише учасникам відповідної кімнати.",[5274,14450,14452],{"id":14451},"крок-5-інтеграція-з-клієнтом","Крок 5. Інтеграція з клієнтом",[5279,14454,14455],{},"Створіть клієнтський застосунок на одній із платформ:",[5198,14457,14458,14464,14470],{},[5201,14459,14460,14463],{},[5229,14461,14462],{},"JavaFX \u002F C# Avalonia:"," Десктопний GUI-клієнт із текстовим полем для введення повідомлень та списком отриманих повідомлень.",[5201,14465,14466,14469],{},[5229,14467,14468],{},"React Native:"," Мобільний застосунок з аналогічним інтерфейсом.",[5201,14471,14472,14475,14476,14478],{},[5229,14473,14474],{},"HTML\u002FJavaScript:"," Веб-сторінка з підключенням через нативний ",[5214,14477,6885],{}," API браузера.",[5279,14480,14481],{},"Продемонструйте роботу системи із трьома одночасно підключеними клієнтами у двох різних кімнатах.",[5266,14483],{},[5269,14485,14487],{"id":14486},"додаткові-матеріали-та-специфікації","Додаткові матеріали та специфікації",[5372,14489,14490,14495],{},[5279,14491,14492],{},[5229,14493,14494],{},"Ключові стандарти та специфікації:",[5198,14496,14497,14508,14517,14526],{},[5201,14498,14499,14501,14502],{},[5229,14500,7042],{}," — The WebSocket Protocol: ",[14503,14504,14505],"a",{"href":14505,"rel":14506},"https:\u002F\u002Fdatatracker.ietf.org\u002Fdoc\u002Fhtml\u002Frfc6455",[14507],"nofollow",[5201,14509,14510,14512,14513],{},[5229,14511,4722],{}," — HTML Living Standard: ",[14503,14514,14515],{"href":14515,"rel":14516},"https:\u002F\u002Fhtml.spec.whatwg.org\u002Fmultipage\u002Fserver-sent-events.html",[14507],[5201,14518,14519,14521,14522],{},[5229,14520,5216],{}," — Документація: ",[14503,14523,14524],{"href":14524,"rel":14525},"https:\u002F\u002Fpkg.go.dev\u002Fgithub.com\u002Fgorilla\u002Fwebsocket",[14507],[5201,14527,14528,14531,14532],{},[5229,14529,14530],{},"WebSocket Security Considerations"," — RFC 7936: ",[14503,14533,14534],{"href":14534,"rel":14535},"https:\u002F\u002Fdatatracker.ietf.org\u002Fdoc\u002Fhtml\u002Frfc7936",[14507],[14537,14538,14540,14555,14564,14577,14588,14603,14613,14625,14636],"terminal-preview",{":cursor":8234,"title":14539},"Демонстрація роботи WebSocket Hub сервера",[14541,14542,14544,14549,14550],"div",{"className":14543},[5451],[5449,14545,14548],{"className":14546},[14547],"opacity-40","$"," ",[5229,14551,14554],{"className":14552},[14553],"font-bold","go run cmd\u002Fwebsocket-hub\u002Fmain.go",[14541,14556,14558,14563],{"className":14557},[5451],[5449,14559,14562],{"className":14560},[14561,14553],"text-blue-400","INFO"," [2026-09-02 14:22:10] WebSocket Hub server listening on :8080",[14541,14565,14567,14572,14573],{"className":14566},[5451],[5449,14568,14571],{"className":14569},[14570,14553],"text-green-400","REGISTER"," Client registered. Total: 1 ",[5449,14574,14576],{"className":14575},[14547],"remote_addr=192.168.1.45:54320",[14541,14578,14580,14583,14584],{"className":14579},[5451],[5449,14581,14571],{"className":14582},[14570,14553]," Client registered. Total: 2 ",[5449,14585,14587],{"className":14586},[14547],"remote_addr=192.168.1.46:54321",[14541,14589,14591,14596,14597,14602],{"className":14590},[5451],[5449,14592,14595],{"className":14593},[14594,14553],"text-purple-400","JOIN"," Client joined room ",[5449,14598,14601],{"className":14599},[14600],"text-yellow-400","chat-42",". Room size: 1",[14541,14604,14606,14596,14609,14612],{"className":14605},[5451],[5449,14607,14595],{"className":14608},[14594,14553],[5449,14610,14601],{"className":14611},[14600],". Room size: 2",[14541,14614,14616,14621,14622],{"className":14615},[5451],[5449,14617,14620],{"className":14618},[14619,14553],"text-cyan-400","BROADCAST"," Message sent to 2 clients in room ",[5449,14623,14601],{"className":14624},[14600],[14541,14626,14628,14631,14632],{"className":14627},[5451],[5449,14629,14571],{"className":14630},[14570,14553]," Client registered. Total: 3 ",[5449,14633,14635],{"className":14634},[14547],"remote_addr=192.168.1.47:54322",[14541,14637,14639,14644,14645],{"className":14638},[5451],[5449,14640,14643],{"className":14641},[14642,14553],"text-red-400","UNREGISTER"," Client unregistered. Total: 2 ",[5449,14646,14648],{"className":14647},[14547],"reason=normal_closure",[14650,14651,14652],"style",{},"html pre.shiki code .su1O8, html code.shiki .su1O8{--shiki-light:#0000FF;--shiki-default:#569CD6;--shiki-dark:#569CD6}html pre.shiki code .s-QsJ, html code.shiki .s-QsJ{--shiki-light:#0070C1;--shiki-default:#4FC1FF;--shiki-dark:#4FC1FF}html pre.shiki code .sHH4Y, html code.shiki .sHH4Y{--shiki-light:#000000;--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .s8Opu, html code.shiki .s8Opu{--shiki-light:#795E26;--shiki-default:#DCDCAA;--shiki-dark:#DCDCAA}html pre.shiki code .sbdoH, html code.shiki .sbdoH{--shiki-light:#A31515;--shiki-default:#CE9178;--shiki-dark:#CE9178}html pre.shiki code .siwwj, html code.shiki .siwwj{--shiki-light:#001080;--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}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 .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 .spJ8K, html code.shiki .spJ8K{--shiki-light:#008000;--shiki-default:#6A9955;--shiki-dark:#6A9955}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 pre.shiki code .sKtos, html code.shiki .sKtos{--shiki-light:#800000;--shiki-default:#569CD6;--shiki-dark:#569CD6}html pre.shiki code .sD7JJ, html code.shiki .sD7JJ{--shiki-light:#000000FF;--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}",{"title":5437,"searchDepth":5484,"depth":5484,"links":14654},[14655,14659,14665,14671,14678,14684,14689,14690,14691,14698],{"id":5271,"depth":5484,"text":5272,"children":14656},[14657,14658],{"id":5276,"depth":5491,"text":5277},{"id":5330,"depth":5491,"text":5331},{"id":5379,"depth":5484,"text":5380,"children":14660},[14661,14662,14663,14664],{"id":5383,"depth":5491,"text":5384},{"id":5652,"depth":5491,"text":5653},{"id":6790,"depth":5491,"text":6791},{"id":6863,"depth":5491,"text":6864},{"id":7031,"depth":5484,"text":7032,"children":14666},[14667,14668,14669,14670],{"id":7035,"depth":5491,"text":7036},{"id":7285,"depth":5491,"text":7286},{"id":7505,"depth":5491,"text":7506},{"id":7647,"depth":5491,"text":7648},{"id":7717,"depth":5484,"text":7718,"children":14672},[14673,14674,14675,14676,14677],{"id":7721,"depth":5491,"text":7722},{"id":7771,"depth":5491,"text":7772},{"id":8345,"depth":5491,"text":8346},{"id":8744,"depth":5491,"text":8745},{"id":9279,"depth":5491,"text":9280},{"id":9941,"depth":5484,"text":9942,"children":14679},[14680,14681,14682,14683],{"id":9945,"depth":5491,"text":9946},{"id":9973,"depth":5491,"text":9974},{"id":10193,"depth":5491,"text":10194},{"id":11939,"depth":5491,"text":11940},{"id":13121,"depth":5484,"text":13122,"children":14685},[14686,14687,14688],{"id":13125,"depth":5491,"text":13126},{"id":13561,"depth":5491,"text":13562},{"id":13957,"depth":5491,"text":13958},{"id":14219,"depth":5484,"text":14220},{"id":14325,"depth":5484,"text":14326},{"id":14403,"depth":5484,"text":14404,"children":14692},[14693,14694,14695,14696,14697],{"id":14410,"depth":5491,"text":14411},{"id":14420,"depth":5491,"text":14421},{"id":14430,"depth":5491,"text":14431},{"id":14437,"depth":5491,"text":14438},{"id":14451,"depth":5491,"text":14452},{"id":14486,"depth":5484,"text":14487},"Технології доставки даних у реальному часі: Server-Sent Events (SSE) та протокол WebSocket (RFC 6455). Встановлення з'єднання через HTTP Upgrade, фреймінг повідомлень, патерн Hub та броадкаст у Go.","md",null,{},{"title":4041,"description":14699},"PIdhz_bzL2aqdJ7ZlOxtH7JyKUxUTJPdfumvHamERLU",[14706,14708],{"title":4037,"path":4038,"stem":4039,"description":14707,"children":-1},"Підключення до PostgreSQL, робота з чистим SQL через pgx, транзакції, міграції та об",{"title":4045,"path":4046,"stem":4047,"description":14709,"children":-1},"Концепція віддаленого виклику процедур (RPC). Формат бінарної серіалізації Protocol Buffers. Транспорт HTTP\u002F2 у gRPC. Типи викликів: Unary, Server Streaming, Client Streaming, Bidirectional Streaming. Реалізація сервісів, інтерцептори та генерація клієнтських стабів.",1791986748248]