[{"data":1,"prerenderedAt":12518},["ShallowReactive",2],{"navigation_docs":3,"-csharp-system-programming-windows-async-synchronization":2949,"-csharp-system-programming-windows-async-synchronization-surround":12513},[4,1640,1765,2219,2352,2559,2641,2691,2748,2782,2908,2945],{"title":5,"icon":6,"path":7,"stem":8,"children":9},"C#","i-devicon-csharp","/csharp","01.csharp",[10,13,60,90,120,202,219,253,379,404,457,650,1346,1636],{"title":11,"path":7,"stem":12},"C# Roadmap","01.csharp/index",{"title":14,"icon":15,"path":16,"stem":17,"children":18,"page":59},"Fundamentals","i-lucide-book-open","/csharp/fundamentals","01.csharp/01.fundamentals",[19,23,27,31,35,39,43,47,51,55],{"title":20,"path":21,"stem":22},"Вступ до екосистеми .NET","/csharp/fundamentals/introduction-to-ecosystem","01.csharp/01.fundamentals/01.introduction-to-ecosystem",{"title":24,"path":25,"stem":26},"Структура програми на C#","/csharp/fundamentals/program-structure","01.csharp/01.fundamentals/02.program-structure",{"title":28,"path":29,"stem":30},"Змінні та Типи Даних","/csharp/fundamentals/variables-data-types","01.csharp/01.fundamentals/03.variables-data-types",{"title":32,"path":33,"stem":34},"Масиви","/csharp/fundamentals/arrays","01.csharp/01.fundamentals/04.arrays",{"title":36,"path":37,"stem":38},"Strings & Text Handling","/csharp/fundamentals/strings-text-handling","01.csharp/01.fundamentals/05.strings-text-handling",{"title":40,"path":41,"stem":42},"Дати і Час","/csharp/fundamentals/dates-time-handling","01.csharp/01.fundamentals/06.dates-time-handling",{"title":44,"path":45,"stem":46},"Потік Керування","/csharp/fundamentals/control-flow","01.csharp/01.fundamentals/07.control-flow",{"title":48,"path":49,"stem":50},"Методи","/csharp/fundamentals/methods","01.csharp/01.fundamentals/08.methods",{"title":52,"path":53,"stem":54},"Основи Відлагодження","/csharp/fundamentals/debugging-basics","01.csharp/01.fundamentals/09.debugging-basics",{"title":56,"path":57,"stem":58},"Інтерактивна Консоль (Classic)","/csharp/fundamentals/interactive-console","01.csharp/01.fundamentals/10.interactive-console",false,{"title":61,"icon":62,"path":63,"stem":64,"children":65,"page":59},"OOP","i-lucide-box","/csharp/oop","01.csharp/02.oop",[66,70,74,78,82,86],{"title":67,"path":68,"stem":69},"Package Management (Управління Пакетами)","/csharp/oop/package-management","01.csharp/02.oop/01.package-management",{"title":71,"path":72,"stem":73},"Класи та Об'єкти","/csharp/oop/classes-objects","01.csharp/02.oop/02.classes-objects",{"title":75,"path":76,"stem":77},"Властивості та Поля","/csharp/oop/properties-fields","01.csharp/02.oop/03.properties-fields",{"title":79,"path":80,"stem":81},"Стовпи ООП","/csharp/oop/oop-pillars","01.csharp/02.oop/04.oop-pillars",{"title":83,"path":84,"stem":85},"Advanced Types","/csharp/oop/advanced-types","01.csharp/02.oop/05.advanced-types",{"title":87,"path":88,"stem":89},"Namespaces (Простори Імен)","/csharp/oop/namespaces","01.csharp/02.oop/06.namespaces",{"title":91,"icon":92,"path":93,"stem":94,"children":95,"page":59},"Advanced Core","i-lucide-zap","/csharp/advanced-core","01.csharp/03.advanced-core",[96,100,104,108,112,116],{"title":97,"path":98,"stem":99},"Generics (Узагальнення)","/csharp/advanced-core/generics","01.csharp/03.advanced-core/01.generics",{"title":101,"path":102,"stem":103},"Делегати, Події та Лямбда-вирази","/csharp/advanced-core/delegates-events-lambdas","01.csharp/03.advanced-core/02.delegates-events-lambdas",{"title":105,"path":106,"stem":107},"Interfaces Deep Dive (Інтерфейси: Поглиблений Розгляд)","/csharp/advanced-core/interfaces-deep-dive","01.csharp/03.advanced-core/03.interfaces-deep-dive",{"title":109,"path":110,"stem":111},"Обробка Винятків","/csharp/advanced-core/exception-handling","01.csharp/03.advanced-core/04.exception-handling",{"title":113,"path":114,"stem":115},"Pattern Matching","/csharp/advanced-core/pattern-matching","01.csharp/03.advanced-core/05.pattern-matching",{"title":117,"path":118,"stem":119},"Додаткові Можливості C#","/csharp/advanced-core/additional-features","01.csharp/03.advanced-core/06.additional-features",{"title":121,"icon":122,"path":123,"stem":124,"children":125,"page":59},"Architecture Best Practices","i-lucide-building-2","/csharp/architecture-best-practices","01.csharp/04.architecture-best-practices",[126,130,149,153,157,161,165,169],{"title":127,"path":128,"stem":129},"Software Design Principles (Частина 1)","/csharp/architecture-best-practices/software-design-principles","01.csharp/04.architecture-best-practices/01.software-design-principles",{"title":131,"icon":132,"path":133,"stem":134,"children":135,"page":59},"Design Patterns","i-lucide-folder","/csharp/architecture-best-practices/design-patterns","01.csharp/04.architecture-best-practices/02.design-patterns",[136],{"title":137,"icon":132,"path":138,"stem":139,"children":140,"page":59},"Creational","/csharp/architecture-best-practices/design-patterns/creational","01.csharp/04.architecture-best-practices/02.design-patterns/creational",[141,145],{"title":142,"path":143,"stem":144},"Singleton (Одинак)","/csharp/architecture-best-practices/design-patterns/creational/singleton","01.csharp/04.architecture-best-practices/02.design-patterns/creational/01.singleton",{"title":146,"path":147,"stem":148},"Builder (Будівельник)","/csharp/architecture-best-practices/design-patterns/creational/builder","01.csharp/04.architecture-best-practices/02.design-patterns/creational/02.builder",{"title":150,"path":151,"stem":152},"Building Professional CLIs","/csharp/architecture-best-practices/building-professional-clis","01.csharp/04.architecture-best-practices/03.building-professional-clis",{"title":154,"path":155,"stem":156},"Validation & Flow Control","/csharp/architecture-best-practices/validation-flow-control","01.csharp/04.architecture-best-practices/04.validation-flow-control",{"title":158,"path":159,"stem":160},"The Modern .NET Host (Microsoft.Extensions)","/csharp/architecture-best-practices/modern-dotnet-host","01.csharp/04.architecture-best-practices/05.modern-dotnet-host",{"title":162,"path":163,"stem":164},"Data Mapper: Repository та DAO патерни (Частина 1)","/csharp/architecture-best-practices/data-mapper-part1","01.csharp/04.architecture-best-practices/06.data-mapper-part1",{"title":166,"path":167,"stem":168},"Data Mapper: Repository та DAO патерни (Частина 2)","/csharp/architecture-best-practices/data-mapper-part2","01.csharp/04.architecture-best-practices/07.data-mapper-part2",{"title":170,"icon":132,"path":171,"stem":172,"children":173,"page":59},"Di Ioc","/csharp/architecture-best-practices/di-ioc","01.csharp/04.architecture-best-practices/08.di-ioc",[174,178,182,186,190,194,198],{"title":175,"path":176,"stem":177},"Проблема залежностей та Інверсія Контролю","/csharp/architecture-best-practices/di-ioc/the-dependency-problem","01.csharp/04.architecture-best-practices/08.di-ioc/01.the-dependency-problem",{"title":179,"path":180,"stem":181},"Будуємо власний Service Container","/csharp/architecture-best-practices/di-ioc/build-your-own-container","01.csharp/04.architecture-best-practices/08.di-ioc/02.build-your-own-container",{"title":183,"path":184,"stem":185},"Service Locator: Паттерн та Анти-паттерн","/csharp/architecture-best-practices/di-ioc/service-locator-pattern","01.csharp/04.architecture-best-practices/08.di-ioc/03.service-locator-pattern",{"title":187,"path":188,"stem":189},"Паттерни Dependency Injection","/csharp/architecture-best-practices/di-ioc/dependency-injection-patterns","01.csharp/04.architecture-best-practices/08.di-ioc/04.dependency-injection-patterns",{"title":191,"path":192,"stem":193},"Microsoft DI: IServiceCollection та IServiceProvider","/csharp/architecture-best-practices/di-ioc/microsoft-di-deep-dive","01.csharp/04.architecture-best-practices/08.di-ioc/05.microsoft-di-deep-dive",{"title":195,"path":196,"stem":197},"Service Lifetimes та Scopes","/csharp/architecture-best-practices/di-ioc/service-lifetimes-and-scopes","01.csharp/04.architecture-best-practices/08.di-ioc/06.service-lifetimes-and-scopes",{"title":199,"path":200,"stem":201},"DI Анти-паттерни та Найкращі Практики","/csharp/architecture-best-practices/di-ioc/di-anti-patterns-and-best-practices","01.csharp/04.architecture-best-practices/08.di-ioc/07.di-anti-patterns-and-best-practices",{"title":203,"icon":132,"path":204,"stem":205,"children":206,"page":59},"Standard Library","/csharp/standard-library","01.csharp/05.standard-library",[207,211,215],{"title":208,"path":209,"stem":210},"Collections (Колекції)","/csharp/standard-library/collections","01.csharp/05.standard-library/01.collections",{"title":212,"path":213,"stem":214},"High Performance Types (Високопродуктивні Типи)","/csharp/standard-library/high-performance-types","01.csharp/05.standard-library/02.high-performance-types",{"title":216,"path":217,"stem":218},"LINQ (Language Integrated Query)","/csharp/standard-library/linq","01.csharp/05.standard-library/03.linq",{"title":220,"icon":221,"path":222,"stem":223,"children":224,"page":59},"System Internals Concurrency","i-lucide-server","/csharp/system-internals-concurrency","01.csharp/06.system-internals-concurrency",[225,229,233,237,241,245,249],{"title":226,"path":227,"stem":228},"Memory Management","/csharp/system-internals-concurrency/memory-management","01.csharp/06.system-internals-concurrency/01.memory-management",{"title":230,"path":231,"stem":232},"Reflection API: System.Type та Метадані","/csharp/system-internals-concurrency/reflection-fundamentals","01.csharp/06.system-internals-concurrency/02.reflection-fundamentals",{"title":234,"path":235,"stem":236},"Attributes та Dynamic Language Runtime","/csharp/system-internals-concurrency/attributes-dynamic","01.csharp/06.system-internals-concurrency/03.attributes-dynamic",{"title":238,"path":239,"stem":240},"Expression Trees: Швидка Альтернатива Рефлексії","/csharp/system-internals-concurrency/expression-trees-compiled","01.csharp/06.system-internals-concurrency/04.expression-trees-compiled",{"title":242,"path":243,"stem":244},"Source Generators: Compile-Time Code Generation","/csharp/system-internals-concurrency/source-generators","01.csharp/06.system-internals-concurrency/05.source-generators",{"title":246,"path":247,"stem":248},"Multithreading Fundamentals","/csharp/system-internals-concurrency/multithreading-fundamentals","01.csharp/06.system-internals-concurrency/06.multithreading-fundamentals",{"title":250,"path":251,"stem":252},"Synchronization Primitives","/csharp/system-internals-concurrency/synchronization-primitives","01.csharp/06.system-internals-concurrency/07.synchronization-primitives",{"title":254,"icon":255,"path":256,"stem":257,"children":258,"page":59},"System Programming Windows","i-lucide-cpu","/csharp/system-programming-windows","01.csharp/07.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},"Як Працює Операційна Система","/csharp/system-programming-windows/how-os-works","01.csharp/07.system-programming-windows/01.how-os-works",{"title":264,"path":265,"stem":266},"Процеси в .NET — API та Запуск","/csharp/system-programming-windows/processes-in-dotnet","01.csharp/07.system-programming-windows/02.processes-in-dotnet",{"title":268,"path":269,"stem":270},"Процеси в .NET — IPC та Міжпроцесна Комунікація","/csharp/system-programming-windows/02a.processes-ipc","01.csharp/07.system-programming-windows/02a.processes-ipc",{"title":272,"path":273,"stem":274},"Application Domains та Збірки — AppDomain і AssemblyLoadContext","/csharp/system-programming-windows/appdomains-assemblies","01.csharp/07.system-programming-windows/03.appdomains-assemblies",{"title":276,"path":277,"stem":278},"Application Domains та Збірки — Plug-in Система з Hot-Reload","/csharp/system-programming-windows/03a.appdomains-plugin-system","01.csharp/07.system-programming-windows/03a.appdomains-plugin-system",{"title":280,"path":281,"stem":282},"Потоки — Основи та API Thread","/csharp/system-programming-windows/thread-fundamentals","01.csharp/07.system-programming-windows/04.thread-fundamentals",{"title":284,"path":285,"stem":286},"Потоки — Lifecycle, Пріоритети та Безпечне Завершення","/csharp/system-programming-windows/04a.thread-lifecycle-priorities","01.csharp/07.system-programming-windows/04a.thread-lifecycle-priorities",{"title":288,"path":289,"stem":290},"Проблеми Спільного Стану — Race Condition та Data Race","/csharp/system-programming-windows/shared-state-problems","01.csharp/07.system-programming-windows/05.shared-state-problems",{"title":292,"path":293,"stem":294},"Проблеми Спільного Стану — Memory Model та volatile","/csharp/system-programming-windows/05a.shared-state-memory-model","01.csharp/07.system-programming-windows/05a.shared-state-memory-model",{"title":296,"path":297,"stem":298},"Синхронізація — Monitor, lock та еволюція примітивів","/csharp/system-programming-windows/synchronization-fundamentals","01.csharp/07.system-programming-windows/06.synchronization-fundamentals",{"title":300,"path":301,"stem":302},"Синхронізація — Наскрізний Приклад та Deadlock Detection","/csharp/system-programming-windows/06a.synchronization-walkthrough","01.csharp/07.system-programming-windows/06a.synchronization-walkthrough",{"title":304,"path":305,"stem":306},"Синхронізація — Mutex, Semaphore та Event-Based Primitives","/csharp/system-programming-windows/synchronization-advanced","01.csharp/07.system-programming-windows/07.synchronization-advanced",{"title":308,"path":309,"stem":310},"Синхронізація — Interlocked, Volatile та Lock-Free Структури","/csharp/system-programming-windows/07a.synchronization-advanced-walkthrough","01.csharp/07.system-programming-windows/07a.synchronization-advanced-walkthrough",{"title":312,"path":313,"stem":314},"Interlocked, CAS та Lock-Free Структури","/csharp/system-programming-windows/interlocked-cas-lockfree","01.csharp/07.system-programming-windows/08.interlocked-cas-lockfree",{"title":316,"path":317,"stem":318},"Volatile, Memory Model та Spinning","/csharp/system-programming-windows/08a.volatile-memory-model","01.csharp/07.system-programming-windows/08a.volatile-memory-model",{"title":320,"path":321,"stem":322},"ThreadPool — Пул Потоків для Ефективного Виконання","/csharp/system-programming-windows/thread-pool","01.csharp/07.system-programming-windows/09.thread-pool",{"title":324,"path":325,"stem":326},"ThreadPool — Просунуті Сценарії та Внутрішня Будова","/csharp/system-programming-windows/09a.thread-pool-advanced","01.csharp/07.system-programming-windows/09a.thread-pool-advanced",{"title":328,"path":329,"stem":330},"Concurrent та Immutable Collections","/csharp/system-programming-windows/concurrent-collections","01.csharp/07.system-programming-windows/10.concurrent-collections",{"title":332,"path":333,"stem":334},"TPL, Task та Композиція — Від Thread до Task","/csharp/system-programming-windows/tpl-parallel-plinq","01.csharp/07.system-programming-windows/11.tpl-parallel-plinq",{"title":336,"path":337,"stem":338},"Parallel Class та PLINQ — Data Parallelism","/csharp/system-programming-windows/11a.tpl-parallel-plinq-advanced","01.csharp/07.system-programming-windows/11a.tpl-parallel-plinq-advanced",{"title":340,"path":341,"stem":342},"Async/Await — Фундамент Асинхронного Програмування","/csharp/system-programming-windows/async-fundamentals","01.csharp/07.system-programming-windows/12.async-fundamentals",{"title":344,"path":345,"stem":346},"SynchronizationContext та ConfigureAwait — Контекст Виконання","/csharp/system-programming-windows/async-context-configureawait","01.csharp/07.system-programming-windows/13.async-context-configureawait",{"title":348,"path":349,"stem":350},"Async — Просунуті Паттерни","/csharp/system-programming-windows/async-advanced","01.csharp/07.system-programming-windows/14.async-advanced",{"title":352,"path":353,"stem":354},"System.Threading.Channels — Async Producer-Consumer","/csharp/system-programming-windows/channels","01.csharp/07.system-programming-windows/15.channels",{"title":356,"path":357,"stem":358},"Асинхронна Синхронізація","/csharp/system-programming-windows/async-synchronization","01.csharp/07.system-programming-windows/16.async-synchronization",{"title":360,"path":361,"stem":362},"Unsafe Code та Вказівники","/csharp/system-programming-windows/unsafe-code","01.csharp/07.system-programming-windows/17.unsafe-code",{"title":364,"path":365,"stem":366},"P/Invoke та Windows API — Міст між .NET та Native Code","/csharp/system-programming-windows/pinvoke-winapi","01.csharp/07.system-programming-windows/18.pinvoke-winapi",{"title":368,"path":369,"stem":370},"Реєстр Windows — Центральна База Конфігурації Системи","/csharp/system-programming-windows/windows-registry","01.csharp/07.system-programming-windows/19.windows-registry",{"title":372,"path":373,"stem":374},"Windows Hooks, Hotkeys та Services — Глибока Інтеграція з ОС","/csharp/system-programming-windows/windows-hooks-services","01.csharp/07.system-programming-windows/20.windows-hooks-services",{"title":376,"path":377,"stem":378},"Системне Програмування C# (Windows) — 07.system-programming-windows","/csharp/system-programming-windows/implementation_plan","01.csharp/07.system-programming-windows/implementation_plan",{"title":380,"icon":132,"path":381,"stem":382,"children":383,"page":59},"Io","/csharp/io","01.csharp/08.io",[384,388,392,396,400],{"title":385,"path":386,"stem":387},"8.1.1. Основи роботи з файловою системою","/csharp/io/file-system-basics","01.csharp/08.io/01.file-system-basics",{"title":389,"path":390,"stem":391},"8.1.2. Потоки (Streams) та Серіалізація Даних","/csharp/io/streams-serialization","01.csharp/08.io/02.streams-serialization",{"title":393,"path":394,"stem":395},"8.2.1. JSON Serialization з System.Text.Json","/csharp/io/json-serialization","01.csharp/08.io/03.json-serialization",{"title":397,"path":398,"stem":399},"8.2.2. XML Serialization та LINQ to XML","/csharp/io/xml-serialization","01.csharp/08.io/04.xml-serialization",{"title":401,"path":402,"stem":403},"8.2.3. Binary Serialization: MessagePack та Protocol Buffers","/csharp/io/binary-serialization","01.csharp/08.io/05.binary-serialization",{"title":405,"icon":132,"path":406,"stem":407,"children":408,"page":59},"Ado Net","/csharp/ado-net","01.csharp/09.ado-net",[409,413,417,421,425,429,433,437,441,445,449,453],{"title":410,"path":411,"stem":412},"9.1. Введення в ADO.NET","/csharp/ado-net/introduction-to-adonet","01.csharp/09.ado-net/01.introduction-to-adonet",{"title":414,"path":415,"stem":416},"9.2. Клас DbConnection — з'єднання з базою даних","/csharp/ado-net/connection","01.csharp/09.ado-net/02.connection",{"title":418,"path":419,"stem":420},"9.3. Клас DbCommand — виконання SQL-запитів","/csharp/ado-net/command-and-queries","01.csharp/09.ado-net/03.command-and-queries",{"title":422,"path":423,"stem":424},"9.4. Клас DbDataReader — ефективне читання даних","/csharp/ado-net/datareader","01.csharp/09.ado-net/04.datareader",{"title":426,"path":427,"stem":428},"9.5. Параметризовані запити та захист від SQL Injection","/csharp/ado-net/parameters-and-sql-injection","01.csharp/09.ado-net/05.parameters-and-sql-injection",{"title":430,"path":431,"stem":432},"9.6. Транзакції в ADO.NET","/csharp/ado-net/transactions","01.csharp/09.ado-net/06.transactions",{"title":434,"path":435,"stem":436},"9.7. DbProviderFactory — провайдер-незалежний код","/csharp/ado-net/provider-factory","01.csharp/09.ado-net/07.provider-factory",{"title":438,"path":439,"stem":440},"9.8. Асинхронний доступ до даних","/csharp/ado-net/async-data-access","01.csharp/09.ado-net/08.async-data-access",{"title":442,"path":443,"stem":444},"9.9. Від'єднаний режим: DataSet, DataTable, DataRow","/csharp/ado-net/disconnected-mode-dataset","01.csharp/09.ado-net/09.disconnected-mode-dataset",{"title":446,"path":447,"stem":448},"9.10. DataAdapter — міст між DataSet та базою даних","/csharp/ado-net/data-adapter","01.csharp/09.ado-net/10.data-adapter",{"title":450,"path":451,"stem":452},"9.11. Data Mapper та Repository: Архітектура доступу до даних","/csharp/ado-net/data-mapper-repository","01.csharp/09.ado-net/11.data-mapper-repository",{"title":454,"path":455,"stem":456},"9.12. Identity Map, Unit of Work та Specification Pattern","/csharp/ado-net/advanced-patterns","01.csharp/09.ado-net/12.advanced-patterns",{"title":458,"icon":255,"path":459,"stem":460,"children":461,"page":59},"Ef Core","/csharp/ef-core","01.csharp/10.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 до об'єктів","/csharp/ef-core/what-is-orm","01.csharp/10.ef-core/01.what-is-orm",{"title":467,"path":468,"stem":469},"Перший проєкт — від нуля до CRUD","/csharp/ef-core/first-project","01.csharp/10.ef-core/02.first-project",{"title":471,"path":472,"stem":473},"DbContext — Серце EF Core","/csharp/ef-core/dbcontext-deep-dive","01.csharp/10.ef-core/03.dbcontext-deep-dive",{"title":475,"path":476,"stem":477},"Провайдери баз даних — Архітектура та Вибір СУБД","/csharp/ef-core/database-providers","01.csharp/10.ef-core/04.database-providers",{"title":479,"path":480,"stem":481},"Конвенції EF Core — Магія без конфігурації","/csharp/ef-core/conventions","01.csharp/10.ef-core/05.conventions",{"title":483,"path":484,"stem":485},"Fluent API та Data Annotations — Явна конфігурація моделі","/csharp/ef-core/fluent-api-vs-annotations","01.csharp/10.ef-core/06.fluent-api-vs-annotations",{"title":487,"path":488,"stem":489},"Зв'язки — One-to-One та One-to-Many","/csharp/ef-core/relationships-basics","01.csharp/10.ef-core/07.relationships-basics",{"title":491,"path":492,"stem":493},"Зв'язки Advanced — Many-to-Many та Складні Сценарії","/csharp/ef-core/relationships-advanced","01.csharp/10.ef-core/08.relationships-advanced",{"title":495,"path":496,"stem":497},"Властивості — Типи, Конвертери, Компаратори (Частина 1)","/csharp/ef-core/property-configuration-part1","01.csharp/10.ef-core/09.property-configuration-part1",{"title":499,"path":500,"stem":501},"Властивості — Value Comparers, Generators, Shadow Properties (Частина 2)","/csharp/ef-core/property-configuration-part2","01.csharp/10.ef-core/09.property-configuration-part2",{"title":503,"path":504,"stem":505},"Складні типи — Owned Types та Complex Types (Частина 1)","/csharp/ef-core/complex-types-owned-part1","01.csharp/10.ef-core/10.complex-types-owned-part1",{"title":507,"path":508,"stem":509},"Складні типи — Complex Types, Keyless Entities, Порівняння (Частина 2)","/csharp/ef-core/complex-types-owned-part2","01.csharp/10.ef-core/10.complex-types-owned-part2",{"title":511,"path":512,"stem":513},"JSON Columns — Складні дані у JSON (Частина 1)","/csharp/ef-core/json-columns-part1","01.csharp/10.ef-core/11.json-columns-part1",{"title":515,"path":516,"stem":517},"JSON Columns — Value Comparers, Індекси, Провайдери (Частина 2)","/csharp/ef-core/json-columns-part2","01.csharp/10.ef-core/11.json-columns-part2",{"title":519,"path":520,"stem":521},"Успадкування — Абстрактні класи та TPH (Частина 1)","/csharp/ef-core/inheritance-part1","01.csharp/10.ef-core/12.inheritance-part1",{"title":523,"path":524,"stem":525},"Успадкування — TPT, TPC та Порівняння Стратегій (Частина 2)","/csharp/ef-core/inheritance-part2","01.csharp/10.ef-core/12.inheritance-part2",{"title":527,"path":528,"stem":529,"children":530},"Індекси, Обмеження та Схема (Частина 1)","/csharp/ef-core/indexes-constraints-part1","01.csharp/10.ef-core/13.indexes-constraints-part1",[531],{"title":527,"path":528,"stem":529},{"title":533,"path":534,"stem":535,"children":536},"Індекси, Обмеження та Схема (Частина 2)","/csharp/ef-core/indexes-constraints-part2","01.csharp/10.ef-core/13.indexes-constraints-part2",[537],{"title":533,"path":534,"stem":535},{"title":539,"path":540,"stem":541},"Seed Data — Початкові Дані (Частина 1)","/csharp/ef-core/seeding-part1","01.csharp/10.ef-core/14.seeding-part1",{"title":543,"path":544,"stem":545},"Seed Data — SQL-скрипти, Bogus та Стратегії (Частина 2)","/csharp/ef-core/seeding-part2","01.csharp/10.ef-core/14.seeding-part2",{"title":547,"path":548,"stem":549},"Global Query Filters — Глобальні Фільтри (Частина 1)","/csharp/ef-core/global-query-filters-part1","01.csharp/10.ef-core/15.global-query-filters-part1",{"title":551,"path":552,"stem":553},"Global Query Filters — Підводні камені та Інтеграція (Частина 2)","/csharp/ef-core/global-query-filters-part2","01.csharp/10.ef-core/15.global-query-filters-part2",{"title":555,"path":556,"stem":557},"LINQ-запити в EF Core (Частина 1)","/csharp/ef-core/linq-queries-part1","01.csharp/10.ef-core/16.linq-queries-part1",{"title":559,"path":560,"stem":561},"LINQ-запити в EF Core (Частина 2)","/csharp/ef-core/linq-queries-part2","01.csharp/10.ef-core/16.linq-queries-part2",{"title":563,"path":564,"stem":565},"Завантаження Пов'язаних Даних (Частина 1)","/csharp/ef-core/loading-related-data-part1","01.csharp/10.ef-core/17.loading-related-data-part1",{"title":567,"path":568,"stem":569},"Завантаження Пов'язаних Даних (Частина 2)","/csharp/ef-core/loading-related-data-part2","01.csharp/10.ef-core/17.loading-related-data-part2",{"title":571,"path":572,"stem":573},"Raw SQL, Views та Stored Procedures (Частина 1)","/csharp/ef-core/raw-sql-part1","01.csharp/10.ef-core/18.raw-sql-part1",{"title":575,"path":576,"stem":577},"Raw SQL — Stored Procedures, DbFunction та Bulk Operations (Частина 2)","/csharp/ef-core/raw-sql-part2","01.csharp/10.ef-core/18.raw-sql-part2",{"title":579,"path":580,"stem":581},"Продвинуті Запити — Compiled Queries, Bulk та Оптимізація (Частина 1)","/csharp/ef-core/advanced-queries-part1","01.csharp/10.ef-core/19.advanced-queries-part1",{"title":583,"path":584,"stem":585},"Продвинуті Запити — Query Tags, Bulk та Interceptors (Частина 2)","/csharp/ef-core/advanced-queries-part2","01.csharp/10.ef-core/19.advanced-queries-part2",{"title":587,"path":588,"stem":589},"Change Tracker — Відстеження Змін (Частина 1)","/csharp/ef-core/change-tracking-part1","01.csharp/10.ef-core/20.change-tracking-part1",{"title":591,"path":592,"stem":593},"Change Tracker — Графи Об'єктів та Disconnected (Частина 2)","/csharp/ef-core/change-tracking-part2","01.csharp/10.ef-core/20.change-tracking-part2",{"title":595,"path":596,"stem":597},"Збереження Даних та Транзакції (Частина 1)","/csharp/ef-core/saving-data-part1","01.csharp/10.ef-core/21.saving-data-part1",{"title":599,"path":600,"stem":601},"Збереження Даних — Concurrency та Outbox (Частина 2)","/csharp/ef-core/saving-data-part2","01.csharp/10.ef-core/21.saving-data-part2",{"title":603,"path":604,"stem":605},"Конкурентність та Блокування (Частина 1)","/csharp/ef-core/concurrency-part1","01.csharp/10.ef-core/22.concurrency-part1",{"title":607,"path":608,"stem":609},"Конкурентність — Дедлоки та Queue Processing (Частина 2)","/csharp/ef-core/concurrency-part2","01.csharp/10.ef-core/22.concurrency-part2",{"title":611,"path":612,"stem":613},"Міграції в EF Core — Основи (Частина 1)","/csharp/ef-core/migrations-basics-part1","01.csharp/10.ef-core/23.migrations-basics-part1",{"title":615,"path":616,"stem":617},"Міграції в EF Core — Основи (Частина 2)","/csharp/ef-core/migrations-basics-part2","01.csharp/10.ef-core/23.migrations-basics-part2",{"title":619,"path":620,"stem":621},"Міграції — Просунуті Сценарії (Частина 1)","/csharp/ef-core/migrations-advanced-part1","01.csharp/10.ef-core/24.migrations-advanced-part1",{"title":623,"path":624,"stem":625},"Міграції — Просунуті Сценарії (Частина 2)","/csharp/ef-core/migrations-advanced-part2","01.csharp/10.ef-core/24.migrations-advanced-part2",{"title":627,"path":628,"stem":629},"Управління Схемою та Database-First (Частина 1)","/csharp/ef-core/schema-management-part1","01.csharp/10.ef-core/25.schema-management-part1",{"title":631,"path":632,"stem":633},"Управління Схемою та Database-First (Частина 2)","/csharp/ef-core/schema-management-part2","01.csharp/10.ef-core/25.schema-management-part2",{"title":635,"path":636,"stem":637},"Продуктивність EF Core — Основи (Частина 1)","/csharp/ef-core/performance-fundamentals-part1","01.csharp/10.ef-core/26.performance-fundamentals-part1",{"title":639,"path":640,"stem":641},"Interceptors в EF Core (Частина 1)","/csharp/ef-core/interceptors-part1","01.csharp/10.ef-core/29.interceptors-part1",{"title":643,"path":644,"stem":645},"Interceptors в EF Core — Connection, Transaction та Materialization (Частина 2)","/csharp/ef-core/interceptors-part2","01.csharp/10.ef-core/29.interceptors-part2",{"title":647,"path":648,"stem":649},"План вивчення Entity Framework Core — Повний курс","/csharp/ef-core/implementation_plan","01.csharp/10.ef-core/implementation_plan",{"title":651,"icon":652,"path":653,"stem":654,"children":655,"page":59},"ASP.NET","i-devicon-dotnetcore","/csharp/aspnet","01.csharp/11.aspnet",[656,730,791,869,927,941,967,1057,1111,1182,1212,1289],{"title":657,"icon":658,"path":659,"stem":660,"children":661,"page":59},"Minimal API","i-lucide-network","/csharp/aspnet/minimal-api","01.csharp/11.aspnet/01.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 та еволюція фреймворку","/csharp/aspnet/minimal-api/introduction","01.csharp/11.aspnet/01.minimal-api/01.introduction",{"title":667,"path":668,"stem":669},"Перший додаток на ASP.NET Core","/csharp/aspnet/minimal-api/first-application","01.csharp/11.aspnet/01.minimal-api/02.first-application",{"title":671,"path":672,"stem":673},"WebApplication, Builder та Dependency Injection","/csharp/aspnet/minimal-api/webapplication-builder","01.csharp/11.aspnet/01.minimal-api/03.webapplication-builder",{"title":675,"path":676,"stem":677},"Конвеєр запитів та Middleware","/csharp/aspnet/minimal-api/request-pipeline-middleware","01.csharp/11.aspnet/01.minimal-api/04.request-pipeline-middleware",{"title":679,"path":680,"stem":681},"Маршрутизація в ASP.NET Core: Основи","/csharp/aspnet/minimal-api/routing-basics","01.csharp/11.aspnet/01.minimal-api/05.routing-basics",{"title":683,"path":684,"stem":685},"Маршрутизація в ASP.NET Core: Розширені можливості","/csharp/aspnet/minimal-api/routing-advanced","01.csharp/11.aspnet/01.minimal-api/06.routing-advanced",{"title":687,"path":688,"stem":689},"Статичні файли в ASP.NET Core","/csharp/aspnet/minimal-api/static-files","01.csharp/11.aspnet/01.minimal-api/07.static-files",{"title":691,"path":692,"stem":693},"Статичні Активи: MapStaticAssets (ASP.NET Core 9.0)","/csharp/aspnet/minimal-api/static-assets","01.csharp/11.aspnet/01.minimal-api/08.static-assets",{"title":695,"path":696,"stem":697},"Конфігурація в ASP.NET Core: Основи","/csharp/aspnet/minimal-api/configuration-fundamentals","01.csharp/11.aspnet/01.minimal-api/09.configuration-fundamentals",{"title":699,"path":700,"stem":701},"Конфігурація: Паттерн Options","/csharp/aspnet/minimal-api/configuration-options","01.csharp/11.aspnet/01.minimal-api/10.configuration-options",{"title":703,"path":704,"stem":705},"Логування в ASP.NET Core: Основи","/csharp/aspnet/minimal-api/logging-basics","01.csharp/11.aspnet/01.minimal-api/11.logging-basics",{"title":707,"path":708,"stem":709},"Логування: Serilog та Middleware","/csharp/aspnet/minimal-api/logging-advanced","01.csharp/11.aspnet/01.minimal-api/12.logging-advanced",{"title":711,"path":712,"stem":713},"Управління станом: HttpContext.Items та Cookies","/csharp/aspnet/minimal-api/state-management","01.csharp/11.aspnet/01.minimal-api/13.state-management",{"title":715,"path":716,"stem":717},"Стан сесії: Sessions","/csharp/aspnet/minimal-api/session-state","01.csharp/11.aspnet/01.minimal-api/14.session-state",{"title":719,"path":720,"stem":721},"Структура проєкту: від хаосу до архітектури","/csharp/aspnet/minimal-api/project-structure","01.csharp/11.aspnet/01.minimal-api/15.project-structure",{"title":723,"path":724,"stem":725},"Scalar у Minimal API: повний проєкт і Fluent OpenAPI","/csharp/aspnet/minimal-api/scalar-openapi-fluent","01.csharp/11.aspnet/01.minimal-api/16.scalar-openapi-fluent",{"title":727,"path":728,"stem":729},"Swagger / Swashbuckle у Minimal API: окремий класичний шлях","/csharp/aspnet/minimal-api/swagger-swashbuckle","01.csharp/11.aspnet/01.minimal-api/17.swagger-swashbuckle",{"title":731,"icon":658,"path":732,"stem":733,"children":734,"page":59},"API","/csharp/aspnet/api","01.csharp/11.aspnet/02.api",[735,739,743,747,751,755,759,763,767,771,775,779,783,787],{"title":736,"path":737,"stem":738},"Що таке API. Клієнт-серверна архітектура","/csharp/aspnet/api/what-is-api","01.csharp/11.aspnet/02.api/01.what-is-api",{"title":740,"path":741,"stem":742},"Формати даних: JSON, XML, TOML та бінарні формати","/csharp/aspnet/api/data-formats","01.csharp/11.aspnet/02.api/02.data-formats",{"title":744,"path":745,"stem":746},"Парадигми API та концепція REST","/csharp/aspnet/api/api-paradigms-rest","01.csharp/11.aspnet/02.api/03.api-paradigms-rest",{"title":748,"path":749,"stem":750},"HTTP-методи, статус-коди та заголовки","/csharp/aspnet/api/http-methods-status-codes","01.csharp/11.aspnet/02.api/04.http-methods-status-codes",{"title":752,"path":753,"stem":754},"Організація HTTP API за принципами REST","/csharp/aspnet/api/rest-organizing","01.csharp/11.aspnet/02.api/05.rest-organizing",{"title":756,"path":757,"stem":758},"Номенклатура URL та CRUD-операції","/csharp/aspnet/api/url-nomenclature-crud","01.csharp/11.aspnet/02.api/06.url-nomenclature-crud",{"title":760,"path":761,"stem":762},"Правила дизайну: іменування та стандарти","/csharp/aspnet/api/api-design-naming","01.csharp/11.aspnet/02.api/07.api-design-naming",{"title":764,"path":765,"stem":766},"Валідація, ліміти та обробка помилок","/csharp/aspnet/api/api-design-validation","01.csharp/11.aspnet/02.api/08.api-design-validation",{"title":768,"path":769,"stem":770},"Обробка помилок у Minimal API","/csharp/aspnet/api/error-handling-http","01.csharp/11.aspnet/02.api/09.error-handling-http",{"title":772,"path":773,"stem":774},"Ідемпотентність та синхронізація стану","/csharp/aspnet/api/idempotency-sync","01.csharp/11.aspnet/02.api/10.idempotency-sync",{"title":776,"path":777,"stem":778},"Пагінація та організація списків","/csharp/aspnet/api/pagination-lists","01.csharp/11.aspnet/02.api/11.pagination-lists",{"title":780,"path":781,"stem":782},"Безпека API, кешування та інтернаціоналізація","/csharp/aspnet/api/security-auth","01.csharp/11.aspnet/02.api/12.security-auth",{"title":784,"path":785,"stem":786},"Процес проєктування API та документування","/csharp/aspnet/api/api-design-process","01.csharp/11.aspnet/02.api/13.api-design-process",{"title":788,"path":789,"stem":790},"OpenAPI: контракт, специфікація та документація API","/csharp/aspnet/api/openapi","01.csharp/11.aspnet/02.api/14.openapi",{"title":792,"icon":793,"path":794,"stem":795,"children":796,"page":59},"Auth","i-lucide-shield-check","/csharp/aspnet/auth","01.csharp/11.aspnet/03.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},"Основи аутентифікації та авторизації","/csharp/aspnet/auth/auth-fundamentals","01.csharp/11.aspnet/03.auth/01.auth-fundamentals",{"title":802,"path":803,"stem":804},"JWT-аутентифікація","/csharp/aspnet/auth/jwt-authentication","01.csharp/11.aspnet/03.auth/02.jwt-authentication",{"title":806,"path":807,"stem":808},"Авторизація: ролі, політики та resource-based доступ","/csharp/aspnet/auth/authorization-policies","01.csharp/11.aspnet/03.auth/03.authorization-policies",{"title":810,"path":811,"stem":812},"Cookie-аутентифікація та ASP.NET Core Identity","/csharp/aspnet/auth/cookie-auth-identity","01.csharp/11.aspnet/03.auth/04.cookie-auth-identity",{"title":814,"path":815,"stem":816},"JWT + Refresh Tokens (HttpOnly Cookie)","/csharp/aspnet/auth/04b.identity-auth-jwt","01.csharp/11.aspnet/03.auth/04b.identity-auth-jwt",{"title":818,"path":819,"stem":820},"Identity: Підтвердження Email та Скидання Пароля","/csharp/aspnet/auth/identity-email-confirmation","01.csharp/11.aspnet/03.auth/05.identity-email-confirmation",{"title":822,"path":823,"stem":824},"Identity: Двофакторна Аутентифікація (2FA)","/csharp/aspnet/auth/identity-two-factor","01.csharp/11.aspnet/03.auth/06.identity-two-factor",{"title":826,"path":827,"stem":828},"Identity: Внутрішня Архітектура та Кастомізація","/csharp/aspnet/auth/identity-internals","01.csharp/11.aspnet/03.auth/07.identity-internals",{"title":830,"path":831,"stem":832},"OAuth 2.0 та зовнішні провайдери","/csharp/aspnet/auth/oauth-external-providers","01.csharp/11.aspnet/03.auth/08.oauth-external-providers",{"title":834,"path":835,"stem":836},"Безпека на практиці: CORS, HTTPS та захист від атак","/csharp/aspnet/auth/security-hardening","01.csharp/11.aspnet/03.auth/09.security-hardening",{"title":838,"path":839,"stem":840},"Теорія OAuth 2.0: Поняття, Аналогії та Флоу","/csharp/aspnet/auth/oauth-theory","01.csharp/11.aspnet/03.auth/10.oauth-theory",{"title":842,"path":843,"stem":844},"OIDC, OAuth 2.0 та Keycloak в ASP.NET Core","/csharp/aspnet/auth/oidc-keycloak","01.csharp/11.aspnet/03.auth/10.oidc-keycloak",{"title":846,"path":847,"stem":848},"API Keys аутентифікація в ASP.NET Core","/csharp/aspnet/auth/api-keys","01.csharp/11.aspnet/03.auth/11.api-keys",{"title":850,"path":851,"stem":852},"Rate Limiting та Throttling в ASP.NET Core","/csharp/aspnet/auth/rate-limiting","01.csharp/11.aspnet/03.auth/12.rate-limiting",{"title":854,"path":855,"stem":856},"Refresh Token Rotation в ASP.NET Core","/csharp/aspnet/auth/refresh-token-rotation","01.csharp/11.aspnet/03.auth/13.refresh-token-rotation",{"title":858,"path":859,"stem":860},"Certificate Authentication та mTLS в ASP.NET Core","/csharp/aspnet/auth/certificate-auth","01.csharp/11.aspnet/03.auth/14.certificate-auth",{"title":862,"path":863,"stem":864},"RBAC, ABAC та ReBAC в ASP.NET Core","/csharp/aspnet/auth/rbac-abac-rebac","01.csharp/11.aspnet/03.auth/15.rbac-abac-rebac",{"title":866,"path":867,"stem":868},"Multi-tenancy та ізоляція даних в ASP.NET Core","/csharp/aspnet/auth/multi-tenancy","01.csharp/11.aspnet/03.auth/16.multi-tenancy",{"title":870,"icon":871,"path":872,"stem":873,"children":874,"page":59},"Нотифікації","i-lucide-bell","/csharp/aspnet/notifications","01.csharp/11.aspnet/04.notifications",[875,879,883,887,891,895,899,903,907,911,915,919,923],{"title":876,"path":877,"stem":878},"In-App нотифікації через базу даних","/csharp/aspnet/notifications/in-app-database-notifications","01.csharp/11.aspnet/04.notifications/01.in-app-database-notifications",{"title":880,"path":881,"stem":882},"Polling: Регулярний запит оновлень","/csharp/aspnet/notifications/polling","01.csharp/11.aspnet/04.notifications/02.polling",{"title":884,"path":885,"stem":886},"Server-Sent Events: Однострімовий push від сервера","/csharp/aspnet/notifications/server-sent-events","01.csharp/11.aspnet/04.notifications/03.server-sent-events",{"title":888,"path":889,"stem":890},"WebSockets: Двостороннє з'єднання в реальному часі","/csharp/aspnet/notifications/websockets","01.csharp/11.aspnet/04.notifications/04.websockets",{"title":892,"path":893,"stem":894},"SignalR: Абстракція над транспортами реального часу","/csharp/aspnet/notifications/signalr","01.csharp/11.aspnet/04.notifications/05.signalr",{"title":896,"path":897,"stem":898},"Background Services: Фонові задачі в ASP.NET Core","/csharp/aspnet/notifications/background-services","01.csharp/11.aspnet/04.notifications/06.background-services",{"title":900,"path":901,"stem":902},"Web Push нотифікації","/csharp/aspnet/notifications/web-push","01.csharp/11.aspnet/04.notifications/07.web-push",{"title":904,"path":905,"stem":906},"Email нотифікації","/csharp/aspnet/notifications/email-notifications","01.csharp/11.aspnet/04.notifications/08.email-notifications",{"title":908,"path":909,"stem":910},"Порівняння підходів: Як вибрати правильну технологію нотифікацій","/csharp/aspnet/notifications/choosing-the-right-approach","01.csharp/11.aspnet/04.notifications/09.choosing-the-right-approach",{"title":912,"path":913,"stem":914},"Hangfire: Надійне планування фонових задач","/csharp/aspnet/notifications/hangfire","01.csharp/11.aspnet/04.notifications/10.hangfire",{"title":916,"path":917,"stem":918},"Практика: Конвертація зображень у WebP через Hangfire","/csharp/aspnet/notifications/hangfire-image-webp","01.csharp/11.aspnet/04.notifications/11.hangfire-image-webp",{"title":920,"path":921,"stem":922},"Практика: Підготовка відео до HLS-стрімінгу через Hangfire","/csharp/aspnet/notifications/hangfire-video-hls","01.csharp/11.aspnet/04.notifications/12.hangfire-video-hls",{"title":924,"path":925,"stem":926},"Telegram-нотифікації: від одного повідомлення до масових розсилок і мульти-канального підходу","/csharp/aspnet/notifications/telegram-notifications","01.csharp/11.aspnet/04.notifications/13.telegram-notifications",{"title":928,"icon":929,"path":930,"stem":931,"children":932,"page":59},"Інтернаціоналізація","i-lucide-languages","/csharp/aspnet/i18n","01.csharp/11.aspnet/05.i18n",[933,937],{"title":934,"path":935,"stem":936},"Інтернаціоналізація (i18n) у Minimal API: від A до Я","/csharp/aspnet/i18n/internationalization","01.csharp/11.aspnet/05.i18n/01.internationalization",{"title":938,"path":939,"stem":940},"Humanizer: людиномовні рядки у .NET","/csharp/aspnet/i18n/humanizer","01.csharp/11.aspnet/05.i18n/02.humanizer",{"title":942,"icon":943,"path":944,"stem":945,"children":946,"page":59},"Кешування","i-lucide-layers","/csharp/aspnet/caching","01.csharp/11.aspnet/06.caching",[947,951,955,959,963],{"title":948,"path":949,"stem":950},"Огляд кешування: чотири рівні і коли що обирати","/csharp/aspnet/caching/caching","01.csharp/11.aspnet/06.caching/01.caching",{"title":952,"path":953,"stem":954},"IMemoryCache: кеш в оперативній пам'яті","/csharp/aspnet/caching/memory-cache","01.csharp/11.aspnet/06.caching/02.memory-cache",{"title":956,"path":957,"stem":958},"IDistributedCache і Redis: розподілений кеш","/csharp/aspnet/caching/distributed-cache","01.csharp/11.aspnet/06.caching/03.distributed-cache",{"title":960,"path":961,"stem":962},"Response Cache: HTTP-кешування через Cache-Control","/csharp/aspnet/caching/response-cache","01.csharp/11.aspnet/06.caching/04.response-cache",{"title":964,"path":965,"stem":966},"Output Cache: серверний кеш HTTP-відповідей (.NET 7+)","/csharp/aspnet/caching/output-cache","01.csharp/11.aspnet/06.caching/05.output-cache",{"title":968,"icon":969,"path":970,"stem":971,"children":972,"page":59},"Тестування","i-lucide-test-tube","/csharp/aspnet/testing","01.csharp/11.aspnet/07.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},"Що таке тестування? Від інтуїції до науки","/csharp/aspnet/testing/what-is-testing","01.csharp/11.aspnet/07.testing/01.what-is-testing",{"title":978,"path":979,"stem":980},"Піраміда тестування — Стратегія, а не Догма","/csharp/aspnet/testing/testing-pyramid","01.csharp/11.aspnet/07.testing/02.testing-pyramid",{"title":982,"path":983,"stem":984},"Дві Школи Тестування — Лондон проти Детройту","/csharp/aspnet/testing/testing-schools","01.csharp/11.aspnet/07.testing/03.testing-schools",{"title":986,"path":987,"stem":988},"TDD та BDD — Тести як Дизайн-інструмент","/csharp/aspnet/testing/tdd-and-bdd","01.csharp/11.aspnet/07.testing/04.tdd-and-bdd",{"title":990,"path":991,"stem":992},"Що саме тестувати — Техніки аналізу та Циклomatична складність","/csharp/aspnet/testing/what-to-test","01.csharp/11.aspnet/07.testing/05.what-to-test",{"title":994,"path":995,"stem":996},"Тестові Фреймворки — Навіщо вони і що всередині","/csharp/aspnet/testing/test-frameworks","01.csharp/11.aspnet/07.testing/06.test-frameworks",{"title":998,"path":999,"stem":1000},"xUnit — Факти, Теорії та Lifecycle тестів","/csharp/aspnet/testing/xunit-basics","01.csharp/11.aspnet/07.testing/07.xunit-basics",{"title":1002,"path":1003,"stem":1004},"xUnit Advanced — Fixtures, Кастомізація та Розширення","/csharp/aspnet/testing/xunit-advanced","01.csharp/11.aspnet/07.testing/08.xunit-advanced",{"title":1006,"path":1007,"stem":1008},"Moq — Глибоке занурення в мокування","/csharp/aspnet/testing/mocking-with-moq","01.csharp/11.aspnet/07.testing/09.mocking-with-moq",{"title":1010,"path":1011,"stem":1012},"Тестування Баз Даних — EF Core, SQLite та Testcontainers","/csharp/aspnet/testing/database-testing","01.csharp/11.aspnet/07.testing/10.database-testing",{"title":1014,"path":1015,"stem":1016},"Integration Testing — Частина 1 [Теорія та WebApplicationFactory]","/csharp/aspnet/testing/integration-testing","01.csharp/11.aspnet/07.testing/11.integration-testing",{"title":1018,"path":1019,"stem":1020},"Інтеграційне тестування — Практика","/csharp/aspnet/testing/11a.integration-testing-practice","01.csharp/11.aspnet/07.testing/11a.integration-testing-practice",{"title":1022,"path":1023,"stem":1024},"Integration Testing — Частина 2 [Просунуті Сценарії та Testcontainers]","/csharp/aspnet/testing/integration-testing-advanced","01.csharp/11.aspnet/07.testing/12.integration-testing-advanced",{"title":1026,"path":1027,"stem":1028},"Професійний Postman: Колекції, Змінні та GitHub Інтеграція","/csharp/aspnet/testing/postman-professional","01.csharp/11.aspnet/07.testing/13.postman-professional",{"title":1030,"path":1031,"stem":1032},"HttpClient у Тестах Частина 1: Архітектура та MockHttpMessageHandler","/csharp/aspnet/testing/httpclient-testing","01.csharp/11.aspnet/07.testing/14.httpclient-testing",{"title":1034,"path":1035,"stem":1036},"HttpClient у Тестах Частина 2: WireMock.Net та Resilience","/csharp/aspnet/testing/wiremock-net","01.csharp/11.aspnet/07.testing/15.wiremock-net",{"title":1038,"path":1039,"stem":1040},"Патерни та Анти-патерни Тестування: Test Smells","/csharp/aspnet/testing/testing-patterns","01.csharp/11.aspnet/07.testing/16.testing-patterns",{"title":1042,"path":1043,"stem":1044},"Просунуті інструменти: Time, Snapshots та Властивості","/csharp/aspnet/testing/advanced-testing-tools","01.csharp/11.aspnet/07.testing/17.advanced-testing-tools",{"title":1046,"path":1047,"stem":1048},"Тестування Архітектури з NetArchTest","/csharp/aspnet/testing/architecture-testing","01.csharp/11.aspnet/07.testing/18.architecture-testing",{"title":1050,"path":1051,"stem":1052},"Тестування Продуктивності: BenchmarkDotNet, NBomber та k6","/csharp/aspnet/testing/performance-testing","01.csharp/11.aspnet/07.testing/19.performance-testing",{"title":1054,"path":1055,"stem":1056},"Залишок плану для курсу \"Тестування ASP.NET Minimal API\"","/csharp/aspnet/testing/remaining_plan","01.csharp/11.aspnet/07.testing/remaining_plan",{"title":1058,"icon":1059,"path":1060,"stem":1061,"children":1062,"page":59},"Платежі","i-lucide-credit-card","/csharp/aspnet/payments","01.csharp/11.aspnet/08.payments",[1063,1067,1071,1075,1079,1083,1087,1091,1095,1099,1103,1107],{"title":1064,"path":1065,"stem":1066},"Основи платіжної інфраструктури","/csharp/aspnet/payments/payment-fundamentals","01.csharp/11.aspnet/08.payments/01.payment-fundamentals",{"title":1068,"path":1069,"stem":1070},"Методи оплати в Україні","/csharp/aspnet/payments/payment-methods-ukraine","01.csharp/11.aspnet/08.payments/02.payment-methods-ukraine",{"title":1072,"path":1073,"stem":1074},"PCI DSS та безпека платежів","/csharp/aspnet/payments/pci-dss-security","01.csharp/11.aspnet/08.payments/03.pci-dss-security",{"title":1076,"path":1077,"stem":1078},"Архітектура платіжної підсистеми","/csharp/aspnet/payments/payment-architecture","01.csharp/11.aspnet/08.payments/04.payment-architecture",{"title":1080,"path":1081,"stem":1082},"Інтеграція LiqPay (ПриватБанк)","/csharp/aspnet/payments/liqpay-integration","01.csharp/11.aspnet/08.payments/05.liqpay-integration",{"title":1084,"path":1085,"stem":1086},"Інтеграція Monobank Acquiring API","/csharp/aspnet/payments/monobank-acquiring","01.csharp/11.aspnet/08.payments/06.monobank-acquiring",{"title":1088,"path":1089,"stem":1090},"Інтеграція Stripe","/csharp/aspnet/payments/stripe-integration","01.csharp/11.aspnet/08.payments/07.stripe-integration",{"title":1092,"path":1093,"stem":1094},"Webhooks — глибоке занурення","/csharp/aspnet/payments/webhooks-deep-dive","01.csharp/11.aspnet/08.payments/08.webhooks-deep-dive",{"title":1096,"path":1097,"stem":1098},"Підписки та рекурентні платежі","/csharp/aspnet/payments/subscriptions-recurring","01.csharp/11.aspnet/08.payments/09.subscriptions-recurring",{"title":1100,"path":1101,"stem":1102},"Повернення коштів та диспути","/csharp/aspnet/payments/refunds-disputes","01.csharp/11.aspnet/08.payments/10.refunds-disputes",{"title":1104,"path":1105,"stem":1106},"Тестування платіжних інтеграцій","/csharp/aspnet/payments/testing-payments","01.csharp/11.aspnet/08.payments/11.testing-payments",{"title":1108,"path":1109,"stem":1110},"Чекліст виходу в Production","/csharp/aspnet/payments/production-checklist","01.csharp/11.aspnet/08.payments/12.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","/csharp/aspnet/libraries","01.csharp/11.aspnet/09.libraries",[1130,1134,1138,1142,1146,1150,1154,1158,1162,1166,1170,1174,1178],{"title":1131,"path":1132,"stem":1133},"Валідація з FluentValidation в ASP.NET Core","/csharp/aspnet/libraries/fluent-validation","01.csharp/11.aspnet/09.libraries/01.fluent-validation",{"title":1135,"path":1136,"stem":1137},"Маппінг об","/csharp/aspnet/libraries/mapster","01.csharp/11.aspnet/09.libraries/02.mapster",{"title":1139,"path":1140,"stem":1141},"Обробка помилок з ErrorOr та Result Pattern в ASP.NET Core","/csharp/aspnet/libraries/erroror-result-pattern","01.csharp/11.aspnet/09.libraries/03.erroror-result-pattern",{"title":1143,"path":1144,"stem":1145},"Структуроване логування з Serilog в ASP.NET Core","/csharp/aspnet/libraries/serilog","01.csharp/11.aspnet/09.libraries/04.serilog",{"title":1147,"path":1148,"stem":1149},"CQRS та Mediator з MediatR в ASP.NET Core","/csharp/aspnet/libraries/mediatr","01.csharp/11.aspnet/09.libraries/05.mediatr",{"title":1151,"path":1152,"stem":1153},"Відмовостійкість з Polly в ASP.NET Core","/csharp/aspnet/libraries/polly","01.csharp/11.aspnet/09.libraries/06.polly",{"title":1155,"path":1156,"stem":1157},"Health Checks в ASP.NET Core","/csharp/aspnet/libraries/health-checks","01.csharp/11.aspnet/09.libraries/07.health-checks",{"title":1159,"path":1160,"stem":1161},"Feature Management та Feature Flags в ASP.NET Core","/csharp/aspnet/libraries/feature-management","01.csharp/11.aspnet/09.libraries/08.feature-management",{"title":1163,"path":1164,"stem":1165},"Відправка Email з FluentEmail в ASP.NET Core","/csharp/aspnet/libraries/fluent-email","01.csharp/11.aspnet/09.libraries/09.fluent-email",{"title":1167,"path":1168,"stem":1169},"Генерація PDF з QuestPDF в ASP.NET Core","/csharp/aspnet/libraries/quest-pdf","01.csharp/11.aspnet/09.libraries/10.quest-pdf",{"title":1171,"path":1172,"stem":1173},"Генерація тестових даних з Bogus в ASP.NET Core","/csharp/aspnet/libraries/bogus","01.csharp/11.aspnet/09.libraries/11.bogus",{"title":1175,"path":1176,"stem":1177},"Humanizer та Guard Clauses в ASP.NET Core","/csharp/aspnet/libraries/humanizer-guard","01.csharp/11.aspnet/09.libraries/12.humanizer-guard",{"title":1179,"path":1180,"stem":1181},"План модуля 10.libraries — Популярні бібліотеки ASP.NET","/csharp/aspnet/libraries/plan","01.csharp/11.aspnet/09.libraries/plan",{"title":1183,"icon":1184,"path":1185,"stem":1186,"children":1187,"page":59},"Razor Pages","i-lucide-layout-template","/csharp/aspnet/razor-pages","01.csharp/11.aspnet/10.razor-pages",[1188,1192,1196,1200,1204,1208],{"title":1189,"path":1190,"stem":1191},"Від Minimal API до Razor Pages: концептуальний перехід","/csharp/aspnet/razor-pages/from-minimal-api","01.csharp/11.aspnet/10.razor-pages/01.from-minimal-api",{"title":1193,"path":1194,"stem":1195},"PageModel: логіка сторінки Razor Pages","/csharp/aspnet/razor-pages/page-model","01.csharp/11.aspnet/10.razor-pages/02.page-model",{"title":1197,"path":1198,"stem":1199},"Razor синтаксис: шаблонізатор у .cshtml","/csharp/aspnet/razor-pages/razor-syntax","01.csharp/11.aspnet/10.razor-pages/03.razor-syntax",{"title":1201,"path":1202,"stem":1203},"Tag Helpers: типізований HTML","/csharp/aspnet/razor-pages/tag-helpers","01.csharp/11.aspnet/10.razor-pages/04.tag-helpers",{"title":1205,"path":1206,"stem":1207},"Форми і валідація: повний цикл обробки даних","/csharp/aspnet/razor-pages/forms-validation","01.csharp/11.aspnet/10.razor-pages/05.forms-validation",{"title":1209,"path":1210,"stem":1211},"Практичний проєкт: TaskManager на Razor Pages","/csharp/aspnet/razor-pages/project-task-manager","01.csharp/11.aspnet/10.razor-pages/06.project-task-manager",{"title":1213,"path":1214,"stem":1215,"children":1216,"page":59},"ASP.NET Core MVC","/csharp/aspnet/mvc","01.csharp/11.aspnet/11.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: архітектура, що змінила веб","/csharp/aspnet/mvc/mvc-pattern","01.csharp/11.aspnet/11.mvc/01.mvc-pattern",{"title":1222,"path":1223,"stem":1224},"Від Razor Pages до MVC: концептуальний перехід","/csharp/aspnet/mvc/from-razor-pages","01.csharp/11.aspnet/11.mvc/02.from-razor-pages",{"title":1226,"path":1227,"stem":1228},"Controllers та Actions: серце MVC","/csharp/aspnet/mvc/controllers-actions","01.csharp/11.aspnet/11.mvc/03.controllers-actions",{"title":1230,"path":1231,"stem":1232},"Маршрутизація в MVC: Convention vs Attribute Routing","/csharp/aspnet/mvc/routing-mvc","01.csharp/11.aspnet/11.mvc/04.routing-mvc",{"title":1234,"path":1235,"stem":1236},"Model Binding: від HTTP до C#","/csharp/aspnet/mvc/model-binding","01.csharp/11.aspnet/11.mvc/05.model-binding",{"title":1238,"path":1239,"stem":1240},"Views, ViewData, ViewBag, TempData і ViewModel","/csharp/aspnet/mvc/views-viewdata-tempdata","01.csharp/11.aspnet/11.mvc/06.views-viewdata-tempdata",{"title":1242,"path":1243,"stem":1244},"Filters: аспектно-орієнтоване програмування в MVC","/csharp/aspnet/mvc/filters","01.csharp/11.aspnet/11.mvc/07.filters",{"title":1246,"path":1247,"stem":1248},"Areas: структурування великих застосунків","/csharp/aspnet/mvc/areas","01.csharp/11.aspnet/11.mvc/08.areas",{"title":1250,"path":1251,"stem":1252},"View Components: повторювані незалежні блоки UI","/csharp/aspnet/mvc/view-components","01.csharp/11.aspnet/11.mvc/09.view-components",{"title":1254,"path":1255,"stem":1256},"Display та Editor Templates","/csharp/aspnet/mvc/display-editor-templates","01.csharp/11.aspnet/11.mvc/10.display-editor-templates",{"title":1258,"path":1259,"stem":1260},"Валідація: IValidatableObject та FluentValidation","/csharp/aspnet/mvc/validation-advanced","01.csharp/11.aspnet/11.mvc/11.validation-advanced",{"title":1262,"path":1263,"stem":1264},"HTMX: інтерактивність через HTML-атрибути","/csharp/aspnet/mvc/htmx","01.csharp/11.aspnet/11.mvc/12.htmx",{"title":1266,"path":1267,"stem":1268},"HTMX у ASP.NET Core MVC: серверна інтеграція","/csharp/aspnet/mvc/ajax-htmx-mvc","01.csharp/11.aspnet/11.mvc/13.ajax-htmx-mvc",{"title":1270,"path":1271,"stem":1272},"Практичний проєкт: Каталог товарів з HTMX","/csharp/aspnet/mvc/htmx-project","01.csharp/11.aspnet/11.mvc/14.htmx-project",{"title":1274,"path":1275,"stem":1276},"Завантаження та обробка файлів","/csharp/aspnet/mvc/file-upload","01.csharp/11.aspnet/11.mvc/15.file-upload",{"title":1278,"path":1279,"stem":1280},"Глобалізація та Локалізація MVC","/csharp/aspnet/mvc/globalization-localization","01.csharp/11.aspnet/11.mvc/16.globalization-localization",{"title":1282,"path":1283,"stem":1284},"Підсумковий проєкт: Блог-платформа","/csharp/aspnet/mvc/mvc-project","01.csharp/11.aspnet/11.mvc/17.mvc-project",{"title":1286,"path":1287,"stem":1288},"План курсу: ASP.NET Core MVC","/csharp/aspnet/mvc/plan","01.csharp/11.aspnet/11.mvc/plan",{"title":1290,"path":1291,"stem":1292,"children":1293,"page":59},"Web Api","/csharp/aspnet/web-api","01.csharp/11.aspnet/12.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","/csharp/aspnet/web-api/from-minimal-api-to-controllers","01.csharp/11.aspnet/12.web-api/01.from-minimal-api-to-controllers",{"title":1299,"path":1300,"stem":1301},"ControllerBase, ActionResult\u003CT> та Response Types","/csharp/aspnet/web-api/controller-base-actionresult","01.csharp/11.aspnet/12.web-api/02.controller-base-actionresult",{"title":1303,"path":1304,"stem":1305},"Content Negotiation - JSON, XML та власні форматери","/csharp/aspnet/web-api/content-negotiation","01.csharp/11.aspnet/12.web-api/03.content-negotiation",{"title":1307,"path":1308,"stem":1309},"Версіонування API","/csharp/aspnet/web-api/api-versioning","01.csharp/11.aspnet/12.web-api/04.api-versioning",{"title":1311,"path":1312,"stem":1313},"ProblemDetails та структурована обробка помилок","/csharp/aspnet/web-api/problemdetails-error-handling","01.csharp/11.aspnet/12.web-api/05.problemdetails-error-handling",{"title":1315,"path":1316,"stem":1317},"Фільтри у Web API контексті","/csharp/aspnet/web-api/filters-for-api","01.csharp/11.aspnet/12.web-api/06.filters-for-api",{"title":1319,"path":1320,"stem":1321},"Пагінація, фільтрація та сортування","/csharp/aspnet/web-api/pagination-filtering-sorting","01.csharp/11.aspnet/12.web-api/07.pagination-filtering-sorting",{"title":1323,"path":1324,"stem":1325},"HATEOAS та Resource Expansion","/csharp/aspnet/web-api/hateoas-resource-expansion","01.csharp/11.aspnet/12.web-api/08.hateoas-resource-expansion",{"title":1327,"path":1328,"stem":1329},"Гібридна архітектура - Minimal API + Controllers","/csharp/aspnet/web-api/minimal-api-vs-controllers-hybrid","01.csharp/11.aspnet/12.web-api/09.minimal-api-vs-controllers-hybrid",{"title":1331,"path":1332,"stem":1333},"Документація API - Swashbuckle, NSwag та генерація клієнтів","/csharp/aspnet/web-api/api-documentation-generation","01.csharp/11.aspnet/12.web-api/10.api-documentation-generation",{"title":1335,"path":1336,"stem":1337},"Health Checks та моніторинг API","/csharp/aspnet/web-api/health-checks-monitoring","01.csharp/11.aspnet/12.web-api/11.health-checks-monitoring",{"title":1339,"path":1340,"stem":1341},"Підсумковий проєкт - Production-Ready REST API","/csharp/aspnet/web-api/web-api-project","01.csharp/11.aspnet/12.web-api/12.web-api-project",{"title":1343,"path":1344,"stem":1345},"План курсу: ASP.NET Core Web API (Controllers)","/csharp/aspnet/web-api/plan","01.csharp/11.aspnet/12.web-api/plan",{"title":1347,"icon":1348,"path":1349,"stem":1350,"children":1351,"page":59},"Desktop UI","i-lucide-app-window","/csharp/desktop-ui","01.csharp/12.desktop-ui",[1352,1356,1360,1364,1368,1372,1376,1380,1384,1388,1392,1396,1400,1404,1408,1412,1416,1420,1424,1428,1432,1436,1440,1444,1448,1452,1456,1460,1464,1468,1472,1476,1480,1484,1488,1492,1496,1500,1504,1508,1512,1516,1520,1524,1528,1532,1536,1540,1544,1548,1552,1556,1560,1564,1568,1572,1576,1580,1584,1588,1592,1596,1600,1604,1608,1612,1616,1620,1624,1628,1632],{"title":1353,"path":1354,"stem":1355},"Що таке десктопна розробка?","/csharp/desktop-ui/what-is-desktop-dev","01.csharp/12.desktop-ui/01.what-is-desktop-dev",{"title":1357,"path":1358,"stem":1359},"Архітектура WPF — як влаштований графічний інтерфейс","/csharp/desktop-ui/wpf-architecture","01.csharp/12.desktop-ui/02.wpf-architecture",{"title":1361,"path":1362,"stem":1363},"Перший WPF-проєкт — від нуля до вікна","/csharp/desktop-ui/first-wpf-app","01.csharp/12.desktop-ui/03.first-wpf-app",{"title":1365,"path":1366,"stem":1367},"Перший Avalonia-проєкт: WPF для всіх платформ","/csharp/desktop-ui/03a.first-avalonia-app","01.csharp/12.desktop-ui/03a.first-avalonia-app",{"title":1369,"path":1370,"stem":1371},"XAML: декларативний інтерфейс","/csharp/desktop-ui/xaml-basics","01.csharp/12.desktop-ui/04.xaml-basics",{"title":1373,"path":1374,"stem":1375},"Fluent UI у WPF — сучасний дизайн Windows 11","/csharp/desktop-ui/04a.wpf-fluent-ui","01.csharp/12.desktop-ui/04a.wpf-fluent-ui",{"title":1377,"path":1378,"stem":1379},"WPF UI — сучасна бібліотека Fluent контролів","/csharp/desktop-ui/04b.wpf-ui-library","01.csharp/12.desktop-ui/04b.wpf-ui-library",{"title":1381,"path":1382,"stem":1383},"HandyControl — велика бібліотека UI контролів для WPF","/csharp/desktop-ui/04c.handycontrol-library","01.csharp/12.desktop-ui/04c.handycontrol-library",{"title":1385,"path":1386,"stem":1387},"Простори імен та ресурси XAML","/csharp/desktop-ui/xaml-namespaces-resources","01.csharp/12.desktop-ui/05.xaml-namespaces-resources",{"title":1389,"path":1390,"stem":1391},"XAML в Avalonia: ключові відмінності від WPF","/csharp/desktop-ui/05a.avalonia-xaml-differences","01.csharp/12.desktop-ui/05a.avalonia-xaml-differences",{"title":1393,"path":1394,"stem":1395},"Розширення розмітки XAML (Markup Extensions)","/csharp/desktop-ui/xaml-markup-extensions","01.csharp/12.desktop-ui/06.xaml-markup-extensions",{"title":1397,"path":1398,"stem":1399},"Панелі Layout: StackPanel, WrapPanel, DockPanel","/csharp/desktop-ui/layout-panels-part1","01.csharp/12.desktop-ui/07.layout-panels-part1",{"title":1401,"path":1402,"stem":1403},"Grid, Canvas, UniformGrid","/csharp/desktop-ui/layout-panels-part2","01.csharp/12.desktop-ui/07.layout-panels-part2",{"title":1405,"path":1406,"stem":1407},"Просунуті техніки Layout","/csharp/desktop-ui/layout-advanced","01.csharp/12.desktop-ui/08.layout-advanced",{"title":1409,"path":1410,"stem":1411},"Адаптивний Layout та найкращі практики","/csharp/desktop-ui/layout-responsive","01.csharp/12.desktop-ui/09.layout-responsive",{"title":1413,"path":1414,"stem":1415},"Layout в Avalonia: відмінності та нові можливості","/csharp/desktop-ui/09a.layout-avalonia","01.csharp/12.desktop-ui/09a.layout-avalonia",{"title":1417,"path":1418,"stem":1419},"Button, Image, ProgressBar та інші базові контроли","/csharp/desktop-ui/basic-controls","01.csharp/12.desktop-ui/10.basic-controls",{"title":1421,"path":1422,"stem":1423},"Контроли в Avalonia: відмінності від WPF","/csharp/desktop-ui/10a.controls-avalonia","01.csharp/12.desktop-ui/10a.controls-avalonia",{"title":1425,"path":1426,"stem":1427},"Текстові контроли — TextBlock, TextBox, RichTextBox","/csharp/desktop-ui/text-controls","01.csharp/12.desktop-ui/11.text-controls",{"title":1429,"path":1430,"stem":1431},"Контроли вибору — CheckBox, RadioButton, ComboBox, ListBox, DatePicker","/csharp/desktop-ui/selection-controls","01.csharp/12.desktop-ui/12.selection-controls",{"title":1433,"path":1434,"stem":1435},"Content Model — GroupBox, Expander, TabControl, StatusBar","/csharp/desktop-ui/content-controls","01.csharp/12.desktop-ui/13.content-controls",{"title":1437,"path":1438,"stem":1439},"UI/UX принципи десктопних застосунків","/csharp/desktop-ui/13a.ui-ux-principles","01.csharp/12.desktop-ui/13a.ui-ux-principles",{"title":1441,"path":1442,"stem":1443},"Dependency Properties — Концепція та Value Resolution","/csharp/desktop-ui/dependency-properties-part1","01.csharp/12.desktop-ui/14.dependency-properties-part1",{"title":1445,"path":1446,"stem":1447},"Avalonia Property System — StyledProperty та DirectProperty","/csharp/desktop-ui/14a.avalonia-property-system","01.csharp/12.desktop-ui/14a.avalonia-property-system",{"title":1449,"path":1450,"stem":1451},"Attached Properties — Властивості без меж","/csharp/desktop-ui/attached-properties","01.csharp/12.desktop-ui/15.attached-properties",{"title":1453,"path":1454,"stem":1455},"Routed Events — Маршрутизація подій у WPF","/csharp/desktop-ui/routed-events","01.csharp/12.desktop-ui/16.routed-events",{"title":1457,"path":1458,"stem":1459},"Data Binding — Від Code-Behind до Декларативності","/csharp/desktop-ui/data-binding-basics-part1","01.csharp/12.desktop-ui/17.data-binding-basics-part1",{"title":1461,"path":1462,"stem":1463},"INotifyPropertyChanged — Живе оновлення UI","/csharp/desktop-ui/data-binding-basics-part2","01.csharp/12.desktop-ui/17.data-binding-basics-part2",{"title":1465,"path":1466,"stem":1467},"Compiled Bindings в Avalonia — Безпека на етапі компіляції","/csharp/desktop-ui/17a.avalonia-compiled-bindings","01.csharp/12.desktop-ui/17a.avalonia-compiled-bindings",{"title":1469,"path":1470,"stem":1471},"Просунутий Data Binding — ElementName, RelativeSource, MultiBinding","/csharp/desktop-ui/data-binding-advanced","01.csharp/12.desktop-ui/18.data-binding-advanced",{"title":1473,"path":1474,"stem":1475},"Value Converters — Перетворення типів даних у Data Binding","/csharp/desktop-ui/value-converters","01.csharp/12.desktop-ui/19.value-converters",{"title":1477,"path":1478,"stem":1479},"Data Templates — Візуалізація об'єктів у WPF","/csharp/desktop-ui/data-templates","01.csharp/12.desktop-ui/20.data-templates",{"title":1481,"path":1482,"stem":1483},"Collections Binding Part 1 — ObservableCollection та ItemsControl","/csharp/desktop-ui/collections-binding-part1","01.csharp/12.desktop-ui/21.collections-binding-part1",{"title":1485,"path":1486,"stem":1487},"Collections Binding Part 2 — ICollectionView, Filtering, Sorting та Virtualization","/csharp/desktop-ui/collections-binding-part2","01.csharp/12.desktop-ui/21.collections-binding-part2",{"title":1489,"path":1490,"stem":1491},"MVVM Pattern — Від Spaghetti Code до архітектури","/csharp/desktop-ui/mvvm-pattern","01.csharp/12.desktop-ui/22.mvvm-pattern",{"title":1493,"path":1494,"stem":1495},"ViewModel Implementation — Від BaseViewModel до валідації","/csharp/desktop-ui/viewmodel-implementation","01.csharp/12.desktop-ui/23.viewmodel-implementation",{"title":1497,"path":1498,"stem":1499},"Commands — Від event handlers до декларативних команд","/csharp/desktop-ui/commands","01.csharp/12.desktop-ui/24.commands",{"title":1501,"path":1502,"stem":1503},"MVVM Toolkit — MVVM без boilerplate через Source Generators","/csharp/desktop-ui/mvvm-toolkit","01.csharp/12.desktop-ui/25.mvvm-toolkit",{"title":1505,"path":1506,"stem":1507},"Messenger Pattern — Комунікація між ViewModel без прямих посилань","/csharp/desktop-ui/messenger-pattern","01.csharp/12.desktop-ui/26.messenger-pattern",{"title":1509,"path":1510,"stem":1511},"Стилі WPF — CSS для десктопу","/csharp/desktop-ui/styles-basics","01.csharp/12.desktop-ui/27.styles-basics",{"title":1513,"path":1514,"stem":1515},"CSS-like стилі Avalonia","/csharp/desktop-ui/27a.avalonia-css-styling","01.csharp/12.desktop-ui/27a.avalonia-css-styling",{"title":1517,"path":1518,"stem":1519},"Control Templates — Частина 1. Концепція та TemplateBinding","/csharp/desktop-ui/control-templates-part1","01.csharp/12.desktop-ui/28.control-templates-part1",{"title":1521,"path":1522,"stem":1523},"Control Templates — Частина 2. Named Parts та ContentPresenter","/csharp/desktop-ui/control-templates-part2","01.csharp/12.desktop-ui/28.control-templates-part2",{"title":1525,"path":1526,"stem":1527},"Control Themes в Avalonia — нова ера стилізації","/csharp/desktop-ui/28a.avalonia-control-themes","01.csharp/12.desktop-ui/28a.avalonia-control-themes",{"title":1529,"path":1530,"stem":1531},"Triggers та Visual State Manager у WPF","/csharp/desktop-ui/triggers-visual-states","01.csharp/12.desktop-ui/29.triggers-visual-states",{"title":1533,"path":1534,"stem":1535},"Pseudo-classes в Avalonia — замість WPF Triggers","/csharp/desktop-ui/29a.avalonia-pseudo-classes","01.csharp/12.desktop-ui/29a.avalonia-pseudo-classes",{"title":1537,"path":1538,"stem":1539},"Теми та ресурсні словники у WPF","/csharp/desktop-ui/resources-themes","01.csharp/12.desktop-ui/30.resources-themes",{"title":1541,"path":1542,"stem":1543},"Avalonia Themes — Fluent Design та система тематизації","/csharp/desktop-ui/30a.avalonia-themes-fluent","01.csharp/12.desktop-ui/30a.avalonia-themes-fluent",{"title":1545,"path":1546,"stem":1547},"Контроли колекцій — глибоке занурення","/csharp/desktop-ui/collection-controls","01.csharp/12.desktop-ui/31.collection-controls",{"title":1549,"path":1550,"stem":1551},"DataGrid — колонки та базове відображення","/csharp/desktop-ui/datagrid-part1","01.csharp/12.desktop-ui/32.datagrid-part1",{"title":1553,"path":1554,"stem":1555},"DataGrid — сортування, фільтрація, редагування","/csharp/desktop-ui/datagrid-part2","01.csharp/12.desktop-ui/32.datagrid-part2",{"title":1557,"path":1558,"stem":1559},"TreeView та GridView","/csharp/desktop-ui/treeview-listview","01.csharp/12.desktop-ui/33.treeview-listview",{"title":1561,"path":1562,"stem":1563},"Меню, Toolbar, ContextMenu, StatusBar","/csharp/desktop-ui/menus-toolbars","01.csharp/12.desktop-ui/34.menus-toolbars",{"title":1565,"path":1566,"stem":1567},"Навігація та керування вікнами. Частина 1: вікна та сторінки","/csharp/desktop-ui/navigation-windows-part1","01.csharp/12.desktop-ui/35.navigation-windows-part1",{"title":1569,"path":1570,"stem":1571},"Навігація та керування вікнами. Частина 2: MVVM-навігація","/csharp/desktop-ui/navigation-windows-part2","01.csharp/12.desktop-ui/35.navigation-windows-part2",{"title":1573,"path":1574,"stem":1575},"Avalonia — Навігація та діалоги","/csharp/desktop-ui/35a.avalonia-navigation-dialogs","01.csharp/12.desktop-ui/35a.avalonia-navigation-dialogs",{"title":1577,"path":1578,"stem":1579},"Діалоги та File Pickers у WPF","/csharp/desktop-ui/dialogs-file-pickers","01.csharp/12.desktop-ui/36.dialogs-file-pickers",{"title":1581,"path":1582,"stem":1583},"UserControl: компонентний підхід у WPF","/csharp/desktop-ui/user-controls","01.csharp/12.desktop-ui/37.user-controls",{"title":1585,"path":1586,"stem":1587},"Custom Controls: Lookless Controls у WPF","/csharp/desktop-ui/custom-controls","01.csharp/12.desktop-ui/38.custom-controls",{"title":1589,"path":1590,"stem":1591},"Avalonia TemplatedControl — Lookless Controls","/csharp/desktop-ui/38a.avalonia-templated-controls","01.csharp/12.desktop-ui/38a.avalonia-templated-controls",{"title":1593,"path":1594,"stem":1595},"Анімації у WPF: Storyboard та Easing Functions","/csharp/desktop-ui/animations-transitions","01.csharp/12.desktop-ui/39.animations-transitions",{"title":1597,"path":1598,"stem":1599},"Анімації в Avalonia","/csharp/desktop-ui/39a.avalonia-animations","01.csharp/12.desktop-ui/39a.avalonia-animations",{"title":1601,"path":1602,"stem":1603},"2D Графіка та Мультимедіа у WPF","/csharp/desktop-ui/media-graphics","01.csharp/12.desktop-ui/40.media-graphics",{"title":1605,"path":1606,"stem":1607},"Dependency Injection у WPF та Avalonia","/csharp/desktop-ui/di-integration","01.csharp/12.desktop-ui/41.di-integration",{"title":1609,"path":1610,"stem":1611},"SQLite та EF Core у десктопних додатках","/csharp/desktop-ui/data-persistence-part1","01.csharp/12.desktop-ui/42.data-persistence-part1",{"title":1613,"path":1614,"stem":1615},"Repository Pattern та Unit of Work","/csharp/desktop-ui/data-persistence-part2","01.csharp/12.desktop-ui/43.data-persistence-part2",{"title":1617,"path":1618,"stem":1619},"Тестування ViewModels","/csharp/desktop-ui/viewmodel-testing","01.csharp/12.desktop-ui/44.viewmodel-testing",{"title":1621,"path":1622,"stem":1623},"Avalonia Headless Testing — тестування UI без вікон","/csharp/desktop-ui/44a.avalonia-headless-testing","01.csharp/12.desktop-ui/44a.avalonia-headless-testing",{"title":1625,"path":1626,"stem":1627},"Кросплатформна розробка з Avalonia","/csharp/desktop-ui/avalonia-cross-platform","01.csharp/12.desktop-ui/45.avalonia-cross-platform",{"title":1629,"path":1630,"stem":1631},"Пакування та розгортання Avalonia додатків","/csharp/desktop-ui/avalonia-packaging-deployment","01.csharp/12.desktop-ui/46.avalonia-packaging-deployment",{"title":1633,"path":1634,"stem":1635},"Розгортання WPF застосунків","/csharp/desktop-ui/wpf-packaging-deployment","01.csharp/12.desktop-ui/47.wpf-packaging-deployment",{"title":1637,"path":1638,"stem":1639},"C# & .NET: The Ultimate Roadmap","/csharp/roadmap","01.csharp/roadmap",{"title":1641,"icon":1642,"path":1643,"stem":1644,"children":1645,"page":59},"C++","i-devicon-cplusplus","/cpp","02.cpp",[1646,1650,1654,1658,1662,1666,1670,1674,1678,1681,1685,1689,1693,1697,1701,1705,1709,1713,1717,1721,1725,1729,1733,1737,1741,1745,1749,1753,1757,1761],{"title":1647,"path":1648,"stem":1649},"Вступ у програмування та алгоритми","/cpp/intro-algorithms","02.cpp/01.intro-algorithms",{"title":1651,"path":1652,"stem":1653},"Code Style: угоди про оформлення коду","/cpp/code-style","02.cpp/02.code-style",{"title":1655,"path":1656,"stem":1657},"Середовище розробки та перший проєкт","/cpp/ide-setup","02.cpp/03.ide-setup",{"title":1659,"path":1660,"stem":1661},"Вивід даних на екран","/cpp/data-output","02.cpp/04.data-output",{"title":1663,"path":1664,"stem":1665},"Типи даних, змінні та константи","/cpp/data-types-variables","02.cpp/05.data-types-variables",{"title":1667,"path":1668,"stem":1669},"Ввід даних з клавіатури","/cpp/data-input","02.cpp/06.data-input",{"title":1671,"path":1672,"stem":1673},"Оператори, перетворення типів та логічні операції","/cpp/operators-type-conversion","02.cpp/07.operators-type-conversion",{"title":1675,"path":1676,"stem":1677},"Цикли","/cpp/loops","02.cpp/08.loops",{"title":32,"path":1679,"stem":1680},"/cpp/arrays","02.cpp/09.arrays",{"title":1682,"path":1683,"stem":1684},"Алгоритми сортування та аналіз складності","/cpp/sorting","02.cpp/10.sorting",{"title":1686,"path":1687,"stem":1688},"Алгоритми пошуку","/cpp/searching","02.cpp/11.searching",{"title":1690,"path":1691,"stem":1692},"Функції: основи","/cpp/functions-basics","02.cpp/12.functions-basics",{"title":1694,"path":1695,"stem":1696},"Функції: прототипи, область видимості та додаткові можливості","/cpp/functions-scope","02.cpp/13.functions-scope",{"title":1698,"path":1699,"stem":1700},"Функції: перевантаження та шаблони","/cpp/functions-overloading-templates","02.cpp/14.functions-overloading-templates",{"title":1702,"path":1703,"stem":1704},"Вказівники: основи","/cpp/pointers-basics","02.cpp/15.pointers-basics",{"title":1706,"path":1707,"stem":1708},"Посилання (References)","/cpp/references","02.cpp/16.references",{"title":1710,"path":1711,"stem":1712},"Вказівники, const і масиви","/cpp/pointers-const-arrays","02.cpp/17.pointers-const-arrays",{"title":1714,"path":1715,"stem":1716},"Адресна арифметика","/cpp/pointer-arithmetic","02.cpp/18.pointer-arithmetic",{"title":1718,"path":1719,"stem":1720},"Динамічна пам'ять","/cpp/dynamic-memory","02.cpp/19.dynamic-memory",{"title":1722,"path":1723,"stem":1724},"Вказівники типу void","/cpp/void-pointers","02.cpp/20.void-pointers",{"title":1726,"path":1727,"stem":1728},"Вказівники на вказівники","/cpp/pointers-to-pointers","02.cpp/21.pointers-to-pointers",{"title":1730,"path":1731,"stem":1732},"Оператор доступу до членів через вказівник (->)","/cpp/member-access-operator","02.cpp/22.member-access-operator",{"title":1734,"path":1735,"stem":1736},"Цикл for-each (Range-based for)","/cpp/foreach-loop","02.cpp/23.foreach-loop",{"title":1738,"path":1739,"stem":1740},"Вказівники на функції","/cpp/function-pointers","02.cpp/24.function-pointers",{"title":1742,"path":1743,"stem":1744},"Лямбда-вирази","/cpp/lambdas","02.cpp/25.lambdas",{"title":1746,"path":1747,"stem":1748},"Лямбда-захоплення","/cpp/lambda-captures","02.cpp/26.lambda-captures",{"title":1750,"path":1751,"stem":1752},"Еліпсис","/cpp/ellipsis","02.cpp/27.ellipsis",{"title":1754,"path":1755,"stem":1756},"Аргументи командного рядка","/cpp/command-line-arguments","02.cpp/28.command-line-arguments",{"title":1758,"path":1759,"stem":1760},"Перерахування (enum)","/cpp/enum","02.cpp/29.enum",{"title":1762,"path":1763,"stem":1764},"План навчання: Курс C++ — Продовження (Статті 29–60+)","/cpp/curriculum-plan","02.cpp/curriculum-plan",{"title":1766,"icon":1767,"path":1768,"stem":1769,"children":1770,"page":59},"JavaScript","i-devicon-javascript","/javascript","03.javascript",[1771,1797,1851,1873,2177,2215],{"title":1772,"icon":1773,"path":1774,"stem":1775,"children":1776,"page":59},"Events","i-lucide-mouse-pointer-click","/javascript/events","03.javascript/01.events",[1777,1781,1785,1789,1793],{"title":1778,"path":1779,"stem":1780},"Вступ до подій браузера","/javascript/events/intro","03.javascript/01.events/01.intro",{"title":1782,"path":1783,"stem":1784},"Бульбашковий механізм (Bubbling) та занурення (Capturing)","/javascript/events/bubbling-capturing","03.javascript/01.events/02.bubbling-capturing",{"title":1786,"path":1787,"stem":1788},"Делегування подій (Event Delegation)","/javascript/events/delegate-events","03.javascript/01.events/03.delegate-events",{"title":1790,"path":1791,"stem":1792},"Типові дії браузера та preventDefault()","/javascript/events/prevent-default","03.javascript/01.events/04.prevent-default",{"title":1794,"path":1795,"stem":1796},"Запуск користувацьких подій (Custom Events)","/javascript/events/custom-events","03.javascript/01.events/05.custom-events",{"title":1798,"icon":1799,"path":1800,"stem":1801,"children":1802,"page":59},"Network","i-lucide-globe","/javascript/network","03.javascript/02.network",[1803,1807,1811,1815,1819,1823,1827,1831,1835,1839,1843,1847],{"title":1804,"path":1805,"stem":1806},"Fetch API - Сучасний підхід до HTTP-запитів","/javascript/network/01-fetch-api","03.javascript/02.network/01-fetch-api",{"title":1808,"path":1809,"stem":1810},"FormData - Робота з формами та файлами","/javascript/network/02-formdata","03.javascript/02.network/02-formdata",{"title":1812,"path":1813,"stem":1814},"Відстеження прогресу завантаження","/javascript/network/03-download-progress","03.javascript/02.network/03-download-progress",{"title":1816,"path":1817,"stem":1818},"Переривання fetch-запитів","/javascript/network/04-abort-requests","03.javascript/02.network/04-abort-requests",{"title":1820,"path":1821,"stem":1822},"CORS - Запити між різними джерелами","/javascript/network/05-cors","03.javascript/02.network/05-cors",{"title":1824,"path":1825,"stem":1826},"Fetch API - Повний довідник опцій","/javascript/network/06-fetch-options","03.javascript/02.network/06-fetch-options",{"title":1828,"path":1829,"stem":1830},"URL Objects - Робота з посиланнями","/javascript/network/07-url-objects","03.javascript/02.network/07-url-objects",{"title":1832,"path":1833,"stem":1834},"XMLHttpRequest - AJAX та низькорівневі запити","/javascript/network/08-xmlhttprequest","03.javascript/02.network/08-xmlhttprequest",{"title":1836,"path":1837,"stem":1838},"Відновлюване завантаження файлів","/javascript/network/09-resumable-upload","03.javascript/02.network/09-resumable-upload",{"title":1840,"path":1841,"stem":1842},"Cookies, document.cookie та світ після \"Cookiepocalypse\"","/javascript/network/10-cookies","03.javascript/02.network/10-cookies",{"title":1844,"path":1845,"stem":1846},"js-cookie: Керування Cookies без Болю","/javascript/network/11-js-cookie","03.javascript/02.network/11-js-cookie",{"title":1848,"path":1849,"stem":1850},"Axios: Потужний HTTP-клієнт для JavaScript","/javascript/network/12-axios","03.javascript/02.network/12-axios",{"title":1852,"icon":1853,"path":1854,"stem":1855,"children":1856,"page":59},"Bom","i-lucide-monitor","/javascript/bom","03.javascript/03.bom",[1857,1861,1865,1869],{"title":1858,"path":1859,"stem":1860},"LocalStorage, SessionStorage та patterns збереження даних","/javascript/bom/01-localstorage","03.javascript/03.bom/01-localstorage",{"title":1862,"path":1863,"stem":1864},"Location Object - Керування адресою сторінки","/javascript/bom/02-location-object","03.javascript/03.bom/02-location-object",{"title":1866,"path":1867,"stem":1868},"History API - Керування історією браузера","/javascript/bom/03-history-api","03.javascript/03.bom/03-history-api",{"title":1870,"path":1871,"stem":1872},"Navigator Object - Ідентифікація та Можливості Пристрою","/javascript/bom/04-navigator-object","03.javascript/03.bom/04-navigator-object",{"title":1874,"icon":1875,"path":1876,"stem":1877,"children":1878},"React","i-devicon-react","/javascript/react","03.javascript/04.react/index",[1879,1880,1884,1888,1892,1896,1959,1994,2146],{"title":1874,"path":1876,"stem":1877},{"title":1881,"path":1882,"stem":1883},"Робота з Формами в React","/javascript/react/react-forms","03.javascript/04.react/01.react-forms",{"title":1885,"path":1886,"stem":1887},"React Hook Form: Професійна Робота з Формами","/javascript/react/react-hook-form","03.javascript/04.react/02.react-hook-form",{"title":1889,"path":1890,"stem":1891},"React Hook Form: Глибоке Розуміння Архітектури та Оптимізації","/javascript/react/react-hook-form-new","03.javascript/04.react/02.react-hook-form-new",{"title":1893,"path":1894,"stem":1895},"Axios та React: Професійна Архітектура Запитів","/javascript/react/data-fetching-axios","03.javascript/04.react/03.data-fetching-axios",{"title":1897,"icon":132,"path":1898,"stem":1899,"children":1900},"Tanstack Query","/javascript/react/tanstack-query","03.javascript/04.react/04.tanstack-query/index",[1901,1903,1907,1911,1915,1919,1923,1927,1931,1935,1939,1943,1947,1951,1955],{"title":1902,"path":1898,"stem":1899},"TanStack Query: Майстерність Керування Станом Сервера",{"title":1904,"path":1905,"stem":1906},"Парадигма Server State: Чому useEffect недостатньо","/javascript/react/tanstack-query/server-state-paradigm","03.javascript/04.react/04.tanstack-query/01.server-state-paradigm",{"title":1908,"path":1909,"stem":1910},"Встановлення та Налаштування: Фундамент","/javascript/react/tanstack-query/installation-and-devtools","03.javascript/04.react/04.tanstack-query/02.installation-and-devtools",{"title":1912,"path":1913,"stem":1914},"Основи Запитів та Магія Ключів","/javascript/react/tanstack-query/query-basics-and-keys","03.javascript/04.react/04.tanstack-query/03.query-basics-and-keys",{"title":1916,"path":1917,"stem":1918},"Синхронізація Даних: Життєвий Цикл Запиту","/javascript/react/tanstack-query/data-synchronization","03.javascript/04.react/04.tanstack-query/04.data-synchronization",{"title":1920,"path":1921,"stem":1922},"Мутації та Інвалідація: Зміна Даних","/javascript/react/tanstack-query/mutations-and-invalidation","03.javascript/04.react/04.tanstack-query/05.mutations-and-invalidation",{"title":1924,"path":1925,"stem":1926},"Оптимістичні Оновлення: Швидше за Світло","/javascript/react/tanstack-query/optimistic-updates","03.javascript/04.react/04.tanstack-query/06.optimistic-updates",{"title":1928,"path":1929,"stem":1930},"Пагінація та Infinite Scroll","/javascript/react/tanstack-query/pagination-and-load-more","03.javascript/04.react/04.tanstack-query/07.pagination-and-load-more",{"title":1932,"path":1933,"stem":1934},"Просунуті Патерни та Оптимізація","/javascript/react/tanstack-query/advanced-patterns","03.javascript/04.react/04.tanstack-query/08.advanced-patterns",{"title":1936,"path":1937,"stem":1938},"Архітектура та Best Practices","/javascript/react/tanstack-query/architecture-and-best-practices","03.javascript/04.react/04.tanstack-query/09.architecture-and-best-practices",{"title":1940,"path":1941,"stem":1942},"Server-Side Rendering (SSR) та Гідратація","/javascript/react/tanstack-query/server-side-rendering","03.javascript/04.react/04.tanstack-query/10.server-side-rendering",{"title":1944,"path":1945,"stem":1946},"Стратегії Тестування","/javascript/react/tanstack-query/testing-strategies","03.javascript/04.react/04.tanstack-query/11.testing-strategies",{"title":1948,"path":1949,"stem":1950},"Аутентифікація та Обробка Помилок","/javascript/react/tanstack-query/authentication-and-errors","03.javascript/04.react/04.tanstack-query/12.authentication-and-errors",{"title":1952,"path":1953,"stem":1954},"React Suspense та Майбутнє","/javascript/react/tanstack-query/react-suspense","03.javascript/04.react/04.tanstack-query/13.react-suspense",{"title":1956,"path":1957,"stem":1958},"Глибоке Занурення в Продуктивність","/javascript/react/tanstack-query/performance-deep-dive","03.javascript/04.react/04.tanstack-query/14.performance-deep-dive",{"title":1960,"icon":1875,"path":1961,"stem":1962,"children":1963},"React Router","/javascript/react/react-router","03.javascript/04.react/05.react-router/index",[1964,1966,1970,1974,1978,1982,1986,1990],{"title":1965,"path":1961,"stem":1962},"React Router: Навігаційна система сучасного вебу",{"title":1967,"path":1968,"stem":1969},"Налаштування та Базовий Роутинг","/javascript/react/react-router/setup-and-basic-routing","03.javascript/04.react/05.react-router/01.setup-and-basic-routing",{"title":1971,"path":1972,"stem":1973},"Динамічна Навігація","/javascript/react/react-router/navigation-and-links","03.javascript/04.react/05.react-router/02.navigation-and-links",{"title":1975,"path":1976,"stem":1977},"Вкладені Маршрути та Макети","/javascript/react/react-router/nested-routes-and-layouts","03.javascript/04.react/05.react-router/03.nested-routes-and-layouts",{"title":1979,"path":1980,"stem":1981},"Динамічні Маршрути та Параметри","/javascript/react/react-router/dynamic-routing","03.javascript/04.react/05.react-router/04.dynamic-routing",{"title":1983,"path":1984,"stem":1985},"Data APIs: Loaders та Actions","/javascript/react/react-router/data-loading","03.javascript/04.react/05.react-router/05.data-loading",{"title":1987,"path":1988,"stem":1989},"Просунуті Патерни","/javascript/react/react-router/advanced-patterns","03.javascript/04.react/05.react-router/06.advanced-patterns",{"title":1991,"path":1992,"stem":1993},"Legacy Routing: Компонентний підхід","/javascript/react/react-router/legacy-routing","03.javascript/04.react/05.react-router/07.legacy-routing",{"title":1995,"icon":132,"path":1996,"stem":1997,"children":1998},"Redux","/javascript/react/redux","03.javascript/04.react/06.redux/index",[1999,2001,2017,2046,2055,2076,2092,2121],{"title":2000,"path":1996,"stem":1997},"Redux: Еволюція управління станом",{"title":14,"icon":15,"path":2002,"stem":2003,"children":2004,"page":59},"/javascript/react/redux/fundamentals","03.javascript/04.react/06.redux/01.fundamentals",[2005,2009,2013],{"title":2006,"path":2007,"stem":2008},"Вступ до State Management","/javascript/react/redux/fundamentals/intro-state-management","03.javascript/04.react/06.redux/01.fundamentals/01.intro-state-management",{"title":2010,"path":2011,"stem":2012},"Філософія Redux та Три Принципи","/javascript/react/redux/fundamentals/redux-philosophy","03.javascript/04.react/06.redux/01.fundamentals/02.redux-philosophy",{"title":2014,"path":2015,"stem":2016},"Чисті функції та Іммутабельність","/javascript/react/redux/fundamentals/pure-functions-immutability","03.javascript/04.react/06.redux/01.fundamentals/03.pure-functions-immutability",{"title":2018,"icon":132,"path":2019,"stem":2020,"children":2021,"page":59},"Classic Redux","/javascript/react/redux/classic-redux","03.javascript/04.react/06.redux/02.classic-redux",[2022,2026,2030,2034,2038,2042],{"title":2023,"path":2024,"stem":2025},"Створення Store (Classic Redux)","/javascript/react/redux/classic-redux/store-setup","03.javascript/04.react/06.redux/02.classic-redux/01.store-setup",{"title":2027,"path":2028,"stem":2029},"Actions, Constants та Action Creators","/javascript/react/redux/classic-redux/actions-constants","03.javascript/04.react/06.redux/02.classic-redux/02.actions-constants",{"title":2031,"path":2032,"stem":2033},"Логіка Reducers","/javascript/react/redux/classic-redux/reducers","03.javascript/04.react/06.redux/02.classic-redux/03.reducers",{"title":2035,"path":2036,"stem":2037},"Комбінування Reducers (Root Reducer)","/javascript/react/redux/classic-redux/data-flow","03.javascript/04.react/06.redux/02.classic-redux/04.data-flow",{"title":2039,"path":2040,"stem":2041},"Підключення до React (React-Redux)","/javascript/react/redux/classic-redux/react-redux-connection","03.javascript/04.react/06.redux/02.classic-redux/05.react-redux-connection",{"title":2043,"path":2044,"stem":2045},"Middleware та Асинхронність (Redux Thunk)","/javascript/react/redux/classic-redux/middleware-thunk","03.javascript/04.react/06.redux/02.classic-redux/06.middleware-thunk",{"title":2047,"icon":132,"path":2048,"stem":2049,"children":2050,"page":59},"Transition To Rtk","/javascript/react/redux/transition-to-rtk","03.javascript/04.react/06.redux/03.transition-to-rtk",[2051],{"title":2052,"path":2053,"stem":2054},"Проблеми класичного Redux","/javascript/react/redux/transition-to-rtk/problems-with-classic","03.javascript/04.react/06.redux/03.transition-to-rtk/01.problems-with-classic",{"title":2056,"icon":132,"path":2057,"stem":2058,"children":2059,"page":59},"Redux Toolkit","/javascript/react/redux/redux-toolkit","03.javascript/04.react/06.redux/04.redux-toolkit",[2060,2064,2068,2072],{"title":2061,"path":2062,"stem":2063},"Налаштування Store з configureStore","/javascript/react/redux/redux-toolkit/configure-store","03.javascript/04.react/06.redux/04.redux-toolkit/01.configure-store",{"title":2065,"path":2066,"stem":2067},"createSlice: Революція в Redux","/javascript/react/redux/redux-toolkit/create-slice","03.javascript/04.react/06.redux/04.redux-toolkit/02.create-slice",{"title":2069,"path":2070,"stem":2071},"Асинхронність з createAsyncThunk","/javascript/react/redux/redux-toolkit/async-thunks","03.javascript/04.react/06.redux/04.redux-toolkit/03.async-thunks",{"title":2073,"path":2074,"stem":2075},"04. Entity Adapter: Керування нормалізованим станом","/javascript/react/redux/redux-toolkit/entity-adapter","03.javascript/04.react/06.redux/04.redux-toolkit/04.entity-adapter",{"title":2077,"icon":92,"path":2078,"stem":2079,"children":2080,"page":59},"Advanced","/javascript/react/redux/advanced","03.javascript/04.react/06.redux/05.advanced",[2081,2085,2089],{"title":2082,"path":2083,"stem":2084},"Мемоізація та Селектори: Повний Гайд по Reselect","/javascript/react/redux/advanced/selectors-reselect","03.javascript/04.react/06.redux/05.advanced/01.selectors-reselect",{"title":2086,"path":2087,"stem":2088},"RTK Query: Архітектура Серверного Кешу","/javascript/react/redux/advanced/rtk-query-intro","03.javascript/04.react/06.redux/05.advanced/02.rtk-query-intro",{"title":1936,"path":2090,"stem":2091},"/javascript/react/redux/advanced/architecture-best-practices","03.javascript/04.react/06.redux/05.advanced/03.architecture-best-practices",{"title":2093,"icon":132,"path":2094,"stem":2095,"children":2096,"page":59},"Project Kanban","/javascript/react/redux/project-kanban","03.javascript/04.react/06.redux/06.project-kanban",[2097,2101,2105,2109,2113,2117],{"title":2098,"path":2099,"stem":2100},"Проєкт: Kanban Board (Trello Clone)","/javascript/react/redux/project-kanban/project-overview","03.javascript/04.react/06.redux/06.project-kanban/01.project-overview",{"title":2102,"path":2103,"stem":2104},"Налаштування та Типізація","/javascript/react/redux/project-kanban/setup-and-types","03.javascript/04.react/06.redux/06.project-kanban/02.setup-and-types",{"title":2106,"path":2107,"stem":2108},"Board Slice: Серце Дошки","/javascript/react/redux/project-kanban/board-slice","03.javascript/04.react/06.redux/06.project-kanban/03.board-slice",{"title":2110,"path":2111,"stem":2112},"Логіка Drag & Drop","/javascript/react/redux/project-kanban/drag-and-drop-logic","03.javascript/04.react/06.redux/06.project-kanban/04.drag-and-drop-logic",{"title":2114,"path":2115,"stem":2116},"Інтеграція з RTK Query","/javascript/react/redux/project-kanban/rtk-query-integration","03.javascript/04.react/06.redux/06.project-kanban/05.rtk-query-integration",{"title":2118,"path":2119,"stem":2120},"Optimistic Updates","/javascript/react/redux/project-kanban/optimistic-updates","03.javascript/04.react/06.redux/06.project-kanban/06.optimistic-updates",{"title":2122,"icon":132,"path":2123,"stem":2124,"children":2125,"page":59},"Testing","/javascript/react/redux/testing","03.javascript/04.react/06.redux/07.testing",[2126,2130,2134,2138,2142],{"title":2127,"path":2128,"stem":2129},"Тестування Redux","/javascript/react/redux/testing/intro-testing","03.javascript/04.react/06.redux/07.testing/01.intro-testing",{"title":2131,"path":2132,"stem":2133},"Тестування Reducers","/javascript/react/redux/testing/testing-reducers","03.javascript/04.react/06.redux/07.testing/02.testing-reducers",{"title":2135,"path":2136,"stem":2137},"Тестування Селекторів","/javascript/react/redux/testing/testing-selectors","03.javascript/04.react/06.redux/07.testing/03.testing-selectors",{"title":2139,"path":2140,"stem":2141},"Тестування Компонентів (Integration)","/javascript/react/redux/testing/testing-components","03.javascript/04.react/06.redux/07.testing/04.testing-components",{"title":2143,"path":2144,"stem":2145},"Тестування Async Thunks","/javascript/react/redux/testing/testing-thunks","03.javascript/04.react/06.redux/07.testing/05.testing-thunks",{"title":2147,"icon":132,"path":2148,"stem":2149,"children":2150},"Ui Libraries","/javascript/react/ui-libraries","03.javascript/04.react/07.ui-libraries/index",[2151,2153,2157,2161,2165,2169,2173],{"title":2152,"path":2148,"stem":2149},"UI Бібліотеки в React",{"title":2154,"path":2155,"stem":2156},"Вступ до UI Бібліотек: Навіщо Винаходити Велосипед Двічі?","/javascript/react/ui-libraries/introduction-to-ui-libraries","03.javascript/04.react/07.ui-libraries/01.introduction-to-ui-libraries",{"title":2158,"path":2159,"stem":2160},"Філософія shadcn/ui: \"Not a Component Library\"","/javascript/react/ui-libraries/shadcn-philosophy","03.javascript/04.react/07.ui-libraries/02.shadcn-philosophy",{"title":2162,"path":2163,"stem":2164},"Установка та Налаштування shadcn/ui","/javascript/react/ui-libraries/shadcn-installation","03.javascript/04.react/07.ui-libraries/03.shadcn-installation",{"title":2166,"path":2167,"stem":2168},"Базові Компоненти shadcn/ui: Фундамент Інтерфейсу","/javascript/react/ui-libraries/shadcn-components-basics","03.javascript/04.react/07.ui-libraries/04.shadcn-components-basics",{"title":2170,"path":2171,"stem":2172},"Компоненти Форм: Побудова Інтерактивних Form","/javascript/react/ui-libraries/shadcn-components-forms","03.javascript/04.react/07.ui-libraries/05.shadcn-components-forms",{"title":2174,"path":2175,"stem":2176},"Складні Компоненти: Dialog, Dropdown, Table та Command","/javascript/react/ui-libraries/shadcn-components-advanced","03.javascript/04.react/07.ui-libraries/06.shadcn-components-advanced",{"title":2178,"icon":2179,"path":2180,"stem":2181,"children":2182,"page":59},"TypeScript","i-devicon-typescript","/javascript/typescript","03.javascript/05.typescript",[2183,2187,2191,2195,2199,2203,2207,2211],{"title":2184,"path":2185,"stem":2186},"TypeScript: Броня для вашого коду","/javascript/typescript/intro-and-basic-types","03.javascript/05.typescript/01.intro-and-basic-types",{"title":2188,"path":2189,"stem":2190},"Майстерність Моделювання Даних: Інтерфейси та Просунуті Типи","/javascript/typescript/interfaces-and-advanced-types","03.javascript/05.typescript/02.interfaces-and-advanced-types",{"title":2192,"path":2193,"stem":2194},"Алхімія Типів: Generics та Utility Types","/javascript/typescript/generics-and-utilities","03.javascript/05.typescript/03.generics-and-utilities",{"title":2196,"path":2197,"stem":2198},"Архітектура та Шаблони: Класи в TypeScript","/javascript/typescript/classes-and-oop","03.javascript/05.typescript/04.classes-and-oop",{"title":2200,"path":2201,"stem":2202},"Продакшн та Екосистема: Advanced Config & Workflow","/javascript/typescript/advanced-patterns-and-config","03.javascript/05.typescript/05.advanced-patterns-and-config",{"title":2204,"path":2205,"stem":2206},"TypeScript у світі React","/javascript/typescript/react-basics","03.javascript/05.typescript/06.react-basics",{"title":2208,"path":2209,"stem":2210},"React + TypeScript: Продвинуті патерни","/javascript/typescript/react-advanced","03.javascript/05.typescript/07.react-advanced",{"title":2212,"path":2213,"stem":2214},"React + TypeScript: Екосистема та бібліотеки","/javascript/typescript/react-ecosystem","03.javascript/05.typescript/08.react-ecosystem",{"title":2216,"path":2217,"stem":2218},"Atomic Design","/javascript/atomic-design","03.javascript/2.atomic-design",{"title":2220,"icon":2221,"path":2222,"stem":2223,"children":2224,"page":59},"Java","i-devicon-java","/java","04.java",[2225,2228,2231,2235,2239,2243,2247],{"title":162,"path":2226,"stem":2227},"/java/data-mapper-part1","04.java/01.data-mapper-part1",{"title":166,"path":2229,"stem":2230},"/java/data-mapper-part2","04.java/02.data-mapper-part2",{"title":2232,"path":2233,"stem":2234},"Service Layer: Організація бізнес-логіки","/java/service-layer","04.java/03.service-layer",{"title":2236,"path":2237,"stem":2238},"Rich Domain Model та State Pattern","/java/rich-domain-model","04.java/04.rich-domain-model",{"title":2240,"path":2241,"stem":2242},"Патерни для складної бізнес-логіки","/java/business-logic-patterns","04.java/05.business-logic-patterns",{"title":2244,"path":2245,"stem":2246},"Обробка помилок та валідація","/java/error-handling-validation","04.java/06.error-handling-validation",{"title":2248,"path":2249,"stem":2250,"children":2251,"page":59},"Проектування баз даних","/java/pr2","04.java/pr2",[2252,2256,2260,2264,2268,2272,2276,2280,2284,2288,2292,2296,2300,2304,2308,2312,2316,2320,2324,2328,2332,2336,2340,2344,2348],{"title":2253,"path":2254,"stem":2255},"Концептуальне моделювання: Мистецтво розуміння предметної області","/java/pr2/conceptual-modeling","04.java/pr2/01.conceptual-modeling",{"title":2257,"path":2258,"stem":2259},"Логічне моделювання: Від бізнес-ідей до структур даних","/java/pr2/logical-modeling","04.java/pr2/02.logical-modeling",{"title":2261,"path":2262,"stem":2263},"Нормалізація: Гігієна даних та боротьба з аномаліями","/java/pr2/normalization","04.java/pr2/03.normalization",{"title":2265,"path":2266,"stem":2267},"Фізична схема: Від абстракції до DDL","/java/pr2/physical-schema","04.java/pr2/04.physical-schema",{"title":2269,"path":2270,"stem":2271},"Архітектурна класифікація таблиць","/java/pr2/table-classification","04.java/pr2/05.table-classification",{"title":2273,"path":2274,"stem":2275},"Database Migrations: Версіонування схеми з Flyway","/java/pr2/database-migrations","04.java/pr2/06.database-migrations",{"title":2277,"path":2278,"stem":2279},"А що, якби це була не реляційна БД?","/java/pr2/beyond-relational","04.java/pr2/07.beyond-relational",{"title":2281,"path":2282,"stem":2283},"Object-Relational Impedance Mismatch: Два світи, що не хочуть дружити","/java/pr2/impedance-mismatch","04.java/pr2/09.impedance-mismatch",{"title":2285,"path":2286,"stem":2287},"JDBC: Перший контакт із базою даних","/java/pr2/jdbc-fundamentals","04.java/pr2/10.jdbc-fundamentals",{"title":2289,"path":2290,"stem":2291},"Якість коду: Spotless, SpotBugs та SonarQube","/java/pr2/10a.code-quality","04.java/pr2/10a.code-quality",{"title":2293,"path":2294,"stem":2295},"Connection Pool: Патерн Object Pool для JDBC-з'єднань","/java/pr2/connection-pool","04.java/pr2/11.connection-pool",{"title":2297,"path":2298,"stem":2299},"Row Data Gateway: Об'єкт як обгортка рядка таблиці","/java/pr2/row-data-gateway","04.java/pr2/12.row-data-gateway",{"title":2301,"path":2302,"stem":2303},"Table Data Gateway: Фасад таблиці як архітектурний відступ","/java/pr2/table-data-gateway","04.java/pr2/13.table-data-gateway",{"title":2305,"path":2306,"stem":2307},"Repository + Data Mapper: Правильна шарова архітектура з JDBC","/java/pr2/repository-data-mapper","04.java/pr2/14.repository-data-mapper",{"title":2309,"path":2310,"stem":2311},"Identity Map: Кешування сутностей у рамках сесії","/java/pr2/identity-map","04.java/pr2/15.identity-map",{"title":2313,"path":2314,"stem":2315},"Unit of Work: Відстеження змін і координація JDBC-транзакцій","/java/pr2/unit-of-work","04.java/pr2/16.unit-of-work",{"title":2317,"path":2318,"stem":2319},"Strategy: Замінювані SQL-стратегії для підтримки різних СУБД","/java/pr2/strategy-sql","04.java/pr2/17.strategy-sql",{"title":2321,"path":2322,"stem":2323},"Proxy: Lazy Loading для One-To-Many колекцій","/java/pr2/proxy-lazy-loading","04.java/pr2/18.proxy-lazy-loading",{"title":2325,"path":2326,"stem":2327},"Generic Repository через Java Reflection: анотації та динамічний SQL","/java/pr2/generic-repository-reflection","04.java/pr2/19.generic-repository-reflection",{"title":2329,"path":2330,"stem":2331},"Specification Pattern: Композиція бізнес-правил для складних запитів","/java/pr2/specification-pattern","04.java/pr2/20.specification-pattern",{"title":2333,"path":2334,"stem":2335},"Розширені можливості Specification Pattern: підзапити, агрегації та гібридний підхід","/java/pr2/20a.advanced-specifications","04.java/pr2/20a.advanced-specifications",{"title":2337,"path":2338,"stem":2339},"Асинхронність у JDBC: Від блокуючих викликів до CompletableFuture","/java/pr2/asynchronous-jdbc","04.java/pr2/21.asynchronous-jdbc",{"title":2341,"path":2342,"stem":2343},"Інтеграційне тестування JDBC-репозиторіїв: Embedded H2 та патерн AAA","/java/pr2/integration-testing-h2","04.java/pr2/22.integration-testing-h2",{"title":2345,"path":2346,"stem":2347},"Testcontainers: Тестування з реальною PostgreSQL у Docker-контейнерах","/java/pr2/integration-testing-testcontainers","04.java/pr2/23.integration-testing-testcontainers",{"title":2349,"path":2350,"stem":2351},"Модуль \"Проектування реляційних баз даних\" для 04.java/pr2","/java/pr2/implementation_plan","04.java/pr2/implementation_plan",{"title":2353,"icon":2354,"path":2355,"stem":2356,"children":2357,"page":59},"Бази даних","i-lucide-database","/databases","06.databases",[2358,2388,2411,2448,2477,2495,2529,2541,2550],{"title":2359,"icon":2360,"path":2361,"stem":2362,"children":2363,"page":59},"Intro","i-lucide-play","/databases/intro","06.databases/01.intro",[2364,2368,2372,2376,2380,2384],{"title":2365,"path":2366,"stem":2367},"Введення в теорію баз даних","/databases/intro/introduction-to-databases","06.databases/01.intro/01.introduction-to-databases",{"title":2369,"path":2370,"stem":2371},"Реляційна модель даних","/databases/intro/relational-model-theory","06.databases/01.intro/02.relational-model-theory",{"title":2373,"path":2374,"stem":2375},"ER-моделювання","/databases/intro/er-modeling","06.databases/01.intro/03.er-modeling",{"title":2377,"path":2378,"stem":2379},"Логічне проектування БД","/databases/intro/logical-schema","06.databases/01.intro/04.logical-schema",{"title":2381,"path":2382,"stem":2383},"Класифікація таблиць","/databases/intro/table-classification","06.databases/01.intro/05.table-classification",{"title":2385,"path":2386,"stem":2387},"PlantUML для баз даних","/databases/intro/plantuml-diagrams","06.databases/01.intro/06.plantuml-diagrams",{"title":2389,"icon":2354,"path":2390,"stem":2391,"children":2392,"page":59},"MS SQL Server Start","/databases/ms-sql-server-start","06.databases/02.ms-sql-server-start",[2393,2397,2403,2407],{"title":2394,"path":2395,"stem":2396},"Типи даних у MS SQL Server","/databases/ms-sql-server-start/data-types","06.databases/02.ms-sql-server-start/01.data-types",{"title":2398,"path":2399,"stem":2400,"children":2401},"Індекси у MS SQL Server","/databases/ms-sql-server-start/sql-indexes","06.databases/02.ms-sql-server-start/02.sql-indexes",[2402],{"title":2398,"path":2399,"stem":2400},{"title":2404,"path":2405,"stem":2406},"Системні бази даних MS SQL Server","/databases/ms-sql-server-start/system-databases","06.databases/02.ms-sql-server-start/03.system-databases",{"title":2408,"path":2409,"stem":2410},"Огляд мови SQL та запитів","/databases/ms-sql-server-start/sql-queries-overview","06.databases/02.ms-sql-server-start/04.sql-queries-overview",{"title":2412,"icon":2354,"path":2413,"stem":2414,"children":2415,"page":59},"SQL","/databases/sql","06.databases/03.sql",[2416,2420,2424,2428,2432,2436,2440,2444],{"title":2417,"path":2418,"stem":2419},"Налаштування демонстраційної бази даних","/databases/sql/sample-database-setup","06.databases/03.sql/00.sample-database-setup",{"title":2421,"path":2422,"stem":2423},"DDL - Створення таблиць (CREATE TABLE)","/databases/sql/ddl-create-table","06.databases/03.sql/01.ddl-create-table",{"title":2425,"path":2426,"stem":2427},"DDL - Зміна та видалення таблиць (ALTER, DROP)","/databases/sql/ddl-alter-drop-table","06.databases/03.sql/02.ddl-alter-drop-table",{"title":2429,"path":2430,"stem":2431},"SELECT запити - Основи","/databases/sql/select-queries-fundamentals","06.databases/03.sql/03.select-queries-fundamentals",{"title":2433,"path":2434,"stem":2435},"SELECT запити - Розширені можливості","/databases/sql/select-queries-advanced","06.databases/03.sql/04.select-queries-advanced",{"title":2437,"path":2438,"stem":2439},"INSERT запити - Додавання даних","/databases/sql/insert-queries","06.databases/03.sql/05.insert-queries",{"title":2441,"path":2442,"stem":2443},"UPDATE та DELETE запити","/databases/sql/update-delete-queries","06.databases/03.sql/06.update-delete-queries",{"title":2445,"path":2446,"stem":2447},"Транзакції в SQL","/databases/sql/transactions","06.databases/03.sql/07.transactions",{"title":2449,"icon":2354,"path":2450,"stem":2451,"children":2452,"page":59},"Multi Table Databases","/databases/multi-table-databases","06.databases/04.multi-table-databases",[2453,2457,2461,2465,2469,2473],{"title":2454,"path":2455,"stem":2456},"Зв'язки та нормалізація БД","/databases/multi-table-databases/relationships-and-normalization","06.databases/04.multi-table-databases/00.relationships-and-normalization",{"title":2458,"path":2459,"stem":2460},"INNER JOIN - З'єднання таблиць","/databases/multi-table-databases/inner-join","06.databases/04.multi-table-databases/01.inner-join",{"title":2462,"path":2463,"stem":2464},"OUTER JOINs - LEFT, RIGHT, FULL","/databases/multi-table-databases/outer-joins","06.databases/04.multi-table-databases/02.outer-joins",{"title":2466,"path":2467,"stem":2468},"CROSS та SELF JOINs","/databases/multi-table-databases/cross-self-joins","06.databases/04.multi-table-databases/03.cross-self-joins",{"title":2470,"path":2471,"stem":2472},"Підзапити (Subqueries)","/databases/multi-table-databases/subqueries","06.databases/04.multi-table-databases/04.subqueries",{"title":2474,"path":2475,"stem":2476},"Агрегації з JOIN","/databases/multi-table-databases/aggregations-with-joins","06.databases/04.multi-table-databases/05.aggregations-with-joins",{"title":2478,"icon":2479,"path":2480,"stem":2481,"children":2482,"page":59},"Aggregate Functions","i-lucide-calculator","/databases/aggregate-functions","06.databases/05.aggregate-functions",[2483,2487,2491],{"title":2484,"path":2485,"stem":2486},"Функції агрегування в MS SQL Server","/databases/aggregate-functions/introduction-aggregate-functions","06.databases/05.aggregate-functions/01.introduction-aggregate-functions",{"title":2488,"path":2489,"stem":2490},"Групування даних в MS SQL Server","/databases/aggregate-functions/grouping-data","06.databases/05.aggregate-functions/02.grouping-data",{"title":2492,"path":2493,"stem":2494},"Підзапити з агрегатними функціями","/databases/aggregate-functions/subqueries-aggregates","06.databases/05.aggregate-functions/03.subqueries-aggregates",{"title":2496,"icon":2497,"path":2498,"stem":2499,"children":2500,"page":59},"Тригери та зберігаємі процедури","i-lucide-database-zap","/databases/triggers-stored-procedures","06.databases/07.triggers-stored-procedures",[2501,2505,2509,2513,2517,2521,2525],{"title":2502,"path":2503,"stem":2504},"DML-тригери","/databases/triggers-stored-procedures/dml-triggers","06.databases/07.triggers-stored-procedures/01.dml-triggers",{"title":2506,"path":2507,"stem":2508},"DDL-тригери","/databases/triggers-stored-procedures/ddl-triggers","06.databases/07.triggers-stored-procedures/02.ddl-triggers",{"title":2510,"path":2511,"stem":2512},"Transact-SQL розширення","/databases/triggers-stored-procedures/transact-sql-extensions","06.databases/07.triggers-stored-procedures/03.transact-sql-extensions",{"title":2514,"path":2515,"stem":2516},"Транзакції","/databases/triggers-stored-procedures/transactions","06.databases/07.triggers-stored-procedures/04.transactions",{"title":2518,"path":2519,"stem":2520},"Зберігаємі процедури","/databases/triggers-stored-procedures/stored-procedures","06.databases/07.triggers-stored-procedures/05.stored-procedures",{"title":2522,"path":2523,"stem":2524},"Користувацькі функції","/databases/triggers-stored-procedures/user-defined-functions","06.databases/07.triggers-stored-procedures/06.user-defined-functions",{"title":2526,"path":2527,"stem":2528},"Безпека баз даних","/databases/triggers-stored-procedures/security","06.databases/07.triggers-stored-procedures/08.security",{"title":2526,"icon":793,"path":2530,"stem":2531,"children":2532,"page":59},"/databases/security","06.databases/08.security",[2533,2537],{"title":2534,"path":2535,"stem":2536},"Вступ до безпеки баз даних","/databases/security/introduction","06.databases/08.security/01.introduction",{"title":2538,"path":2539,"stem":2540},"Системні представлення та метадані","/databases/security/system-views","06.databases/08.security/02.system-views",{"title":2542,"icon":2543,"path":2544,"stem":2545,"children":2546,"page":59},"Резервне копіювання та відновлення","i-lucide-database-backup","/databases/backup-recovery","06.databases/09.backup-recovery",[2547],{"title":2542,"path":2548,"stem":2549},"/databases/backup-recovery/backup-restore","06.databases/09.backup-recovery/01.backup-restore",{"title":2551,"icon":2552,"path":2553,"stem":2554,"children":2555,"page":59},"Повнотекстовий пошук","i-lucide-search","/databases/full-text-search","06.databases/10.full-text-search",[2556],{"title":2551,"path":2557,"stem":2558},"/databases/full-text-search/full-text-search","06.databases/10.full-text-search/01.full-text-search",{"title":2560,"icon":2561,"path":2562,"stem":2563,"children":2564,"page":59},"Tools","i-lucide-wrench","/tools","07.tools",[2565],{"title":2566,"icon":2567,"path":2568,"stem":2569,"children":2570},"Docker","i-simple-icons-docker","/tools/docker","07.tools/01.docker/index",[2571,2573,2577,2581,2585,2589,2593,2597,2601,2605,2609,2613,2617,2621,2625,2629,2633,2637],{"title":2572,"path":2568,"stem":2569},"Docker: від нуля до production",{"title":2574,"path":2575,"stem":2576},"Контейнеризація — від проблеми до рішення","/tools/docker/containerization-concept","07.tools/01.docker/01.containerization-concept",{"title":2578,"path":2579,"stem":2580},"Docker — що це і навіщо?","/tools/docker/docker-what-and-why","07.tools/01.docker/02.docker-what-and-why",{"title":2582,"path":2583,"stem":2584},"Архітектура Docker Engine","/tools/docker/docker-architecture","07.tools/01.docker/03.docker-architecture",{"title":2586,"path":2587,"stem":2588},"Встановлення Docker","/tools/docker/installation","07.tools/01.docker/04.installation",{"title":2590,"path":2591,"stem":2592},"Перший контейнер — docker run","/tools/docker/first-container","07.tools/01.docker/05.first-container",{"title":2594,"path":2595,"stem":2596},"Життєвий цикл контейнера","/tools/docker/container-lifecycle","07.tools/01.docker/06.container-lifecycle",{"title":2598,"path":2599,"stem":2600},"Docker Images — фундаментальні концепції","/tools/docker/docker-images-fundamentals","07.tools/01.docker/07.docker-images-fundamentals",{"title":2602,"path":2603,"stem":2604},"Dockerfile — основи","/tools/docker/dockerfile-basics","07.tools/01.docker/08.dockerfile-basics",{"title":2606,"path":2607,"stem":2608},"Dockerfile — просунуті техніки","/tools/docker/dockerfile-advanced","07.tools/01.docker/09.dockerfile-advanced",{"title":2610,"path":2611,"stem":2612},"Build Context та кешування шарів","/tools/docker/build-context-and-cache","07.tools/01.docker/10.build-context-and-cache",{"title":2614,"path":2615,"stem":2616},"Реєстри Docker-образів","/tools/docker/image-registries","07.tools/01.docker/11.image-registries",{"title":2618,"path":2619,"stem":2620},"Контейнеризація .NET додатків","/tools/docker/dotnet-containerization","07.tools/01.docker/12.dotnet-containerization",{"title":2622,"path":2623,"stem":2624},"Томи та збереження даних","/tools/docker/volumes-and-data","07.tools/01.docker/13.volumes-and-data",{"title":2626,"path":2627,"stem":2628},"Основи мережі в Docker","/tools/docker/networking-basics","07.tools/01.docker/14.networking-basics",{"title":2630,"path":2631,"stem":2632},"Змінні оточення та конфігурація","/tools/docker/environment-and-configuration","07.tools/01.docker/15.environment-and-configuration",{"title":2634,"path":2635,"stem":2636},"Docker Compose — оркестрація контейнерів","/tools/docker/docker-compose-basics","07.tools/01.docker/16.docker-compose-basics",{"title":2638,"path":2639,"stem":2640},"Docker Compose — Multi-Service застосунки","/tools/docker/compose-multi-service","07.tools/01.docker/17.compose-multi-service",{"title":2642,"icon":2643,"path":2644,"stem":2645,"children":2646,"page":59},"Software Engineering","i-lucide-code-2","/software-engineering","09.software-engineering",[2647,2651,2655,2659,2663,2667,2671,2675,2679,2683,2687],{"title":2648,"path":2649,"stem":2650},"1. Аналіз предметної області. Експертні знання та складність","/software-engineering/intro.subdomains","09.software-engineering/01.intro.subdomains",{"title":2652,"path":2653,"stem":2654},"2. Обмежені контексти. Інтеграція обмежених контекстів","/software-engineering/integrating-limited-contexts","09.software-engineering/02.integrating-limited-contexts",{"title":2656,"path":2657,"stem":2658},"3. Реалізація простої бізнес-логіки","/software-engineering/simple","09.software-engineering/03.simple",{"title":2660,"path":2661,"stem":2662},"4. Опрацювання складної бізнес-логіки","/software-engineering/complex-business-logic","09.software-engineering/04.complex-business-logic",{"title":2664,"path":2665,"stem":2666},"5. Моделювання фактора часу. Подієво-орієнтована архітектура.","/software-engineering/modelling-the-time-factor","09.software-engineering/05.modelling-the-time-factor",{"title":2668,"path":2669,"stem":2670},"6. Архітектурні патерни","/software-engineering/architectural-patterns","09.software-engineering/06.architectural-patterns",{"title":2672,"path":2673,"stem":2674},"Паттерни взаємодії","/software-engineering/patterns-of-interaction","09.software-engineering/07.patterns-of-interaction",{"title":2676,"path":2677,"stem":2678},"Евристика проєктування","/software-engineering/design-heuristics","09.software-engineering/08.design-heuristics",{"title":2680,"path":2681,"stem":2682},"Еволюція проєктних рішень","/software-engineering/evolution-of-design-solutions","09.software-engineering/09.evolution-of-design-solutions",{"title":2684,"path":2685,"stem":2686},"EventStorming","/software-engineering/eventstorming","09.software-engineering/10.eventstorming",{"title":2688,"path":2689,"stem":2690},"DDD на практиці","/software-engineering/ddd-in-practice","09.software-engineering/11.ddd-in-practice",{"title":2692,"icon":943,"path":2693,"stem":2694,"children":2695,"page":59},"DDD","/ddd","10.ddd",[2696,2700,2704,2708,2712,2716,2720,2724,2728,2732,2736,2740,2744],{"title":2697,"path":2698,"stem":2699},"Аналіз предметної області","/ddd/domain-analysis","10.ddd/01.domain-analysis",{"title":2701,"path":2702,"stem":2703},"Експертні знання про предметну область","/ddd/domain-expert-knowledge","10.ddd/02.domain-expert-knowledge",{"title":2705,"path":2706,"stem":2707},"Як осмислити складність предметної області","/ddd/managing-domain-complexity","10.ddd/03.managing-domain-complexity",{"title":2709,"path":2710,"stem":2711},"Інтеграція обмежених контекстів","/ddd/bounded-context-integration","10.ddd/04.bounded-context-integration",{"title":2713,"path":2714,"stem":2715},"Реалізація простої бізнес-логіки","/ddd/simple-business-logic","10.ddd/05.simple-business-logic",{"title":2717,"path":2718,"stem":2719},"Обробка складної бізнес-логіки","/ddd/complex-business-logic","10.ddd/06.complex-business-logic",{"title":2721,"path":2722,"stem":2723},"Моделювання фактора часу","/ddd/time-modeling","10.ddd/07.time-modeling",{"title":2725,"path":2726,"stem":2727},"Глава 8. Архітектурні Патерни","/ddd/architectural-patterns","10.ddd/08.architectural-patterns",{"title":2729,"path":2730,"stem":2731},"Глава 9. Патерни Взаємодії","/ddd/interaction-patterns","10.ddd/09.interaction-patterns",{"title":2733,"path":2734,"stem":2735},"Глава 10. Проектні Евристики","/ddd/design-heuristics","10.ddd/10.design-heuristics",{"title":2737,"path":2738,"stem":2739},"Глава 11. Еволюція Проектних Рішень","/ddd/evolution-of-design-decisions","10.ddd/11.evolution-of-design-decisions",{"title":2741,"path":2742,"stem":2743},"Глава 12. EventStorming","/ddd/event-storming","10.ddd/12.event-storming",{"title":2745,"path":2746,"stem":2747},"Глава 13. DDD на Практиці","/ddd/ddd-in-practice","10.ddd/13.ddd-in-practice",{"title":2749,"icon":2750,"path":2751,"stem":2752,"children":2753,"page":59},"Media Streaming","i-lucide-video","/media-streaming","11.media-streaming",[2754,2758,2762,2766,2770,2774,2778],{"title":2755,"path":2756,"stem":2757},"01. Магія Стрімінгу: Що відбувається, коли ви натискаєте \"Play\"","/media-streaming/introduction","11.media-streaming/01.introduction",{"title":2759,"path":2760,"stem":2761},"02. Анатомія Медіа: Кодеки, Контейнери та Стиснення","/media-streaming/audio-video-anatomy","11.media-streaming/02.audio-video-anatomy",{"title":2763,"path":2764,"stem":2765},"03. The Gym: FFmpeg Deep Dive","/media-streaming/ffmpeg-gym","11.media-streaming/03.ffmpeg-gym",{"title":2767,"path":2768,"stem":2769},"04. HLS Protocol: HTTP Live Streaming у Деталях","/media-streaming/hls-protocol","11.media-streaming/04.hls-protocol",{"title":2771,"path":2772,"stem":2773},"05. DASH Protocol: Відкритий Стандарт","/media-streaming/dash-protocol","11.media-streaming/05.dash-protocol",{"title":2775,"path":2776,"stem":2777},"06. Масштабування: CDN та Adaptive Bitrate","/media-streaming/cdn-and-adaptive-bitrate","11.media-streaming/06.cdn-and-adaptive-bitrate",{"title":2779,"path":2780,"stem":2781},"07. Війна із Затримкою (Latency)","/media-streaming/realtime-latency","11.media-streaming/07.realtime-latency",{"title":2783,"icon":2784,"path":2785,"stem":2786,"children":2787,"page":59},"HTML & CSS","i-devicon-html5","/html-css","12.html-css",[2788,2792,2796,2800,2804,2808,2812,2816,2820,2824,2828,2832,2836,2840,2844,2848,2852,2856,2860,2864,2868,2872,2876,2880,2884,2888,2892,2896,2900,2904],{"title":2789,"path":2790,"stem":2791},"Вступ до HTML. Структура документа","/html-css/intro-html-structure","12.html-css/01.intro-html-structure",{"title":2793,"path":2794,"stem":2795},"Форматування тексту в HTML","/html-css/html-text-formatting","12.html-css/02.html-text-formatting",{"title":2797,"path":2798,"stem":2799},"Посилання та зображення в HTML","/html-css/html-links-images","12.html-css/03.html-links-images",{"title":2801,"path":2802,"stem":2803},"Списки та таблиці в HTML","/html-css/html-lists-tables","12.html-css/04.html-lists-tables",{"title":2805,"path":2806,"stem":2807},"Форми в HTML","/html-css/html-forms","12.html-css/05.html-forms",{"title":2809,"path":2810,"stem":2811},"Семантичні елементи HTML5","/html-css/html-semantic-elements","12.html-css/06.html-semantic-elements",{"title":2813,"path":2814,"stem":2815},"Мультимедіа та розширені елементи HTML","/html-css/html-multimedia-advanced","12.html-css/07.html-multimedia-advanced",{"title":2817,"path":2818,"stem":2819},"Мікророзмітка та SEO в HTML","/html-css/html-microdata-seo","12.html-css/08.html-microdata-seo",{"title":2821,"path":2822,"stem":2823},"Вступ до CSS. Селектори та специфічність","/html-css/css-intro-selectors","12.html-css/09.css-intro-selectors",{"title":2825,"path":2826,"stem":2827},"Блокова модель CSS. Відступи. Box Sizing","/html-css/css-box-model","12.html-css/10.css-box-model",{"title":2829,"path":2830,"stem":2831},"Розміри у CSS: повний довідник одиниць і ключових слів","/html-css/10a.css-sizing","12.html-css/10a.css-sizing",{"title":2833,"path":2834,"stem":2835},"Типографіка в CSS. Шрифти та текст","/html-css/css-typography","12.html-css/11.css-typography",{"title":2837,"path":2838,"stem":2839},"Кольори та фони в CSS","/html-css/css-colors-backgrounds","12.html-css/12.css-colors-backgrounds",{"title":2841,"path":2842,"stem":2843},"Тіні та фільтри в CSS","/html-css/12b.css-shadows-filters","12.html-css/12b.css-shadows-filters",{"title":2845,"path":2846,"stem":2847},"CSS Flexbox: Фундамент гнучких макетів","/html-css/css-flexbox-fundamentals","12.html-css/13.css-flexbox-fundamentals",{"title":2849,"path":2850,"stem":2851},"CSS Flexbox: Вирівнювання та Позиціонування","/html-css/css-flexbox-alignment-sizing-and-patterns","12.html-css/14.css-flexbox-alignment-sizing-and-patterns",{"title":2853,"path":2854,"stem":2855},"CSS Grid. Двовимірний макет. Частина 1","/html-css/css-layout-grid","12.html-css/15.css-layout-grid",{"title":2857,"path":2858,"stem":2859},"CSS Grid. Двовимірний макет. Частина 2","/html-css/css-layout-grid-advanced","12.html-css/16.css-layout-grid-advanced",{"title":2861,"path":2862,"stem":2863},"Позиціонування в CSS. Z-index. Stacking Context","/html-css/css-positioning","12.html-css/17.css-positioning",{"title":2865,"path":2866,"stem":2867},"CSS Анімації та Переходи","/html-css/css-animations-transitions","12.html-css/18.css-animations-transitions",{"title":2869,"path":2870,"stem":2871},"Адаптивний дизайн. Media Queries. Частина 1","/html-css/css-responsive-media-queries","12.html-css/19.css-responsive-media-queries",{"title":2873,"path":2874,"stem":2875},"Адаптивний дизайн. Частина 2: clamp(), Container Queries, @layer","/html-css/css-responsive-advanced","12.html-css/20.css-responsive-advanced",{"title":2877,"path":2878,"stem":2879},"CSS Custom Properties. Методології. Сучасний CSS","/html-css/css-variables-methodologies","12.html-css/21.css-variables-methodologies",{"title":2881,"path":2882,"stem":2883},"Сучасний CSS 2023–2025: Нові можливості","/html-css/css-modern-features","12.html-css/22.css-modern-features",{"title":2885,"path":2886,"stem":2887},"CSS Nesting, @layer, @scope та @property: нативний препроцесор","/html-css/22a.css-nesting-modern-syntax","12.html-css/22a.css-nesting-modern-syntax",{"title":2889,"path":2890,"stem":2891},"CSS для форм та інтерактивних станів","/html-css/css-forms-interactive-states","12.html-css/23.css-forms-interactive-states",{"title":2893,"path":2894,"stem":2895},"Доступність у CSS (CSS Accessibility)","/html-css/css-accessibility","12.html-css/24.css-accessibility",{"title":2897,"path":2898,"stem":2899},"CSS-функції та сучасні sizing primitives","/html-css/css-functions-sizing","12.html-css/25.css-functions-sizing",{"title":2901,"path":2902,"stem":2903},"Rendering Pipeline і CSS Performance","/html-css/css-rendering-performance","12.html-css/26.css-rendering-performance",{"title":2905,"path":2906,"stem":2907},"CSS Best Practices: типові ситуації та правильні рішення","/html-css/css-best-practices","12.html-css/27.css-best-practices",{"title":2909,"path":2910,"stem":2911,"children":2912,"page":59},"Tailwind","/tailwind","21.tailwind",[2913,2917,2921,2925,2929,2933,2937,2941],{"title":2914,"path":2915,"stem":2916},"Що таке Tailwind CSS і навіщо він потрібен","/tailwind/tailwind-intro-philosophy","21.tailwind/01.tailwind-intro-philosophy",{"title":2918,"path":2919,"stem":2920},"Встановлення та налаштування Tailwind CSS v4","/tailwind/tailwind-installation-setup","21.tailwind/02.tailwind-installation-setup",{"title":2922,"path":2923,"stem":2924},"Utility-класи: основи та система Tailwind","/tailwind/tailwind-utility-classes-core","21.tailwind/03.tailwind-utility-classes-core",{"title":2926,"path":2927,"stem":2928},"Layout: Flexbox та Grid через Tailwind","/tailwind/tailwind-flexbox-grid","21.tailwind/04.tailwind-flexbox-grid",{"title":2930,"path":2931,"stem":2932},"Кастомізація теми через @theme у Tailwind v4","/tailwind/tailwind-theme-customization","21.tailwind/05.tailwind-theme-customization",{"title":2934,"path":2935,"stem":2936},"Варіанти: hover, focus, responsive, dark mode та нові v4","/tailwind/tailwind-variants-states","21.tailwind/06.tailwind-variants-states",{"title":2938,"path":2939,"stem":2940},"Типографіка та система кольорів у Tailwind v4","/tailwind/tailwind-typography-colors","21.tailwind/07.tailwind-typography-colors",{"title":2942,"path":2943,"stem":2944},"Компоненти та повторюваність: @apply, @utility та патерни","/tailwind/tailwind-components-patterns","21.tailwind/08.tailwind-components-patterns",{"title":2946,"path":2947,"stem":2948},"Showcase Компонентів kostyl.dev","/test-new-components","98.test-new-components",{"id":2950,"title":356,"body":2951,"description":12507,"extension":12508,"links":12509,"meta":12510,"navigation":3050,"path":357,"seo":12511,"stem":358,"__hash__":12512},"docs/01.csharp/07.system-programming-windows/16.async-synchronization.md",{"type":2952,"value":2953,"toc":12455},"minimark",[2954,2958,2963,2987,2990,3007,3139,3155,3164,3173,3184,3187,3191,3196,3202,3352,3373,3377,3514,3529,3543,3547,3558,3601,3604,3606,3610,3614,3631,3640,3644,4010,4021,4025,4032,4313,4317,4433,4460,4462,4466,4470,4480,4486,4490,4496,4932,4985,4989,4992,5757,5763,5765,5769,5773,5779,5783,5786,6172,6184,6188,6194,6504,6509,6529,6533,6536,6902,6906,6909,7543,7545,7549,7553,7558,7563,7584,7588,7591,7744,7751,7762,7766,7769,8132,8140,8147,8371,8378,8381,8665,8669,8675,8987,8991,9090,9111,9113,9117,9120,11835,11982,11984,11988,12161,12163,12167,12249,12251,12255,12259,12262,12292,12297,12308,12312,12315,12332,12337,12351,12355,12358,12390,12395,12415,12419,12433,12435,12451],[2955,2956,356],"h1",{"id":2957},"асинхронна-синхронізація",[2959,2960,2962],"h2",{"id":2961},"навіщо-async-synchronization","Навіщо Async Synchronization?",[2964,2965,2966,2967,2971,2972,2971,2975,2971,2978,2981,2982,2986],"p",{},"У попередніх темах ми вивчили синхронізацію для багатопоточного коду: ",[2968,2969,2970],"code",{},"lock",", ",[2968,2973,2974],{},"Monitor",[2968,2976,2977],{},"Mutex",[2968,2979,2980],{},"Semaphore",". Всі ці примітиви розроблені для ",[2983,2984,2985],"strong",{},"синхронного"," коду — вони блокують потік до отримання доступу до ресурсу.",[2964,2988,2989],{},"Проте в асинхронному світі блокування потоків — це антипатерн. Розглянемо три типові проблеми:",[2964,2991,2992,2995,2996,2998,2999,3002,3003,3006],{},[2983,2993,2994],{},"Проблема перша: lock не працює з await."," Спроба використати ",[2968,2997,2970],{}," всередині ",[2968,3000,3001],{},"async"," методу з ",[2968,3004,3005],{},"await"," призводить до compiler error:",[3008,3009,3014],"pre",{"className":3010,"code":3011,"language":3012,"meta":3013,"style":3013},"language-csharp shiki shiki-themes light-plus dark-plus dark-plus","private readonly object _lock = new();\n\nasync Task ProcessAsync()\n{\n    lock (_lock)  // ✅ OK\n    {\n        await Task.Delay(100);  // ❌ CS1996: Cannot await in the body of a lock statement\n    }\n}\n","csharp","",[2968,3015,3016,3045,3052,3068,3074,3094,3100,3127,3133],{"__ignoreMap":3013},[3017,3018,3021,3025,3028,3031,3035,3039,3042],"span",{"class":3019,"line":3020},"line",1,[3017,3022,3024],{"class":3023},"su1O8","private",[3017,3026,3027],{"class":3023}," readonly",[3017,3029,3030],{"class":3023}," object",[3017,3032,3034],{"class":3033},"siwwj"," _lock",[3017,3036,3038],{"class":3037},"sHH4Y"," = ",[3017,3040,3041],{"class":3023},"new",[3017,3043,3044],{"class":3037},"();\n",[3017,3046,3048],{"class":3019,"line":3047},2,[3017,3049,3051],{"emptyLinePlaceholder":3050},true,"\n",[3017,3053,3055,3057,3061,3065],{"class":3019,"line":3054},3,[3017,3056,3001],{"class":3023},[3017,3058,3060],{"class":3059},"sN1BT"," Task",[3017,3062,3064],{"class":3063},"s8Opu"," ProcessAsync",[3017,3066,3067],{"class":3037},"()\n",[3017,3069,3071],{"class":3019,"line":3070},4,[3017,3072,3073],{"class":3037},"{\n",[3017,3075,3077,3081,3084,3087,3090],{"class":3019,"line":3076},5,[3017,3078,3080],{"class":3079},"sCDza","    lock",[3017,3082,3083],{"class":3037}," (",[3017,3085,3086],{"class":3033},"_lock",[3017,3088,3089],{"class":3037},")  ",[3017,3091,3093],{"class":3092},"spJ8K","// ✅ OK\n",[3017,3095,3097],{"class":3019,"line":3096},6,[3017,3098,3099],{"class":3037},"    {\n",[3017,3101,3103,3106,3108,3111,3114,3117,3121,3124],{"class":3019,"line":3102},7,[3017,3104,3105],{"class":3023},"        await",[3017,3107,3060],{"class":3033},[3017,3109,3110],{"class":3037},".",[3017,3112,3113],{"class":3063},"Delay",[3017,3115,3116],{"class":3037},"(",[3017,3118,3120],{"class":3119},"sJj4R","100",[3017,3122,3123],{"class":3037},");  ",[3017,3125,3126],{"class":3092},"// ❌ CS1996: Cannot await in the body of a lock statement\n",[3017,3128,3130],{"class":3019,"line":3129},8,[3017,3131,3132],{"class":3037},"    }\n",[3017,3134,3136],{"class":3019,"line":3135},9,[3017,3137,3138],{"class":3037},"}\n",[2964,3140,3141,3144,3145,3147,3148,3150,3151,3154],{},[2983,3142,3143],{},"Чому заборонено?"," ",[2968,3146,2970],{}," — це thread-affine примітив: він прив'язаний до конкретного потоку. Після ",[2968,3149,3005],{}," виконання може продовжитись на ",[2983,3152,3153],{},"іншому"," потоці, що порушує семантику lock (один потік захопив lock, інший звільнив — undefined behavior).",[2964,3156,3157,3160,3161,3163],{},[2983,3158,3159],{},"Проблема друга: Throttling async операцій."," API дозволяє максимум 10 одночасних HTTP запитів. Як обмежити кількість паралельних ",[2968,3162,3001],{}," операцій без блокування потоків?",[2964,3165,3166,3169,3170,3172],{},[2983,3167,3168],{},"Проблема третя: Timeout для async операцій."," Як встановити таймаут для ",[2968,3171,3005],{}," без блокування потоку на чеканні?",[2964,3174,3175,3176,3179,3180,3183],{},"Ця тема надає рішення для всіх трьох проблем: ",[2968,3177,3178],{},"SemaphoreSlim.WaitAsync()"," для async mutual exclusion, throttling patterns, timeout strategies, та огляд бібліотеки ",[2968,3181,3182],{},"Nito.AsyncEx"," з готовими async примітивами.",[3185,3186],"hr",{},[2959,3188,3190],{"id":3189},"проблема-чому-lock-не-працює-з-await","Проблема: Чому lock Не Працює з await",[3192,3193,3195],"h3",{"id":3194},"анатомія-lock-statement","Анатомія lock Statement",[2964,3197,3198,3199,3201],{},"Щоб зрозуміти проблему, розглянемо що компілятор генерує з ",[2968,3200,2970],{},":",[3008,3203,3205],{"className":3010,"code":3204,"language":3012,"meta":3013,"style":3013},"// Вихідний код\nlock (_lock)\n{\n    // Critical section\n}\n\n// Компілятор генерує (спрощено)\nbool lockTaken = false;\ntry\n{\n    Monitor.Enter(_lock, ref lockTaken);\n    // Critical section\n}\nfinally\n{\n    if (lockTaken)\n        Monitor.Exit(_lock);\n}\n",[2968,3206,3207,3212,3223,3227,3232,3236,3240,3245,3261,3266,3271,3296,3301,3306,3312,3317,3330,3347],{"__ignoreMap":3013},[3017,3208,3209],{"class":3019,"line":3020},[3017,3210,3211],{"class":3092},"// Вихідний код\n",[3017,3213,3214,3216,3218,3220],{"class":3019,"line":3047},[3017,3215,2970],{"class":3079},[3017,3217,3083],{"class":3037},[3017,3219,3086],{"class":3033},[3017,3221,3222],{"class":3037},")\n",[3017,3224,3225],{"class":3019,"line":3054},[3017,3226,3073],{"class":3037},[3017,3228,3229],{"class":3019,"line":3070},[3017,3230,3231],{"class":3092},"    // Critical section\n",[3017,3233,3234],{"class":3019,"line":3076},[3017,3235,3138],{"class":3037},[3017,3237,3238],{"class":3019,"line":3096},[3017,3239,3051],{"emptyLinePlaceholder":3050},[3017,3241,3242],{"class":3019,"line":3102},[3017,3243,3244],{"class":3092},"// Компілятор генерує (спрощено)\n",[3017,3246,3247,3250,3253,3255,3258],{"class":3019,"line":3129},[3017,3248,3249],{"class":3023},"bool",[3017,3251,3252],{"class":3033}," lockTaken",[3017,3254,3038],{"class":3037},[3017,3256,3257],{"class":3023},"false",[3017,3259,3260],{"class":3037},";\n",[3017,3262,3263],{"class":3019,"line":3135},[3017,3264,3265],{"class":3079},"try\n",[3017,3267,3269],{"class":3019,"line":3268},10,[3017,3270,3073],{"class":3037},[3017,3272,3274,3277,3279,3282,3284,3286,3288,3291,3293],{"class":3019,"line":3273},11,[3017,3275,3276],{"class":3033},"    Monitor",[3017,3278,3110],{"class":3037},[3017,3280,3281],{"class":3063},"Enter",[3017,3283,3116],{"class":3037},[3017,3285,3086],{"class":3033},[3017,3287,2971],{"class":3037},[3017,3289,3290],{"class":3023},"ref",[3017,3292,3252],{"class":3033},[3017,3294,3295],{"class":3037},");\n",[3017,3297,3299],{"class":3019,"line":3298},12,[3017,3300,3231],{"class":3092},[3017,3302,3304],{"class":3019,"line":3303},13,[3017,3305,3138],{"class":3037},[3017,3307,3309],{"class":3019,"line":3308},14,[3017,3310,3311],{"class":3079},"finally\n",[3017,3313,3315],{"class":3019,"line":3314},15,[3017,3316,3073],{"class":3037},[3017,3318,3320,3323,3325,3328],{"class":3019,"line":3319},16,[3017,3321,3322],{"class":3079},"    if",[3017,3324,3083],{"class":3037},[3017,3326,3327],{"class":3033},"lockTaken",[3017,3329,3222],{"class":3037},[3017,3331,3333,3336,3338,3341,3343,3345],{"class":3019,"line":3332},17,[3017,3334,3335],{"class":3033},"        Monitor",[3017,3337,3110],{"class":3037},[3017,3339,3340],{"class":3063},"Exit",[3017,3342,3116],{"class":3037},[3017,3344,3086],{"class":3033},[3017,3346,3295],{"class":3037},[3017,3348,3350],{"class":3019,"line":3349},18,[3017,3351,3138],{"class":3037},[2964,3353,3354,3144,3357,3360,3361,3364,3365,3368,3369,3372],{},[2983,3355,3356],{},"Ключовий момент:",[2968,3358,3359],{},"Monitor.Enter()"," запам'ятовує ",[2983,3362,3363],{},"ID потоку",", що захопив lock. ",[2968,3366,3367],{},"Monitor.Exit()"," перевіряє, що звільнення відбувається на ",[2983,3370,3371],{},"тому ж"," потоці. Це thread-affinity.",[3192,3374,3376],{"id":3375},"що-відбувається-з-await","Що Відбувається з await",[3008,3378,3380],{"className":3010,"code":3379,"language":3012,"meta":3013,"style":3013},"async Task ProcessAsync()\n{\n    lock (_lock)\n    {\n        Console.WriteLine($\"Before await: Thread {Thread.CurrentThread.ManagedThreadId}\");\n        await Task.Delay(100);  // Suspension point\n        Console.WriteLine($\"After await: Thread {Thread.CurrentThread.ManagedThreadId}\");\n        // Потоки можуть бути різними!\n    }\n}\n",[2968,3381,3382,3392,3396,3406,3410,3451,3470,3501,3506,3510],{"__ignoreMap":3013},[3017,3383,3384,3386,3388,3390],{"class":3019,"line":3020},[3017,3385,3001],{"class":3023},[3017,3387,3060],{"class":3059},[3017,3389,3064],{"class":3063},[3017,3391,3067],{"class":3037},[3017,3393,3394],{"class":3019,"line":3047},[3017,3395,3073],{"class":3037},[3017,3397,3398,3400,3402,3404],{"class":3019,"line":3054},[3017,3399,3080],{"class":3079},[3017,3401,3083],{"class":3037},[3017,3403,3086],{"class":3033},[3017,3405,3222],{"class":3037},[3017,3407,3408],{"class":3019,"line":3070},[3017,3409,3099],{"class":3037},[3017,3411,3412,3415,3417,3420,3422,3426,3430,3433,3435,3438,3440,3443,3446,3449],{"class":3019,"line":3076},[3017,3413,3414],{"class":3033},"        Console",[3017,3416,3110],{"class":3037},[3017,3418,3419],{"class":3063},"WriteLine",[3017,3421,3116],{"class":3037},[3017,3423,3425],{"class":3424},"sbdoH","$\"Before await: Thread ",[3017,3427,3429],{"class":3428},"sD7JJ","{",[3017,3431,3432],{"class":3033},"Thread",[3017,3434,3110],{"class":3428},[3017,3436,3437],{"class":3033},"CurrentThread",[3017,3439,3110],{"class":3428},[3017,3441,3442],{"class":3033},"ManagedThreadId",[3017,3444,3445],{"class":3428},"}",[3017,3447,3448],{"class":3424},"\"",[3017,3450,3295],{"class":3037},[3017,3452,3453,3455,3457,3459,3461,3463,3465,3467],{"class":3019,"line":3096},[3017,3454,3105],{"class":3023},[3017,3456,3060],{"class":3033},[3017,3458,3110],{"class":3037},[3017,3460,3113],{"class":3063},[3017,3462,3116],{"class":3037},[3017,3464,3120],{"class":3119},[3017,3466,3123],{"class":3037},[3017,3468,3469],{"class":3092},"// Suspension point\n",[3017,3471,3472,3474,3476,3478,3480,3483,3485,3487,3489,3491,3493,3495,3497,3499],{"class":3019,"line":3102},[3017,3473,3414],{"class":3033},[3017,3475,3110],{"class":3037},[3017,3477,3419],{"class":3063},[3017,3479,3116],{"class":3037},[3017,3481,3482],{"class":3424},"$\"After await: Thread ",[3017,3484,3429],{"class":3428},[3017,3486,3432],{"class":3033},[3017,3488,3110],{"class":3428},[3017,3490,3437],{"class":3033},[3017,3492,3110],{"class":3428},[3017,3494,3442],{"class":3033},[3017,3496,3445],{"class":3428},[3017,3498,3448],{"class":3424},[3017,3500,3295],{"class":3037},[3017,3502,3503],{"class":3019,"line":3129},[3017,3504,3505],{"class":3092},"        // Потоки можуть бути різними!\n",[3017,3507,3508],{"class":3019,"line":3135},[3017,3509,3132],{"class":3037},[3017,3511,3512],{"class":3019,"line":3268},[3017,3513,3138],{"class":3037},[2964,3515,3516,3519,3520,3522,3523,3525,3526,3110],{},[2983,3517,3518],{},"Проблема:"," Після ",[2968,3521,3005],{}," continuation може виконатись на іншому потоці ThreadPool. Якщо Thread 5 захопив lock, а Thread 8 намагається звільнити — ",[2968,3524,3367],{}," викине ",[2968,3527,3528],{},"SynchronizationLockException",[3530,3531,3532,3535,3536,3538,3539,3542],"warning",{},[2983,3533,3534],{},"Deadlock Scenario:"," Якщо після ",[2968,3537,3005],{}," continuation повертається на той самий потік (через ",[2968,3540,3541],{},"SynchronizationContext","), але цей потік вже зайнятий іншою роботою — deadlock. Lock тримається, потік чекає, continuation не виконується.",[3192,3544,3546],{"id":3545},"compiler-error-захист-від-помилок","Compiler Error: Захист від Помилок",[2964,3548,3549,3550,3144,3553,2998,3555,3557],{},"Компілятор C# ",[2983,3551,3552],{},"забороняє",[2968,3554,3005],{},[2968,3556,2970],{}," саме через ці проблеми:",[3008,3559,3561],{"className":3010,"code":3560,"language":3012,"meta":3013,"style":3013},"lock (_lock)\n{\n    await Task.Delay(100);  // CS1996: Cannot await in the body of a lock statement\n}\n",[2968,3562,3563,3573,3577,3597],{"__ignoreMap":3013},[3017,3564,3565,3567,3569,3571],{"class":3019,"line":3020},[3017,3566,2970],{"class":3079},[3017,3568,3083],{"class":3037},[3017,3570,3086],{"class":3033},[3017,3572,3222],{"class":3037},[3017,3574,3575],{"class":3019,"line":3047},[3017,3576,3073],{"class":3037},[3017,3578,3579,3582,3584,3586,3588,3590,3592,3594],{"class":3019,"line":3054},[3017,3580,3581],{"class":3023},"    await",[3017,3583,3060],{"class":3033},[3017,3585,3110],{"class":3037},[3017,3587,3113],{"class":3063},[3017,3589,3116],{"class":3037},[3017,3591,3120],{"class":3119},[3017,3593,3123],{"class":3037},[3017,3595,3596],{"class":3092},"// CS1996: Cannot await in the body of a lock statement\n",[3017,3598,3599],{"class":3019,"line":3070},[3017,3600,3138],{"class":3037},[2964,3602,3603],{},"Це не обмеження технічне — це захист від race conditions та deadlocks.",[3185,3605],{},[2959,3607,3609],{"id":3608},"semaphoreslimwaitasync-async-mutex","SemaphoreSlim.WaitAsync(): Async Mutex",[3192,3611,3613],{"id":3612},"концепція-async-compatible-synchronization","Концепція: Async-Compatible Synchronization",[2964,3615,3616,3619,3620,3623,3624,3627,3628,3630],{},[2968,3617,3618],{},"SemaphoreSlim"," — це легковаговий semaphore, що підтримує ",[2983,3621,3622],{},"асинхронне"," очікування через ",[2968,3625,3626],{},"WaitAsync()",". На відміну від ",[2968,3629,2970],{},", він не прив'язаний до потоку — можна захопити на одному потоці, звільнити на іншому.",[2964,3632,3633,3144,3636,3639],{},[2983,3634,3635],{},"Ключова ідея:",[2968,3637,3638],{},"SemaphoreSlim(1, 1)"," — це async-compatible mutex (mutual exclusion для одного потоку/task).",[3192,3641,3643],{"id":3642},"базовий-приклад-async-lock","Базовий Приклад: Async Lock",[3008,3645,3649],{"className":3010,"code":3646,"filename":3647,"language":3012,"meta":3648,"style":3013},"class AsyncCounter\n{\n    private int _count;\n    private readonly SemaphoreSlim _lock = new(1, 1);  // initialCount: 1, maxCount: 1\n\n    public async Task\u003Cint> IncrementAsync()\n    {\n        // Асинхронне очікування доступу (не блокує потік)\n        await _lock.WaitAsync();\n        try\n        {\n            // Critical section — тільки один task одночасно\n            await Task.Delay(10);  // ✅ await всередині \"lock\" — OK!\n            _count++;\n            return _count;\n        }\n        finally\n        {\n            // Звільнення lock — ЗАВЖДИ у finally\n            _lock.Release();\n        }\n    }\n}\n\n// Використання — 10 паралельних tasks\nvar counter = new AsyncCounter();\nvar tasks = Enumerable.Range(0, 10)\n    .Select(_ => counter.IncrementAsync())\n    .ToArray();\n\nawait Task.WhenAll(tasks);\nConsole.WriteLine($\"Final count: {await counter.IncrementAsync()}\");  // 11\n","AsyncLockBasics.cs","showLineNumbers",[2968,3650,3651,3659,3663,3676,3705,3709,3733,3737,3742,3755,3760,3765,3770,3791,3799,3808,3813,3818,3822,3828,3841,3846,3851,3856,3861,3867,3885,3914,3941,3951,3956,3975],{"__ignoreMap":3013},[3017,3652,3653,3656],{"class":3019,"line":3020},[3017,3654,3655],{"class":3023},"class",[3017,3657,3658],{"class":3059}," AsyncCounter\n",[3017,3660,3661],{"class":3019,"line":3047},[3017,3662,3073],{"class":3037},[3017,3664,3665,3668,3671,3674],{"class":3019,"line":3054},[3017,3666,3667],{"class":3023},"    private",[3017,3669,3670],{"class":3023}," int",[3017,3672,3673],{"class":3033}," _count",[3017,3675,3260],{"class":3037},[3017,3677,3678,3680,3682,3685,3687,3689,3691,3693,3696,3698,3700,3702],{"class":3019,"line":3070},[3017,3679,3667],{"class":3023},[3017,3681,3027],{"class":3023},[3017,3683,3684],{"class":3059}," SemaphoreSlim",[3017,3686,3034],{"class":3033},[3017,3688,3038],{"class":3037},[3017,3690,3041],{"class":3023},[3017,3692,3116],{"class":3037},[3017,3694,3695],{"class":3119},"1",[3017,3697,2971],{"class":3037},[3017,3699,3695],{"class":3119},[3017,3701,3123],{"class":3037},[3017,3703,3704],{"class":3092},"// initialCount: 1, maxCount: 1\n",[3017,3706,3707],{"class":3019,"line":3076},[3017,3708,3051],{"emptyLinePlaceholder":3050},[3017,3710,3711,3714,3717,3719,3722,3725,3728,3731],{"class":3019,"line":3096},[3017,3712,3713],{"class":3023},"    public",[3017,3715,3716],{"class":3023}," async",[3017,3718,3060],{"class":3059},[3017,3720,3721],{"class":3037},"\u003C",[3017,3723,3724],{"class":3023},"int",[3017,3726,3727],{"class":3037},"> ",[3017,3729,3730],{"class":3063},"IncrementAsync",[3017,3732,3067],{"class":3037},[3017,3734,3735],{"class":3019,"line":3102},[3017,3736,3099],{"class":3037},[3017,3738,3739],{"class":3019,"line":3129},[3017,3740,3741],{"class":3092},"        // Асинхронне очікування доступу (не блокує потік)\n",[3017,3743,3744,3746,3748,3750,3753],{"class":3019,"line":3135},[3017,3745,3105],{"class":3023},[3017,3747,3034],{"class":3033},[3017,3749,3110],{"class":3037},[3017,3751,3752],{"class":3063},"WaitAsync",[3017,3754,3044],{"class":3037},[3017,3756,3757],{"class":3019,"line":3268},[3017,3758,3759],{"class":3079},"        try\n",[3017,3761,3762],{"class":3019,"line":3273},[3017,3763,3764],{"class":3037},"        {\n",[3017,3766,3767],{"class":3019,"line":3298},[3017,3768,3769],{"class":3092},"            // Critical section — тільки один task одночасно\n",[3017,3771,3772,3775,3777,3779,3781,3783,3786,3788],{"class":3019,"line":3303},[3017,3773,3774],{"class":3023},"            await",[3017,3776,3060],{"class":3033},[3017,3778,3110],{"class":3037},[3017,3780,3113],{"class":3063},[3017,3782,3116],{"class":3037},[3017,3784,3785],{"class":3119},"10",[3017,3787,3123],{"class":3037},[3017,3789,3790],{"class":3092},"// ✅ await всередині \"lock\" — OK!\n",[3017,3792,3793,3796],{"class":3019,"line":3308},[3017,3794,3795],{"class":3033},"            _count",[3017,3797,3798],{"class":3037},"++;\n",[3017,3800,3801,3804,3806],{"class":3019,"line":3314},[3017,3802,3803],{"class":3079},"            return",[3017,3805,3673],{"class":3033},[3017,3807,3260],{"class":3037},[3017,3809,3810],{"class":3019,"line":3319},[3017,3811,3812],{"class":3037},"        }\n",[3017,3814,3815],{"class":3019,"line":3332},[3017,3816,3817],{"class":3079},"        finally\n",[3017,3819,3820],{"class":3019,"line":3349},[3017,3821,3764],{"class":3037},[3017,3823,3825],{"class":3019,"line":3824},19,[3017,3826,3827],{"class":3092},"            // Звільнення lock — ЗАВЖДИ у finally\n",[3017,3829,3831,3834,3836,3839],{"class":3019,"line":3830},20,[3017,3832,3833],{"class":3033},"            _lock",[3017,3835,3110],{"class":3037},[3017,3837,3838],{"class":3063},"Release",[3017,3840,3044],{"class":3037},[3017,3842,3844],{"class":3019,"line":3843},21,[3017,3845,3812],{"class":3037},[3017,3847,3849],{"class":3019,"line":3848},22,[3017,3850,3132],{"class":3037},[3017,3852,3854],{"class":3019,"line":3853},23,[3017,3855,3138],{"class":3037},[3017,3857,3859],{"class":3019,"line":3858},24,[3017,3860,3051],{"emptyLinePlaceholder":3050},[3017,3862,3864],{"class":3019,"line":3863},25,[3017,3865,3866],{"class":3092},"// Використання — 10 паралельних tasks\n",[3017,3868,3870,3873,3876,3878,3880,3883],{"class":3019,"line":3869},26,[3017,3871,3872],{"class":3023},"var",[3017,3874,3875],{"class":3033}," counter",[3017,3877,3038],{"class":3037},[3017,3879,3041],{"class":3023},[3017,3881,3882],{"class":3059}," AsyncCounter",[3017,3884,3044],{"class":3037},[3017,3886,3888,3890,3893,3895,3898,3900,3903,3905,3908,3910,3912],{"class":3019,"line":3887},27,[3017,3889,3872],{"class":3023},[3017,3891,3892],{"class":3033}," tasks",[3017,3894,3038],{"class":3037},[3017,3896,3897],{"class":3033},"Enumerable",[3017,3899,3110],{"class":3037},[3017,3901,3902],{"class":3063},"Range",[3017,3904,3116],{"class":3037},[3017,3906,3907],{"class":3119},"0",[3017,3909,2971],{"class":3037},[3017,3911,3785],{"class":3119},[3017,3913,3222],{"class":3037},[3017,3915,3917,3920,3923,3925,3928,3931,3934,3936,3938],{"class":3019,"line":3916},28,[3017,3918,3919],{"class":3037},"    .",[3017,3921,3922],{"class":3063},"Select",[3017,3924,3116],{"class":3037},[3017,3926,3927],{"class":3033},"_",[3017,3929,3930],{"class":3037}," => ",[3017,3932,3933],{"class":3033},"counter",[3017,3935,3110],{"class":3037},[3017,3937,3730],{"class":3063},[3017,3939,3940],{"class":3037},"())\n",[3017,3942,3944,3946,3949],{"class":3019,"line":3943},29,[3017,3945,3919],{"class":3037},[3017,3947,3948],{"class":3063},"ToArray",[3017,3950,3044],{"class":3037},[3017,3952,3954],{"class":3019,"line":3953},30,[3017,3955,3051],{"emptyLinePlaceholder":3050},[3017,3957,3959,3961,3963,3965,3968,3970,3973],{"class":3019,"line":3958},31,[3017,3960,3005],{"class":3023},[3017,3962,3060],{"class":3033},[3017,3964,3110],{"class":3037},[3017,3966,3967],{"class":3063},"WhenAll",[3017,3969,3116],{"class":3037},[3017,3971,3972],{"class":3033},"tasks",[3017,3974,3295],{"class":3037},[3017,3976,3978,3981,3983,3985,3987,3990,3992,3994,3996,3998,4000,4003,4005,4007],{"class":3019,"line":3977},32,[3017,3979,3980],{"class":3033},"Console",[3017,3982,3110],{"class":3037},[3017,3984,3419],{"class":3063},[3017,3986,3116],{"class":3037},[3017,3988,3989],{"class":3424},"$\"Final count: ",[3017,3991,3429],{"class":3428},[3017,3993,3005],{"class":3023},[3017,3995,3875],{"class":3033},[3017,3997,3110],{"class":3428},[3017,3999,3730],{"class":3063},[3017,4001,4002],{"class":3428},"()}",[3017,4004,3448],{"class":3424},[3017,4006,3123],{"class":3037},[3017,4008,4009],{"class":3092},"// 11\n",[4011,4012,4013,4016,4017,4020],"note",{},[2983,4014,4015],{},"Чому finally обов'язковий?"," Якщо exception виникне всередині critical section, ",[2968,4018,4019],{},"Release()"," має бути викликаний обов'язково. Інакше lock залишиться захопленим назавжди (deadlock для всіх наступних waiters).",[3192,4022,4024],{"id":4023},"pattern-idisposable-для-automatic-release","Pattern: IDisposable для Automatic Release",[2964,4026,4027,4028,4031],{},"Щоб уникнути ручного ",[2968,4029,4030],{},"try/finally",", можна створити helper:",[3008,4033,4036],{"className":3010,"code":4034,"filename":4035,"language":3012,"meta":3648,"style":3013},"class AsyncLock\n{\n    private readonly SemaphoreSlim _semaphore = new(1, 1);\n\n    public async Task\u003CIDisposable> LockAsync()\n    {\n        await _semaphore.WaitAsync();\n        return new ReleaseWrapper(_semaphore);\n    }\n\n    private class ReleaseWrapper : IDisposable\n    {\n        private readonly SemaphoreSlim _semaphore;\n\n        public ReleaseWrapper(SemaphoreSlim semaphore) => _semaphore = semaphore;\n\n        public void Dispose() => _semaphore.Release();\n    }\n}\n\n// Використання — елегантний синтаксис\nvar asyncLock = new AsyncLock();\n\nusing (await asyncLock.LockAsync())\n{\n    // Critical section\n    await Task.Delay(100);\n}  // Автоматичний Release при виході з using\n","AsyncLockHelper.cs",[2968,4037,4038,4045,4049,4074,4078,4098,4102,4114,4132,4136,4140,4155,4159,4172,4176,4202,4206,4227,4231,4235,4239,4244,4260,4264,4281,4285,4289,4305],{"__ignoreMap":3013},[3017,4039,4040,4042],{"class":3019,"line":3020},[3017,4041,3655],{"class":3023},[3017,4043,4044],{"class":3059}," AsyncLock\n",[3017,4046,4047],{"class":3019,"line":3047},[3017,4048,3073],{"class":3037},[3017,4050,4051,4053,4055,4057,4060,4062,4064,4066,4068,4070,4072],{"class":3019,"line":3054},[3017,4052,3667],{"class":3023},[3017,4054,3027],{"class":3023},[3017,4056,3684],{"class":3059},[3017,4058,4059],{"class":3033}," _semaphore",[3017,4061,3038],{"class":3037},[3017,4063,3041],{"class":3023},[3017,4065,3116],{"class":3037},[3017,4067,3695],{"class":3119},[3017,4069,2971],{"class":3037},[3017,4071,3695],{"class":3119},[3017,4073,3295],{"class":3037},[3017,4075,4076],{"class":3019,"line":3070},[3017,4077,3051],{"emptyLinePlaceholder":3050},[3017,4079,4080,4082,4084,4086,4088,4091,4093,4096],{"class":3019,"line":3076},[3017,4081,3713],{"class":3023},[3017,4083,3716],{"class":3023},[3017,4085,3060],{"class":3059},[3017,4087,3721],{"class":3037},[3017,4089,4090],{"class":3059},"IDisposable",[3017,4092,3727],{"class":3037},[3017,4094,4095],{"class":3063},"LockAsync",[3017,4097,3067],{"class":3037},[3017,4099,4100],{"class":3019,"line":3096},[3017,4101,3099],{"class":3037},[3017,4103,4104,4106,4108,4110,4112],{"class":3019,"line":3102},[3017,4105,3105],{"class":3023},[3017,4107,4059],{"class":3033},[3017,4109,3110],{"class":3037},[3017,4111,3752],{"class":3063},[3017,4113,3044],{"class":3037},[3017,4115,4116,4119,4122,4125,4127,4130],{"class":3019,"line":3129},[3017,4117,4118],{"class":3079},"        return",[3017,4120,4121],{"class":3023}," new",[3017,4123,4124],{"class":3059}," ReleaseWrapper",[3017,4126,3116],{"class":3037},[3017,4128,4129],{"class":3033},"_semaphore",[3017,4131,3295],{"class":3037},[3017,4133,4134],{"class":3019,"line":3135},[3017,4135,3132],{"class":3037},[3017,4137,4138],{"class":3019,"line":3268},[3017,4139,3051],{"emptyLinePlaceholder":3050},[3017,4141,4142,4144,4147,4149,4152],{"class":3019,"line":3273},[3017,4143,3667],{"class":3023},[3017,4145,4146],{"class":3023}," class",[3017,4148,4124],{"class":3059},[3017,4150,4151],{"class":3037}," : ",[3017,4153,4154],{"class":3059},"IDisposable\n",[3017,4156,4157],{"class":3019,"line":3298},[3017,4158,3099],{"class":3037},[3017,4160,4161,4164,4166,4168,4170],{"class":3019,"line":3303},[3017,4162,4163],{"class":3023},"        private",[3017,4165,3027],{"class":3023},[3017,4167,3684],{"class":3059},[3017,4169,4059],{"class":3033},[3017,4171,3260],{"class":3037},[3017,4173,4174],{"class":3019,"line":3308},[3017,4175,3051],{"emptyLinePlaceholder":3050},[3017,4177,4178,4181,4183,4185,4187,4190,4193,4195,4197,4200],{"class":3019,"line":3314},[3017,4179,4180],{"class":3023},"        public",[3017,4182,4124],{"class":3063},[3017,4184,3116],{"class":3037},[3017,4186,3618],{"class":3059},[3017,4188,4189],{"class":3033}," semaphore",[3017,4191,4192],{"class":3037},") => ",[3017,4194,4129],{"class":3033},[3017,4196,3038],{"class":3037},[3017,4198,4199],{"class":3033},"semaphore",[3017,4201,3260],{"class":3037},[3017,4203,4204],{"class":3019,"line":3319},[3017,4205,3051],{"emptyLinePlaceholder":3050},[3017,4207,4208,4210,4213,4216,4219,4221,4223,4225],{"class":3019,"line":3332},[3017,4209,4180],{"class":3023},[3017,4211,4212],{"class":3023}," void",[3017,4214,4215],{"class":3063}," Dispose",[3017,4217,4218],{"class":3037},"() => ",[3017,4220,4129],{"class":3033},[3017,4222,3110],{"class":3037},[3017,4224,3838],{"class":3063},[3017,4226,3044],{"class":3037},[3017,4228,4229],{"class":3019,"line":3349},[3017,4230,3132],{"class":3037},[3017,4232,4233],{"class":3019,"line":3824},[3017,4234,3138],{"class":3037},[3017,4236,4237],{"class":3019,"line":3830},[3017,4238,3051],{"emptyLinePlaceholder":3050},[3017,4240,4241],{"class":3019,"line":3843},[3017,4242,4243],{"class":3092},"// Використання — елегантний синтаксис\n",[3017,4245,4246,4248,4251,4253,4255,4258],{"class":3019,"line":3848},[3017,4247,3872],{"class":3023},[3017,4249,4250],{"class":3033}," asyncLock",[3017,4252,3038],{"class":3037},[3017,4254,3041],{"class":3023},[3017,4256,4257],{"class":3059}," AsyncLock",[3017,4259,3044],{"class":3037},[3017,4261,4262],{"class":3019,"line":3853},[3017,4263,3051],{"emptyLinePlaceholder":3050},[3017,4265,4266,4269,4271,4273,4275,4277,4279],{"class":3019,"line":3858},[3017,4267,4268],{"class":3079},"using",[3017,4270,3083],{"class":3037},[3017,4272,3005],{"class":3023},[3017,4274,4250],{"class":3033},[3017,4276,3110],{"class":3037},[3017,4278,4095],{"class":3063},[3017,4280,3940],{"class":3037},[3017,4282,4283],{"class":3019,"line":3863},[3017,4284,3073],{"class":3037},[3017,4286,4287],{"class":3019,"line":3869},[3017,4288,3231],{"class":3092},[3017,4290,4291,4293,4295,4297,4299,4301,4303],{"class":3019,"line":3887},[3017,4292,3581],{"class":3023},[3017,4294,3060],{"class":3033},[3017,4296,3110],{"class":3037},[3017,4298,3113],{"class":3063},[3017,4300,3116],{"class":3037},[3017,4302,3120],{"class":3119},[3017,4304,3295],{"class":3037},[3017,4306,4307,4310],{"class":3019,"line":3916},[3017,4308,4309],{"class":3037},"}  ",[3017,4311,4312],{"class":3092},"// Автоматичний Release при виході з using\n",[3192,4314,4316],{"id":4315},"порівняння-lock-vs-semaphoreslim","Порівняння: lock vs SemaphoreSlim",[4318,4319,4320,4339],"table",{},[4321,4322,4323],"thead",{},[4324,4325,4326,4330,4335],"tr",{},[4327,4328,4329],"th",{},"Аспект",[4327,4331,4332,4334],{},[2968,4333,2970],{}," (Monitor)",[4327,4336,4337],{},[2968,4338,3178],{},[4340,4341,4342,4361,4374,4387,4403,4420],"tbody",{},[4324,4343,4344,4350,4356],{},[4345,4346,4347],"td",{},[2983,4348,4349],{},"Async support",[4345,4351,4352,4353,4355],{},"❌ Не можна ",[2968,4354,3005],{}," всередині",[4345,4357,4358,4359],{},"✅ Повна підтримка ",[2968,4360,3005],{},[4324,4362,4363,4368,4371],{},[4345,4364,4365],{},[2983,4366,4367],{},"Thread affinity",[4345,4369,4370],{},"✅ Прив'язаний до потоку",[4345,4372,4373],{},"❌ Thread-agnostic",[4324,4375,4376,4381,4384],{},[4345,4377,4378],{},[2983,4379,4380],{},"Performance",[4345,4382,4383],{},"⚡ Найшвидший (user-mode)",[4345,4385,4386],{},"🐢 Повільніший (~2x)",[4324,4388,4389,4394,4397],{},[4345,4390,4391],{},[2983,4392,4393],{},"Cancellation",[4345,4395,4396],{},"❌ Немає",[4345,4398,4399,4400],{},"✅ ",[2968,4401,4402],{},"WaitAsync(CancellationToken)",[4324,4404,4405,4410,4415],{},[4345,4406,4407],{},[2983,4408,4409],{},"Timeout",[4345,4411,4399,4412],{},[2968,4413,4414],{},"Monitor.TryEnter(timeout)",[4345,4416,4399,4417],{},[2968,4418,4419],{},"WaitAsync(timeout)",[4324,4421,4422,4427,4430],{},[4345,4423,4424],{},[2983,4425,4426],{},"Use case",[4345,4428,4429],{},"Синхронний код",[4345,4431,4432],{},"Async код",[4434,4435,4436,4441],"tip",{},[2964,4437,4438],{},[2983,4439,4440],{},"Коли використовувати що:",[4442,4443,4444,4451],"ul",{},[4445,4446,4447,4450],"li",{},[2983,4448,4449],{},"lock:"," Синхронний код, критичні секції без I/O, максимальна швидкість.",[4445,4452,4453,4456,4457,4459],{},[2983,4454,4455],{},"SemaphoreSlim:"," Async код, критичні секції з ",[2968,4458,3005],{},", cancellation support.",[3185,4461],{},[2959,4463,4465],{"id":4464},"throttling-та-rate-limiting","Throttling та Rate Limiting",[3192,4467,4469],{"id":4468},"концепція-обмеження-паралелізму","Концепція: Обмеження Паралелізму",[2964,4471,4472,4473,4476,4477,3110],{},"Throttling — це обмеження кількості ",[2983,4474,4475],{},"одночасних"," операцій. Rate limiting — обмеження кількості операцій ",[2983,4478,4479],{},"за одиницю часу",[2964,4481,4482,4485],{},[2983,4483,4484],{},"Приклад:"," API дозволяє максимум 5 одночасних запитів та 100 запитів на хвилину.",[3192,4487,4489],{"id":4488},"throttling-через-semaphoreslim","Throttling через SemaphoreSlim",[2964,4491,4492,4495],{},[2968,4493,4494],{},"SemaphoreSlim(N, N)"," дозволяє максимум N одночасних операцій:",[3008,4497,4500],{"className":3010,"code":4498,"filename":4499,"language":3012,"meta":3648,"style":3013},"class ThrottledHttpClient\n{\n    private readonly HttpClient _http = new();\n    private readonly SemaphoreSlim _throttle = new(5, 5);  // Максимум 5 одночасних запитів\n\n    public async Task\u003Cstring> GetAsync(string url, CancellationToken ct = default)\n    {\n        // Чекаємо доки з'явиться \"слот\" для запиту\n        await _throttle.WaitAsync(ct);\n        try\n        {\n            Console.WriteLine($\"Запит до {url} (активних: {5 - _throttle.CurrentCount})\");\n            return await _http.GetStringAsync(url, ct);\n        }\n        finally\n        {\n            // Звільняємо слот\n            _throttle.Release();\n        }\n    }\n}\n\n// Використання — 20 паралельних запитів, але максимум 5 одночасно\nvar client = new ThrottledHttpClient();\nvar urls = Enumerable.Range(1, 20)\n    .Select(i => $\"https://jsonplaceholder.typicode.com/posts/{i}\")\n    .ToArray();\n\nvar tasks = urls.Select(url => client.GetAsync(url)).ToArray();\nvar results = await Task.WhenAll(tasks);\n\nConsole.WriteLine($\"Завантажено {results.Length} сторінок\");\n","ThrottlingExample.cs",[2968,4501,4502,4509,4513,4531,4560,4564,4604,4608,4613,4630,4634,4638,4683,4707,4711,4715,4719,4724,4735,4739,4743,4747,4751,4756,4772,4798,4824,4832,4836,4875,4898,4902],{"__ignoreMap":3013},[3017,4503,4504,4506],{"class":3019,"line":3020},[3017,4505,3655],{"class":3023},[3017,4507,4508],{"class":3059}," ThrottledHttpClient\n",[3017,4510,4511],{"class":3019,"line":3047},[3017,4512,3073],{"class":3037},[3017,4514,4515,4517,4519,4522,4525,4527,4529],{"class":3019,"line":3054},[3017,4516,3667],{"class":3023},[3017,4518,3027],{"class":3023},[3017,4520,4521],{"class":3059}," HttpClient",[3017,4523,4524],{"class":3033}," _http",[3017,4526,3038],{"class":3037},[3017,4528,3041],{"class":3023},[3017,4530,3044],{"class":3037},[3017,4532,4533,4535,4537,4539,4542,4544,4546,4548,4551,4553,4555,4557],{"class":3019,"line":3070},[3017,4534,3667],{"class":3023},[3017,4536,3027],{"class":3023},[3017,4538,3684],{"class":3059},[3017,4540,4541],{"class":3033}," _throttle",[3017,4543,3038],{"class":3037},[3017,4545,3041],{"class":3023},[3017,4547,3116],{"class":3037},[3017,4549,4550],{"class":3119},"5",[3017,4552,2971],{"class":3037},[3017,4554,4550],{"class":3119},[3017,4556,3123],{"class":3037},[3017,4558,4559],{"class":3092},"// Максимум 5 одночасних запитів\n",[3017,4561,4562],{"class":3019,"line":3076},[3017,4563,3051],{"emptyLinePlaceholder":3050},[3017,4565,4566,4568,4570,4572,4574,4577,4579,4582,4584,4586,4589,4591,4594,4597,4599,4602],{"class":3019,"line":3096},[3017,4567,3713],{"class":3023},[3017,4569,3716],{"class":3023},[3017,4571,3060],{"class":3059},[3017,4573,3721],{"class":3037},[3017,4575,4576],{"class":3023},"string",[3017,4578,3727],{"class":3037},[3017,4580,4581],{"class":3063},"GetAsync",[3017,4583,3116],{"class":3037},[3017,4585,4576],{"class":3023},[3017,4587,4588],{"class":3033}," url",[3017,4590,2971],{"class":3037},[3017,4592,4593],{"class":3059},"CancellationToken",[3017,4595,4596],{"class":3033}," ct",[3017,4598,3038],{"class":3037},[3017,4600,4601],{"class":3023},"default",[3017,4603,3222],{"class":3037},[3017,4605,4606],{"class":3019,"line":3102},[3017,4607,3099],{"class":3037},[3017,4609,4610],{"class":3019,"line":3129},[3017,4611,4612],{"class":3092},"        // Чекаємо доки з'явиться \"слот\" для запиту\n",[3017,4614,4615,4617,4619,4621,4623,4625,4628],{"class":3019,"line":3135},[3017,4616,3105],{"class":3023},[3017,4618,4541],{"class":3033},[3017,4620,3110],{"class":3037},[3017,4622,3752],{"class":3063},[3017,4624,3116],{"class":3037},[3017,4626,4627],{"class":3033},"ct",[3017,4629,3295],{"class":3037},[3017,4631,4632],{"class":3019,"line":3268},[3017,4633,3759],{"class":3079},[3017,4635,4636],{"class":3019,"line":3273},[3017,4637,3764],{"class":3037},[3017,4639,4640,4643,4645,4647,4649,4652,4654,4657,4659,4662,4664,4666,4669,4671,4673,4676,4678,4681],{"class":3019,"line":3298},[3017,4641,4642],{"class":3033},"            Console",[3017,4644,3110],{"class":3037},[3017,4646,3419],{"class":3063},[3017,4648,3116],{"class":3037},[3017,4650,4651],{"class":3424},"$\"Запит до ",[3017,4653,3429],{"class":3428},[3017,4655,4656],{"class":3033},"url",[3017,4658,3445],{"class":3428},[3017,4660,4661],{"class":3424}," (активних: ",[3017,4663,3429],{"class":3428},[3017,4665,4550],{"class":3119},[3017,4667,4668],{"class":3037}," -",[3017,4670,4541],{"class":3033},[3017,4672,3110],{"class":3428},[3017,4674,4675],{"class":3033},"CurrentCount",[3017,4677,3445],{"class":3428},[3017,4679,4680],{"class":3424},")\"",[3017,4682,3295],{"class":3037},[3017,4684,4685,4687,4690,4692,4694,4697,4699,4701,4703,4705],{"class":3019,"line":3303},[3017,4686,3803],{"class":3079},[3017,4688,4689],{"class":3023}," await",[3017,4691,4524],{"class":3033},[3017,4693,3110],{"class":3037},[3017,4695,4696],{"class":3063},"GetStringAsync",[3017,4698,3116],{"class":3037},[3017,4700,4656],{"class":3033},[3017,4702,2971],{"class":3037},[3017,4704,4627],{"class":3033},[3017,4706,3295],{"class":3037},[3017,4708,4709],{"class":3019,"line":3308},[3017,4710,3812],{"class":3037},[3017,4712,4713],{"class":3019,"line":3314},[3017,4714,3817],{"class":3079},[3017,4716,4717],{"class":3019,"line":3319},[3017,4718,3764],{"class":3037},[3017,4720,4721],{"class":3019,"line":3332},[3017,4722,4723],{"class":3092},"            // Звільняємо слот\n",[3017,4725,4726,4729,4731,4733],{"class":3019,"line":3349},[3017,4727,4728],{"class":3033},"            _throttle",[3017,4730,3110],{"class":3037},[3017,4732,3838],{"class":3063},[3017,4734,3044],{"class":3037},[3017,4736,4737],{"class":3019,"line":3824},[3017,4738,3812],{"class":3037},[3017,4740,4741],{"class":3019,"line":3830},[3017,4742,3132],{"class":3037},[3017,4744,4745],{"class":3019,"line":3843},[3017,4746,3138],{"class":3037},[3017,4748,4749],{"class":3019,"line":3848},[3017,4750,3051],{"emptyLinePlaceholder":3050},[3017,4752,4753],{"class":3019,"line":3853},[3017,4754,4755],{"class":3092},"// Використання — 20 паралельних запитів, але максимум 5 одночасно\n",[3017,4757,4758,4760,4763,4765,4767,4770],{"class":3019,"line":3858},[3017,4759,3872],{"class":3023},[3017,4761,4762],{"class":3033}," client",[3017,4764,3038],{"class":3037},[3017,4766,3041],{"class":3023},[3017,4768,4769],{"class":3059}," ThrottledHttpClient",[3017,4771,3044],{"class":3037},[3017,4773,4774,4776,4779,4781,4783,4785,4787,4789,4791,4793,4796],{"class":3019,"line":3863},[3017,4775,3872],{"class":3023},[3017,4777,4778],{"class":3033}," urls",[3017,4780,3038],{"class":3037},[3017,4782,3897],{"class":3033},[3017,4784,3110],{"class":3037},[3017,4786,3902],{"class":3063},[3017,4788,3116],{"class":3037},[3017,4790,3695],{"class":3119},[3017,4792,2971],{"class":3037},[3017,4794,4795],{"class":3119},"20",[3017,4797,3222],{"class":3037},[3017,4799,4800,4802,4804,4806,4809,4811,4814,4816,4818,4820,4822],{"class":3019,"line":3869},[3017,4801,3919],{"class":3037},[3017,4803,3922],{"class":3063},[3017,4805,3116],{"class":3037},[3017,4807,4808],{"class":3033},"i",[3017,4810,3930],{"class":3037},[3017,4812,4813],{"class":3424},"$\"https://jsonplaceholder.typicode.com/posts/",[3017,4815,3429],{"class":3428},[3017,4817,4808],{"class":3033},[3017,4819,3445],{"class":3428},[3017,4821,3448],{"class":3424},[3017,4823,3222],{"class":3037},[3017,4825,4826,4828,4830],{"class":3019,"line":3887},[3017,4827,3919],{"class":3037},[3017,4829,3948],{"class":3063},[3017,4831,3044],{"class":3037},[3017,4833,4834],{"class":3019,"line":3916},[3017,4835,3051],{"emptyLinePlaceholder":3050},[3017,4837,4838,4840,4842,4844,4847,4849,4851,4853,4855,4857,4860,4862,4864,4866,4868,4871,4873],{"class":3019,"line":3943},[3017,4839,3872],{"class":3023},[3017,4841,3892],{"class":3033},[3017,4843,3038],{"class":3037},[3017,4845,4846],{"class":3033},"urls",[3017,4848,3110],{"class":3037},[3017,4850,3922],{"class":3063},[3017,4852,3116],{"class":3037},[3017,4854,4656],{"class":3033},[3017,4856,3930],{"class":3037},[3017,4858,4859],{"class":3033},"client",[3017,4861,3110],{"class":3037},[3017,4863,4581],{"class":3063},[3017,4865,3116],{"class":3037},[3017,4867,4656],{"class":3033},[3017,4869,4870],{"class":3037},")).",[3017,4872,3948],{"class":3063},[3017,4874,3044],{"class":3037},[3017,4876,4877,4879,4882,4884,4886,4888,4890,4892,4894,4896],{"class":3019,"line":3953},[3017,4878,3872],{"class":3023},[3017,4880,4881],{"class":3033}," results",[3017,4883,3038],{"class":3037},[3017,4885,3005],{"class":3023},[3017,4887,3060],{"class":3033},[3017,4889,3110],{"class":3037},[3017,4891,3967],{"class":3063},[3017,4893,3116],{"class":3037},[3017,4895,3972],{"class":3033},[3017,4897,3295],{"class":3037},[3017,4899,4900],{"class":3019,"line":3958},[3017,4901,3051],{"emptyLinePlaceholder":3050},[3017,4903,4904,4906,4908,4910,4912,4915,4917,4920,4922,4925,4927,4930],{"class":3019,"line":3977},[3017,4905,3980],{"class":3033},[3017,4907,3110],{"class":3037},[3017,4909,3419],{"class":3063},[3017,4911,3116],{"class":3037},[3017,4913,4914],{"class":3424},"$\"Завантажено ",[3017,4916,3429],{"class":3428},[3017,4918,4919],{"class":3033},"results",[3017,4921,3110],{"class":3428},[3017,4923,4924],{"class":3033},"Length",[3017,4926,3445],{"class":3428},[3017,4928,4929],{"class":3424}," сторінок\"",[3017,4931,3295],{"class":3037},[4933,4934,4936,4941,4945,4949,4953,4957,4965,4969,4973,4977],"terminal-preview",{"title":4935},"Throttling Output",[4937,4938,4940],"div",{"className":4939},[3019],"Запит до https://jsonplaceholder.typicode.com/posts/1 (активних: 1)",[4937,4942,4944],{"className":4943},[3019],"Запит до https://jsonplaceholder.typicode.com/posts/2 (активних: 2)",[4937,4946,4948],{"className":4947},[3019],"Запит до https://jsonplaceholder.typicode.com/posts/3 (активних: 3)",[4937,4950,4952],{"className":4951},[3019],"Запит до https://jsonplaceholder.typicode.com/posts/4 (активних: 4)",[4937,4954,4956],{"className":4955},[3019],"Запит до https://jsonplaceholder.typicode.com/posts/5 (активних: 5)",[4937,4958,4960],{"className":4959},[3019],[3017,4961,4964],{"className":4962},[4963],"text-yellow-400","... чекаємо завершення одного з 5 запитів ...",[4937,4966,4968],{"className":4967},[3019],"Запит до https://jsonplaceholder.typicode.com/posts/6 (активних: 5)",[4937,4970,4972],{"className":4971},[3019],"Запит до https://jsonplaceholder.typicode.com/posts/7 (активних: 5)",[4937,4974,4976],{"className":4975},[3019],"...",[4937,4978,4980],{"className":4979},[3019],[3017,4981,4984],{"className":4982},[4983],"text-green-400","Завантажено 20 сторінок",[3192,4986,4988],{"id":4987},"rate-limiting-sliding-window","Rate Limiting: Sliding Window",[2964,4990,4991],{},"Для обмеження кількості операцій за одиницю часу потрібен складніший алгоритм:",[3008,4993,4996],{"className":3010,"code":4994,"filename":4995,"language":3012,"meta":3648,"style":3013},"class RateLimiter\n{\n    private readonly int _maxRequests;\n    private readonly TimeSpan _timeWindow;\n    private readonly Queue\u003CDateTime> _requestTimestamps = new();\n    private readonly SemaphoreSlim _lock = new(1, 1);\n\n    public RateLimiter(int maxRequests, TimeSpan timeWindow)\n    {\n        _maxRequests = maxRequests;\n        _timeWindow = timeWindow;\n    }\n\n    public async Task WaitAsync(CancellationToken ct = default)\n    {\n        await _lock.WaitAsync(ct);\n        try\n        {\n            var now = DateTime.UtcNow;\n            var windowStart = now - _timeWindow;\n\n            // Видаляємо старі timestamps (поза вікном)\n            while (_requestTimestamps.Count > 0 && _requestTimestamps.Peek() \u003C windowStart)\n            {\n                _requestTimestamps.Dequeue();\n            }\n\n            // Якщо досягнуто ліміту — чекаємо\n            if (_requestTimestamps.Count >= _maxRequests)\n            {\n                var oldestRequest = _requestTimestamps.Peek();\n                var delay = oldestRequest + _timeWindow - now;\n\n                if (delay > TimeSpan.Zero)\n                {\n                    Console.WriteLine($\"Rate limit досягнуто. Чекаємо {delay.TotalSeconds:F1}s...\");\n                    await Task.Delay(delay, ct);\n                }\n\n                // Після затримки — видаляємо найстаріший\n                _requestTimestamps.Dequeue();\n            }\n\n            // Реєструємо новий запит\n            _requestTimestamps.Enqueue(now);\n        }\n        finally\n        {\n            _lock.Release();\n        }\n    }\n}\n\n// Використання — максимум 10 запитів на 5 секунд\nvar rateLimiter = new RateLimiter(maxRequests: 10, timeWindow: TimeSpan.FromSeconds(5));\n\nfor (int i = 0; i \u003C 25; i++)\n{\n    await rateLimiter.WaitAsync();\n    Console.WriteLine($\"Запит {i + 1} виконано о {DateTime.Now:HH:mm:ss.fff}\");\n}\n","RateLimiter.cs",[2968,4997,4998,5005,5009,5022,5036,5061,5085,5089,5113,5117,5129,5141,5145,5149,5172,5176,5192,5196,5200,5219,5239,5243,5248,5285,5290,5302,5307,5311,5316,5337,5341,5359,5382,5387,5409,5415,5451,5473,5479,5484,5490,5501,5506,5511,5517,5534,5539,5544,5549,5560,5565,5570,5575,5580,5586,5629,5634,5669,5674,5687,5752],{"__ignoreMap":3013},[3017,4999,5000,5002],{"class":3019,"line":3020},[3017,5001,3655],{"class":3023},[3017,5003,5004],{"class":3059}," RateLimiter\n",[3017,5006,5007],{"class":3019,"line":3047},[3017,5008,3073],{"class":3037},[3017,5010,5011,5013,5015,5017,5020],{"class":3019,"line":3054},[3017,5012,3667],{"class":3023},[3017,5014,3027],{"class":3023},[3017,5016,3670],{"class":3023},[3017,5018,5019],{"class":3033}," _maxRequests",[3017,5021,3260],{"class":3037},[3017,5023,5024,5026,5028,5031,5034],{"class":3019,"line":3070},[3017,5025,3667],{"class":3023},[3017,5027,3027],{"class":3023},[3017,5029,5030],{"class":3059}," TimeSpan",[3017,5032,5033],{"class":3033}," _timeWindow",[3017,5035,3260],{"class":3037},[3017,5037,5038,5040,5042,5045,5047,5050,5052,5055,5057,5059],{"class":3019,"line":3076},[3017,5039,3667],{"class":3023},[3017,5041,3027],{"class":3023},[3017,5043,5044],{"class":3059}," Queue",[3017,5046,3721],{"class":3037},[3017,5048,5049],{"class":3059},"DateTime",[3017,5051,3727],{"class":3037},[3017,5053,5054],{"class":3033},"_requestTimestamps",[3017,5056,3038],{"class":3037},[3017,5058,3041],{"class":3023},[3017,5060,3044],{"class":3037},[3017,5062,5063,5065,5067,5069,5071,5073,5075,5077,5079,5081,5083],{"class":3019,"line":3096},[3017,5064,3667],{"class":3023},[3017,5066,3027],{"class":3023},[3017,5068,3684],{"class":3059},[3017,5070,3034],{"class":3033},[3017,5072,3038],{"class":3037},[3017,5074,3041],{"class":3023},[3017,5076,3116],{"class":3037},[3017,5078,3695],{"class":3119},[3017,5080,2971],{"class":3037},[3017,5082,3695],{"class":3119},[3017,5084,3295],{"class":3037},[3017,5086,5087],{"class":3019,"line":3102},[3017,5088,3051],{"emptyLinePlaceholder":3050},[3017,5090,5091,5093,5096,5098,5100,5103,5105,5108,5111],{"class":3019,"line":3129},[3017,5092,3713],{"class":3023},[3017,5094,5095],{"class":3063}," RateLimiter",[3017,5097,3116],{"class":3037},[3017,5099,3724],{"class":3023},[3017,5101,5102],{"class":3033}," maxRequests",[3017,5104,2971],{"class":3037},[3017,5106,5107],{"class":3059},"TimeSpan",[3017,5109,5110],{"class":3033}," timeWindow",[3017,5112,3222],{"class":3037},[3017,5114,5115],{"class":3019,"line":3135},[3017,5116,3099],{"class":3037},[3017,5118,5119,5122,5124,5127],{"class":3019,"line":3268},[3017,5120,5121],{"class":3033},"        _maxRequests",[3017,5123,3038],{"class":3037},[3017,5125,5126],{"class":3033},"maxRequests",[3017,5128,3260],{"class":3037},[3017,5130,5131,5134,5136,5139],{"class":3019,"line":3273},[3017,5132,5133],{"class":3033},"        _timeWindow",[3017,5135,3038],{"class":3037},[3017,5137,5138],{"class":3033},"timeWindow",[3017,5140,3260],{"class":3037},[3017,5142,5143],{"class":3019,"line":3298},[3017,5144,3132],{"class":3037},[3017,5146,5147],{"class":3019,"line":3303},[3017,5148,3051],{"emptyLinePlaceholder":3050},[3017,5150,5151,5153,5155,5157,5160,5162,5164,5166,5168,5170],{"class":3019,"line":3308},[3017,5152,3713],{"class":3023},[3017,5154,3716],{"class":3023},[3017,5156,3060],{"class":3059},[3017,5158,5159],{"class":3063}," WaitAsync",[3017,5161,3116],{"class":3037},[3017,5163,4593],{"class":3059},[3017,5165,4596],{"class":3033},[3017,5167,3038],{"class":3037},[3017,5169,4601],{"class":3023},[3017,5171,3222],{"class":3037},[3017,5173,5174],{"class":3019,"line":3314},[3017,5175,3099],{"class":3037},[3017,5177,5178,5180,5182,5184,5186,5188,5190],{"class":3019,"line":3319},[3017,5179,3105],{"class":3023},[3017,5181,3034],{"class":3033},[3017,5183,3110],{"class":3037},[3017,5185,3752],{"class":3063},[3017,5187,3116],{"class":3037},[3017,5189,4627],{"class":3033},[3017,5191,3295],{"class":3037},[3017,5193,5194],{"class":3019,"line":3332},[3017,5195,3759],{"class":3079},[3017,5197,5198],{"class":3019,"line":3349},[3017,5199,3764],{"class":3037},[3017,5201,5202,5205,5208,5210,5212,5214,5217],{"class":3019,"line":3824},[3017,5203,5204],{"class":3023},"            var",[3017,5206,5207],{"class":3033}," now",[3017,5209,3038],{"class":3037},[3017,5211,5049],{"class":3033},[3017,5213,3110],{"class":3037},[3017,5215,5216],{"class":3033},"UtcNow",[3017,5218,3260],{"class":3037},[3017,5220,5221,5223,5226,5228,5231,5234,5237],{"class":3019,"line":3830},[3017,5222,5204],{"class":3023},[3017,5224,5225],{"class":3033}," windowStart",[3017,5227,3038],{"class":3037},[3017,5229,5230],{"class":3033},"now",[3017,5232,5233],{"class":3037}," - ",[3017,5235,5236],{"class":3033},"_timeWindow",[3017,5238,3260],{"class":3037},[3017,5240,5241],{"class":3019,"line":3843},[3017,5242,3051],{"emptyLinePlaceholder":3050},[3017,5244,5245],{"class":3019,"line":3848},[3017,5246,5247],{"class":3092},"            // Видаляємо старі timestamps (поза вікном)\n",[3017,5249,5250,5253,5255,5257,5259,5262,5265,5267,5270,5272,5274,5277,5280,5283],{"class":3019,"line":3853},[3017,5251,5252],{"class":3079},"            while",[3017,5254,3083],{"class":3037},[3017,5256,5054],{"class":3033},[3017,5258,3110],{"class":3037},[3017,5260,5261],{"class":3033},"Count",[3017,5263,5264],{"class":3037}," > ",[3017,5266,3907],{"class":3119},[3017,5268,5269],{"class":3037}," && ",[3017,5271,5054],{"class":3033},[3017,5273,3110],{"class":3037},[3017,5275,5276],{"class":3063},"Peek",[3017,5278,5279],{"class":3037},"() \u003C ",[3017,5281,5282],{"class":3033},"windowStart",[3017,5284,3222],{"class":3037},[3017,5286,5287],{"class":3019,"line":3858},[3017,5288,5289],{"class":3037},"            {\n",[3017,5291,5292,5295,5297,5300],{"class":3019,"line":3863},[3017,5293,5294],{"class":3033},"                _requestTimestamps",[3017,5296,3110],{"class":3037},[3017,5298,5299],{"class":3063},"Dequeue",[3017,5301,3044],{"class":3037},[3017,5303,5304],{"class":3019,"line":3869},[3017,5305,5306],{"class":3037},"            }\n",[3017,5308,5309],{"class":3019,"line":3887},[3017,5310,3051],{"emptyLinePlaceholder":3050},[3017,5312,5313],{"class":3019,"line":3916},[3017,5314,5315],{"class":3092},"            // Якщо досягнуто ліміту — чекаємо\n",[3017,5317,5318,5321,5323,5325,5327,5329,5332,5335],{"class":3019,"line":3943},[3017,5319,5320],{"class":3079},"            if",[3017,5322,3083],{"class":3037},[3017,5324,5054],{"class":3033},[3017,5326,3110],{"class":3037},[3017,5328,5261],{"class":3033},[3017,5330,5331],{"class":3037}," >= ",[3017,5333,5334],{"class":3033},"_maxRequests",[3017,5336,3222],{"class":3037},[3017,5338,5339],{"class":3019,"line":3953},[3017,5340,5289],{"class":3037},[3017,5342,5343,5346,5349,5351,5353,5355,5357],{"class":3019,"line":3958},[3017,5344,5345],{"class":3023},"                var",[3017,5347,5348],{"class":3033}," oldestRequest",[3017,5350,3038],{"class":3037},[3017,5352,5054],{"class":3033},[3017,5354,3110],{"class":3037},[3017,5356,5276],{"class":3063},[3017,5358,3044],{"class":3037},[3017,5360,5361,5363,5366,5368,5371,5374,5376,5378,5380],{"class":3019,"line":3977},[3017,5362,5345],{"class":3023},[3017,5364,5365],{"class":3033}," delay",[3017,5367,3038],{"class":3037},[3017,5369,5370],{"class":3033},"oldestRequest",[3017,5372,5373],{"class":3037}," + ",[3017,5375,5236],{"class":3033},[3017,5377,5233],{"class":3037},[3017,5379,5230],{"class":3033},[3017,5381,3260],{"class":3037},[3017,5383,5385],{"class":3019,"line":5384},33,[3017,5386,3051],{"emptyLinePlaceholder":3050},[3017,5388,5390,5393,5395,5398,5400,5402,5404,5407],{"class":3019,"line":5389},34,[3017,5391,5392],{"class":3079},"                if",[3017,5394,3083],{"class":3037},[3017,5396,5397],{"class":3033},"delay",[3017,5399,5264],{"class":3037},[3017,5401,5107],{"class":3033},[3017,5403,3110],{"class":3037},[3017,5405,5406],{"class":3033},"Zero",[3017,5408,3222],{"class":3037},[3017,5410,5412],{"class":3019,"line":5411},35,[3017,5413,5414],{"class":3037},"                {\n",[3017,5416,5418,5421,5423,5425,5427,5430,5432,5434,5436,5439,5441,5444,5446,5449],{"class":3019,"line":5417},36,[3017,5419,5420],{"class":3033},"                    Console",[3017,5422,3110],{"class":3037},[3017,5424,3419],{"class":3063},[3017,5426,3116],{"class":3037},[3017,5428,5429],{"class":3424},"$\"Rate limit досягнуто. Чекаємо ",[3017,5431,3429],{"class":3428},[3017,5433,5397],{"class":3033},[3017,5435,3110],{"class":3428},[3017,5437,5438],{"class":3033},"TotalSeconds",[3017,5440,3201],{"class":3037},[3017,5442,5443],{"class":3033},"F1",[3017,5445,3445],{"class":3428},[3017,5447,5448],{"class":3424},"s...\"",[3017,5450,3295],{"class":3037},[3017,5452,5454,5457,5459,5461,5463,5465,5467,5469,5471],{"class":3019,"line":5453},37,[3017,5455,5456],{"class":3023},"                    await",[3017,5458,3060],{"class":3033},[3017,5460,3110],{"class":3037},[3017,5462,3113],{"class":3063},[3017,5464,3116],{"class":3037},[3017,5466,5397],{"class":3033},[3017,5468,2971],{"class":3037},[3017,5470,4627],{"class":3033},[3017,5472,3295],{"class":3037},[3017,5474,5476],{"class":3019,"line":5475},38,[3017,5477,5478],{"class":3037},"                }\n",[3017,5480,5482],{"class":3019,"line":5481},39,[3017,5483,3051],{"emptyLinePlaceholder":3050},[3017,5485,5487],{"class":3019,"line":5486},40,[3017,5488,5489],{"class":3092},"                // Після затримки — видаляємо найстаріший\n",[3017,5491,5493,5495,5497,5499],{"class":3019,"line":5492},41,[3017,5494,5294],{"class":3033},[3017,5496,3110],{"class":3037},[3017,5498,5299],{"class":3063},[3017,5500,3044],{"class":3037},[3017,5502,5504],{"class":3019,"line":5503},42,[3017,5505,5306],{"class":3037},[3017,5507,5509],{"class":3019,"line":5508},43,[3017,5510,3051],{"emptyLinePlaceholder":3050},[3017,5512,5514],{"class":3019,"line":5513},44,[3017,5515,5516],{"class":3092},"            // Реєструємо новий запит\n",[3017,5518,5520,5523,5525,5528,5530,5532],{"class":3019,"line":5519},45,[3017,5521,5522],{"class":3033},"            _requestTimestamps",[3017,5524,3110],{"class":3037},[3017,5526,5527],{"class":3063},"Enqueue",[3017,5529,3116],{"class":3037},[3017,5531,5230],{"class":3033},[3017,5533,3295],{"class":3037},[3017,5535,5537],{"class":3019,"line":5536},46,[3017,5538,3812],{"class":3037},[3017,5540,5542],{"class":3019,"line":5541},47,[3017,5543,3817],{"class":3079},[3017,5545,5547],{"class":3019,"line":5546},48,[3017,5548,3764],{"class":3037},[3017,5550,5552,5554,5556,5558],{"class":3019,"line":5551},49,[3017,5553,3833],{"class":3033},[3017,5555,3110],{"class":3037},[3017,5557,3838],{"class":3063},[3017,5559,3044],{"class":3037},[3017,5561,5563],{"class":3019,"line":5562},50,[3017,5564,3812],{"class":3037},[3017,5566,5568],{"class":3019,"line":5567},51,[3017,5569,3132],{"class":3037},[3017,5571,5573],{"class":3019,"line":5572},52,[3017,5574,3138],{"class":3037},[3017,5576,5578],{"class":3019,"line":5577},53,[3017,5579,3051],{"emptyLinePlaceholder":3050},[3017,5581,5583],{"class":3019,"line":5582},54,[3017,5584,5585],{"class":3092},"// Використання — максимум 10 запитів на 5 секунд\n",[3017,5587,5589,5591,5594,5596,5598,5600,5602,5604,5607,5609,5611,5613,5615,5617,5619,5622,5624,5626],{"class":3019,"line":5588},55,[3017,5590,3872],{"class":3023},[3017,5592,5593],{"class":3033}," rateLimiter",[3017,5595,3038],{"class":3037},[3017,5597,3041],{"class":3023},[3017,5599,5095],{"class":3059},[3017,5601,3116],{"class":3037},[3017,5603,5126],{"class":3033},[3017,5605,5606],{"class":3037},": ",[3017,5608,3785],{"class":3119},[3017,5610,2971],{"class":3037},[3017,5612,5138],{"class":3033},[3017,5614,5606],{"class":3037},[3017,5616,5107],{"class":3033},[3017,5618,3110],{"class":3037},[3017,5620,5621],{"class":3063},"FromSeconds",[3017,5623,3116],{"class":3037},[3017,5625,4550],{"class":3119},[3017,5627,5628],{"class":3037},"));\n",[3017,5630,5632],{"class":3019,"line":5631},56,[3017,5633,3051],{"emptyLinePlaceholder":3050},[3017,5635,5637,5640,5642,5644,5647,5649,5651,5654,5656,5659,5662,5664,5666],{"class":3019,"line":5636},57,[3017,5638,5639],{"class":3079},"for",[3017,5641,3083],{"class":3037},[3017,5643,3724],{"class":3023},[3017,5645,5646],{"class":3033}," i",[3017,5648,3038],{"class":3037},[3017,5650,3907],{"class":3119},[3017,5652,5653],{"class":3037},"; ",[3017,5655,4808],{"class":3033},[3017,5657,5658],{"class":3037}," \u003C ",[3017,5660,5661],{"class":3119},"25",[3017,5663,5653],{"class":3037},[3017,5665,4808],{"class":3033},[3017,5667,5668],{"class":3037},"++)\n",[3017,5670,5672],{"class":3019,"line":5671},58,[3017,5673,3073],{"class":3037},[3017,5675,5677,5679,5681,5683,5685],{"class":3019,"line":5676},59,[3017,5678,3581],{"class":3023},[3017,5680,5593],{"class":3033},[3017,5682,3110],{"class":3037},[3017,5684,3752],{"class":3063},[3017,5686,3044],{"class":3037},[3017,5688,5690,5693,5695,5697,5699,5702,5704,5706,5709,5712,5714,5717,5719,5721,5723,5726,5728,5731,5733,5736,5738,5741,5743,5746,5748,5750],{"class":3019,"line":5689},60,[3017,5691,5692],{"class":3033},"    Console",[3017,5694,3110],{"class":3037},[3017,5696,3419],{"class":3063},[3017,5698,3116],{"class":3037},[3017,5700,5701],{"class":3424},"$\"Запит ",[3017,5703,3429],{"class":3428},[3017,5705,4808],{"class":3033},[3017,5707,5708],{"class":3037}," +",[3017,5710,5711],{"class":3119}," 1",[3017,5713,3445],{"class":3428},[3017,5715,5716],{"class":3424}," виконано о ",[3017,5718,3429],{"class":3428},[3017,5720,5049],{"class":3033},[3017,5722,3110],{"class":3428},[3017,5724,5725],{"class":3033},"Now",[3017,5727,3201],{"class":3037},[3017,5729,5730],{"class":3033},"HH",[3017,5732,3201],{"class":3037},[3017,5734,5735],{"class":3033},"mm",[3017,5737,3201],{"class":3037},[3017,5739,5740],{"class":3033},"ss",[3017,5742,3110],{"class":3428},[3017,5744,5745],{"class":3033},"fff",[3017,5747,3445],{"class":3428},[3017,5749,3448],{"class":3424},[3017,5751,3295],{"class":3037},[3017,5753,5755],{"class":3019,"line":5754},61,[3017,5756,3138],{"class":3037},[4011,5758,5759,5762],{},[2983,5760,5761],{},"Sliding Window vs Fixed Window:"," Sliding window рахує запити у рухомому вікні (останні N секунд). Fixed window скидає лічильник кожні N секунд (простіший, але може пропустити burst на межі вікон).",[3185,5764],{},[2959,5766,5768],{"id":5767},"timeout-та-cancellation-patterns","Timeout та Cancellation Patterns",[3192,5770,5772],{"id":5771},"проблема-як-встановити-timeout-для-async-операції","Проблема: Як Встановити Timeout для Async Операції",[2964,5774,5775,5776,5778],{},"Стандартний ",[2968,5777,3005],{}," не має вбудованого timeout. Якщо операція \"зависла\" — вона чекатиме нескінченно.",[3192,5780,5782],{"id":5781},"pattern-1-taskwhenany-з-taskdelay","Pattern 1: Task.WhenAny з Task.Delay",[2964,5784,5785],{},"Найпростіший спосіб — змагання між операцією та таймером:",[3008,5787,5790],{"className":3010,"code":5788,"filename":5789,"language":3012,"meta":3648,"style":3013},"static async Task\u003CT> WithTimeout\u003CT>(Task\u003CT> task, TimeSpan timeout)\n{\n    var delayTask = Task.Delay(timeout);\n    var completedTask = await Task.WhenAny(task, delayTask);\n\n    if (completedTask == delayTask)\n    {\n        throw new TimeoutException($\"Операція не завершилась за {timeout}\");\n    }\n\n    return await task;  // Повертаємо результат\n}\n\n// Використання\ntry\n{\n    var result = await WithTimeout(\n        SlowOperationAsync(),\n        TimeSpan.FromSeconds(5)\n    );\n    Console.WriteLine($\"Результат: {result}\");\n}\ncatch (TimeoutException ex)\n{\n    Console.WriteLine($\"Таймаут: {ex.Message}\");\n}\n\nasync Task\u003Cstring> SlowOperationAsync()\n{\n    await Task.Delay(10_000);  // 10 секунд\n    return \"Completed\";\n}\n","TimeoutPattern1.cs",[2968,5791,5792,5839,5843,5866,5895,5899,5915,5919,5944,5948,5952,5968,5972,5976,5981,5985,5989,6006,6014,6029,6034,6058,6062,6077,6081,6110,6114,6118,6135,6139,6159,6168],{"__ignoreMap":3013},[3017,5793,5794,5797,5799,5801,5803,5806,5808,5811,5813,5815,5818,5821,5823,5825,5827,5830,5832,5834,5837],{"class":3019,"line":3020},[3017,5795,5796],{"class":3023},"static",[3017,5798,3716],{"class":3023},[3017,5800,3060],{"class":3059},[3017,5802,3721],{"class":3037},[3017,5804,5805],{"class":3059},"T",[3017,5807,3727],{"class":3037},[3017,5809,5810],{"class":3063},"WithTimeout",[3017,5812,3721],{"class":3037},[3017,5814,5805],{"class":3059},[3017,5816,5817],{"class":3037},">(",[3017,5819,5820],{"class":3059},"Task",[3017,5822,3721],{"class":3037},[3017,5824,5805],{"class":3059},[3017,5826,3727],{"class":3037},[3017,5828,5829],{"class":3033},"task",[3017,5831,2971],{"class":3037},[3017,5833,5107],{"class":3059},[3017,5835,5836],{"class":3033}," timeout",[3017,5838,3222],{"class":3037},[3017,5840,5841],{"class":3019,"line":3047},[3017,5842,3073],{"class":3037},[3017,5844,5845,5848,5851,5853,5855,5857,5859,5861,5864],{"class":3019,"line":3054},[3017,5846,5847],{"class":3023},"    var",[3017,5849,5850],{"class":3033}," delayTask",[3017,5852,3038],{"class":3037},[3017,5854,5820],{"class":3033},[3017,5856,3110],{"class":3037},[3017,5858,3113],{"class":3063},[3017,5860,3116],{"class":3037},[3017,5862,5863],{"class":3033},"timeout",[3017,5865,3295],{"class":3037},[3017,5867,5868,5870,5873,5875,5877,5879,5881,5884,5886,5888,5890,5893],{"class":3019,"line":3070},[3017,5869,5847],{"class":3023},[3017,5871,5872],{"class":3033}," completedTask",[3017,5874,3038],{"class":3037},[3017,5876,3005],{"class":3023},[3017,5878,3060],{"class":3033},[3017,5880,3110],{"class":3037},[3017,5882,5883],{"class":3063},"WhenAny",[3017,5885,3116],{"class":3037},[3017,5887,5829],{"class":3033},[3017,5889,2971],{"class":3037},[3017,5891,5892],{"class":3033},"delayTask",[3017,5894,3295],{"class":3037},[3017,5896,5897],{"class":3019,"line":3076},[3017,5898,3051],{"emptyLinePlaceholder":3050},[3017,5900,5901,5903,5905,5908,5911,5913],{"class":3019,"line":3096},[3017,5902,3322],{"class":3079},[3017,5904,3083],{"class":3037},[3017,5906,5907],{"class":3033},"completedTask",[3017,5909,5910],{"class":3037}," == ",[3017,5912,5892],{"class":3033},[3017,5914,3222],{"class":3037},[3017,5916,5917],{"class":3019,"line":3102},[3017,5918,3099],{"class":3037},[3017,5920,5921,5924,5926,5929,5931,5934,5936,5938,5940,5942],{"class":3019,"line":3129},[3017,5922,5923],{"class":3079},"        throw",[3017,5925,4121],{"class":3023},[3017,5927,5928],{"class":3059}," TimeoutException",[3017,5930,3116],{"class":3037},[3017,5932,5933],{"class":3424},"$\"Операція не завершилась за ",[3017,5935,3429],{"class":3428},[3017,5937,5863],{"class":3033},[3017,5939,3445],{"class":3428},[3017,5941,3448],{"class":3424},[3017,5943,3295],{"class":3037},[3017,5945,5946],{"class":3019,"line":3135},[3017,5947,3132],{"class":3037},[3017,5949,5950],{"class":3019,"line":3268},[3017,5951,3051],{"emptyLinePlaceholder":3050},[3017,5953,5954,5957,5959,5962,5965],{"class":3019,"line":3273},[3017,5955,5956],{"class":3079},"    return",[3017,5958,4689],{"class":3023},[3017,5960,5961],{"class":3033}," task",[3017,5963,5964],{"class":3037},";  ",[3017,5966,5967],{"class":3092},"// Повертаємо результат\n",[3017,5969,5970],{"class":3019,"line":3298},[3017,5971,3138],{"class":3037},[3017,5973,5974],{"class":3019,"line":3303},[3017,5975,3051],{"emptyLinePlaceholder":3050},[3017,5977,5978],{"class":3019,"line":3308},[3017,5979,5980],{"class":3092},"// Використання\n",[3017,5982,5983],{"class":3019,"line":3314},[3017,5984,3265],{"class":3079},[3017,5986,5987],{"class":3019,"line":3319},[3017,5988,3073],{"class":3037},[3017,5990,5991,5993,5996,5998,6000,6003],{"class":3019,"line":3332},[3017,5992,5847],{"class":3023},[3017,5994,5995],{"class":3033}," result",[3017,5997,3038],{"class":3037},[3017,5999,3005],{"class":3023},[3017,6001,6002],{"class":3063}," WithTimeout",[3017,6004,6005],{"class":3037},"(\n",[3017,6007,6008,6011],{"class":3019,"line":3349},[3017,6009,6010],{"class":3063},"        SlowOperationAsync",[3017,6012,6013],{"class":3037},"(),\n",[3017,6015,6016,6019,6021,6023,6025,6027],{"class":3019,"line":3824},[3017,6017,6018],{"class":3033},"        TimeSpan",[3017,6020,3110],{"class":3037},[3017,6022,5621],{"class":3063},[3017,6024,3116],{"class":3037},[3017,6026,4550],{"class":3119},[3017,6028,3222],{"class":3037},[3017,6030,6031],{"class":3019,"line":3830},[3017,6032,6033],{"class":3037},"    );\n",[3017,6035,6036,6038,6040,6042,6044,6047,6049,6052,6054,6056],{"class":3019,"line":3843},[3017,6037,5692],{"class":3033},[3017,6039,3110],{"class":3037},[3017,6041,3419],{"class":3063},[3017,6043,3116],{"class":3037},[3017,6045,6046],{"class":3424},"$\"Результат: ",[3017,6048,3429],{"class":3428},[3017,6050,6051],{"class":3033},"result",[3017,6053,3445],{"class":3428},[3017,6055,3448],{"class":3424},[3017,6057,3295],{"class":3037},[3017,6059,6060],{"class":3019,"line":3848},[3017,6061,3138],{"class":3037},[3017,6063,6064,6067,6069,6072,6075],{"class":3019,"line":3853},[3017,6065,6066],{"class":3079},"catch",[3017,6068,3083],{"class":3037},[3017,6070,6071],{"class":3059},"TimeoutException",[3017,6073,6074],{"class":3033}," ex",[3017,6076,3222],{"class":3037},[3017,6078,6079],{"class":3019,"line":3858},[3017,6080,3073],{"class":3037},[3017,6082,6083,6085,6087,6089,6091,6094,6096,6099,6101,6104,6106,6108],{"class":3019,"line":3863},[3017,6084,5692],{"class":3033},[3017,6086,3110],{"class":3037},[3017,6088,3419],{"class":3063},[3017,6090,3116],{"class":3037},[3017,6092,6093],{"class":3424},"$\"Таймаут: ",[3017,6095,3429],{"class":3428},[3017,6097,6098],{"class":3033},"ex",[3017,6100,3110],{"class":3428},[3017,6102,6103],{"class":3033},"Message",[3017,6105,3445],{"class":3428},[3017,6107,3448],{"class":3424},[3017,6109,3295],{"class":3037},[3017,6111,6112],{"class":3019,"line":3869},[3017,6113,3138],{"class":3037},[3017,6115,6116],{"class":3019,"line":3887},[3017,6117,3051],{"emptyLinePlaceholder":3050},[3017,6119,6120,6122,6124,6126,6128,6130,6133],{"class":3019,"line":3916},[3017,6121,3001],{"class":3023},[3017,6123,3060],{"class":3059},[3017,6125,3721],{"class":3037},[3017,6127,4576],{"class":3023},[3017,6129,3727],{"class":3037},[3017,6131,6132],{"class":3063},"SlowOperationAsync",[3017,6134,3067],{"class":3037},[3017,6136,6137],{"class":3019,"line":3943},[3017,6138,3073],{"class":3037},[3017,6140,6141,6143,6145,6147,6149,6151,6154,6156],{"class":3019,"line":3953},[3017,6142,3581],{"class":3023},[3017,6144,3060],{"class":3033},[3017,6146,3110],{"class":3037},[3017,6148,3113],{"class":3063},[3017,6150,3116],{"class":3037},[3017,6152,6153],{"class":3119},"10_000",[3017,6155,3123],{"class":3037},[3017,6157,6158],{"class":3092},"// 10 секунд\n",[3017,6160,6161,6163,6166],{"class":3019,"line":3958},[3017,6162,5956],{"class":3079},[3017,6164,6165],{"class":3424}," \"Completed\"",[3017,6167,3260],{"class":3037},[3017,6169,6170],{"class":3019,"line":3977},[3017,6171,3138],{"class":3037},[3530,6173,6174,6177,6178,3144,6180,6183],{},[2983,6175,6176],{},"Важливо:"," Якщо timeout спрацював, оригінальний ",[2968,6179,5829],{},[2983,6181,6182],{},"продовжує виконуватись"," у фоні! Він не скасовується автоматично. Це може призвести до витоку ресурсів (відкриті з'єднання, файли).",[3192,6185,6187],{"id":6186},"pattern-2-cancellationtokensourcecancelafter","Pattern 2: CancellationTokenSource.CancelAfter",[2964,6189,6190,6191,6193],{},"Правильний спосіб — передати ",[2968,6192,4593],{}," з автоматичним timeout:",[3008,6195,6198],{"className":3010,"code":6196,"filename":6197,"language":3012,"meta":3648,"style":3013},"static async Task\u003CT> WithTimeoutAndCancellation\u003CT>(\n    Func\u003CCancellationToken, Task\u003CT>> operation,\n    TimeSpan timeout)\n{\n    using var cts = new CancellationTokenSource(timeout);\n    return await operation(cts.Token);\n}\n\n// Використання\ntry\n{\n    var result = await WithTimeoutAndCancellation(\n        ct => SlowOperationAsync(ct),\n        TimeSpan.FromSeconds(5)\n    );\n    Console.WriteLine($\"Результат: {result}\");\n}\ncatch (OperationCanceledException)\n{\n    Console.WriteLine(\"Операція скасована через таймаут\");\n}\n\nasync Task\u003Cstring> SlowOperationAsync(CancellationToken ct)\n{\n    // Операція перевіряє cancellation\n    await Task.Delay(10_000, ct);\n    return \"Completed\";\n}\n","TimeoutPattern2.cs",[2968,6199,6200,6224,6250,6259,6263,6287,6308,6312,6316,6320,6324,6328,6343,6359,6373,6377,6399,6403,6414,6418,6433,6437,6441,6463,6467,6472,6492,6500],{"__ignoreMap":3013},[3017,6201,6202,6204,6206,6208,6210,6212,6214,6217,6219,6221],{"class":3019,"line":3020},[3017,6203,5796],{"class":3023},[3017,6205,3716],{"class":3023},[3017,6207,3060],{"class":3059},[3017,6209,3721],{"class":3037},[3017,6211,5805],{"class":3059},[3017,6213,3727],{"class":3037},[3017,6215,6216],{"class":3063},"WithTimeoutAndCancellation",[3017,6218,3721],{"class":3037},[3017,6220,5805],{"class":3059},[3017,6222,6223],{"class":3037},">(\n",[3017,6225,6226,6229,6231,6233,6235,6237,6239,6241,6244,6247],{"class":3019,"line":3047},[3017,6227,6228],{"class":3059},"    Func",[3017,6230,3721],{"class":3037},[3017,6232,4593],{"class":3059},[3017,6234,2971],{"class":3037},[3017,6236,5820],{"class":3059},[3017,6238,3721],{"class":3037},[3017,6240,5805],{"class":3059},[3017,6242,6243],{"class":3037},">> ",[3017,6245,6246],{"class":3033},"operation",[3017,6248,6249],{"class":3037},",\n",[3017,6251,6252,6255,6257],{"class":3019,"line":3054},[3017,6253,6254],{"class":3059},"    TimeSpan",[3017,6256,5836],{"class":3033},[3017,6258,3222],{"class":3037},[3017,6260,6261],{"class":3019,"line":3070},[3017,6262,3073],{"class":3037},[3017,6264,6265,6268,6271,6274,6276,6278,6281,6283,6285],{"class":3019,"line":3076},[3017,6266,6267],{"class":3079},"    using",[3017,6269,6270],{"class":3023}," var",[3017,6272,6273],{"class":3033}," cts",[3017,6275,3038],{"class":3037},[3017,6277,3041],{"class":3023},[3017,6279,6280],{"class":3059}," CancellationTokenSource",[3017,6282,3116],{"class":3037},[3017,6284,5863],{"class":3033},[3017,6286,3295],{"class":3037},[3017,6288,6289,6291,6293,6296,6298,6301,6303,6306],{"class":3019,"line":3096},[3017,6290,5956],{"class":3079},[3017,6292,4689],{"class":3023},[3017,6294,6295],{"class":3063}," operation",[3017,6297,3116],{"class":3037},[3017,6299,6300],{"class":3033},"cts",[3017,6302,3110],{"class":3037},[3017,6304,6305],{"class":3033},"Token",[3017,6307,3295],{"class":3037},[3017,6309,6310],{"class":3019,"line":3102},[3017,6311,3138],{"class":3037},[3017,6313,6314],{"class":3019,"line":3129},[3017,6315,3051],{"emptyLinePlaceholder":3050},[3017,6317,6318],{"class":3019,"line":3135},[3017,6319,5980],{"class":3092},[3017,6321,6322],{"class":3019,"line":3268},[3017,6323,3265],{"class":3079},[3017,6325,6326],{"class":3019,"line":3273},[3017,6327,3073],{"class":3037},[3017,6329,6330,6332,6334,6336,6338,6341],{"class":3019,"line":3298},[3017,6331,5847],{"class":3023},[3017,6333,5995],{"class":3033},[3017,6335,3038],{"class":3037},[3017,6337,3005],{"class":3023},[3017,6339,6340],{"class":3063}," WithTimeoutAndCancellation",[3017,6342,6005],{"class":3037},[3017,6344,6345,6348,6350,6352,6354,6356],{"class":3019,"line":3303},[3017,6346,6347],{"class":3033},"        ct",[3017,6349,3930],{"class":3037},[3017,6351,6132],{"class":3063},[3017,6353,3116],{"class":3037},[3017,6355,4627],{"class":3033},[3017,6357,6358],{"class":3037},"),\n",[3017,6360,6361,6363,6365,6367,6369,6371],{"class":3019,"line":3308},[3017,6362,6018],{"class":3033},[3017,6364,3110],{"class":3037},[3017,6366,5621],{"class":3063},[3017,6368,3116],{"class":3037},[3017,6370,4550],{"class":3119},[3017,6372,3222],{"class":3037},[3017,6374,6375],{"class":3019,"line":3314},[3017,6376,6033],{"class":3037},[3017,6378,6379,6381,6383,6385,6387,6389,6391,6393,6395,6397],{"class":3019,"line":3319},[3017,6380,5692],{"class":3033},[3017,6382,3110],{"class":3037},[3017,6384,3419],{"class":3063},[3017,6386,3116],{"class":3037},[3017,6388,6046],{"class":3424},[3017,6390,3429],{"class":3428},[3017,6392,6051],{"class":3033},[3017,6394,3445],{"class":3428},[3017,6396,3448],{"class":3424},[3017,6398,3295],{"class":3037},[3017,6400,6401],{"class":3019,"line":3332},[3017,6402,3138],{"class":3037},[3017,6404,6405,6407,6409,6412],{"class":3019,"line":3349},[3017,6406,6066],{"class":3079},[3017,6408,3083],{"class":3037},[3017,6410,6411],{"class":3059},"OperationCanceledException",[3017,6413,3222],{"class":3037},[3017,6415,6416],{"class":3019,"line":3824},[3017,6417,3073],{"class":3037},[3017,6419,6420,6422,6424,6426,6428,6431],{"class":3019,"line":3830},[3017,6421,5692],{"class":3033},[3017,6423,3110],{"class":3037},[3017,6425,3419],{"class":3063},[3017,6427,3116],{"class":3037},[3017,6429,6430],{"class":3424},"\"Операція скасована через таймаут\"",[3017,6432,3295],{"class":3037},[3017,6434,6435],{"class":3019,"line":3843},[3017,6436,3138],{"class":3037},[3017,6438,6439],{"class":3019,"line":3848},[3017,6440,3051],{"emptyLinePlaceholder":3050},[3017,6442,6443,6445,6447,6449,6451,6453,6455,6457,6459,6461],{"class":3019,"line":3853},[3017,6444,3001],{"class":3023},[3017,6446,3060],{"class":3059},[3017,6448,3721],{"class":3037},[3017,6450,4576],{"class":3023},[3017,6452,3727],{"class":3037},[3017,6454,6132],{"class":3063},[3017,6456,3116],{"class":3037},[3017,6458,4593],{"class":3059},[3017,6460,4596],{"class":3033},[3017,6462,3222],{"class":3037},[3017,6464,6465],{"class":3019,"line":3858},[3017,6466,3073],{"class":3037},[3017,6468,6469],{"class":3019,"line":3863},[3017,6470,6471],{"class":3092},"    // Операція перевіряє cancellation\n",[3017,6473,6474,6476,6478,6480,6482,6484,6486,6488,6490],{"class":3019,"line":3869},[3017,6475,3581],{"class":3023},[3017,6477,3060],{"class":3033},[3017,6479,3110],{"class":3037},[3017,6481,3113],{"class":3063},[3017,6483,3116],{"class":3037},[3017,6485,6153],{"class":3119},[3017,6487,2971],{"class":3037},[3017,6489,4627],{"class":3033},[3017,6491,3295],{"class":3037},[3017,6493,6494,6496,6498],{"class":3019,"line":3887},[3017,6495,5956],{"class":3079},[3017,6497,6165],{"class":3424},[3017,6499,3260],{"class":3037},[3017,6501,6502],{"class":3019,"line":3916},[3017,6503,3138],{"class":3037},[2964,6505,6506],{},[2983,6507,6508],{},"Переваги:",[4442,6510,6511,6521,6524],{},[4445,6512,6513,6514,6517,6518,6520],{},"Операція ",[2983,6515,6516],{},"справді скасовується"," (якщо підтримує ",[2968,6519,4593],{},")",[4445,6522,6523],{},"Ресурси звільняються одразу",[4445,6525,6526,6527],{},"Стандартна семантика через ",[2968,6528,6411],{},[3192,6530,6532],{"id":6531},"pattern-3-linked-cancellationtokens","Pattern 3: Linked CancellationTokens",[2964,6534,6535],{},"Коли потрібно об'єднати timeout та зовнішній cancellation:",[3008,6537,6540],{"className":3010,"code":6538,"filename":6539,"language":3012,"meta":3648,"style":3013},"async Task\u003Cstring> FetchWithTimeoutAsync(string url, CancellationToken externalCt)\n{\n    // Створюємо токен з timeout\n    using var timeoutCts = new CancellationTokenSource(TimeSpan.FromSeconds(10));\n    \n    // Об'єднуємо з зовнішнім токеном\n    using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(\n        externalCt,\n        timeoutCts.Token\n    );\n\n    // Операція скасується або при timeout, або при зовнішньому cancellation\n    var response = await _http.GetStringAsync(url, linkedCts.Token);\n    return response;\n}\n\n// Використання\nusing var userCts = new CancellationTokenSource();\n\n// Користувач може скасувати через Ctrl+C\nConsole.CancelKeyPress += (_, e) =>\n{\n    e.Cancel = true;\n    userCts.Cancel();\n};\n\ntry\n{\n    var data = await FetchWithTimeoutAsync(\"https://slow-api.com/data\", userCts.Token);\n    Console.WriteLine(data);\n}\ncatch (OperationCanceledException)\n{\n    Console.WriteLine(\"Скасовано (timeout або користувач)\");\n}\n","LinkedTokens.cs",[2968,6541,6542,6572,6576,6581,6610,6615,6620,6641,6648,6658,6662,6666,6671,6703,6711,6715,6719,6723,6740,6744,6749,6771,6775,6792,6803,6808,6812,6816,6820,6850,6865,6869,6879,6883,6898],{"__ignoreMap":3013},[3017,6543,6544,6546,6548,6550,6552,6554,6557,6559,6561,6563,6565,6567,6570],{"class":3019,"line":3020},[3017,6545,3001],{"class":3023},[3017,6547,3060],{"class":3059},[3017,6549,3721],{"class":3037},[3017,6551,4576],{"class":3023},[3017,6553,3727],{"class":3037},[3017,6555,6556],{"class":3063},"FetchWithTimeoutAsync",[3017,6558,3116],{"class":3037},[3017,6560,4576],{"class":3023},[3017,6562,4588],{"class":3033},[3017,6564,2971],{"class":3037},[3017,6566,4593],{"class":3059},[3017,6568,6569],{"class":3033}," externalCt",[3017,6571,3222],{"class":3037},[3017,6573,6574],{"class":3019,"line":3047},[3017,6575,3073],{"class":3037},[3017,6577,6578],{"class":3019,"line":3054},[3017,6579,6580],{"class":3092},"    // Створюємо токен з timeout\n",[3017,6582,6583,6585,6587,6590,6592,6594,6596,6598,6600,6602,6604,6606,6608],{"class":3019,"line":3070},[3017,6584,6267],{"class":3079},[3017,6586,6270],{"class":3023},[3017,6588,6589],{"class":3033}," timeoutCts",[3017,6591,3038],{"class":3037},[3017,6593,3041],{"class":3023},[3017,6595,6280],{"class":3059},[3017,6597,3116],{"class":3037},[3017,6599,5107],{"class":3033},[3017,6601,3110],{"class":3037},[3017,6603,5621],{"class":3063},[3017,6605,3116],{"class":3037},[3017,6607,3785],{"class":3119},[3017,6609,5628],{"class":3037},[3017,6611,6612],{"class":3019,"line":3076},[3017,6613,6614],{"class":3037},"    \n",[3017,6616,6617],{"class":3019,"line":3096},[3017,6618,6619],{"class":3092},"    // Об'єднуємо з зовнішнім токеном\n",[3017,6621,6622,6624,6626,6629,6631,6634,6636,6639],{"class":3019,"line":3102},[3017,6623,6267],{"class":3079},[3017,6625,6270],{"class":3023},[3017,6627,6628],{"class":3033}," linkedCts",[3017,6630,3038],{"class":3037},[3017,6632,6633],{"class":3033},"CancellationTokenSource",[3017,6635,3110],{"class":3037},[3017,6637,6638],{"class":3063},"CreateLinkedTokenSource",[3017,6640,6005],{"class":3037},[3017,6642,6643,6646],{"class":3019,"line":3129},[3017,6644,6645],{"class":3033},"        externalCt",[3017,6647,6249],{"class":3037},[3017,6649,6650,6653,6655],{"class":3019,"line":3135},[3017,6651,6652],{"class":3033},"        timeoutCts",[3017,6654,3110],{"class":3037},[3017,6656,6657],{"class":3033},"Token\n",[3017,6659,6660],{"class":3019,"line":3268},[3017,6661,6033],{"class":3037},[3017,6663,6664],{"class":3019,"line":3273},[3017,6665,3051],{"emptyLinePlaceholder":3050},[3017,6667,6668],{"class":3019,"line":3298},[3017,6669,6670],{"class":3092},"    // Операція скасується або при timeout, або при зовнішньому cancellation\n",[3017,6672,6673,6675,6678,6680,6682,6684,6686,6688,6690,6692,6694,6697,6699,6701],{"class":3019,"line":3303},[3017,6674,5847],{"class":3023},[3017,6676,6677],{"class":3033}," response",[3017,6679,3038],{"class":3037},[3017,6681,3005],{"class":3023},[3017,6683,4524],{"class":3033},[3017,6685,3110],{"class":3037},[3017,6687,4696],{"class":3063},[3017,6689,3116],{"class":3037},[3017,6691,4656],{"class":3033},[3017,6693,2971],{"class":3037},[3017,6695,6696],{"class":3033},"linkedCts",[3017,6698,3110],{"class":3037},[3017,6700,6305],{"class":3033},[3017,6702,3295],{"class":3037},[3017,6704,6705,6707,6709],{"class":3019,"line":3308},[3017,6706,5956],{"class":3079},[3017,6708,6677],{"class":3033},[3017,6710,3260],{"class":3037},[3017,6712,6713],{"class":3019,"line":3314},[3017,6714,3138],{"class":3037},[3017,6716,6717],{"class":3019,"line":3319},[3017,6718,3051],{"emptyLinePlaceholder":3050},[3017,6720,6721],{"class":3019,"line":3332},[3017,6722,5980],{"class":3092},[3017,6724,6725,6727,6729,6732,6734,6736,6738],{"class":3019,"line":3349},[3017,6726,4268],{"class":3079},[3017,6728,6270],{"class":3023},[3017,6730,6731],{"class":3033}," userCts",[3017,6733,3038],{"class":3037},[3017,6735,3041],{"class":3023},[3017,6737,6280],{"class":3059},[3017,6739,3044],{"class":3037},[3017,6741,6742],{"class":3019,"line":3824},[3017,6743,3051],{"emptyLinePlaceholder":3050},[3017,6745,6746],{"class":3019,"line":3830},[3017,6747,6748],{"class":3092},"// Користувач може скасувати через Ctrl+C\n",[3017,6750,6751,6753,6755,6758,6761,6763,6765,6768],{"class":3019,"line":3843},[3017,6752,3980],{"class":3033},[3017,6754,3110],{"class":3037},[3017,6756,6757],{"class":3033},"CancelKeyPress",[3017,6759,6760],{"class":3037}," += (",[3017,6762,3927],{"class":3033},[3017,6764,2971],{"class":3037},[3017,6766,6767],{"class":3033},"e",[3017,6769,6770],{"class":3037},") =>\n",[3017,6772,6773],{"class":3019,"line":3848},[3017,6774,3073],{"class":3037},[3017,6776,6777,6780,6782,6785,6787,6790],{"class":3019,"line":3853},[3017,6778,6779],{"class":3033},"    e",[3017,6781,3110],{"class":3037},[3017,6783,6784],{"class":3033},"Cancel",[3017,6786,3038],{"class":3037},[3017,6788,6789],{"class":3023},"true",[3017,6791,3260],{"class":3037},[3017,6793,6794,6797,6799,6801],{"class":3019,"line":3858},[3017,6795,6796],{"class":3033},"    userCts",[3017,6798,3110],{"class":3037},[3017,6800,6784],{"class":3063},[3017,6802,3044],{"class":3037},[3017,6804,6805],{"class":3019,"line":3863},[3017,6806,6807],{"class":3037},"};\n",[3017,6809,6810],{"class":3019,"line":3869},[3017,6811,3051],{"emptyLinePlaceholder":3050},[3017,6813,6814],{"class":3019,"line":3887},[3017,6815,3265],{"class":3079},[3017,6817,6818],{"class":3019,"line":3916},[3017,6819,3073],{"class":3037},[3017,6821,6822,6824,6827,6829,6831,6834,6836,6839,6841,6844,6846,6848],{"class":3019,"line":3943},[3017,6823,5847],{"class":3023},[3017,6825,6826],{"class":3033}," data",[3017,6828,3038],{"class":3037},[3017,6830,3005],{"class":3023},[3017,6832,6833],{"class":3063}," FetchWithTimeoutAsync",[3017,6835,3116],{"class":3037},[3017,6837,6838],{"class":3424},"\"https://slow-api.com/data\"",[3017,6840,2971],{"class":3037},[3017,6842,6843],{"class":3033},"userCts",[3017,6845,3110],{"class":3037},[3017,6847,6305],{"class":3033},[3017,6849,3295],{"class":3037},[3017,6851,6852,6854,6856,6858,6860,6863],{"class":3019,"line":3953},[3017,6853,5692],{"class":3033},[3017,6855,3110],{"class":3037},[3017,6857,3419],{"class":3063},[3017,6859,3116],{"class":3037},[3017,6861,6862],{"class":3033},"data",[3017,6864,3295],{"class":3037},[3017,6866,6867],{"class":3019,"line":3958},[3017,6868,3138],{"class":3037},[3017,6870,6871,6873,6875,6877],{"class":3019,"line":3977},[3017,6872,6066],{"class":3079},[3017,6874,3083],{"class":3037},[3017,6876,6411],{"class":3059},[3017,6878,3222],{"class":3037},[3017,6880,6881],{"class":3019,"line":5384},[3017,6882,3073],{"class":3037},[3017,6884,6885,6887,6889,6891,6893,6896],{"class":3019,"line":5389},[3017,6886,5692],{"class":3033},[3017,6888,3110],{"class":3037},[3017,6890,3419],{"class":3063},[3017,6892,3116],{"class":3037},[3017,6894,6895],{"class":3424},"\"Скасовано (timeout або користувач)\"",[3017,6897,3295],{"class":3037},[3017,6899,6900],{"class":3019,"line":5411},[3017,6901,3138],{"class":3037},[3192,6903,6905],{"id":6904},"pattern-4-retry-з-exponential-backoff","Pattern 4: Retry з Exponential Backoff",[2964,6907,6908],{},"Комбінація timeout + retry для нестабільних операцій:",[3008,6910,6913],{"className":3010,"code":6911,"filename":6912,"language":3012,"meta":3648,"style":3013},"static async Task\u003CT> RetryWithTimeoutAsync\u003CT>(\n    Func\u003CCancellationToken, Task\u003CT>> operation,\n    int maxRetries = 3,\n    TimeSpan? initialDelay = null,\n    CancellationToken ct = default)\n{\n    initialDelay ??= TimeSpan.FromSeconds(1);\n    var delay = initialDelay.Value;\n\n    for (int attempt = 1; attempt \u003C= maxRetries; attempt++)\n    {\n        using var attemptCts = CancellationTokenSource.CreateLinkedTokenSource(ct);\n        attemptCts.CancelAfter(TimeSpan.FromSeconds(5));  // Timeout на спробу\n\n        try\n        {\n            return await operation(attemptCts.Token);\n        }\n        catch (Exception ex) when (attempt \u003C maxRetries && \n            (ex is OperationCanceledException || ex is HttpRequestException))\n        {\n            Console.WriteLine($\"Спроба {attempt} невдала: {ex.Message}. Повтор через {delay.TotalSeconds}s...\");\n            await Task.Delay(delay, ct);\n            delay *= 2;  // Exponential backoff\n        }\n    }\n\n    // Остання спроба без catch\n    using var finalCts = CancellationTokenSource.CreateLinkedTokenSource(ct);\n    finalCts.CancelAfter(TimeSpan.FromSeconds(5));\n    return await operation(finalCts.Token);\n}\n\n// Використання\nvar result = await RetryWithTimeoutAsync(\n    async ct =>\n    {\n        var response = await _http.GetAsync(\"https://flaky-api.com/data\", ct);\n        response.EnsureSuccessStatusCode();\n        return await response.Content.ReadAsStringAsync(ct);\n    },\n    maxRetries: 5,\n    initialDelay: TimeSpan.FromSeconds(1)\n);\n","RetryWithTimeout.cs",[2968,6914,6915,6938,6960,6975,6992,7005,7009,7029,7046,7050,7083,7087,7111,7139,7143,7147,7151,7170,7174,7203,7229,7233,7282,7302,7318,7322,7326,7330,7335,7358,7381,7400,7404,7408,7412,7427,7437,7441,7469,7481,7505,7510,7521,7539],{"__ignoreMap":3013},[3017,6916,6917,6919,6921,6923,6925,6927,6929,6932,6934,6936],{"class":3019,"line":3020},[3017,6918,5796],{"class":3023},[3017,6920,3716],{"class":3023},[3017,6922,3060],{"class":3059},[3017,6924,3721],{"class":3037},[3017,6926,5805],{"class":3059},[3017,6928,3727],{"class":3037},[3017,6930,6931],{"class":3063},"RetryWithTimeoutAsync",[3017,6933,3721],{"class":3037},[3017,6935,5805],{"class":3059},[3017,6937,6223],{"class":3037},[3017,6939,6940,6942,6944,6946,6948,6950,6952,6954,6956,6958],{"class":3019,"line":3047},[3017,6941,6228],{"class":3059},[3017,6943,3721],{"class":3037},[3017,6945,4593],{"class":3059},[3017,6947,2971],{"class":3037},[3017,6949,5820],{"class":3059},[3017,6951,3721],{"class":3037},[3017,6953,5805],{"class":3059},[3017,6955,6243],{"class":3037},[3017,6957,6246],{"class":3033},[3017,6959,6249],{"class":3037},[3017,6961,6962,6965,6968,6970,6973],{"class":3019,"line":3054},[3017,6963,6964],{"class":3023},"    int",[3017,6966,6967],{"class":3033}," maxRetries",[3017,6969,3038],{"class":3037},[3017,6971,6972],{"class":3119},"3",[3017,6974,6249],{"class":3037},[3017,6976,6977,6979,6982,6985,6987,6990],{"class":3019,"line":3070},[3017,6978,6254],{"class":3059},[3017,6980,6981],{"class":3037},"? ",[3017,6983,6984],{"class":3033},"initialDelay",[3017,6986,3038],{"class":3037},[3017,6988,6989],{"class":3023},"null",[3017,6991,6249],{"class":3037},[3017,6993,6994,6997,6999,7001,7003],{"class":3019,"line":3076},[3017,6995,6996],{"class":3059},"    CancellationToken",[3017,6998,4596],{"class":3033},[3017,7000,3038],{"class":3037},[3017,7002,4601],{"class":3023},[3017,7004,3222],{"class":3037},[3017,7006,7007],{"class":3019,"line":3096},[3017,7008,3073],{"class":3037},[3017,7010,7011,7014,7017,7019,7021,7023,7025,7027],{"class":3019,"line":3102},[3017,7012,7013],{"class":3033},"    initialDelay",[3017,7015,7016],{"class":3037}," ??= ",[3017,7018,5107],{"class":3033},[3017,7020,3110],{"class":3037},[3017,7022,5621],{"class":3063},[3017,7024,3116],{"class":3037},[3017,7026,3695],{"class":3119},[3017,7028,3295],{"class":3037},[3017,7030,7031,7033,7035,7037,7039,7041,7044],{"class":3019,"line":3129},[3017,7032,5847],{"class":3023},[3017,7034,5365],{"class":3033},[3017,7036,3038],{"class":3037},[3017,7038,6984],{"class":3033},[3017,7040,3110],{"class":3037},[3017,7042,7043],{"class":3033},"Value",[3017,7045,3260],{"class":3037},[3017,7047,7048],{"class":3019,"line":3135},[3017,7049,3051],{"emptyLinePlaceholder":3050},[3017,7051,7052,7055,7057,7059,7062,7064,7066,7068,7071,7074,7077,7079,7081],{"class":3019,"line":3268},[3017,7053,7054],{"class":3079},"    for",[3017,7056,3083],{"class":3037},[3017,7058,3724],{"class":3023},[3017,7060,7061],{"class":3033}," attempt",[3017,7063,3038],{"class":3037},[3017,7065,3695],{"class":3119},[3017,7067,5653],{"class":3037},[3017,7069,7070],{"class":3033},"attempt",[3017,7072,7073],{"class":3037}," \u003C= ",[3017,7075,7076],{"class":3033},"maxRetries",[3017,7078,5653],{"class":3037},[3017,7080,7070],{"class":3033},[3017,7082,5668],{"class":3037},[3017,7084,7085],{"class":3019,"line":3273},[3017,7086,3099],{"class":3037},[3017,7088,7089,7092,7094,7097,7099,7101,7103,7105,7107,7109],{"class":3019,"line":3298},[3017,7090,7091],{"class":3079},"        using",[3017,7093,6270],{"class":3023},[3017,7095,7096],{"class":3033}," attemptCts",[3017,7098,3038],{"class":3037},[3017,7100,6633],{"class":3033},[3017,7102,3110],{"class":3037},[3017,7104,6638],{"class":3063},[3017,7106,3116],{"class":3037},[3017,7108,4627],{"class":3033},[3017,7110,3295],{"class":3037},[3017,7112,7113,7116,7118,7121,7123,7125,7127,7129,7131,7133,7136],{"class":3019,"line":3303},[3017,7114,7115],{"class":3033},"        attemptCts",[3017,7117,3110],{"class":3037},[3017,7119,7120],{"class":3063},"CancelAfter",[3017,7122,3116],{"class":3037},[3017,7124,5107],{"class":3033},[3017,7126,3110],{"class":3037},[3017,7128,5621],{"class":3063},[3017,7130,3116],{"class":3037},[3017,7132,4550],{"class":3119},[3017,7134,7135],{"class":3037},"));  ",[3017,7137,7138],{"class":3092},"// Timeout на спробу\n",[3017,7140,7141],{"class":3019,"line":3308},[3017,7142,3051],{"emptyLinePlaceholder":3050},[3017,7144,7145],{"class":3019,"line":3314},[3017,7146,3759],{"class":3079},[3017,7148,7149],{"class":3019,"line":3319},[3017,7150,3764],{"class":3037},[3017,7152,7153,7155,7157,7159,7161,7164,7166,7168],{"class":3019,"line":3332},[3017,7154,3803],{"class":3079},[3017,7156,4689],{"class":3023},[3017,7158,6295],{"class":3063},[3017,7160,3116],{"class":3037},[3017,7162,7163],{"class":3033},"attemptCts",[3017,7165,3110],{"class":3037},[3017,7167,6305],{"class":3033},[3017,7169,3295],{"class":3037},[3017,7171,7172],{"class":3019,"line":3349},[3017,7173,3812],{"class":3037},[3017,7175,7176,7179,7181,7184,7186,7189,7192,7194,7196,7198,7200],{"class":3019,"line":3824},[3017,7177,7178],{"class":3079},"        catch",[3017,7180,3083],{"class":3037},[3017,7182,7183],{"class":3059},"Exception",[3017,7185,6074],{"class":3033},[3017,7187,7188],{"class":3037},") ",[3017,7190,7191],{"class":3079},"when",[3017,7193,3083],{"class":3037},[3017,7195,7070],{"class":3033},[3017,7197,5658],{"class":3037},[3017,7199,7076],{"class":3033},[3017,7201,7202],{"class":3037}," && \n",[3017,7204,7205,7208,7210,7213,7216,7219,7221,7223,7226],{"class":3019,"line":3830},[3017,7206,7207],{"class":3037},"            (",[3017,7209,6098],{"class":3033},[3017,7211,7212],{"class":3023}," is",[3017,7214,7215],{"class":3059}," OperationCanceledException",[3017,7217,7218],{"class":3037}," || ",[3017,7220,6098],{"class":3033},[3017,7222,7212],{"class":3023},[3017,7224,7225],{"class":3059}," HttpRequestException",[3017,7227,7228],{"class":3037},"))\n",[3017,7230,7231],{"class":3019,"line":3843},[3017,7232,3764],{"class":3037},[3017,7234,7235,7237,7239,7241,7243,7246,7248,7250,7252,7255,7257,7259,7261,7263,7265,7268,7270,7272,7274,7276,7278,7280],{"class":3019,"line":3848},[3017,7236,4642],{"class":3033},[3017,7238,3110],{"class":3037},[3017,7240,3419],{"class":3063},[3017,7242,3116],{"class":3037},[3017,7244,7245],{"class":3424},"$\"Спроба ",[3017,7247,3429],{"class":3428},[3017,7249,7070],{"class":3033},[3017,7251,3445],{"class":3428},[3017,7253,7254],{"class":3424}," невдала: ",[3017,7256,3429],{"class":3428},[3017,7258,6098],{"class":3033},[3017,7260,3110],{"class":3428},[3017,7262,6103],{"class":3033},[3017,7264,3445],{"class":3428},[3017,7266,7267],{"class":3424},". Повтор через ",[3017,7269,3429],{"class":3428},[3017,7271,5397],{"class":3033},[3017,7273,3110],{"class":3428},[3017,7275,5438],{"class":3033},[3017,7277,3445],{"class":3428},[3017,7279,5448],{"class":3424},[3017,7281,3295],{"class":3037},[3017,7283,7284,7286,7288,7290,7292,7294,7296,7298,7300],{"class":3019,"line":3853},[3017,7285,3774],{"class":3023},[3017,7287,3060],{"class":3033},[3017,7289,3110],{"class":3037},[3017,7291,3113],{"class":3063},[3017,7293,3116],{"class":3037},[3017,7295,5397],{"class":3033},[3017,7297,2971],{"class":3037},[3017,7299,4627],{"class":3033},[3017,7301,3295],{"class":3037},[3017,7303,7304,7307,7310,7313,7315],{"class":3019,"line":3858},[3017,7305,7306],{"class":3033},"            delay",[3017,7308,7309],{"class":3037}," *= ",[3017,7311,7312],{"class":3119},"2",[3017,7314,5964],{"class":3037},[3017,7316,7317],{"class":3092},"// Exponential backoff\n",[3017,7319,7320],{"class":3019,"line":3863},[3017,7321,3812],{"class":3037},[3017,7323,7324],{"class":3019,"line":3869},[3017,7325,3132],{"class":3037},[3017,7327,7328],{"class":3019,"line":3887},[3017,7329,3051],{"emptyLinePlaceholder":3050},[3017,7331,7332],{"class":3019,"line":3916},[3017,7333,7334],{"class":3092},"    // Остання спроба без catch\n",[3017,7336,7337,7339,7341,7344,7346,7348,7350,7352,7354,7356],{"class":3019,"line":3943},[3017,7338,6267],{"class":3079},[3017,7340,6270],{"class":3023},[3017,7342,7343],{"class":3033}," finalCts",[3017,7345,3038],{"class":3037},[3017,7347,6633],{"class":3033},[3017,7349,3110],{"class":3037},[3017,7351,6638],{"class":3063},[3017,7353,3116],{"class":3037},[3017,7355,4627],{"class":3033},[3017,7357,3295],{"class":3037},[3017,7359,7360,7363,7365,7367,7369,7371,7373,7375,7377,7379],{"class":3019,"line":3953},[3017,7361,7362],{"class":3033},"    finalCts",[3017,7364,3110],{"class":3037},[3017,7366,7120],{"class":3063},[3017,7368,3116],{"class":3037},[3017,7370,5107],{"class":3033},[3017,7372,3110],{"class":3037},[3017,7374,5621],{"class":3063},[3017,7376,3116],{"class":3037},[3017,7378,4550],{"class":3119},[3017,7380,5628],{"class":3037},[3017,7382,7383,7385,7387,7389,7391,7394,7396,7398],{"class":3019,"line":3958},[3017,7384,5956],{"class":3079},[3017,7386,4689],{"class":3023},[3017,7388,6295],{"class":3063},[3017,7390,3116],{"class":3037},[3017,7392,7393],{"class":3033},"finalCts",[3017,7395,3110],{"class":3037},[3017,7397,6305],{"class":3033},[3017,7399,3295],{"class":3037},[3017,7401,7402],{"class":3019,"line":3977},[3017,7403,3138],{"class":3037},[3017,7405,7406],{"class":3019,"line":5384},[3017,7407,3051],{"emptyLinePlaceholder":3050},[3017,7409,7410],{"class":3019,"line":5389},[3017,7411,5980],{"class":3092},[3017,7413,7414,7416,7418,7420,7422,7425],{"class":3019,"line":5411},[3017,7415,3872],{"class":3023},[3017,7417,5995],{"class":3033},[3017,7419,3038],{"class":3037},[3017,7421,3005],{"class":3023},[3017,7423,7424],{"class":3063}," RetryWithTimeoutAsync",[3017,7426,6005],{"class":3037},[3017,7428,7429,7432,7434],{"class":3019,"line":5417},[3017,7430,7431],{"class":3023},"    async",[3017,7433,4596],{"class":3033},[3017,7435,7436],{"class":3037}," =>\n",[3017,7438,7439],{"class":3019,"line":5453},[3017,7440,3099],{"class":3037},[3017,7442,7443,7446,7448,7450,7452,7454,7456,7458,7460,7463,7465,7467],{"class":3019,"line":5475},[3017,7444,7445],{"class":3023},"        var",[3017,7447,6677],{"class":3033},[3017,7449,3038],{"class":3037},[3017,7451,3005],{"class":3023},[3017,7453,4524],{"class":3033},[3017,7455,3110],{"class":3037},[3017,7457,4581],{"class":3063},[3017,7459,3116],{"class":3037},[3017,7461,7462],{"class":3424},"\"https://flaky-api.com/data\"",[3017,7464,2971],{"class":3037},[3017,7466,4627],{"class":3033},[3017,7468,3295],{"class":3037},[3017,7470,7471,7474,7476,7479],{"class":3019,"line":5481},[3017,7472,7473],{"class":3033},"        response",[3017,7475,3110],{"class":3037},[3017,7477,7478],{"class":3063},"EnsureSuccessStatusCode",[3017,7480,3044],{"class":3037},[3017,7482,7483,7485,7487,7489,7491,7494,7496,7499,7501,7503],{"class":3019,"line":5486},[3017,7484,4118],{"class":3079},[3017,7486,4689],{"class":3023},[3017,7488,6677],{"class":3033},[3017,7490,3110],{"class":3037},[3017,7492,7493],{"class":3033},"Content",[3017,7495,3110],{"class":3037},[3017,7497,7498],{"class":3063},"ReadAsStringAsync",[3017,7500,3116],{"class":3037},[3017,7502,4627],{"class":3033},[3017,7504,3295],{"class":3037},[3017,7506,7507],{"class":3019,"line":5492},[3017,7508,7509],{"class":3037},"    },\n",[3017,7511,7512,7515,7517,7519],{"class":3019,"line":5503},[3017,7513,7514],{"class":3033},"    maxRetries",[3017,7516,5606],{"class":3037},[3017,7518,4550],{"class":3119},[3017,7520,6249],{"class":3037},[3017,7522,7523,7525,7527,7529,7531,7533,7535,7537],{"class":3019,"line":5508},[3017,7524,7013],{"class":3033},[3017,7526,5606],{"class":3037},[3017,7528,5107],{"class":3033},[3017,7530,3110],{"class":3037},[3017,7532,5621],{"class":3063},[3017,7534,3116],{"class":3037},[3017,7536,3695],{"class":3119},[3017,7538,3222],{"class":3037},[3017,7540,7541],{"class":3019,"line":5513},[3017,7542,3295],{"class":3037},[3185,7544],{},[2959,7546,7548],{"id":7547},"nitoasyncex-бібліотека-async-primitives","Nito.AsyncEx: Бібліотека Async Primitives",[3192,7550,7552],{"id":7551},"огляд-бібліотеки","Огляд Бібліотеки",[2964,7554,7555,7557],{},[2968,7556,3182],{}," — це community-driven бібліотека, що надає async-compatible версії стандартних синхронізаційних примітивів.",[2964,7559,7560],{},[2983,7561,7562],{},"Встановлення:",[3008,7564,7568],{"className":7565,"code":7566,"language":7567,"meta":3013,"style":3013},"language-bash shiki shiki-themes light-plus dark-plus dark-plus","dotnet add package Nito.AsyncEx\n","bash",[2968,7569,7570],{"__ignoreMap":3013},[3017,7571,7572,7575,7578,7581],{"class":3019,"line":3020},[3017,7573,7574],{"class":3063},"dotnet",[3017,7576,7577],{"class":3424}," add",[3017,7579,7580],{"class":3424}," package",[3017,7582,7583],{"class":3424}," Nito.AsyncEx\n",[3192,7585,7587],{"id":7586},"asynclock-async-mutex","AsyncLock: Async Mutex",[2964,7589,7590],{},"Готова реалізація async lock з правильною семантикою:",[3008,7592,7595],{"className":3010,"code":7593,"filename":7594,"language":3012,"meta":3648,"style":3013},"using Nito.AsyncEx;\n\nclass SharedResource\n{\n    private readonly AsyncLock _lock = new();\n    private int _value;\n\n    public async Task\u003Cint> IncrementAsync()\n    {\n        // using + await — елегантний синтаксис\n        using (await _lock.LockAsync())\n        {\n            await Task.Delay(10);\n            return ++_value;\n        }\n    }\n}\n","NitoAsyncLock.cs",[2968,7596,7597,7611,7615,7622,7626,7642,7653,7657,7675,7679,7684,7700,7704,7720,7732,7736,7740],{"__ignoreMap":3013},[3017,7598,7599,7601,7604,7606,7609],{"class":3019,"line":3020},[3017,7600,4268],{"class":3079},[3017,7602,7603],{"class":3059}," Nito",[3017,7605,3110],{"class":3037},[3017,7607,7608],{"class":3059},"AsyncEx",[3017,7610,3260],{"class":3037},[3017,7612,7613],{"class":3019,"line":3047},[3017,7614,3051],{"emptyLinePlaceholder":3050},[3017,7616,7617,7619],{"class":3019,"line":3054},[3017,7618,3655],{"class":3023},[3017,7620,7621],{"class":3059}," SharedResource\n",[3017,7623,7624],{"class":3019,"line":3070},[3017,7625,3073],{"class":3037},[3017,7627,7628,7630,7632,7634,7636,7638,7640],{"class":3019,"line":3076},[3017,7629,3667],{"class":3023},[3017,7631,3027],{"class":3023},[3017,7633,4257],{"class":3059},[3017,7635,3034],{"class":3033},[3017,7637,3038],{"class":3037},[3017,7639,3041],{"class":3023},[3017,7641,3044],{"class":3037},[3017,7643,7644,7646,7648,7651],{"class":3019,"line":3096},[3017,7645,3667],{"class":3023},[3017,7647,3670],{"class":3023},[3017,7649,7650],{"class":3033}," _value",[3017,7652,3260],{"class":3037},[3017,7654,7655],{"class":3019,"line":3102},[3017,7656,3051],{"emptyLinePlaceholder":3050},[3017,7658,7659,7661,7663,7665,7667,7669,7671,7673],{"class":3019,"line":3129},[3017,7660,3713],{"class":3023},[3017,7662,3716],{"class":3023},[3017,7664,3060],{"class":3059},[3017,7666,3721],{"class":3037},[3017,7668,3724],{"class":3023},[3017,7670,3727],{"class":3037},[3017,7672,3730],{"class":3063},[3017,7674,3067],{"class":3037},[3017,7676,7677],{"class":3019,"line":3135},[3017,7678,3099],{"class":3037},[3017,7680,7681],{"class":3019,"line":3268},[3017,7682,7683],{"class":3092},"        // using + await — елегантний синтаксис\n",[3017,7685,7686,7688,7690,7692,7694,7696,7698],{"class":3019,"line":3273},[3017,7687,7091],{"class":3079},[3017,7689,3083],{"class":3037},[3017,7691,3005],{"class":3023},[3017,7693,3034],{"class":3033},[3017,7695,3110],{"class":3037},[3017,7697,4095],{"class":3063},[3017,7699,3940],{"class":3037},[3017,7701,7702],{"class":3019,"line":3298},[3017,7703,3764],{"class":3037},[3017,7705,7706,7708,7710,7712,7714,7716,7718],{"class":3019,"line":3303},[3017,7707,3774],{"class":3023},[3017,7709,3060],{"class":3033},[3017,7711,3110],{"class":3037},[3017,7713,3113],{"class":3063},[3017,7715,3116],{"class":3037},[3017,7717,3785],{"class":3119},[3017,7719,3295],{"class":3037},[3017,7721,7722,7724,7727,7730],{"class":3019,"line":3308},[3017,7723,3803],{"class":3079},[3017,7725,7726],{"class":3037}," ++",[3017,7728,7729],{"class":3033},"_value",[3017,7731,3260],{"class":3037},[3017,7733,7734],{"class":3019,"line":3314},[3017,7735,3812],{"class":3037},[3017,7737,7738],{"class":3019,"line":3319},[3017,7739,3132],{"class":3037},[3017,7741,7742],{"class":3019,"line":3332},[3017,7743,3138],{"class":3037},[2964,7745,7746],{},[2983,7747,7748,7749,3201],{},"Переваги над ручним ",[2968,7750,3618],{},[4442,7752,7753,7756,7759],{},[4445,7754,7755],{},"Правильна обробка cancellation",[4445,7757,7758],{},"Підтримка reentrancy detection (опціонально)",[4445,7760,7761],{},"Оптимізована реалізація",[3192,7763,7765],{"id":7764},"asyncautoresetevent-та-asyncmanualresetevent","AsyncAutoResetEvent та AsyncManualResetEvent",[2964,7767,7768],{},"Async версії event primitives:",[3008,7770,7773],{"className":3010,"code":7771,"filename":7772,"language":3012,"meta":3648,"style":3013},"using Nito.AsyncEx;\n\n// Auto-reset: один waiter проходить, event скидається\nvar autoEvent = new AsyncAutoResetEvent(signaled: false);\n\n// Producer\n_ = Task.Run(async () =>\n{\n    await Task.Delay(1000);\n    autoEvent.Set();  // Дозволяє одному waiter пройти\n    Console.WriteLine(\"Event set\");\n});\n\n// Consumer\nawait autoEvent.WaitAsync();\nConsole.WriteLine(\"Event received\");\n\n// Manual-reset: всі waiters проходять\nvar manualEvent = new AsyncManualResetEvent(signaled: false);\n\n// Кілька consumers\nvar waiters = Enumerable.Range(0, 5)\n    .Select(async i =>\n    {\n        await manualEvent.WaitAsync();\n        Console.WriteLine($\"Waiter {i} пройшов\");\n    })\n    .ToArray();\n\nawait Task.Delay(1000);\nmanualEvent.Set();  // Всі 5 waiters проходять одночасно\n\nawait Task.WhenAll(waiters);\n","NitoAsyncEvents.cs",[2968,7774,7775,7787,7791,7796,7821,7825,7830,7850,7854,7871,7887,7902,7907,7911,7916,7928,7943,7947,7952,7976,7980,7985,8010,8024,8028,8040,8064,8069,8077,8081,8097,8111,8115],{"__ignoreMap":3013},[3017,7776,7777,7779,7781,7783,7785],{"class":3019,"line":3020},[3017,7778,4268],{"class":3079},[3017,7780,7603],{"class":3059},[3017,7782,3110],{"class":3037},[3017,7784,7608],{"class":3059},[3017,7786,3260],{"class":3037},[3017,7788,7789],{"class":3019,"line":3047},[3017,7790,3051],{"emptyLinePlaceholder":3050},[3017,7792,7793],{"class":3019,"line":3054},[3017,7794,7795],{"class":3092},"// Auto-reset: один waiter проходить, event скидається\n",[3017,7797,7798,7800,7803,7805,7807,7810,7812,7815,7817,7819],{"class":3019,"line":3070},[3017,7799,3872],{"class":3023},[3017,7801,7802],{"class":3033}," autoEvent",[3017,7804,3038],{"class":3037},[3017,7806,3041],{"class":3023},[3017,7808,7809],{"class":3059}," AsyncAutoResetEvent",[3017,7811,3116],{"class":3037},[3017,7813,7814],{"class":3033},"signaled",[3017,7816,5606],{"class":3037},[3017,7818,3257],{"class":3023},[3017,7820,3295],{"class":3037},[3017,7822,7823],{"class":3019,"line":3076},[3017,7824,3051],{"emptyLinePlaceholder":3050},[3017,7826,7827],{"class":3019,"line":3096},[3017,7828,7829],{"class":3092},"// Producer\n",[3017,7831,7832,7834,7836,7838,7840,7843,7845,7847],{"class":3019,"line":3102},[3017,7833,3927],{"class":3033},[3017,7835,3038],{"class":3037},[3017,7837,5820],{"class":3033},[3017,7839,3110],{"class":3037},[3017,7841,7842],{"class":3063},"Run",[3017,7844,3116],{"class":3037},[3017,7846,3001],{"class":3023},[3017,7848,7849],{"class":3037}," () =>\n",[3017,7851,7852],{"class":3019,"line":3129},[3017,7853,3073],{"class":3037},[3017,7855,7856,7858,7860,7862,7864,7866,7869],{"class":3019,"line":3135},[3017,7857,3581],{"class":3023},[3017,7859,3060],{"class":3033},[3017,7861,3110],{"class":3037},[3017,7863,3113],{"class":3063},[3017,7865,3116],{"class":3037},[3017,7867,7868],{"class":3119},"1000",[3017,7870,3295],{"class":3037},[3017,7872,7873,7876,7878,7881,7884],{"class":3019,"line":3268},[3017,7874,7875],{"class":3033},"    autoEvent",[3017,7877,3110],{"class":3037},[3017,7879,7880],{"class":3063},"Set",[3017,7882,7883],{"class":3037},"();  ",[3017,7885,7886],{"class":3092},"// Дозволяє одному waiter пройти\n",[3017,7888,7889,7891,7893,7895,7897,7900],{"class":3019,"line":3273},[3017,7890,5692],{"class":3033},[3017,7892,3110],{"class":3037},[3017,7894,3419],{"class":3063},[3017,7896,3116],{"class":3037},[3017,7898,7899],{"class":3424},"\"Event set\"",[3017,7901,3295],{"class":3037},[3017,7903,7904],{"class":3019,"line":3298},[3017,7905,7906],{"class":3037},"});\n",[3017,7908,7909],{"class":3019,"line":3303},[3017,7910,3051],{"emptyLinePlaceholder":3050},[3017,7912,7913],{"class":3019,"line":3308},[3017,7914,7915],{"class":3092},"// Consumer\n",[3017,7917,7918,7920,7922,7924,7926],{"class":3019,"line":3314},[3017,7919,3005],{"class":3023},[3017,7921,7802],{"class":3033},[3017,7923,3110],{"class":3037},[3017,7925,3752],{"class":3063},[3017,7927,3044],{"class":3037},[3017,7929,7930,7932,7934,7936,7938,7941],{"class":3019,"line":3319},[3017,7931,3980],{"class":3033},[3017,7933,3110],{"class":3037},[3017,7935,3419],{"class":3063},[3017,7937,3116],{"class":3037},[3017,7939,7940],{"class":3424},"\"Event received\"",[3017,7942,3295],{"class":3037},[3017,7944,7945],{"class":3019,"line":3332},[3017,7946,3051],{"emptyLinePlaceholder":3050},[3017,7948,7949],{"class":3019,"line":3349},[3017,7950,7951],{"class":3092},"// Manual-reset: всі waiters проходять\n",[3017,7953,7954,7956,7959,7961,7963,7966,7968,7970,7972,7974],{"class":3019,"line":3824},[3017,7955,3872],{"class":3023},[3017,7957,7958],{"class":3033}," manualEvent",[3017,7960,3038],{"class":3037},[3017,7962,3041],{"class":3023},[3017,7964,7965],{"class":3059}," AsyncManualResetEvent",[3017,7967,3116],{"class":3037},[3017,7969,7814],{"class":3033},[3017,7971,5606],{"class":3037},[3017,7973,3257],{"class":3023},[3017,7975,3295],{"class":3037},[3017,7977,7978],{"class":3019,"line":3830},[3017,7979,3051],{"emptyLinePlaceholder":3050},[3017,7981,7982],{"class":3019,"line":3843},[3017,7983,7984],{"class":3092},"// Кілька consumers\n",[3017,7986,7987,7989,7992,7994,7996,7998,8000,8002,8004,8006,8008],{"class":3019,"line":3848},[3017,7988,3872],{"class":3023},[3017,7990,7991],{"class":3033}," waiters",[3017,7993,3038],{"class":3037},[3017,7995,3897],{"class":3033},[3017,7997,3110],{"class":3037},[3017,7999,3902],{"class":3063},[3017,8001,3116],{"class":3037},[3017,8003,3907],{"class":3119},[3017,8005,2971],{"class":3037},[3017,8007,4550],{"class":3119},[3017,8009,3222],{"class":3037},[3017,8011,8012,8014,8016,8018,8020,8022],{"class":3019,"line":3853},[3017,8013,3919],{"class":3037},[3017,8015,3922],{"class":3063},[3017,8017,3116],{"class":3037},[3017,8019,3001],{"class":3023},[3017,8021,5646],{"class":3033},[3017,8023,7436],{"class":3037},[3017,8025,8026],{"class":3019,"line":3858},[3017,8027,3099],{"class":3037},[3017,8029,8030,8032,8034,8036,8038],{"class":3019,"line":3863},[3017,8031,3105],{"class":3023},[3017,8033,7958],{"class":3033},[3017,8035,3110],{"class":3037},[3017,8037,3752],{"class":3063},[3017,8039,3044],{"class":3037},[3017,8041,8042,8044,8046,8048,8050,8053,8055,8057,8059,8062],{"class":3019,"line":3869},[3017,8043,3414],{"class":3033},[3017,8045,3110],{"class":3037},[3017,8047,3419],{"class":3063},[3017,8049,3116],{"class":3037},[3017,8051,8052],{"class":3424},"$\"Waiter ",[3017,8054,3429],{"class":3428},[3017,8056,4808],{"class":3033},[3017,8058,3445],{"class":3428},[3017,8060,8061],{"class":3424}," пройшов\"",[3017,8063,3295],{"class":3037},[3017,8065,8066],{"class":3019,"line":3887},[3017,8067,8068],{"class":3037},"    })\n",[3017,8070,8071,8073,8075],{"class":3019,"line":3916},[3017,8072,3919],{"class":3037},[3017,8074,3948],{"class":3063},[3017,8076,3044],{"class":3037},[3017,8078,8079],{"class":3019,"line":3943},[3017,8080,3051],{"emptyLinePlaceholder":3050},[3017,8082,8083,8085,8087,8089,8091,8093,8095],{"class":3019,"line":3953},[3017,8084,3005],{"class":3023},[3017,8086,3060],{"class":3033},[3017,8088,3110],{"class":3037},[3017,8090,3113],{"class":3063},[3017,8092,3116],{"class":3037},[3017,8094,7868],{"class":3119},[3017,8096,3295],{"class":3037},[3017,8098,8099,8102,8104,8106,8108],{"class":3019,"line":3958},[3017,8100,8101],{"class":3033},"manualEvent",[3017,8103,3110],{"class":3037},[3017,8105,7880],{"class":3063},[3017,8107,7883],{"class":3037},[3017,8109,8110],{"class":3092},"// Всі 5 waiters проходять одночасно\n",[3017,8112,8113],{"class":3019,"line":3977},[3017,8114,3051],{"emptyLinePlaceholder":3050},[3017,8116,8117,8119,8121,8123,8125,8127,8130],{"class":3019,"line":5384},[3017,8118,3005],{"class":3023},[3017,8120,3060],{"class":3033},[3017,8122,3110],{"class":3037},[3017,8124,3967],{"class":3063},[3017,8126,3116],{"class":3037},[3017,8128,8129],{"class":3033},"waiters",[3017,8131,3295],{"class":3037},[3192,8133,8135,8136],{"id":8134},"asynccollection-async-producer-consumer","AsyncCollection",[8137,8138,8139],"t",{},": Async Producer-Consumer",[2964,8141,8142,8143,8146],{},"Альтернатива ",[2968,8144,8145],{},"Channel\u003CT>"," з додатковими можливостями:",[3008,8148,8151],{"className":3010,"code":8149,"filename":8150,"language":3012,"meta":3648,"style":3013},"using Nito.AsyncEx;\n\nvar collection = new AsyncCollection\u003Cint>();\n\n// Producer\n_ = Task.Run(async () =>\n{\n    for (int i = 0; i \u003C 10; i++)\n    {\n        await collection.AddAsync(i);\n        await Task.Delay(100);\n    }\n    collection.CompleteAdding();\n});\n\n// Consumer\nawait foreach (var item in collection.GetConsumingAsyncEnumerable())\n{\n    Console.WriteLine($\"Consumed: {item}\");\n}\n","NitoAsyncCollection.cs",[2968,8152,8153,8165,8169,8190,8194,8198,8216,8220,8248,8252,8269,8285,8289,8301,8305,8309,8313,8339,8343,8367],{"__ignoreMap":3013},[3017,8154,8155,8157,8159,8161,8163],{"class":3019,"line":3020},[3017,8156,4268],{"class":3079},[3017,8158,7603],{"class":3059},[3017,8160,3110],{"class":3037},[3017,8162,7608],{"class":3059},[3017,8164,3260],{"class":3037},[3017,8166,8167],{"class":3019,"line":3047},[3017,8168,3051],{"emptyLinePlaceholder":3050},[3017,8170,8171,8173,8176,8178,8180,8183,8185,8187],{"class":3019,"line":3054},[3017,8172,3872],{"class":3023},[3017,8174,8175],{"class":3033}," collection",[3017,8177,3038],{"class":3037},[3017,8179,3041],{"class":3023},[3017,8181,8182],{"class":3059}," AsyncCollection",[3017,8184,3721],{"class":3037},[3017,8186,3724],{"class":3023},[3017,8188,8189],{"class":3037},">();\n",[3017,8191,8192],{"class":3019,"line":3070},[3017,8193,3051],{"emptyLinePlaceholder":3050},[3017,8195,8196],{"class":3019,"line":3076},[3017,8197,7829],{"class":3092},[3017,8199,8200,8202,8204,8206,8208,8210,8212,8214],{"class":3019,"line":3096},[3017,8201,3927],{"class":3033},[3017,8203,3038],{"class":3037},[3017,8205,5820],{"class":3033},[3017,8207,3110],{"class":3037},[3017,8209,7842],{"class":3063},[3017,8211,3116],{"class":3037},[3017,8213,3001],{"class":3023},[3017,8215,7849],{"class":3037},[3017,8217,8218],{"class":3019,"line":3102},[3017,8219,3073],{"class":3037},[3017,8221,8222,8224,8226,8228,8230,8232,8234,8236,8238,8240,8242,8244,8246],{"class":3019,"line":3129},[3017,8223,7054],{"class":3079},[3017,8225,3083],{"class":3037},[3017,8227,3724],{"class":3023},[3017,8229,5646],{"class":3033},[3017,8231,3038],{"class":3037},[3017,8233,3907],{"class":3119},[3017,8235,5653],{"class":3037},[3017,8237,4808],{"class":3033},[3017,8239,5658],{"class":3037},[3017,8241,3785],{"class":3119},[3017,8243,5653],{"class":3037},[3017,8245,4808],{"class":3033},[3017,8247,5668],{"class":3037},[3017,8249,8250],{"class":3019,"line":3135},[3017,8251,3099],{"class":3037},[3017,8253,8254,8256,8258,8260,8263,8265,8267],{"class":3019,"line":3268},[3017,8255,3105],{"class":3023},[3017,8257,8175],{"class":3033},[3017,8259,3110],{"class":3037},[3017,8261,8262],{"class":3063},"AddAsync",[3017,8264,3116],{"class":3037},[3017,8266,4808],{"class":3033},[3017,8268,3295],{"class":3037},[3017,8270,8271,8273,8275,8277,8279,8281,8283],{"class":3019,"line":3273},[3017,8272,3105],{"class":3023},[3017,8274,3060],{"class":3033},[3017,8276,3110],{"class":3037},[3017,8278,3113],{"class":3063},[3017,8280,3116],{"class":3037},[3017,8282,3120],{"class":3119},[3017,8284,3295],{"class":3037},[3017,8286,8287],{"class":3019,"line":3298},[3017,8288,3132],{"class":3037},[3017,8290,8291,8294,8296,8299],{"class":3019,"line":3303},[3017,8292,8293],{"class":3033},"    collection",[3017,8295,3110],{"class":3037},[3017,8297,8298],{"class":3063},"CompleteAdding",[3017,8300,3044],{"class":3037},[3017,8302,8303],{"class":3019,"line":3308},[3017,8304,7906],{"class":3037},[3017,8306,8307],{"class":3019,"line":3314},[3017,8308,3051],{"emptyLinePlaceholder":3050},[3017,8310,8311],{"class":3019,"line":3319},[3017,8312,7915],{"class":3092},[3017,8314,8315,8317,8320,8322,8324,8327,8330,8332,8334,8337],{"class":3019,"line":3332},[3017,8316,3005],{"class":3023},[3017,8318,8319],{"class":3079}," foreach",[3017,8321,3083],{"class":3037},[3017,8323,3872],{"class":3023},[3017,8325,8326],{"class":3033}," item",[3017,8328,8329],{"class":3079}," in",[3017,8331,8175],{"class":3033},[3017,8333,3110],{"class":3037},[3017,8335,8336],{"class":3063},"GetConsumingAsyncEnumerable",[3017,8338,3940],{"class":3037},[3017,8340,8341],{"class":3019,"line":3349},[3017,8342,3073],{"class":3037},[3017,8344,8345,8347,8349,8351,8353,8356,8358,8361,8363,8365],{"class":3019,"line":3824},[3017,8346,5692],{"class":3033},[3017,8348,3110],{"class":3037},[3017,8350,3419],{"class":3063},[3017,8352,3116],{"class":3037},[3017,8354,8355],{"class":3424},"$\"Consumed: ",[3017,8357,3429],{"class":3428},[3017,8359,8360],{"class":3033},"item",[3017,8362,3445],{"class":3428},[3017,8364,3448],{"class":3424},[3017,8366,3295],{"class":3037},[3017,8368,8369],{"class":3019,"line":3830},[3017,8370,3138],{"class":3037},[3192,8372,8374,8375],{"id":8373},"asynclazy-lazy-async-initialization","AsyncLazy",[8137,8376,8377],{},": Lazy Async Initialization",[2964,8379,8380],{},"Правильна реалізація lazy async initialization:",[3008,8382,8385],{"className":3010,"code":8383,"filename":8384,"language":3012,"meta":3648,"style":3013},"using Nito.AsyncEx;\n\nclass ExpensiveService\n{\n    private readonly AsyncLazy\u003Cstring> _data;\n\n    public ExpensiveService()\n    {\n        _data = new AsyncLazy\u003Cstring>(async () =>\n        {\n            Console.WriteLine(\"Ініціалізація...\");\n            await Task.Delay(2000);\n            return \"Expensive data\";\n        });\n    }\n\n    public Task\u003Cstring> GetDataAsync() => _data.Task;\n}\n\n// Використання\nvar service = new ExpensiveService();\n\n// Перший виклик — запускає ініціалізацію\nvar data1 = await service.GetDataAsync();  // 2 секунди\n\n// Наступні виклики — повертають кешований результат\nvar data2 = await service.GetDataAsync();  // Instant\nvar data3 = await service.GetDataAsync();  // Instant\n","NitoAsyncLazy.cs",[2968,8386,8387,8399,8403,8410,8414,8434,8438,8447,8451,8472,8476,8491,8508,8517,8522,8526,8530,8555,8559,8563,8567,8582,8586,8591,8613,8617,8622,8644],{"__ignoreMap":3013},[3017,8388,8389,8391,8393,8395,8397],{"class":3019,"line":3020},[3017,8390,4268],{"class":3079},[3017,8392,7603],{"class":3059},[3017,8394,3110],{"class":3037},[3017,8396,7608],{"class":3059},[3017,8398,3260],{"class":3037},[3017,8400,8401],{"class":3019,"line":3047},[3017,8402,3051],{"emptyLinePlaceholder":3050},[3017,8404,8405,8407],{"class":3019,"line":3054},[3017,8406,3655],{"class":3023},[3017,8408,8409],{"class":3059}," ExpensiveService\n",[3017,8411,8412],{"class":3019,"line":3070},[3017,8413,3073],{"class":3037},[3017,8415,8416,8418,8420,8423,8425,8427,8429,8432],{"class":3019,"line":3076},[3017,8417,3667],{"class":3023},[3017,8419,3027],{"class":3023},[3017,8421,8422],{"class":3059}," AsyncLazy",[3017,8424,3721],{"class":3037},[3017,8426,4576],{"class":3023},[3017,8428,3727],{"class":3037},[3017,8430,8431],{"class":3033},"_data",[3017,8433,3260],{"class":3037},[3017,8435,8436],{"class":3019,"line":3096},[3017,8437,3051],{"emptyLinePlaceholder":3050},[3017,8439,8440,8442,8445],{"class":3019,"line":3102},[3017,8441,3713],{"class":3023},[3017,8443,8444],{"class":3063}," ExpensiveService",[3017,8446,3067],{"class":3037},[3017,8448,8449],{"class":3019,"line":3129},[3017,8450,3099],{"class":3037},[3017,8452,8453,8456,8458,8460,8462,8464,8466,8468,8470],{"class":3019,"line":3135},[3017,8454,8455],{"class":3033},"        _data",[3017,8457,3038],{"class":3037},[3017,8459,3041],{"class":3023},[3017,8461,8422],{"class":3059},[3017,8463,3721],{"class":3037},[3017,8465,4576],{"class":3023},[3017,8467,5817],{"class":3037},[3017,8469,3001],{"class":3023},[3017,8471,7849],{"class":3037},[3017,8473,8474],{"class":3019,"line":3268},[3017,8475,3764],{"class":3037},[3017,8477,8478,8480,8482,8484,8486,8489],{"class":3019,"line":3273},[3017,8479,4642],{"class":3033},[3017,8481,3110],{"class":3037},[3017,8483,3419],{"class":3063},[3017,8485,3116],{"class":3037},[3017,8487,8488],{"class":3424},"\"Ініціалізація...\"",[3017,8490,3295],{"class":3037},[3017,8492,8493,8495,8497,8499,8501,8503,8506],{"class":3019,"line":3298},[3017,8494,3774],{"class":3023},[3017,8496,3060],{"class":3033},[3017,8498,3110],{"class":3037},[3017,8500,3113],{"class":3063},[3017,8502,3116],{"class":3037},[3017,8504,8505],{"class":3119},"2000",[3017,8507,3295],{"class":3037},[3017,8509,8510,8512,8515],{"class":3019,"line":3303},[3017,8511,3803],{"class":3079},[3017,8513,8514],{"class":3424}," \"Expensive data\"",[3017,8516,3260],{"class":3037},[3017,8518,8519],{"class":3019,"line":3308},[3017,8520,8521],{"class":3037},"        });\n",[3017,8523,8524],{"class":3019,"line":3314},[3017,8525,3132],{"class":3037},[3017,8527,8528],{"class":3019,"line":3319},[3017,8529,3051],{"emptyLinePlaceholder":3050},[3017,8531,8532,8534,8536,8538,8540,8542,8545,8547,8549,8551,8553],{"class":3019,"line":3332},[3017,8533,3713],{"class":3023},[3017,8535,3060],{"class":3059},[3017,8537,3721],{"class":3037},[3017,8539,4576],{"class":3023},[3017,8541,3727],{"class":3037},[3017,8543,8544],{"class":3063},"GetDataAsync",[3017,8546,4218],{"class":3037},[3017,8548,8431],{"class":3033},[3017,8550,3110],{"class":3037},[3017,8552,5820],{"class":3033},[3017,8554,3260],{"class":3037},[3017,8556,8557],{"class":3019,"line":3349},[3017,8558,3138],{"class":3037},[3017,8560,8561],{"class":3019,"line":3824},[3017,8562,3051],{"emptyLinePlaceholder":3050},[3017,8564,8565],{"class":3019,"line":3830},[3017,8566,5980],{"class":3092},[3017,8568,8569,8571,8574,8576,8578,8580],{"class":3019,"line":3843},[3017,8570,3872],{"class":3023},[3017,8572,8573],{"class":3033}," service",[3017,8575,3038],{"class":3037},[3017,8577,3041],{"class":3023},[3017,8579,8444],{"class":3059},[3017,8581,3044],{"class":3037},[3017,8583,8584],{"class":3019,"line":3848},[3017,8585,3051],{"emptyLinePlaceholder":3050},[3017,8587,8588],{"class":3019,"line":3853},[3017,8589,8590],{"class":3092},"// Перший виклик — запускає ініціалізацію\n",[3017,8592,8593,8595,8598,8600,8602,8604,8606,8608,8610],{"class":3019,"line":3858},[3017,8594,3872],{"class":3023},[3017,8596,8597],{"class":3033}," data1",[3017,8599,3038],{"class":3037},[3017,8601,3005],{"class":3023},[3017,8603,8573],{"class":3033},[3017,8605,3110],{"class":3037},[3017,8607,8544],{"class":3063},[3017,8609,7883],{"class":3037},[3017,8611,8612],{"class":3092},"// 2 секунди\n",[3017,8614,8615],{"class":3019,"line":3863},[3017,8616,3051],{"emptyLinePlaceholder":3050},[3017,8618,8619],{"class":3019,"line":3869},[3017,8620,8621],{"class":3092},"// Наступні виклики — повертають кешований результат\n",[3017,8623,8624,8626,8629,8631,8633,8635,8637,8639,8641],{"class":3019,"line":3887},[3017,8625,3872],{"class":3023},[3017,8627,8628],{"class":3033}," data2",[3017,8630,3038],{"class":3037},[3017,8632,3005],{"class":3023},[3017,8634,8573],{"class":3033},[3017,8636,3110],{"class":3037},[3017,8638,8544],{"class":3063},[3017,8640,7883],{"class":3037},[3017,8642,8643],{"class":3092},"// Instant\n",[3017,8645,8646,8648,8651,8653,8655,8657,8659,8661,8663],{"class":3019,"line":3916},[3017,8647,3872],{"class":3023},[3017,8649,8650],{"class":3033}," data3",[3017,8652,3038],{"class":3037},[3017,8654,3005],{"class":3023},[3017,8656,8573],{"class":3033},[3017,8658,3110],{"class":3037},[3017,8660,8544],{"class":3063},[3017,8662,7883],{"class":3037},[3017,8664,8643],{"class":3092},[3192,8666,8668],{"id":8667},"asyncreaderwriterlock-async-rw-lock","AsyncReaderWriterLock: Async RW Lock",[2964,8670,8671,8672,3201],{},"Async версія ",[2968,8673,8674],{},"ReaderWriterLockSlim",[3008,8676,8679],{"className":3010,"code":8677,"filename":8678,"language":3012,"meta":3648,"style":3013},"using Nito.AsyncEx;\n\nclass AsyncCache\n{\n    private readonly AsyncReaderWriterLock _lock = new();\n    private readonly Dictionary\u003Cstring, string> _cache = new();\n\n    public async Task\u003Cstring?> GetAsync(string key)\n    {\n        // Множинні readers можуть читати одночасно\n        using (await _lock.ReaderLockAsync())\n        {\n            await Task.Delay(10);  // Імітація читання\n            return _cache.TryGetValue(key, out var value) ? value : null;\n        }\n    }\n\n    public async Task SetAsync(string key, string value)\n    {\n        // Тільки один writer одночасно\n        using (await _lock.WriterLockAsync())\n        {\n            await Task.Delay(50);  // Імітація запису\n            _cache[key] = value;\n        }\n    }\n}\n","NitoAsyncRWLock.cs",[2968,8680,8681,8693,8697,8704,8708,8725,8753,8757,8783,8787,8792,8809,8813,8832,8871,8875,8879,8883,8908,8912,8917,8934,8938,8958,8975,8979,8983],{"__ignoreMap":3013},[3017,8682,8683,8685,8687,8689,8691],{"class":3019,"line":3020},[3017,8684,4268],{"class":3079},[3017,8686,7603],{"class":3059},[3017,8688,3110],{"class":3037},[3017,8690,7608],{"class":3059},[3017,8692,3260],{"class":3037},[3017,8694,8695],{"class":3019,"line":3047},[3017,8696,3051],{"emptyLinePlaceholder":3050},[3017,8698,8699,8701],{"class":3019,"line":3054},[3017,8700,3655],{"class":3023},[3017,8702,8703],{"class":3059}," AsyncCache\n",[3017,8705,8706],{"class":3019,"line":3070},[3017,8707,3073],{"class":3037},[3017,8709,8710,8712,8714,8717,8719,8721,8723],{"class":3019,"line":3076},[3017,8711,3667],{"class":3023},[3017,8713,3027],{"class":3023},[3017,8715,8716],{"class":3059}," AsyncReaderWriterLock",[3017,8718,3034],{"class":3033},[3017,8720,3038],{"class":3037},[3017,8722,3041],{"class":3023},[3017,8724,3044],{"class":3037},[3017,8726,8727,8729,8731,8734,8736,8738,8740,8742,8744,8747,8749,8751],{"class":3019,"line":3096},[3017,8728,3667],{"class":3023},[3017,8730,3027],{"class":3023},[3017,8732,8733],{"class":3059}," Dictionary",[3017,8735,3721],{"class":3037},[3017,8737,4576],{"class":3023},[3017,8739,2971],{"class":3037},[3017,8741,4576],{"class":3023},[3017,8743,3727],{"class":3037},[3017,8745,8746],{"class":3033},"_cache",[3017,8748,3038],{"class":3037},[3017,8750,3041],{"class":3023},[3017,8752,3044],{"class":3037},[3017,8754,8755],{"class":3019,"line":3102},[3017,8756,3051],{"emptyLinePlaceholder":3050},[3017,8758,8759,8761,8763,8765,8767,8769,8772,8774,8776,8778,8781],{"class":3019,"line":3129},[3017,8760,3713],{"class":3023},[3017,8762,3716],{"class":3023},[3017,8764,3060],{"class":3059},[3017,8766,3721],{"class":3037},[3017,8768,4576],{"class":3023},[3017,8770,8771],{"class":3037},"?> ",[3017,8773,4581],{"class":3063},[3017,8775,3116],{"class":3037},[3017,8777,4576],{"class":3023},[3017,8779,8780],{"class":3033}," key",[3017,8782,3222],{"class":3037},[3017,8784,8785],{"class":3019,"line":3135},[3017,8786,3099],{"class":3037},[3017,8788,8789],{"class":3019,"line":3268},[3017,8790,8791],{"class":3092},"        // Множинні readers можуть читати одночасно\n",[3017,8793,8794,8796,8798,8800,8802,8804,8807],{"class":3019,"line":3273},[3017,8795,7091],{"class":3079},[3017,8797,3083],{"class":3037},[3017,8799,3005],{"class":3023},[3017,8801,3034],{"class":3033},[3017,8803,3110],{"class":3037},[3017,8805,8806],{"class":3063},"ReaderLockAsync",[3017,8808,3940],{"class":3037},[3017,8810,8811],{"class":3019,"line":3298},[3017,8812,3764],{"class":3037},[3017,8814,8815,8817,8819,8821,8823,8825,8827,8829],{"class":3019,"line":3303},[3017,8816,3774],{"class":3023},[3017,8818,3060],{"class":3033},[3017,8820,3110],{"class":3037},[3017,8822,3113],{"class":3063},[3017,8824,3116],{"class":3037},[3017,8826,3785],{"class":3119},[3017,8828,3123],{"class":3037},[3017,8830,8831],{"class":3092},"// Імітація читання\n",[3017,8833,8834,8836,8839,8841,8844,8846,8849,8851,8854,8856,8859,8862,8865,8867,8869],{"class":3019,"line":3308},[3017,8835,3803],{"class":3079},[3017,8837,8838],{"class":3033}," _cache",[3017,8840,3110],{"class":3037},[3017,8842,8843],{"class":3063},"TryGetValue",[3017,8845,3116],{"class":3037},[3017,8847,8848],{"class":3033},"key",[3017,8850,2971],{"class":3037},[3017,8852,8853],{"class":3023},"out",[3017,8855,6270],{"class":3023},[3017,8857,8858],{"class":3033}," value",[3017,8860,8861],{"class":3037},") ? ",[3017,8863,8864],{"class":3033},"value",[3017,8866,4151],{"class":3037},[3017,8868,6989],{"class":3023},[3017,8870,3260],{"class":3037},[3017,8872,8873],{"class":3019,"line":3314},[3017,8874,3812],{"class":3037},[3017,8876,8877],{"class":3019,"line":3319},[3017,8878,3132],{"class":3037},[3017,8880,8881],{"class":3019,"line":3332},[3017,8882,3051],{"emptyLinePlaceholder":3050},[3017,8884,8885,8887,8889,8891,8894,8896,8898,8900,8902,8904,8906],{"class":3019,"line":3349},[3017,8886,3713],{"class":3023},[3017,8888,3716],{"class":3023},[3017,8890,3060],{"class":3059},[3017,8892,8893],{"class":3063}," SetAsync",[3017,8895,3116],{"class":3037},[3017,8897,4576],{"class":3023},[3017,8899,8780],{"class":3033},[3017,8901,2971],{"class":3037},[3017,8903,4576],{"class":3023},[3017,8905,8858],{"class":3033},[3017,8907,3222],{"class":3037},[3017,8909,8910],{"class":3019,"line":3824},[3017,8911,3099],{"class":3037},[3017,8913,8914],{"class":3019,"line":3830},[3017,8915,8916],{"class":3092},"        // Тільки один writer одночасно\n",[3017,8918,8919,8921,8923,8925,8927,8929,8932],{"class":3019,"line":3843},[3017,8920,7091],{"class":3079},[3017,8922,3083],{"class":3037},[3017,8924,3005],{"class":3023},[3017,8926,3034],{"class":3033},[3017,8928,3110],{"class":3037},[3017,8930,8931],{"class":3063},"WriterLockAsync",[3017,8933,3940],{"class":3037},[3017,8935,8936],{"class":3019,"line":3848},[3017,8937,3764],{"class":3037},[3017,8939,8940,8942,8944,8946,8948,8950,8953,8955],{"class":3019,"line":3853},[3017,8941,3774],{"class":3023},[3017,8943,3060],{"class":3033},[3017,8945,3110],{"class":3037},[3017,8947,3113],{"class":3063},[3017,8949,3116],{"class":3037},[3017,8951,8952],{"class":3119},"50",[3017,8954,3123],{"class":3037},[3017,8956,8957],{"class":3092},"// Імітація запису\n",[3017,8959,8960,8963,8966,8968,8971,8973],{"class":3019,"line":3858},[3017,8961,8962],{"class":3033},"            _cache",[3017,8964,8965],{"class":3037},"[",[3017,8967,8848],{"class":3033},[3017,8969,8970],{"class":3037},"] = ",[3017,8972,8864],{"class":3033},[3017,8974,3260],{"class":3037},[3017,8976,8977],{"class":3019,"line":3863},[3017,8978,3812],{"class":3037},[3017,8980,8981],{"class":3019,"line":3869},[3017,8982,3132],{"class":3037},[3017,8984,8985],{"class":3019,"line":3887},[3017,8986,3138],{"class":3037},[3192,8988,8990],{"id":8989},"порівняння-nitoasyncex-vs-manual-implementation","Порівняння: Nito.AsyncEx vs Manual Implementation",[4318,8992,8993,9005],{},[4321,8994,8995],{},[4324,8996,8997,9000,9003],{},[4327,8998,8999],{},"Примітив",[4327,9001,9002],{},"Manual (SemaphoreSlim)",[4327,9004,3182],{},[4340,9006,9007,9023,9035,9048,9063,9078],{},[4324,9008,9009,9014,9017],{},[4345,9010,9011],{},[2983,9012,9013],{},"Async Lock",[4345,9015,9016],{},"~20 рядків коду",[4345,9018,9019,9022],{},[2968,9020,9021],{},"AsyncLock"," — 1 рядок",[4324,9024,9025,9029,9032],{},[4345,9026,9027],{},[2983,9028,4393],{},[4345,9030,9031],{},"Ручна обробка",[4345,9033,9034],{},"Вбудована підтримка",[4324,9036,9037,9042,9045],{},[4345,9038,9039],{},[2983,9040,9041],{},"Reentrancy",[4345,9043,9044],{},"Немає",[4345,9046,9047],{},"Опціональна підтримка",[4324,9049,9050,9055,9058],{},[4345,9051,9052],{},[2983,9053,9054],{},"Reader/Writer",[4345,9056,9057],{},"~100 рядків",[4345,9059,9060],{},[2968,9061,9062],{},"AsyncReaderWriterLock",[4324,9064,9065,9070,9073],{},[4345,9066,9067],{},[2983,9068,9069],{},"Lazy Init",[4345,9071,9072],{},"Складна логіка",[4345,9074,9075],{},[2968,9076,9077],{},"AsyncLazy\u003CT>",[4324,9079,9080,9084,9087],{},[4345,9081,9082],{},[2983,9083,2122],{},[4345,9085,9086],{},"Потрібні власні тести",[4345,9088,9089],{},"Протестовано community",[4434,9091,9092,9097],{},[2964,9093,9094],{},[2983,9095,9096],{},"Коли використовувати Nito.AsyncEx:",[4442,9098,9099,9102,9105,9108],{},[4445,9100,9101],{},"Складні async synchronization scenarios",[4445,9103,9104],{},"Потрібна підтримка cancellation out-of-the-box",[4445,9106,9107],{},"Немає часу писати та тестувати власні реалізації",[4445,9109,9110],{},"Проєкт вже використовує інші async patterns",[3185,9112],{},[2959,9114,9116],{"id":9115},"наскрізний-приклад-resilient-http-client","Наскрізний Приклад: Resilient HTTP Client",[2964,9118,9119],{},"Побудуємо HTTP client з усіма вивченими паттернами: throttling, rate limiting, retry, timeout, cancellation.",[9121,9122,9123,9127,9164,9168,9583,9587,10504,10508,11172,11176,11819,11823],"steps",{},[3192,9124,9126],{"id":9125},"крок-1-структура-проєкту","Крок 1: Структура проєкту",[3008,9128,9130],{"className":7565,"code":9129,"language":7567,"meta":3013,"style":3013},"dotnet new console -n ResilientHttpClient\ncd ResilientHttpClient\ndotnet add package Nito.AsyncEx\n",[2968,9131,9132,9147,9154],{"__ignoreMap":3013},[3017,9133,9134,9136,9138,9141,9144],{"class":3019,"line":3020},[3017,9135,7574],{"class":3063},[3017,9137,4121],{"class":3424},[3017,9139,9140],{"class":3424}," console",[3017,9142,9143],{"class":3023}," -n",[3017,9145,9146],{"class":3424}," ResilientHttpClient\n",[3017,9148,9149,9152],{"class":3019,"line":3047},[3017,9150,9151],{"class":3063},"cd",[3017,9153,9146],{"class":3424},[3017,9155,9156,9158,9160,9162],{"class":3019,"line":3054},[3017,9157,7574],{"class":3063},[3017,9159,7577],{"class":3424},[3017,9161,7580],{"class":3424},[3017,9163,7583],{"class":3424},[3192,9165,9167],{"id":9166},"крок-2-rate-limiter","Крок 2: Rate Limiter",[3008,9169,9171],{"className":3010,"code":9170,"filename":4995,"language":3012,"meta":3648,"style":3013},"using Nito.AsyncEx;\n\nclass RateLimiter\n{\n    private readonly int _maxRequests;\n    private readonly TimeSpan _timeWindow;\n    private readonly Queue\u003CDateTime> _timestamps = new();\n    private readonly AsyncLock _lock = new();\n\n    public RateLimiter(int maxRequests, TimeSpan timeWindow)\n    {\n        _maxRequests = maxRequests;\n        _timeWindow = timeWindow;\n    }\n\n    public async Task WaitAsync(CancellationToken ct = default)\n    {\n        using (await _lock.LockAsync(ct))\n        {\n            var now = DateTime.UtcNow;\n            var windowStart = now - _timeWindow;\n\n            while (_timestamps.Count > 0 && _timestamps.Peek() \u003C windowStart)\n                _timestamps.Dequeue();\n\n            if (_timestamps.Count >= _maxRequests)\n            {\n                var delay = _timestamps.Peek() + _timeWindow - now;\n                if (delay > TimeSpan.Zero)\n                    await Task.Delay(delay, ct);\n\n                _timestamps.Dequeue();\n            }\n\n            _timestamps.Enqueue(now);\n        }\n    }\n}\n",[2968,9172,9173,9185,9189,9195,9199,9211,9223,9246,9262,9266,9286,9290,9300,9310,9314,9318,9340,9344,9364,9368,9384,9400,9404,9434,9445,9449,9467,9471,9496,9514,9534,9538,9548,9552,9556,9571,9575,9579],{"__ignoreMap":3013},[3017,9174,9175,9177,9179,9181,9183],{"class":3019,"line":3020},[3017,9176,4268],{"class":3079},[3017,9178,7603],{"class":3059},[3017,9180,3110],{"class":3037},[3017,9182,7608],{"class":3059},[3017,9184,3260],{"class":3037},[3017,9186,9187],{"class":3019,"line":3047},[3017,9188,3051],{"emptyLinePlaceholder":3050},[3017,9190,9191,9193],{"class":3019,"line":3054},[3017,9192,3655],{"class":3023},[3017,9194,5004],{"class":3059},[3017,9196,9197],{"class":3019,"line":3070},[3017,9198,3073],{"class":3037},[3017,9200,9201,9203,9205,9207,9209],{"class":3019,"line":3076},[3017,9202,3667],{"class":3023},[3017,9204,3027],{"class":3023},[3017,9206,3670],{"class":3023},[3017,9208,5019],{"class":3033},[3017,9210,3260],{"class":3037},[3017,9212,9213,9215,9217,9219,9221],{"class":3019,"line":3096},[3017,9214,3667],{"class":3023},[3017,9216,3027],{"class":3023},[3017,9218,5030],{"class":3059},[3017,9220,5033],{"class":3033},[3017,9222,3260],{"class":3037},[3017,9224,9225,9227,9229,9231,9233,9235,9237,9240,9242,9244],{"class":3019,"line":3102},[3017,9226,3667],{"class":3023},[3017,9228,3027],{"class":3023},[3017,9230,5044],{"class":3059},[3017,9232,3721],{"class":3037},[3017,9234,5049],{"class":3059},[3017,9236,3727],{"class":3037},[3017,9238,9239],{"class":3033},"_timestamps",[3017,9241,3038],{"class":3037},[3017,9243,3041],{"class":3023},[3017,9245,3044],{"class":3037},[3017,9247,9248,9250,9252,9254,9256,9258,9260],{"class":3019,"line":3129},[3017,9249,3667],{"class":3023},[3017,9251,3027],{"class":3023},[3017,9253,4257],{"class":3059},[3017,9255,3034],{"class":3033},[3017,9257,3038],{"class":3037},[3017,9259,3041],{"class":3023},[3017,9261,3044],{"class":3037},[3017,9263,9264],{"class":3019,"line":3135},[3017,9265,3051],{"emptyLinePlaceholder":3050},[3017,9267,9268,9270,9272,9274,9276,9278,9280,9282,9284],{"class":3019,"line":3268},[3017,9269,3713],{"class":3023},[3017,9271,5095],{"class":3063},[3017,9273,3116],{"class":3037},[3017,9275,3724],{"class":3023},[3017,9277,5102],{"class":3033},[3017,9279,2971],{"class":3037},[3017,9281,5107],{"class":3059},[3017,9283,5110],{"class":3033},[3017,9285,3222],{"class":3037},[3017,9287,9288],{"class":3019,"line":3273},[3017,9289,3099],{"class":3037},[3017,9291,9292,9294,9296,9298],{"class":3019,"line":3298},[3017,9293,5121],{"class":3033},[3017,9295,3038],{"class":3037},[3017,9297,5126],{"class":3033},[3017,9299,3260],{"class":3037},[3017,9301,9302,9304,9306,9308],{"class":3019,"line":3303},[3017,9303,5133],{"class":3033},[3017,9305,3038],{"class":3037},[3017,9307,5138],{"class":3033},[3017,9309,3260],{"class":3037},[3017,9311,9312],{"class":3019,"line":3308},[3017,9313,3132],{"class":3037},[3017,9315,9316],{"class":3019,"line":3314},[3017,9317,3051],{"emptyLinePlaceholder":3050},[3017,9319,9320,9322,9324,9326,9328,9330,9332,9334,9336,9338],{"class":3019,"line":3319},[3017,9321,3713],{"class":3023},[3017,9323,3716],{"class":3023},[3017,9325,3060],{"class":3059},[3017,9327,5159],{"class":3063},[3017,9329,3116],{"class":3037},[3017,9331,4593],{"class":3059},[3017,9333,4596],{"class":3033},[3017,9335,3038],{"class":3037},[3017,9337,4601],{"class":3023},[3017,9339,3222],{"class":3037},[3017,9341,9342],{"class":3019,"line":3332},[3017,9343,3099],{"class":3037},[3017,9345,9346,9348,9350,9352,9354,9356,9358,9360,9362],{"class":3019,"line":3349},[3017,9347,7091],{"class":3079},[3017,9349,3083],{"class":3037},[3017,9351,3005],{"class":3023},[3017,9353,3034],{"class":3033},[3017,9355,3110],{"class":3037},[3017,9357,4095],{"class":3063},[3017,9359,3116],{"class":3037},[3017,9361,4627],{"class":3033},[3017,9363,7228],{"class":3037},[3017,9365,9366],{"class":3019,"line":3824},[3017,9367,3764],{"class":3037},[3017,9369,9370,9372,9374,9376,9378,9380,9382],{"class":3019,"line":3830},[3017,9371,5204],{"class":3023},[3017,9373,5207],{"class":3033},[3017,9375,3038],{"class":3037},[3017,9377,5049],{"class":3033},[3017,9379,3110],{"class":3037},[3017,9381,5216],{"class":3033},[3017,9383,3260],{"class":3037},[3017,9385,9386,9388,9390,9392,9394,9396,9398],{"class":3019,"line":3843},[3017,9387,5204],{"class":3023},[3017,9389,5225],{"class":3033},[3017,9391,3038],{"class":3037},[3017,9393,5230],{"class":3033},[3017,9395,5233],{"class":3037},[3017,9397,5236],{"class":3033},[3017,9399,3260],{"class":3037},[3017,9401,9402],{"class":3019,"line":3848},[3017,9403,3051],{"emptyLinePlaceholder":3050},[3017,9405,9406,9408,9410,9412,9414,9416,9418,9420,9422,9424,9426,9428,9430,9432],{"class":3019,"line":3853},[3017,9407,5252],{"class":3079},[3017,9409,3083],{"class":3037},[3017,9411,9239],{"class":3033},[3017,9413,3110],{"class":3037},[3017,9415,5261],{"class":3033},[3017,9417,5264],{"class":3037},[3017,9419,3907],{"class":3119},[3017,9421,5269],{"class":3037},[3017,9423,9239],{"class":3033},[3017,9425,3110],{"class":3037},[3017,9427,5276],{"class":3063},[3017,9429,5279],{"class":3037},[3017,9431,5282],{"class":3033},[3017,9433,3222],{"class":3037},[3017,9435,9436,9439,9441,9443],{"class":3019,"line":3858},[3017,9437,9438],{"class":3033},"                _timestamps",[3017,9440,3110],{"class":3037},[3017,9442,5299],{"class":3063},[3017,9444,3044],{"class":3037},[3017,9446,9447],{"class":3019,"line":3863},[3017,9448,3051],{"emptyLinePlaceholder":3050},[3017,9450,9451,9453,9455,9457,9459,9461,9463,9465],{"class":3019,"line":3869},[3017,9452,5320],{"class":3079},[3017,9454,3083],{"class":3037},[3017,9456,9239],{"class":3033},[3017,9458,3110],{"class":3037},[3017,9460,5261],{"class":3033},[3017,9462,5331],{"class":3037},[3017,9464,5334],{"class":3033},[3017,9466,3222],{"class":3037},[3017,9468,9469],{"class":3019,"line":3887},[3017,9470,5289],{"class":3037},[3017,9472,9473,9475,9477,9479,9481,9483,9485,9488,9490,9492,9494],{"class":3019,"line":3916},[3017,9474,5345],{"class":3023},[3017,9476,5365],{"class":3033},[3017,9478,3038],{"class":3037},[3017,9480,9239],{"class":3033},[3017,9482,3110],{"class":3037},[3017,9484,5276],{"class":3063},[3017,9486,9487],{"class":3037},"() + ",[3017,9489,5236],{"class":3033},[3017,9491,5233],{"class":3037},[3017,9493,5230],{"class":3033},[3017,9495,3260],{"class":3037},[3017,9497,9498,9500,9502,9504,9506,9508,9510,9512],{"class":3019,"line":3943},[3017,9499,5392],{"class":3079},[3017,9501,3083],{"class":3037},[3017,9503,5397],{"class":3033},[3017,9505,5264],{"class":3037},[3017,9507,5107],{"class":3033},[3017,9509,3110],{"class":3037},[3017,9511,5406],{"class":3033},[3017,9513,3222],{"class":3037},[3017,9515,9516,9518,9520,9522,9524,9526,9528,9530,9532],{"class":3019,"line":3953},[3017,9517,5456],{"class":3023},[3017,9519,3060],{"class":3033},[3017,9521,3110],{"class":3037},[3017,9523,3113],{"class":3063},[3017,9525,3116],{"class":3037},[3017,9527,5397],{"class":3033},[3017,9529,2971],{"class":3037},[3017,9531,4627],{"class":3033},[3017,9533,3295],{"class":3037},[3017,9535,9536],{"class":3019,"line":3958},[3017,9537,3051],{"emptyLinePlaceholder":3050},[3017,9539,9540,9542,9544,9546],{"class":3019,"line":3977},[3017,9541,9438],{"class":3033},[3017,9543,3110],{"class":3037},[3017,9545,5299],{"class":3063},[3017,9547,3044],{"class":3037},[3017,9549,9550],{"class":3019,"line":5384},[3017,9551,5306],{"class":3037},[3017,9553,9554],{"class":3019,"line":5389},[3017,9555,3051],{"emptyLinePlaceholder":3050},[3017,9557,9558,9561,9563,9565,9567,9569],{"class":3019,"line":5411},[3017,9559,9560],{"class":3033},"            _timestamps",[3017,9562,3110],{"class":3037},[3017,9564,5527],{"class":3063},[3017,9566,3116],{"class":3037},[3017,9568,5230],{"class":3033},[3017,9570,3295],{"class":3037},[3017,9572,9573],{"class":3019,"line":5417},[3017,9574,3812],{"class":3037},[3017,9576,9577],{"class":3019,"line":5453},[3017,9578,3132],{"class":3037},[3017,9580,9581],{"class":3019,"line":5475},[3017,9582,3138],{"class":3037},[3192,9584,9586],{"id":9585},"крок-3-resilient-client","Крок 3: Resilient Client",[3008,9588,9591],{"className":3010,"code":9589,"filename":9590,"language":3012,"meta":3648,"style":3013},"class ResilientHttpClient : IDisposable\n{\n    private readonly HttpClient _http = new();\n    private readonly SemaphoreSlim _throttle;\n    private readonly RateLimiter _rateLimiter;\n    private readonly int _maxRetries;\n    private readonly TimeSpan _timeout;\n\n    public ResilientHttpClient(\n        int maxConcurrent = 5,\n        int maxRequestsPerMinute = 60,\n        int maxRetries = 3,\n        TimeSpan? timeout = null)\n    {\n        _throttle = new SemaphoreSlim(maxConcurrent, maxConcurrent);\n        _rateLimiter = new RateLimiter(maxRequestsPerMinute, TimeSpan.FromMinutes(1));\n        _maxRetries = maxRetries;\n        _timeout = timeout ?? TimeSpan.FromSeconds(30);\n    }\n\n    public async Task\u003Cstring> GetAsync(string url, CancellationToken ct = default)\n    {\n        // Rate limiting\n        await _rateLimiter.WaitAsync(ct);\n\n        // Throttling\n        await _throttle.WaitAsync(ct);\n        try\n        {\n            return await RetryAsync(async attemptCt =>\n            {\n                using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(ct, attemptCt);\n                linkedCts.CancelAfter(_timeout);\n\n                var response = await _http.GetAsync(url, linkedCts.Token);\n                response.EnsureSuccessStatusCode();\n                return await response.Content.ReadAsStringAsync(linkedCts.Token);\n            }, ct);\n        }\n        finally\n        {\n            _throttle.Release();\n        }\n    }\n\n    private async Task\u003CT> RetryAsync\u003CT>(\n        Func\u003CCancellationToken, Task\u003CT>> operation,\n        CancellationToken ct)\n    {\n        var delay = TimeSpan.FromSeconds(1);\n\n        for (int attempt = 1; attempt \u003C= _maxRetries; attempt++)\n        {\n            using var attemptCts = CancellationTokenSource.CreateLinkedTokenSource(ct);\n\n            try\n            {\n                return await operation(attemptCts.Token);\n            }\n            catch (Exception ex) when (attempt \u003C _maxRetries &&\n                (ex is HttpRequestException || ex is OperationCanceledException))\n            {\n                Console.WriteLine($\"  Спроба {attempt} невдала. Повтор через {delay.TotalSeconds}s...\");\n                await Task.Delay(delay, ct);\n                delay *= 2;\n            }\n        }\n\n        return await operation(ct);\n    }\n\n    public void Dispose()\n    {\n        _http.Dispose();\n        _throttle.Dispose();\n    }\n}\n","ResilientHttpClient.cs",[2968,9592,9593,9604,9608,9624,9636,9649,9662,9675,9679,9687,9701,9715,9727,9741,9745,9767,9798,9809,9834,9838,9842,9876,9880,9885,9901,9905,9910,9926,9930,9934,9952,9956,9984,10000,10004,10034,10045,10072,10081,10085,10089,10093,10103,10107,10111,10115,10138,10161,10170,10174,10194,10198,10228,10232,10255,10259,10264,10268,10286,10290,10316,10337,10342,10380,10402,10414,10419,10424,10429,10444,10449,10454,10465,10470,10483,10494,10499],{"__ignoreMap":3013},[3017,9594,9595,9597,9600,9602],{"class":3019,"line":3020},[3017,9596,3655],{"class":3023},[3017,9598,9599],{"class":3059}," ResilientHttpClient",[3017,9601,4151],{"class":3037},[3017,9603,4154],{"class":3059},[3017,9605,9606],{"class":3019,"line":3047},[3017,9607,3073],{"class":3037},[3017,9609,9610,9612,9614,9616,9618,9620,9622],{"class":3019,"line":3054},[3017,9611,3667],{"class":3023},[3017,9613,3027],{"class":3023},[3017,9615,4521],{"class":3059},[3017,9617,4524],{"class":3033},[3017,9619,3038],{"class":3037},[3017,9621,3041],{"class":3023},[3017,9623,3044],{"class":3037},[3017,9625,9626,9628,9630,9632,9634],{"class":3019,"line":3070},[3017,9627,3667],{"class":3023},[3017,9629,3027],{"class":3023},[3017,9631,3684],{"class":3059},[3017,9633,4541],{"class":3033},[3017,9635,3260],{"class":3037},[3017,9637,9638,9640,9642,9644,9647],{"class":3019,"line":3076},[3017,9639,3667],{"class":3023},[3017,9641,3027],{"class":3023},[3017,9643,5095],{"class":3059},[3017,9645,9646],{"class":3033}," _rateLimiter",[3017,9648,3260],{"class":3037},[3017,9650,9651,9653,9655,9657,9660],{"class":3019,"line":3096},[3017,9652,3667],{"class":3023},[3017,9654,3027],{"class":3023},[3017,9656,3670],{"class":3023},[3017,9658,9659],{"class":3033}," _maxRetries",[3017,9661,3260],{"class":3037},[3017,9663,9664,9666,9668,9670,9673],{"class":3019,"line":3102},[3017,9665,3667],{"class":3023},[3017,9667,3027],{"class":3023},[3017,9669,5030],{"class":3059},[3017,9671,9672],{"class":3033}," _timeout",[3017,9674,3260],{"class":3037},[3017,9676,9677],{"class":3019,"line":3129},[3017,9678,3051],{"emptyLinePlaceholder":3050},[3017,9680,9681,9683,9685],{"class":3019,"line":3135},[3017,9682,3713],{"class":3023},[3017,9684,9599],{"class":3063},[3017,9686,6005],{"class":3037},[3017,9688,9689,9692,9695,9697,9699],{"class":3019,"line":3268},[3017,9690,9691],{"class":3023},"        int",[3017,9693,9694],{"class":3033}," maxConcurrent",[3017,9696,3038],{"class":3037},[3017,9698,4550],{"class":3119},[3017,9700,6249],{"class":3037},[3017,9702,9703,9705,9708,9710,9713],{"class":3019,"line":3273},[3017,9704,9691],{"class":3023},[3017,9706,9707],{"class":3033}," maxRequestsPerMinute",[3017,9709,3038],{"class":3037},[3017,9711,9712],{"class":3119},"60",[3017,9714,6249],{"class":3037},[3017,9716,9717,9719,9721,9723,9725],{"class":3019,"line":3298},[3017,9718,9691],{"class":3023},[3017,9720,6967],{"class":3033},[3017,9722,3038],{"class":3037},[3017,9724,6972],{"class":3119},[3017,9726,6249],{"class":3037},[3017,9728,9729,9731,9733,9735,9737,9739],{"class":3019,"line":3303},[3017,9730,6018],{"class":3059},[3017,9732,6981],{"class":3037},[3017,9734,5863],{"class":3033},[3017,9736,3038],{"class":3037},[3017,9738,6989],{"class":3023},[3017,9740,3222],{"class":3037},[3017,9742,9743],{"class":3019,"line":3308},[3017,9744,3099],{"class":3037},[3017,9746,9747,9750,9752,9754,9756,9758,9761,9763,9765],{"class":3019,"line":3314},[3017,9748,9749],{"class":3033},"        _throttle",[3017,9751,3038],{"class":3037},[3017,9753,3041],{"class":3023},[3017,9755,3684],{"class":3059},[3017,9757,3116],{"class":3037},[3017,9759,9760],{"class":3033},"maxConcurrent",[3017,9762,2971],{"class":3037},[3017,9764,9760],{"class":3033},[3017,9766,3295],{"class":3037},[3017,9768,9769,9772,9774,9776,9778,9780,9783,9785,9787,9789,9792,9794,9796],{"class":3019,"line":3319},[3017,9770,9771],{"class":3033},"        _rateLimiter",[3017,9773,3038],{"class":3037},[3017,9775,3041],{"class":3023},[3017,9777,5095],{"class":3059},[3017,9779,3116],{"class":3037},[3017,9781,9782],{"class":3033},"maxRequestsPerMinute",[3017,9784,2971],{"class":3037},[3017,9786,5107],{"class":3033},[3017,9788,3110],{"class":3037},[3017,9790,9791],{"class":3063},"FromMinutes",[3017,9793,3116],{"class":3037},[3017,9795,3695],{"class":3119},[3017,9797,5628],{"class":3037},[3017,9799,9800,9803,9805,9807],{"class":3019,"line":3332},[3017,9801,9802],{"class":3033},"        _maxRetries",[3017,9804,3038],{"class":3037},[3017,9806,7076],{"class":3033},[3017,9808,3260],{"class":3037},[3017,9810,9811,9814,9816,9818,9821,9823,9825,9827,9829,9832],{"class":3019,"line":3349},[3017,9812,9813],{"class":3033},"        _timeout",[3017,9815,3038],{"class":3037},[3017,9817,5863],{"class":3033},[3017,9819,9820],{"class":3037}," ?? ",[3017,9822,5107],{"class":3033},[3017,9824,3110],{"class":3037},[3017,9826,5621],{"class":3063},[3017,9828,3116],{"class":3037},[3017,9830,9831],{"class":3119},"30",[3017,9833,3295],{"class":3037},[3017,9835,9836],{"class":3019,"line":3824},[3017,9837,3132],{"class":3037},[3017,9839,9840],{"class":3019,"line":3830},[3017,9841,3051],{"emptyLinePlaceholder":3050},[3017,9843,9844,9846,9848,9850,9852,9854,9856,9858,9860,9862,9864,9866,9868,9870,9872,9874],{"class":3019,"line":3843},[3017,9845,3713],{"class":3023},[3017,9847,3716],{"class":3023},[3017,9849,3060],{"class":3059},[3017,9851,3721],{"class":3037},[3017,9853,4576],{"class":3023},[3017,9855,3727],{"class":3037},[3017,9857,4581],{"class":3063},[3017,9859,3116],{"class":3037},[3017,9861,4576],{"class":3023},[3017,9863,4588],{"class":3033},[3017,9865,2971],{"class":3037},[3017,9867,4593],{"class":3059},[3017,9869,4596],{"class":3033},[3017,9871,3038],{"class":3037},[3017,9873,4601],{"class":3023},[3017,9875,3222],{"class":3037},[3017,9877,9878],{"class":3019,"line":3848},[3017,9879,3099],{"class":3037},[3017,9881,9882],{"class":3019,"line":3853},[3017,9883,9884],{"class":3092},"        // Rate limiting\n",[3017,9886,9887,9889,9891,9893,9895,9897,9899],{"class":3019,"line":3858},[3017,9888,3105],{"class":3023},[3017,9890,9646],{"class":3033},[3017,9892,3110],{"class":3037},[3017,9894,3752],{"class":3063},[3017,9896,3116],{"class":3037},[3017,9898,4627],{"class":3033},[3017,9900,3295],{"class":3037},[3017,9902,9903],{"class":3019,"line":3863},[3017,9904,3051],{"emptyLinePlaceholder":3050},[3017,9906,9907],{"class":3019,"line":3869},[3017,9908,9909],{"class":3092},"        // Throttling\n",[3017,9911,9912,9914,9916,9918,9920,9922,9924],{"class":3019,"line":3887},[3017,9913,3105],{"class":3023},[3017,9915,4541],{"class":3033},[3017,9917,3110],{"class":3037},[3017,9919,3752],{"class":3063},[3017,9921,3116],{"class":3037},[3017,9923,4627],{"class":3033},[3017,9925,3295],{"class":3037},[3017,9927,9928],{"class":3019,"line":3916},[3017,9929,3759],{"class":3079},[3017,9931,9932],{"class":3019,"line":3943},[3017,9933,3764],{"class":3037},[3017,9935,9936,9938,9940,9943,9945,9947,9950],{"class":3019,"line":3953},[3017,9937,3803],{"class":3079},[3017,9939,4689],{"class":3023},[3017,9941,9942],{"class":3063}," RetryAsync",[3017,9944,3116],{"class":3037},[3017,9946,3001],{"class":3023},[3017,9948,9949],{"class":3033}," attemptCt",[3017,9951,7436],{"class":3037},[3017,9953,9954],{"class":3019,"line":3958},[3017,9955,5289],{"class":3037},[3017,9957,9958,9961,9963,9965,9967,9969,9971,9973,9975,9977,9979,9982],{"class":3019,"line":3977},[3017,9959,9960],{"class":3079},"                using",[3017,9962,6270],{"class":3023},[3017,9964,6628],{"class":3033},[3017,9966,3038],{"class":3037},[3017,9968,6633],{"class":3033},[3017,9970,3110],{"class":3037},[3017,9972,6638],{"class":3063},[3017,9974,3116],{"class":3037},[3017,9976,4627],{"class":3033},[3017,9978,2971],{"class":3037},[3017,9980,9981],{"class":3033},"attemptCt",[3017,9983,3295],{"class":3037},[3017,9985,9986,9989,9991,9993,9995,9998],{"class":3019,"line":5384},[3017,9987,9988],{"class":3033},"                linkedCts",[3017,9990,3110],{"class":3037},[3017,9992,7120],{"class":3063},[3017,9994,3116],{"class":3037},[3017,9996,9997],{"class":3033},"_timeout",[3017,9999,3295],{"class":3037},[3017,10001,10002],{"class":3019,"line":5389},[3017,10003,3051],{"emptyLinePlaceholder":3050},[3017,10005,10006,10008,10010,10012,10014,10016,10018,10020,10022,10024,10026,10028,10030,10032],{"class":3019,"line":5411},[3017,10007,5345],{"class":3023},[3017,10009,6677],{"class":3033},[3017,10011,3038],{"class":3037},[3017,10013,3005],{"class":3023},[3017,10015,4524],{"class":3033},[3017,10017,3110],{"class":3037},[3017,10019,4581],{"class":3063},[3017,10021,3116],{"class":3037},[3017,10023,4656],{"class":3033},[3017,10025,2971],{"class":3037},[3017,10027,6696],{"class":3033},[3017,10029,3110],{"class":3037},[3017,10031,6305],{"class":3033},[3017,10033,3295],{"class":3037},[3017,10035,10036,10039,10041,10043],{"class":3019,"line":5417},[3017,10037,10038],{"class":3033},"                response",[3017,10040,3110],{"class":3037},[3017,10042,7478],{"class":3063},[3017,10044,3044],{"class":3037},[3017,10046,10047,10050,10052,10054,10056,10058,10060,10062,10064,10066,10068,10070],{"class":3019,"line":5453},[3017,10048,10049],{"class":3079},"                return",[3017,10051,4689],{"class":3023},[3017,10053,6677],{"class":3033},[3017,10055,3110],{"class":3037},[3017,10057,7493],{"class":3033},[3017,10059,3110],{"class":3037},[3017,10061,7498],{"class":3063},[3017,10063,3116],{"class":3037},[3017,10065,6696],{"class":3033},[3017,10067,3110],{"class":3037},[3017,10069,6305],{"class":3033},[3017,10071,3295],{"class":3037},[3017,10073,10074,10077,10079],{"class":3019,"line":5475},[3017,10075,10076],{"class":3037},"            }, ",[3017,10078,4627],{"class":3033},[3017,10080,3295],{"class":3037},[3017,10082,10083],{"class":3019,"line":5481},[3017,10084,3812],{"class":3037},[3017,10086,10087],{"class":3019,"line":5486},[3017,10088,3817],{"class":3079},[3017,10090,10091],{"class":3019,"line":5492},[3017,10092,3764],{"class":3037},[3017,10094,10095,10097,10099,10101],{"class":3019,"line":5503},[3017,10096,4728],{"class":3033},[3017,10098,3110],{"class":3037},[3017,10100,3838],{"class":3063},[3017,10102,3044],{"class":3037},[3017,10104,10105],{"class":3019,"line":5508},[3017,10106,3812],{"class":3037},[3017,10108,10109],{"class":3019,"line":5513},[3017,10110,3132],{"class":3037},[3017,10112,10113],{"class":3019,"line":5519},[3017,10114,3051],{"emptyLinePlaceholder":3050},[3017,10116,10117,10119,10121,10123,10125,10127,10129,10132,10134,10136],{"class":3019,"line":5536},[3017,10118,3667],{"class":3023},[3017,10120,3716],{"class":3023},[3017,10122,3060],{"class":3059},[3017,10124,3721],{"class":3037},[3017,10126,5805],{"class":3059},[3017,10128,3727],{"class":3037},[3017,10130,10131],{"class":3063},"RetryAsync",[3017,10133,3721],{"class":3037},[3017,10135,5805],{"class":3059},[3017,10137,6223],{"class":3037},[3017,10139,10140,10143,10145,10147,10149,10151,10153,10155,10157,10159],{"class":3019,"line":5541},[3017,10141,10142],{"class":3059},"        Func",[3017,10144,3721],{"class":3037},[3017,10146,4593],{"class":3059},[3017,10148,2971],{"class":3037},[3017,10150,5820],{"class":3059},[3017,10152,3721],{"class":3037},[3017,10154,5805],{"class":3059},[3017,10156,6243],{"class":3037},[3017,10158,6246],{"class":3033},[3017,10160,6249],{"class":3037},[3017,10162,10163,10166,10168],{"class":3019,"line":5546},[3017,10164,10165],{"class":3059},"        CancellationToken",[3017,10167,4596],{"class":3033},[3017,10169,3222],{"class":3037},[3017,10171,10172],{"class":3019,"line":5551},[3017,10173,3099],{"class":3037},[3017,10175,10176,10178,10180,10182,10184,10186,10188,10190,10192],{"class":3019,"line":5562},[3017,10177,7445],{"class":3023},[3017,10179,5365],{"class":3033},[3017,10181,3038],{"class":3037},[3017,10183,5107],{"class":3033},[3017,10185,3110],{"class":3037},[3017,10187,5621],{"class":3063},[3017,10189,3116],{"class":3037},[3017,10191,3695],{"class":3119},[3017,10193,3295],{"class":3037},[3017,10195,10196],{"class":3019,"line":5567},[3017,10197,3051],{"emptyLinePlaceholder":3050},[3017,10199,10200,10203,10205,10207,10209,10211,10213,10215,10217,10219,10222,10224,10226],{"class":3019,"line":5572},[3017,10201,10202],{"class":3079},"        for",[3017,10204,3083],{"class":3037},[3017,10206,3724],{"class":3023},[3017,10208,7061],{"class":3033},[3017,10210,3038],{"class":3037},[3017,10212,3695],{"class":3119},[3017,10214,5653],{"class":3037},[3017,10216,7070],{"class":3033},[3017,10218,7073],{"class":3037},[3017,10220,10221],{"class":3033},"_maxRetries",[3017,10223,5653],{"class":3037},[3017,10225,7070],{"class":3033},[3017,10227,5668],{"class":3037},[3017,10229,10230],{"class":3019,"line":5577},[3017,10231,3764],{"class":3037},[3017,10233,10234,10237,10239,10241,10243,10245,10247,10249,10251,10253],{"class":3019,"line":5582},[3017,10235,10236],{"class":3079},"            using",[3017,10238,6270],{"class":3023},[3017,10240,7096],{"class":3033},[3017,10242,3038],{"class":3037},[3017,10244,6633],{"class":3033},[3017,10246,3110],{"class":3037},[3017,10248,6638],{"class":3063},[3017,10250,3116],{"class":3037},[3017,10252,4627],{"class":3033},[3017,10254,3295],{"class":3037},[3017,10256,10257],{"class":3019,"line":5588},[3017,10258,3051],{"emptyLinePlaceholder":3050},[3017,10260,10261],{"class":3019,"line":5631},[3017,10262,10263],{"class":3079},"            try\n",[3017,10265,10266],{"class":3019,"line":5636},[3017,10267,5289],{"class":3037},[3017,10269,10270,10272,10274,10276,10278,10280,10282,10284],{"class":3019,"line":5671},[3017,10271,10049],{"class":3079},[3017,10273,4689],{"class":3023},[3017,10275,6295],{"class":3063},[3017,10277,3116],{"class":3037},[3017,10279,7163],{"class":3033},[3017,10281,3110],{"class":3037},[3017,10283,6305],{"class":3033},[3017,10285,3295],{"class":3037},[3017,10287,10288],{"class":3019,"line":5676},[3017,10289,5306],{"class":3037},[3017,10291,10292,10295,10297,10299,10301,10303,10305,10307,10309,10311,10313],{"class":3019,"line":5689},[3017,10293,10294],{"class":3079},"            catch",[3017,10296,3083],{"class":3037},[3017,10298,7183],{"class":3059},[3017,10300,6074],{"class":3033},[3017,10302,7188],{"class":3037},[3017,10304,7191],{"class":3079},[3017,10306,3083],{"class":3037},[3017,10308,7070],{"class":3033},[3017,10310,5658],{"class":3037},[3017,10312,10221],{"class":3033},[3017,10314,10315],{"class":3037}," &&\n",[3017,10317,10318,10321,10323,10325,10327,10329,10331,10333,10335],{"class":3019,"line":5754},[3017,10319,10320],{"class":3037},"                (",[3017,10322,6098],{"class":3033},[3017,10324,7212],{"class":3023},[3017,10326,7225],{"class":3059},[3017,10328,7218],{"class":3037},[3017,10330,6098],{"class":3033},[3017,10332,7212],{"class":3023},[3017,10334,7215],{"class":3059},[3017,10336,7228],{"class":3037},[3017,10338,10340],{"class":3019,"line":10339},62,[3017,10341,5289],{"class":3037},[3017,10343,10345,10348,10350,10352,10354,10357,10359,10361,10363,10366,10368,10370,10372,10374,10376,10378],{"class":3019,"line":10344},63,[3017,10346,10347],{"class":3033},"                Console",[3017,10349,3110],{"class":3037},[3017,10351,3419],{"class":3063},[3017,10353,3116],{"class":3037},[3017,10355,10356],{"class":3424},"$\"  Спроба ",[3017,10358,3429],{"class":3428},[3017,10360,7070],{"class":3033},[3017,10362,3445],{"class":3428},[3017,10364,10365],{"class":3424}," невдала. Повтор через ",[3017,10367,3429],{"class":3428},[3017,10369,5397],{"class":3033},[3017,10371,3110],{"class":3428},[3017,10373,5438],{"class":3033},[3017,10375,3445],{"class":3428},[3017,10377,5448],{"class":3424},[3017,10379,3295],{"class":3037},[3017,10381,10383,10386,10388,10390,10392,10394,10396,10398,10400],{"class":3019,"line":10382},64,[3017,10384,10385],{"class":3023},"                await",[3017,10387,3060],{"class":3033},[3017,10389,3110],{"class":3037},[3017,10391,3113],{"class":3063},[3017,10393,3116],{"class":3037},[3017,10395,5397],{"class":3033},[3017,10397,2971],{"class":3037},[3017,10399,4627],{"class":3033},[3017,10401,3295],{"class":3037},[3017,10403,10405,10408,10410,10412],{"class":3019,"line":10404},65,[3017,10406,10407],{"class":3033},"                delay",[3017,10409,7309],{"class":3037},[3017,10411,7312],{"class":3119},[3017,10413,3260],{"class":3037},[3017,10415,10417],{"class":3019,"line":10416},66,[3017,10418,5306],{"class":3037},[3017,10420,10422],{"class":3019,"line":10421},67,[3017,10423,3812],{"class":3037},[3017,10425,10427],{"class":3019,"line":10426},68,[3017,10428,3051],{"emptyLinePlaceholder":3050},[3017,10430,10432,10434,10436,10438,10440,10442],{"class":3019,"line":10431},69,[3017,10433,4118],{"class":3079},[3017,10435,4689],{"class":3023},[3017,10437,6295],{"class":3063},[3017,10439,3116],{"class":3037},[3017,10441,4627],{"class":3033},[3017,10443,3295],{"class":3037},[3017,10445,10447],{"class":3019,"line":10446},70,[3017,10448,3132],{"class":3037},[3017,10450,10452],{"class":3019,"line":10451},71,[3017,10453,3051],{"emptyLinePlaceholder":3050},[3017,10455,10457,10459,10461,10463],{"class":3019,"line":10456},72,[3017,10458,3713],{"class":3023},[3017,10460,4212],{"class":3023},[3017,10462,4215],{"class":3063},[3017,10464,3067],{"class":3037},[3017,10466,10468],{"class":3019,"line":10467},73,[3017,10469,3099],{"class":3037},[3017,10471,10473,10476,10478,10481],{"class":3019,"line":10472},74,[3017,10474,10475],{"class":3033},"        _http",[3017,10477,3110],{"class":3037},[3017,10479,10480],{"class":3063},"Dispose",[3017,10482,3044],{"class":3037},[3017,10484,10486,10488,10490,10492],{"class":3019,"line":10485},75,[3017,10487,9749],{"class":3033},[3017,10489,3110],{"class":3037},[3017,10491,10480],{"class":3063},[3017,10493,3044],{"class":3037},[3017,10495,10497],{"class":3019,"line":10496},76,[3017,10498,3132],{"class":3037},[3017,10500,10502],{"class":3019,"line":10501},77,[3017,10503,3138],{"class":3037},[3192,10505,10507],{"id":10506},"крок-4-statistics-tracker","Крок 4: Statistics Tracker",[3008,10509,10512],{"className":3010,"code":10510,"filename":10511,"language":3012,"meta":3648,"style":3013},"class RequestStats\n{\n    private int _totalRequests;\n    private int _successfulRequests;\n    private int _failedRequests;\n    private readonly List\u003CTimeSpan> _responseTimes = new();\n    private readonly AsyncLock _lock = new();\n\n    public async Task RecordSuccessAsync(TimeSpan responseTime)\n    {\n        using (await _lock.LockAsync())\n        {\n            _totalRequests++;\n            _successfulRequests++;\n            _responseTimes.Add(responseTime);\n        }\n    }\n\n    public async Task RecordFailureAsync()\n    {\n        using (await _lock.LockAsync())\n        {\n            _totalRequests++;\n            _failedRequests++;\n        }\n    }\n\n    public async Task PrintStatsAsync()\n    {\n        using (await _lock.LockAsync())\n        {\n            Console.WriteLine(\"\\n\" + new string('═', 60));\n            Console.WriteLine(\"📊 СТАТИСТИКА ЗАПИТІВ\");\n            Console.WriteLine(new string('─', 60));\n            Console.WriteLine($\"Всього запитів:       {_totalRequests}\");\n            Console.WriteLine($\"Успішних:             {_successfulRequests}\");\n            Console.WriteLine($\"Невдалих:             {_failedRequests}\");\n            \n            if (_responseTimes.Count > 0)\n            {\n                var avg = TimeSpan.FromMilliseconds(_responseTimes.Average(t => t.TotalMilliseconds));\n                var min = _responseTimes.Min();\n                var max = _responseTimes.Max();\n                \n                Console.WriteLine($\"Середній час відповіді: {avg.TotalMilliseconds:F0}ms\");\n                Console.WriteLine($\"Мін/Макс:             {min.TotalMilliseconds:F0}ms / {max.TotalMilliseconds:F0}ms\");\n            }\n            \n            Console.WriteLine(new string('═', 60));\n        }\n    }\n}\n","RequestStats.cs",[2968,10513,10514,10521,10525,10536,10547,10558,10582,10598,10602,10622,10626,10642,10646,10653,10660,10677,10681,10685,10689,10702,10706,10722,10726,10732,10739,10743,10747,10751,10764,10768,10784,10788,10824,10839,10864,10888,10912,10936,10941,10959,10963,11003,11021,11039,11044,11078,11128,11132,11136,11160,11164,11168],{"__ignoreMap":3013},[3017,10515,10516,10518],{"class":3019,"line":3020},[3017,10517,3655],{"class":3023},[3017,10519,10520],{"class":3059}," RequestStats\n",[3017,10522,10523],{"class":3019,"line":3047},[3017,10524,3073],{"class":3037},[3017,10526,10527,10529,10531,10534],{"class":3019,"line":3054},[3017,10528,3667],{"class":3023},[3017,10530,3670],{"class":3023},[3017,10532,10533],{"class":3033}," _totalRequests",[3017,10535,3260],{"class":3037},[3017,10537,10538,10540,10542,10545],{"class":3019,"line":3070},[3017,10539,3667],{"class":3023},[3017,10541,3670],{"class":3023},[3017,10543,10544],{"class":3033}," _successfulRequests",[3017,10546,3260],{"class":3037},[3017,10548,10549,10551,10553,10556],{"class":3019,"line":3076},[3017,10550,3667],{"class":3023},[3017,10552,3670],{"class":3023},[3017,10554,10555],{"class":3033}," _failedRequests",[3017,10557,3260],{"class":3037},[3017,10559,10560,10562,10564,10567,10569,10571,10573,10576,10578,10580],{"class":3019,"line":3096},[3017,10561,3667],{"class":3023},[3017,10563,3027],{"class":3023},[3017,10565,10566],{"class":3059}," List",[3017,10568,3721],{"class":3037},[3017,10570,5107],{"class":3059},[3017,10572,3727],{"class":3037},[3017,10574,10575],{"class":3033},"_responseTimes",[3017,10577,3038],{"class":3037},[3017,10579,3041],{"class":3023},[3017,10581,3044],{"class":3037},[3017,10583,10584,10586,10588,10590,10592,10594,10596],{"class":3019,"line":3102},[3017,10585,3667],{"class":3023},[3017,10587,3027],{"class":3023},[3017,10589,4257],{"class":3059},[3017,10591,3034],{"class":3033},[3017,10593,3038],{"class":3037},[3017,10595,3041],{"class":3023},[3017,10597,3044],{"class":3037},[3017,10599,10600],{"class":3019,"line":3129},[3017,10601,3051],{"emptyLinePlaceholder":3050},[3017,10603,10604,10606,10608,10610,10613,10615,10617,10620],{"class":3019,"line":3135},[3017,10605,3713],{"class":3023},[3017,10607,3716],{"class":3023},[3017,10609,3060],{"class":3059},[3017,10611,10612],{"class":3063}," RecordSuccessAsync",[3017,10614,3116],{"class":3037},[3017,10616,5107],{"class":3059},[3017,10618,10619],{"class":3033}," responseTime",[3017,10621,3222],{"class":3037},[3017,10623,10624],{"class":3019,"line":3268},[3017,10625,3099],{"class":3037},[3017,10627,10628,10630,10632,10634,10636,10638,10640],{"class":3019,"line":3273},[3017,10629,7091],{"class":3079},[3017,10631,3083],{"class":3037},[3017,10633,3005],{"class":3023},[3017,10635,3034],{"class":3033},[3017,10637,3110],{"class":3037},[3017,10639,4095],{"class":3063},[3017,10641,3940],{"class":3037},[3017,10643,10644],{"class":3019,"line":3298},[3017,10645,3764],{"class":3037},[3017,10647,10648,10651],{"class":3019,"line":3303},[3017,10649,10650],{"class":3033},"            _totalRequests",[3017,10652,3798],{"class":3037},[3017,10654,10655,10658],{"class":3019,"line":3308},[3017,10656,10657],{"class":3033},"            _successfulRequests",[3017,10659,3798],{"class":3037},[3017,10661,10662,10665,10667,10670,10672,10675],{"class":3019,"line":3314},[3017,10663,10664],{"class":3033},"            _responseTimes",[3017,10666,3110],{"class":3037},[3017,10668,10669],{"class":3063},"Add",[3017,10671,3116],{"class":3037},[3017,10673,10674],{"class":3033},"responseTime",[3017,10676,3295],{"class":3037},[3017,10678,10679],{"class":3019,"line":3319},[3017,10680,3812],{"class":3037},[3017,10682,10683],{"class":3019,"line":3332},[3017,10684,3132],{"class":3037},[3017,10686,10687],{"class":3019,"line":3349},[3017,10688,3051],{"emptyLinePlaceholder":3050},[3017,10690,10691,10693,10695,10697,10700],{"class":3019,"line":3824},[3017,10692,3713],{"class":3023},[3017,10694,3716],{"class":3023},[3017,10696,3060],{"class":3059},[3017,10698,10699],{"class":3063}," RecordFailureAsync",[3017,10701,3067],{"class":3037},[3017,10703,10704],{"class":3019,"line":3830},[3017,10705,3099],{"class":3037},[3017,10707,10708,10710,10712,10714,10716,10718,10720],{"class":3019,"line":3843},[3017,10709,7091],{"class":3079},[3017,10711,3083],{"class":3037},[3017,10713,3005],{"class":3023},[3017,10715,3034],{"class":3033},[3017,10717,3110],{"class":3037},[3017,10719,4095],{"class":3063},[3017,10721,3940],{"class":3037},[3017,10723,10724],{"class":3019,"line":3848},[3017,10725,3764],{"class":3037},[3017,10727,10728,10730],{"class":3019,"line":3853},[3017,10729,10650],{"class":3033},[3017,10731,3798],{"class":3037},[3017,10733,10734,10737],{"class":3019,"line":3858},[3017,10735,10736],{"class":3033},"            _failedRequests",[3017,10738,3798],{"class":3037},[3017,10740,10741],{"class":3019,"line":3863},[3017,10742,3812],{"class":3037},[3017,10744,10745],{"class":3019,"line":3869},[3017,10746,3132],{"class":3037},[3017,10748,10749],{"class":3019,"line":3887},[3017,10750,3051],{"emptyLinePlaceholder":3050},[3017,10752,10753,10755,10757,10759,10762],{"class":3019,"line":3916},[3017,10754,3713],{"class":3023},[3017,10756,3716],{"class":3023},[3017,10758,3060],{"class":3059},[3017,10760,10761],{"class":3063}," PrintStatsAsync",[3017,10763,3067],{"class":3037},[3017,10765,10766],{"class":3019,"line":3943},[3017,10767,3099],{"class":3037},[3017,10769,10770,10772,10774,10776,10778,10780,10782],{"class":3019,"line":3953},[3017,10771,7091],{"class":3079},[3017,10773,3083],{"class":3037},[3017,10775,3005],{"class":3023},[3017,10777,3034],{"class":3033},[3017,10779,3110],{"class":3037},[3017,10781,4095],{"class":3063},[3017,10783,3940],{"class":3037},[3017,10785,10786],{"class":3019,"line":3958},[3017,10787,3764],{"class":3037},[3017,10789,10790,10792,10794,10796,10798,10800,10804,10806,10808,10810,10813,10815,10818,10820,10822],{"class":3019,"line":3977},[3017,10791,4642],{"class":3033},[3017,10793,3110],{"class":3037},[3017,10795,3419],{"class":3063},[3017,10797,3116],{"class":3037},[3017,10799,3448],{"class":3424},[3017,10801,10803],{"class":10802},"sjcCO","\\n",[3017,10805,3448],{"class":3424},[3017,10807,5373],{"class":3037},[3017,10809,3041],{"class":3023},[3017,10811,10812],{"class":3023}," string",[3017,10814,3116],{"class":3037},[3017,10816,10817],{"class":3424},"'═'",[3017,10819,2971],{"class":3037},[3017,10821,9712],{"class":3119},[3017,10823,5628],{"class":3037},[3017,10825,10826,10828,10830,10832,10834,10837],{"class":3019,"line":5384},[3017,10827,4642],{"class":3033},[3017,10829,3110],{"class":3037},[3017,10831,3419],{"class":3063},[3017,10833,3116],{"class":3037},[3017,10835,10836],{"class":3424},"\"📊 СТАТИСТИКА ЗАПИТІВ\"",[3017,10838,3295],{"class":3037},[3017,10840,10841,10843,10845,10847,10849,10851,10853,10855,10858,10860,10862],{"class":3019,"line":5389},[3017,10842,4642],{"class":3033},[3017,10844,3110],{"class":3037},[3017,10846,3419],{"class":3063},[3017,10848,3116],{"class":3037},[3017,10850,3041],{"class":3023},[3017,10852,10812],{"class":3023},[3017,10854,3116],{"class":3037},[3017,10856,10857],{"class":3424},"'─'",[3017,10859,2971],{"class":3037},[3017,10861,9712],{"class":3119},[3017,10863,5628],{"class":3037},[3017,10865,10866,10868,10870,10872,10874,10877,10879,10882,10884,10886],{"class":3019,"line":5411},[3017,10867,4642],{"class":3033},[3017,10869,3110],{"class":3037},[3017,10871,3419],{"class":3063},[3017,10873,3116],{"class":3037},[3017,10875,10876],{"class":3424},"$\"Всього запитів:       ",[3017,10878,3429],{"class":3428},[3017,10880,10881],{"class":3033},"_totalRequests",[3017,10883,3445],{"class":3428},[3017,10885,3448],{"class":3424},[3017,10887,3295],{"class":3037},[3017,10889,10890,10892,10894,10896,10898,10901,10903,10906,10908,10910],{"class":3019,"line":5417},[3017,10891,4642],{"class":3033},[3017,10893,3110],{"class":3037},[3017,10895,3419],{"class":3063},[3017,10897,3116],{"class":3037},[3017,10899,10900],{"class":3424},"$\"Успішних:             ",[3017,10902,3429],{"class":3428},[3017,10904,10905],{"class":3033},"_successfulRequests",[3017,10907,3445],{"class":3428},[3017,10909,3448],{"class":3424},[3017,10911,3295],{"class":3037},[3017,10913,10914,10916,10918,10920,10922,10925,10927,10930,10932,10934],{"class":3019,"line":5453},[3017,10915,4642],{"class":3033},[3017,10917,3110],{"class":3037},[3017,10919,3419],{"class":3063},[3017,10921,3116],{"class":3037},[3017,10923,10924],{"class":3424},"$\"Невдалих:             ",[3017,10926,3429],{"class":3428},[3017,10928,10929],{"class":3033},"_failedRequests",[3017,10931,3445],{"class":3428},[3017,10933,3448],{"class":3424},[3017,10935,3295],{"class":3037},[3017,10937,10938],{"class":3019,"line":5475},[3017,10939,10940],{"class":3037},"            \n",[3017,10942,10943,10945,10947,10949,10951,10953,10955,10957],{"class":3019,"line":5481},[3017,10944,5320],{"class":3079},[3017,10946,3083],{"class":3037},[3017,10948,10575],{"class":3033},[3017,10950,3110],{"class":3037},[3017,10952,5261],{"class":3033},[3017,10954,5264],{"class":3037},[3017,10956,3907],{"class":3119},[3017,10958,3222],{"class":3037},[3017,10960,10961],{"class":3019,"line":5486},[3017,10962,5289],{"class":3037},[3017,10964,10965,10967,10970,10972,10974,10976,10979,10981,10983,10985,10988,10990,10992,10994,10996,10998,11001],{"class":3019,"line":5492},[3017,10966,5345],{"class":3023},[3017,10968,10969],{"class":3033}," avg",[3017,10971,3038],{"class":3037},[3017,10973,5107],{"class":3033},[3017,10975,3110],{"class":3037},[3017,10977,10978],{"class":3063},"FromMilliseconds",[3017,10980,3116],{"class":3037},[3017,10982,10575],{"class":3033},[3017,10984,3110],{"class":3037},[3017,10986,10987],{"class":3063},"Average",[3017,10989,3116],{"class":3037},[3017,10991,8137],{"class":3033},[3017,10993,3930],{"class":3037},[3017,10995,8137],{"class":3033},[3017,10997,3110],{"class":3037},[3017,10999,11000],{"class":3033},"TotalMilliseconds",[3017,11002,5628],{"class":3037},[3017,11004,11005,11007,11010,11012,11014,11016,11019],{"class":3019,"line":5503},[3017,11006,5345],{"class":3023},[3017,11008,11009],{"class":3033}," min",[3017,11011,3038],{"class":3037},[3017,11013,10575],{"class":3033},[3017,11015,3110],{"class":3037},[3017,11017,11018],{"class":3063},"Min",[3017,11020,3044],{"class":3037},[3017,11022,11023,11025,11028,11030,11032,11034,11037],{"class":3019,"line":5508},[3017,11024,5345],{"class":3023},[3017,11026,11027],{"class":3033}," max",[3017,11029,3038],{"class":3037},[3017,11031,10575],{"class":3033},[3017,11033,3110],{"class":3037},[3017,11035,11036],{"class":3063},"Max",[3017,11038,3044],{"class":3037},[3017,11040,11041],{"class":3019,"line":5513},[3017,11042,11043],{"class":3037},"                \n",[3017,11045,11046,11048,11050,11052,11054,11057,11059,11062,11064,11066,11068,11071,11073,11076],{"class":3019,"line":5519},[3017,11047,10347],{"class":3033},[3017,11049,3110],{"class":3037},[3017,11051,3419],{"class":3063},[3017,11053,3116],{"class":3037},[3017,11055,11056],{"class":3424},"$\"Середній час відповіді: ",[3017,11058,3429],{"class":3428},[3017,11060,11061],{"class":3033},"avg",[3017,11063,3110],{"class":3428},[3017,11065,11000],{"class":3033},[3017,11067,3201],{"class":3037},[3017,11069,11070],{"class":3033},"F0",[3017,11072,3445],{"class":3428},[3017,11074,11075],{"class":3424},"ms\"",[3017,11077,3295],{"class":3037},[3017,11079,11080,11082,11084,11086,11088,11091,11093,11096,11098,11100,11102,11104,11106,11109,11111,11114,11116,11118,11120,11122,11124,11126],{"class":3019,"line":5536},[3017,11081,10347],{"class":3033},[3017,11083,3110],{"class":3037},[3017,11085,3419],{"class":3063},[3017,11087,3116],{"class":3037},[3017,11089,11090],{"class":3424},"$\"Мін/Макс:             ",[3017,11092,3429],{"class":3428},[3017,11094,11095],{"class":3033},"min",[3017,11097,3110],{"class":3428},[3017,11099,11000],{"class":3033},[3017,11101,3201],{"class":3037},[3017,11103,11070],{"class":3033},[3017,11105,3445],{"class":3428},[3017,11107,11108],{"class":3424},"ms / ",[3017,11110,3429],{"class":3428},[3017,11112,11113],{"class":3033},"max",[3017,11115,3110],{"class":3428},[3017,11117,11000],{"class":3033},[3017,11119,3201],{"class":3037},[3017,11121,11070],{"class":3033},[3017,11123,3445],{"class":3428},[3017,11125,11075],{"class":3424},[3017,11127,3295],{"class":3037},[3017,11129,11130],{"class":3019,"line":5541},[3017,11131,5306],{"class":3037},[3017,11133,11134],{"class":3019,"line":5546},[3017,11135,10940],{"class":3037},[3017,11137,11138,11140,11142,11144,11146,11148,11150,11152,11154,11156,11158],{"class":3019,"line":5551},[3017,11139,4642],{"class":3033},[3017,11141,3110],{"class":3037},[3017,11143,3419],{"class":3063},[3017,11145,3116],{"class":3037},[3017,11147,3041],{"class":3023},[3017,11149,10812],{"class":3023},[3017,11151,3116],{"class":3037},[3017,11153,10817],{"class":3424},[3017,11155,2971],{"class":3037},[3017,11157,9712],{"class":3119},[3017,11159,5628],{"class":3037},[3017,11161,11162],{"class":3019,"line":5562},[3017,11163,3812],{"class":3037},[3017,11165,11166],{"class":3019,"line":5567},[3017,11167,3132],{"class":3037},[3017,11169,11170],{"class":3019,"line":5572},[3017,11171,3138],{"class":3037},[3192,11173,11175],{"id":11174},"крок-5-точка-входу","Крок 5: Точка входу",[3008,11177,11180],{"className":3010,"code":11178,"filename":11179,"language":3012,"meta":3648,"style":3013},"using System.Diagnostics;\n\nvar urls = new[]\n{\n    \"https://jsonplaceholder.typicode.com/posts/1\",\n    \"https://jsonplaceholder.typicode.com/posts/2\",\n    \"https://jsonplaceholder.typicode.com/posts/3\",\n    \"https://jsonplaceholder.typicode.com/posts/4\",\n    \"https://jsonplaceholder.typicode.com/posts/5\",\n    \"https://jsonplaceholder.typicode.com/users/1\",\n    \"https://jsonplaceholder.typicode.com/users/2\",\n    \"https://jsonplaceholder.typicode.com/comments/1\",\n    \"https://jsonplaceholder.typicode.com/comments/2\",\n    \"https://jsonplaceholder.typicode.com/albums/1\"\n};\n\nusing var client = new ResilientHttpClient(\n    maxConcurrent: 3,\n    maxRequestsPerMinute: 20,\n    maxRetries: 3,\n    timeout: TimeSpan.FromSeconds(10)\n);\n\nvar stats = new RequestStats();\nvar cts = new CancellationTokenSource();\n\nConsole.CancelKeyPress += (_, e) =>\n{\n    e.Cancel = true;\n    Console.WriteLine(\"\\n⚠️ Скасування...\");\n    cts.Cancel();\n};\n\nConsole.WriteLine(\"🚀 Початок завантаження...\\n\");\n\nvar tasks = urls.Select(async url =>\n{\n    var sw = Stopwatch.StartNew();\n    try\n    {\n        var content = await client.GetAsync(url, cts.Token);\n        sw.Stop();\n        \n        await stats.RecordSuccessAsync(sw.Elapsed);\n        Console.WriteLine($\"✅ {url} ({sw.ElapsedMilliseconds}ms)\");\n    }\n    catch (OperationCanceledException)\n    {\n        Console.WriteLine($\"⚠️ {url} — скасовано\");\n    }\n    catch (Exception ex)\n    {\n        await stats.RecordFailureAsync();\n        Console.WriteLine($\"❌ {url} — {ex.Message}\");\n    }\n}).ToArray();\n\nawait Task.WhenAll(tasks);\nawait stats.PrintStatsAsync();\n","Program.cs",[2968,11181,11182,11196,11200,11213,11217,11224,11231,11238,11245,11252,11259,11266,11273,11280,11285,11289,11293,11309,11320,11331,11341,11360,11364,11368,11384,11398,11402,11420,11424,11438,11457,11468,11472,11476,11495,11499,11521,11525,11544,11549,11553,11584,11596,11601,11624,11661,11665,11676,11680,11704,11708,11720,11724,11737,11773,11777,11786,11790,11806],{"__ignoreMap":3013},[3017,11183,11184,11186,11189,11191,11194],{"class":3019,"line":3020},[3017,11185,4268],{"class":3079},[3017,11187,11188],{"class":3059}," System",[3017,11190,3110],{"class":3037},[3017,11192,11193],{"class":3059},"Diagnostics",[3017,11195,3260],{"class":3037},[3017,11197,11198],{"class":3019,"line":3047},[3017,11199,3051],{"emptyLinePlaceholder":3050},[3017,11201,11202,11204,11206,11208,11210],{"class":3019,"line":3054},[3017,11203,3872],{"class":3023},[3017,11205,4778],{"class":3033},[3017,11207,3038],{"class":3037},[3017,11209,3041],{"class":3023},[3017,11211,11212],{"class":3037},"[]\n",[3017,11214,11215],{"class":3019,"line":3070},[3017,11216,3073],{"class":3037},[3017,11218,11219,11222],{"class":3019,"line":3076},[3017,11220,11221],{"class":3424},"    \"https://jsonplaceholder.typicode.com/posts/1\"",[3017,11223,6249],{"class":3037},[3017,11225,11226,11229],{"class":3019,"line":3096},[3017,11227,11228],{"class":3424},"    \"https://jsonplaceholder.typicode.com/posts/2\"",[3017,11230,6249],{"class":3037},[3017,11232,11233,11236],{"class":3019,"line":3102},[3017,11234,11235],{"class":3424},"    \"https://jsonplaceholder.typicode.com/posts/3\"",[3017,11237,6249],{"class":3037},[3017,11239,11240,11243],{"class":3019,"line":3129},[3017,11241,11242],{"class":3424},"    \"https://jsonplaceholder.typicode.com/posts/4\"",[3017,11244,6249],{"class":3037},[3017,11246,11247,11250],{"class":3019,"line":3135},[3017,11248,11249],{"class":3424},"    \"https://jsonplaceholder.typicode.com/posts/5\"",[3017,11251,6249],{"class":3037},[3017,11253,11254,11257],{"class":3019,"line":3268},[3017,11255,11256],{"class":3424},"    \"https://jsonplaceholder.typicode.com/users/1\"",[3017,11258,6249],{"class":3037},[3017,11260,11261,11264],{"class":3019,"line":3273},[3017,11262,11263],{"class":3424},"    \"https://jsonplaceholder.typicode.com/users/2\"",[3017,11265,6249],{"class":3037},[3017,11267,11268,11271],{"class":3019,"line":3298},[3017,11269,11270],{"class":3424},"    \"https://jsonplaceholder.typicode.com/comments/1\"",[3017,11272,6249],{"class":3037},[3017,11274,11275,11278],{"class":3019,"line":3303},[3017,11276,11277],{"class":3424},"    \"https://jsonplaceholder.typicode.com/comments/2\"",[3017,11279,6249],{"class":3037},[3017,11281,11282],{"class":3019,"line":3308},[3017,11283,11284],{"class":3424},"    \"https://jsonplaceholder.typicode.com/albums/1\"\n",[3017,11286,11287],{"class":3019,"line":3314},[3017,11288,6807],{"class":3037},[3017,11290,11291],{"class":3019,"line":3319},[3017,11292,3051],{"emptyLinePlaceholder":3050},[3017,11294,11295,11297,11299,11301,11303,11305,11307],{"class":3019,"line":3332},[3017,11296,4268],{"class":3079},[3017,11298,6270],{"class":3023},[3017,11300,4762],{"class":3033},[3017,11302,3038],{"class":3037},[3017,11304,3041],{"class":3023},[3017,11306,9599],{"class":3059},[3017,11308,6005],{"class":3037},[3017,11310,11311,11314,11316,11318],{"class":3019,"line":3349},[3017,11312,11313],{"class":3033},"    maxConcurrent",[3017,11315,5606],{"class":3037},[3017,11317,6972],{"class":3119},[3017,11319,6249],{"class":3037},[3017,11321,11322,11325,11327,11329],{"class":3019,"line":3824},[3017,11323,11324],{"class":3033},"    maxRequestsPerMinute",[3017,11326,5606],{"class":3037},[3017,11328,4795],{"class":3119},[3017,11330,6249],{"class":3037},[3017,11332,11333,11335,11337,11339],{"class":3019,"line":3830},[3017,11334,7514],{"class":3033},[3017,11336,5606],{"class":3037},[3017,11338,6972],{"class":3119},[3017,11340,6249],{"class":3037},[3017,11342,11343,11346,11348,11350,11352,11354,11356,11358],{"class":3019,"line":3843},[3017,11344,11345],{"class":3033},"    timeout",[3017,11347,5606],{"class":3037},[3017,11349,5107],{"class":3033},[3017,11351,3110],{"class":3037},[3017,11353,5621],{"class":3063},[3017,11355,3116],{"class":3037},[3017,11357,3785],{"class":3119},[3017,11359,3222],{"class":3037},[3017,11361,11362],{"class":3019,"line":3848},[3017,11363,3295],{"class":3037},[3017,11365,11366],{"class":3019,"line":3853},[3017,11367,3051],{"emptyLinePlaceholder":3050},[3017,11369,11370,11372,11375,11377,11379,11382],{"class":3019,"line":3858},[3017,11371,3872],{"class":3023},[3017,11373,11374],{"class":3033}," stats",[3017,11376,3038],{"class":3037},[3017,11378,3041],{"class":3023},[3017,11380,11381],{"class":3059}," RequestStats",[3017,11383,3044],{"class":3037},[3017,11385,11386,11388,11390,11392,11394,11396],{"class":3019,"line":3863},[3017,11387,3872],{"class":3023},[3017,11389,6273],{"class":3033},[3017,11391,3038],{"class":3037},[3017,11393,3041],{"class":3023},[3017,11395,6280],{"class":3059},[3017,11397,3044],{"class":3037},[3017,11399,11400],{"class":3019,"line":3869},[3017,11401,3051],{"emptyLinePlaceholder":3050},[3017,11403,11404,11406,11408,11410,11412,11414,11416,11418],{"class":3019,"line":3887},[3017,11405,3980],{"class":3033},[3017,11407,3110],{"class":3037},[3017,11409,6757],{"class":3033},[3017,11411,6760],{"class":3037},[3017,11413,3927],{"class":3033},[3017,11415,2971],{"class":3037},[3017,11417,6767],{"class":3033},[3017,11419,6770],{"class":3037},[3017,11421,11422],{"class":3019,"line":3916},[3017,11423,3073],{"class":3037},[3017,11425,11426,11428,11430,11432,11434,11436],{"class":3019,"line":3943},[3017,11427,6779],{"class":3033},[3017,11429,3110],{"class":3037},[3017,11431,6784],{"class":3033},[3017,11433,3038],{"class":3037},[3017,11435,6789],{"class":3023},[3017,11437,3260],{"class":3037},[3017,11439,11440,11442,11444,11446,11448,11450,11452,11455],{"class":3019,"line":3953},[3017,11441,5692],{"class":3033},[3017,11443,3110],{"class":3037},[3017,11445,3419],{"class":3063},[3017,11447,3116],{"class":3037},[3017,11449,3448],{"class":3424},[3017,11451,10803],{"class":10802},[3017,11453,11454],{"class":3424},"⚠️ Скасування...\"",[3017,11456,3295],{"class":3037},[3017,11458,11459,11462,11464,11466],{"class":3019,"line":3958},[3017,11460,11461],{"class":3033},"    cts",[3017,11463,3110],{"class":3037},[3017,11465,6784],{"class":3063},[3017,11467,3044],{"class":3037},[3017,11469,11470],{"class":3019,"line":3977},[3017,11471,6807],{"class":3037},[3017,11473,11474],{"class":3019,"line":5384},[3017,11475,3051],{"emptyLinePlaceholder":3050},[3017,11477,11478,11480,11482,11484,11486,11489,11491,11493],{"class":3019,"line":5389},[3017,11479,3980],{"class":3033},[3017,11481,3110],{"class":3037},[3017,11483,3419],{"class":3063},[3017,11485,3116],{"class":3037},[3017,11487,11488],{"class":3424},"\"🚀 Початок завантаження...",[3017,11490,10803],{"class":10802},[3017,11492,3448],{"class":3424},[3017,11494,3295],{"class":3037},[3017,11496,11497],{"class":3019,"line":5411},[3017,11498,3051],{"emptyLinePlaceholder":3050},[3017,11500,11501,11503,11505,11507,11509,11511,11513,11515,11517,11519],{"class":3019,"line":5417},[3017,11502,3872],{"class":3023},[3017,11504,3892],{"class":3033},[3017,11506,3038],{"class":3037},[3017,11508,4846],{"class":3033},[3017,11510,3110],{"class":3037},[3017,11512,3922],{"class":3063},[3017,11514,3116],{"class":3037},[3017,11516,3001],{"class":3023},[3017,11518,4588],{"class":3033},[3017,11520,7436],{"class":3037},[3017,11522,11523],{"class":3019,"line":5453},[3017,11524,3073],{"class":3037},[3017,11526,11527,11529,11532,11534,11537,11539,11542],{"class":3019,"line":5475},[3017,11528,5847],{"class":3023},[3017,11530,11531],{"class":3033}," sw",[3017,11533,3038],{"class":3037},[3017,11535,11536],{"class":3033},"Stopwatch",[3017,11538,3110],{"class":3037},[3017,11540,11541],{"class":3063},"StartNew",[3017,11543,3044],{"class":3037},[3017,11545,11546],{"class":3019,"line":5481},[3017,11547,11548],{"class":3079},"    try\n",[3017,11550,11551],{"class":3019,"line":5486},[3017,11552,3099],{"class":3037},[3017,11554,11555,11557,11560,11562,11564,11566,11568,11570,11572,11574,11576,11578,11580,11582],{"class":3019,"line":5492},[3017,11556,7445],{"class":3023},[3017,11558,11559],{"class":3033}," content",[3017,11561,3038],{"class":3037},[3017,11563,3005],{"class":3023},[3017,11565,4762],{"class":3033},[3017,11567,3110],{"class":3037},[3017,11569,4581],{"class":3063},[3017,11571,3116],{"class":3037},[3017,11573,4656],{"class":3033},[3017,11575,2971],{"class":3037},[3017,11577,6300],{"class":3033},[3017,11579,3110],{"class":3037},[3017,11581,6305],{"class":3033},[3017,11583,3295],{"class":3037},[3017,11585,11586,11589,11591,11594],{"class":3019,"line":5503},[3017,11587,11588],{"class":3033},"        sw",[3017,11590,3110],{"class":3037},[3017,11592,11593],{"class":3063},"Stop",[3017,11595,3044],{"class":3037},[3017,11597,11598],{"class":3019,"line":5508},[3017,11599,11600],{"class":3037},"        \n",[3017,11602,11603,11605,11607,11609,11612,11614,11617,11619,11622],{"class":3019,"line":5513},[3017,11604,3105],{"class":3023},[3017,11606,11374],{"class":3033},[3017,11608,3110],{"class":3037},[3017,11610,11611],{"class":3063},"RecordSuccessAsync",[3017,11613,3116],{"class":3037},[3017,11615,11616],{"class":3033},"sw",[3017,11618,3110],{"class":3037},[3017,11620,11621],{"class":3033},"Elapsed",[3017,11623,3295],{"class":3037},[3017,11625,11626,11628,11630,11632,11634,11637,11639,11641,11643,11645,11647,11649,11651,11654,11656,11659],{"class":3019,"line":5519},[3017,11627,3414],{"class":3033},[3017,11629,3110],{"class":3037},[3017,11631,3419],{"class":3063},[3017,11633,3116],{"class":3037},[3017,11635,11636],{"class":3424},"$\"✅ ",[3017,11638,3429],{"class":3428},[3017,11640,4656],{"class":3033},[3017,11642,3445],{"class":3428},[3017,11644,3083],{"class":3424},[3017,11646,3429],{"class":3428},[3017,11648,11616],{"class":3033},[3017,11650,3110],{"class":3428},[3017,11652,11653],{"class":3033},"ElapsedMilliseconds",[3017,11655,3445],{"class":3428},[3017,11657,11658],{"class":3424},"ms)\"",[3017,11660,3295],{"class":3037},[3017,11662,11663],{"class":3019,"line":5536},[3017,11664,3132],{"class":3037},[3017,11666,11667,11670,11672,11674],{"class":3019,"line":5541},[3017,11668,11669],{"class":3079},"    catch",[3017,11671,3083],{"class":3037},[3017,11673,6411],{"class":3059},[3017,11675,3222],{"class":3037},[3017,11677,11678],{"class":3019,"line":5546},[3017,11679,3099],{"class":3037},[3017,11681,11682,11684,11686,11688,11690,11693,11695,11697,11699,11702],{"class":3019,"line":5551},[3017,11683,3414],{"class":3033},[3017,11685,3110],{"class":3037},[3017,11687,3419],{"class":3063},[3017,11689,3116],{"class":3037},[3017,11691,11692],{"class":3424},"$\"⚠️ ",[3017,11694,3429],{"class":3428},[3017,11696,4656],{"class":3033},[3017,11698,3445],{"class":3428},[3017,11700,11701],{"class":3424}," — скасовано\"",[3017,11703,3295],{"class":3037},[3017,11705,11706],{"class":3019,"line":5562},[3017,11707,3132],{"class":3037},[3017,11709,11710,11712,11714,11716,11718],{"class":3019,"line":5567},[3017,11711,11669],{"class":3079},[3017,11713,3083],{"class":3037},[3017,11715,7183],{"class":3059},[3017,11717,6074],{"class":3033},[3017,11719,3222],{"class":3037},[3017,11721,11722],{"class":3019,"line":5572},[3017,11723,3099],{"class":3037},[3017,11725,11726,11728,11730,11732,11735],{"class":3019,"line":5577},[3017,11727,3105],{"class":3023},[3017,11729,11374],{"class":3033},[3017,11731,3110],{"class":3037},[3017,11733,11734],{"class":3063},"RecordFailureAsync",[3017,11736,3044],{"class":3037},[3017,11738,11739,11741,11743,11745,11747,11750,11752,11754,11756,11759,11761,11763,11765,11767,11769,11771],{"class":3019,"line":5582},[3017,11740,3414],{"class":3033},[3017,11742,3110],{"class":3037},[3017,11744,3419],{"class":3063},[3017,11746,3116],{"class":3037},[3017,11748,11749],{"class":3424},"$\"❌ ",[3017,11751,3429],{"class":3428},[3017,11753,4656],{"class":3033},[3017,11755,3445],{"class":3428},[3017,11757,11758],{"class":3424}," — ",[3017,11760,3429],{"class":3428},[3017,11762,6098],{"class":3033},[3017,11764,3110],{"class":3428},[3017,11766,6103],{"class":3033},[3017,11768,3445],{"class":3428},[3017,11770,3448],{"class":3424},[3017,11772,3295],{"class":3037},[3017,11774,11775],{"class":3019,"line":5588},[3017,11776,3132],{"class":3037},[3017,11778,11779,11782,11784],{"class":3019,"line":5631},[3017,11780,11781],{"class":3037},"}).",[3017,11783,3948],{"class":3063},[3017,11785,3044],{"class":3037},[3017,11787,11788],{"class":3019,"line":5636},[3017,11789,3051],{"emptyLinePlaceholder":3050},[3017,11791,11792,11794,11796,11798,11800,11802,11804],{"class":3019,"line":5671},[3017,11793,3005],{"class":3023},[3017,11795,3060],{"class":3033},[3017,11797,3110],{"class":3037},[3017,11799,3967],{"class":3063},[3017,11801,3116],{"class":3037},[3017,11803,3972],{"class":3033},[3017,11805,3295],{"class":3037},[3017,11807,11808,11810,11812,11814,11817],{"class":3019,"line":5676},[3017,11809,3005],{"class":3023},[3017,11811,11374],{"class":3033},[3017,11813,3110],{"class":3037},[3017,11815,11816],{"class":3063},"PrintStatsAsync",[3017,11818,3044],{"class":3037},[3192,11820,11822],{"id":11821},"крок-6-запуск","Крок 6: Запуск",[3008,11824,11826],{"className":7565,"code":11825,"language":7567,"meta":3013,"style":3013},"dotnet run\n",[2968,11827,11828],{"__ignoreMap":3013},[3017,11829,11830,11832],{"class":3019,"line":3020},[3017,11831,7574],{"class":3063},[3017,11833,11834],{"class":3424}," run\n",[4933,11836,11838,11851,11855,11858,11866,11873,11880,11887,11894,11901,11908,11915,11922,11929,11932,11936,11944,11948,11952,11959,11967,11975,11979],{"title":11837},"Resilient HTTP Client Output",[4937,11839,11841,3144,11846],{"className":11840},[3019],[3017,11842,11845],{"className":11843},[11844],"opacity-40","$",[2983,11847,11850],{"className":11848},[11849],"font-bold","dotnet run",[4937,11852,11854],{"className":11853},[3019],"🚀 Початок завантаження...",[4937,11856],{"className":11857},[3019],[4937,11859,11861,11865],{"className":11860},[3019],[3017,11862,11864],{"className":11863},[4983],"✅"," https://jsonplaceholder.typicode.com/posts/1 (342ms)",[4937,11867,11869,11872],{"className":11868},[3019],[3017,11870,11864],{"className":11871},[4983]," https://jsonplaceholder.typicode.com/posts/2 (356ms)",[4937,11874,11876,11879],{"className":11875},[3019],[3017,11877,11864],{"className":11878},[4983]," https://jsonplaceholder.typicode.com/posts/3 (378ms)",[4937,11881,11883,11886],{"className":11882},[3019],[3017,11884,11864],{"className":11885},[4983]," https://jsonplaceholder.typicode.com/posts/4 (312ms)",[4937,11888,11890,11893],{"className":11889},[3019],[3017,11891,11864],{"className":11892},[4983]," https://jsonplaceholder.typicode.com/posts/5 (298ms)",[4937,11895,11897,11900],{"className":11896},[3019],[3017,11898,11864],{"className":11899},[4983]," https://jsonplaceholder.typicode.com/users/1 (287ms)",[4937,11902,11904,11907],{"className":11903},[3019],[3017,11905,11864],{"className":11906},[4983]," https://jsonplaceholder.typicode.com/users/2 (301ms)",[4937,11909,11911,11914],{"className":11910},[3019],[3017,11912,11864],{"className":11913},[4983]," https://jsonplaceholder.typicode.com/comments/1 (324ms)",[4937,11916,11918,11921],{"className":11917},[3019],[3017,11919,11864],{"className":11920},[4983]," https://jsonplaceholder.typicode.com/comments/2 (318ms)",[4937,11923,11925,11928],{"className":11924},[3019],[3017,11926,11864],{"className":11927},[4983]," https://jsonplaceholder.typicode.com/albums/1 (295ms)",[4937,11930],{"className":11931},[3019],[4937,11933,11935],{"className":11934},[3019],"════════════════════════════════════════════════════════════",[4937,11937,11939],{"className":11938},[3019],[3017,11940,11943],{"className":11941},[11942,11849],"text-blue-400","📊 СТАТИСТИКА ЗАПИТІВ",[4937,11945,11947],{"className":11946},[3019],"────────────────────────────────────────────────────────────",[4937,11949,11951],{"className":11950},[3019],"Всього запитів:       10",[4937,11953,11955,11956],{"className":11954},[3019],"Успішних:             ",[3017,11957,3785],{"className":11958},[4983,11849],[4937,11960,11962,11963],{"className":11961},[3019],"Невдалих:             ",[3017,11964,3907],{"className":11965},[11966],"text-gray-400",[4937,11968,11970,11971],{"className":11969},[3019],"Середній час відповіді: ",[3017,11972,11974],{"className":11973},[4963],"321ms",[4937,11976,11978],{"className":11977},[3019],"Мін/Макс:             287ms / 378ms",[4937,11980,11935],{"className":11981},[3019],[3185,11983],{},[2959,11985,11987],{"id":11986},"діаграма-async-synchronization-patterns","Діаграма: Async Synchronization Patterns",[11989,11990,11991],"mermaid",{},[3008,11992,11995],{"className":11993,"code":11994,"language":11989,"meta":3013,"style":3013},"language-mermaid shiki shiki-themes light-plus dark-plus dark-plus","graph TB\n    subgraph \"Problem\"\n        A[lock + await\u003Cbr/>❌ Compiler Error]\n    end\n\n    subgraph \"Solutions\"\n        B[SemaphoreSlim\u003Cbr/>WaitAsync]\n        C[Throttling\u003Cbr/>N concurrent]\n        D[Rate Limiting\u003Cbr/>N per time]\n        E[Timeout\u003Cbr/>Patterns]\n    end\n\n    subgraph \"Libraries\"\n        F[Nito.AsyncEx\u003Cbr/>AsyncLock]\n        G[Nito.AsyncEx\u003Cbr/>AsyncRWLock]\n        H[Nito.AsyncEx\u003Cbr/>AsyncLazy]\n    end\n\n    A --> B\n    B --> C\n    B --> D\n    B --> E\n    B --> F\n    F --> G\n    F --> H\n\n    style A fill:#ef4444,stroke:#b91c1c,color:#ffffff\n    style B fill:#3b82f6,stroke:#1d4ed8,color:#ffffff\n    style C fill:#f59e0b,stroke:#b45309,color:#ffffff\n    style D fill:#f59e0b,stroke:#b45309,color:#ffffff\n    style E fill:#f59e0b,stroke:#b45309,color:#ffffff\n    style F fill:#10b981,stroke:#059669,color:#ffffff\n    style G fill:#10b981,stroke:#059669,color:#ffffff\n    style H fill:#10b981,stroke:#059669,color:#ffffff\n",[2968,11996,11997,12002,12007,12012,12017,12021,12026,12031,12036,12041,12046,12050,12054,12059,12064,12069,12074,12078,12082,12087,12092,12097,12102,12107,12112,12117,12121,12126,12131,12136,12141,12146,12151,12156],{"__ignoreMap":3013},[3017,11998,11999],{"class":3019,"line":3020},[3017,12000,12001],{},"graph TB\n",[3017,12003,12004],{"class":3019,"line":3047},[3017,12005,12006],{},"    subgraph \"Problem\"\n",[3017,12008,12009],{"class":3019,"line":3054},[3017,12010,12011],{},"        A[lock + await\u003Cbr/>❌ Compiler Error]\n",[3017,12013,12014],{"class":3019,"line":3070},[3017,12015,12016],{},"    end\n",[3017,12018,12019],{"class":3019,"line":3076},[3017,12020,3051],{"emptyLinePlaceholder":3050},[3017,12022,12023],{"class":3019,"line":3096},[3017,12024,12025],{},"    subgraph \"Solutions\"\n",[3017,12027,12028],{"class":3019,"line":3102},[3017,12029,12030],{},"        B[SemaphoreSlim\u003Cbr/>WaitAsync]\n",[3017,12032,12033],{"class":3019,"line":3129},[3017,12034,12035],{},"        C[Throttling\u003Cbr/>N concurrent]\n",[3017,12037,12038],{"class":3019,"line":3135},[3017,12039,12040],{},"        D[Rate Limiting\u003Cbr/>N per time]\n",[3017,12042,12043],{"class":3019,"line":3268},[3017,12044,12045],{},"        E[Timeout\u003Cbr/>Patterns]\n",[3017,12047,12048],{"class":3019,"line":3273},[3017,12049,12016],{},[3017,12051,12052],{"class":3019,"line":3298},[3017,12053,3051],{"emptyLinePlaceholder":3050},[3017,12055,12056],{"class":3019,"line":3303},[3017,12057,12058],{},"    subgraph \"Libraries\"\n",[3017,12060,12061],{"class":3019,"line":3308},[3017,12062,12063],{},"        F[Nito.AsyncEx\u003Cbr/>AsyncLock]\n",[3017,12065,12066],{"class":3019,"line":3314},[3017,12067,12068],{},"        G[Nito.AsyncEx\u003Cbr/>AsyncRWLock]\n",[3017,12070,12071],{"class":3019,"line":3319},[3017,12072,12073],{},"        H[Nito.AsyncEx\u003Cbr/>AsyncLazy]\n",[3017,12075,12076],{"class":3019,"line":3332},[3017,12077,12016],{},[3017,12079,12080],{"class":3019,"line":3349},[3017,12081,3051],{"emptyLinePlaceholder":3050},[3017,12083,12084],{"class":3019,"line":3824},[3017,12085,12086],{},"    A --> B\n",[3017,12088,12089],{"class":3019,"line":3830},[3017,12090,12091],{},"    B --> C\n",[3017,12093,12094],{"class":3019,"line":3843},[3017,12095,12096],{},"    B --> D\n",[3017,12098,12099],{"class":3019,"line":3848},[3017,12100,12101],{},"    B --> E\n",[3017,12103,12104],{"class":3019,"line":3853},[3017,12105,12106],{},"    B --> F\n",[3017,12108,12109],{"class":3019,"line":3858},[3017,12110,12111],{},"    F --> G\n",[3017,12113,12114],{"class":3019,"line":3863},[3017,12115,12116],{},"    F --> H\n",[3017,12118,12119],{"class":3019,"line":3869},[3017,12120,3051],{"emptyLinePlaceholder":3050},[3017,12122,12123],{"class":3019,"line":3887},[3017,12124,12125],{},"    style A fill:#ef4444,stroke:#b91c1c,color:#ffffff\n",[3017,12127,12128],{"class":3019,"line":3916},[3017,12129,12130],{},"    style B fill:#3b82f6,stroke:#1d4ed8,color:#ffffff\n",[3017,12132,12133],{"class":3019,"line":3943},[3017,12134,12135],{},"    style C fill:#f59e0b,stroke:#b45309,color:#ffffff\n",[3017,12137,12138],{"class":3019,"line":3953},[3017,12139,12140],{},"    style D fill:#f59e0b,stroke:#b45309,color:#ffffff\n",[3017,12142,12143],{"class":3019,"line":3958},[3017,12144,12145],{},"    style E fill:#f59e0b,stroke:#b45309,color:#ffffff\n",[3017,12147,12148],{"class":3019,"line":3977},[3017,12149,12150],{},"    style F fill:#10b981,stroke:#059669,color:#ffffff\n",[3017,12152,12153],{"class":3019,"line":5384},[3017,12154,12155],{},"    style G fill:#10b981,stroke:#059669,color:#ffffff\n",[3017,12157,12158],{"class":3019,"line":5389},[3017,12159,12160],{},"    style H fill:#10b981,stroke:#059669,color:#ffffff\n",[3185,12162],{},[2959,12164,12166],{"id":12165},"підсумок","Підсумок",[12168,12169,12170,12194,12214,12232],"card-group",{},[12171,12172,12174],"card",{"icon":12173,"title":3178},"i-lucide-lock",[4442,12175,12176,12179,12185,12191],{},[4445,12177,12178],{},"Async-compatible mutex",[4445,12180,12181,12184],{},[2968,12182,12183],{},"new SemaphoreSlim(1, 1)"," для mutual exclusion",[4445,12186,12187,12188,12190],{},"Завжди ",[2968,12189,4030],{}," для Release",[4445,12192,12193],{},"Підтримка CancellationToken та timeout",[12171,12195,12198],{"icon":12196,"title":12197},"i-lucide-gauge","Throttling",[4442,12199,12200,12203,12208,12211],{},[4445,12201,12202],{},"Обмеження одночасних операцій",[4445,12204,12205,12207],{},[2968,12206,4494],{}," для N concurrent",[4445,12209,12210],{},"Backpressure для захисту від перевантаження",[4445,12212,12213],{},"Ідеально для HTTP clients, DB connections",[12171,12215,12218],{"icon":12216,"title":12217},"i-lucide-timer","Rate Limiting",[4442,12219,12220,12223,12226,12229],{},[4445,12221,12222],{},"Обмеження операцій за одиницю часу",[4445,12224,12225],{},"Sliding window algorithm",[4445,12227,12228],{},"Захист від API rate limits",[4445,12230,12231],{},"Exponential backoff для retry",[12171,12233,12235],{"icon":12234,"title":3182},"i-lucide-package",[4442,12236,12237,12240,12243,12246],{},[4445,12238,12239],{},"AsyncLock, AsyncRWLock, AsyncLazy",[4445,12241,12242],{},"AsyncAutoResetEvent, AsyncManualResetEvent",[4445,12244,12245],{},"Протестовані community реалізації",[4445,12247,12248],{},"Економія часу розробки",[3185,12250],{},[2959,12252,12254],{"id":12253},"практичні-завдання","Практичні Завдання",[3192,12256,12258],{"id":12257},"рівень-1-async-mutex-для-file-access","Рівень 1: Async Mutex для File Access",[2964,12260,12261],{},"Реалізуйте async-safe file manager:",[12263,12264,12265,12281,12286,12289],"ol",{},[4445,12266,12267,12268,12271,12272,2971,12275,2971,12278],{},"Клас ",[2968,12269,12270],{},"AsyncFileManager"," з методами ",[2968,12273,12274],{},"ReadAsync()",[2968,12276,12277],{},"WriteAsync()",[2968,12279,12280],{},"AppendAsync()",[4445,12282,12283,12284,12184],{},"Використовуйте ",[2968,12285,3618],{},[4445,12287,12288],{},"Підтримка CancellationToken",[4445,12290,12291],{},"Правильна обробка exceptions (файл не існує, доступ заборонено)",[2964,12293,12294],{},[2983,12295,12296],{},"Тести:",[4442,12298,12299,12302,12305],{},[4445,12300,12301],{},"10 паралельних readers — всі читають одночасно",[4445,12303,12304],{},"10 паралельних writers — виконуються послідовно",[4445,12306,12307],{},"Mix readers + writers — writers блокують readers",[3192,12309,12311],{"id":12310},"рівень-2-throttled-web-scraper","Рівень 2: Throttled Web Scraper",[2964,12313,12314],{},"Створіть web scraper з обмеженнями:",[12263,12316,12317,12320,12323,12326,12329],{},[4445,12318,12319],{},"Максимум 5 одночасних запитів (throttling)",[4445,12321,12322],{},"Максимум 20 запитів на хвилину (rate limiting)",[4445,12324,12325],{},"Retry з exponential backoff (3 спроби)",[4445,12327,12328],{},"Timeout 10 секунд на запит",[4445,12330,12331],{},"Graceful shutdown при Ctrl+C",[2964,12333,12334],{},[2983,12335,12336],{},"Вимоги:",[4442,12338,12339,12342,12345,12348],{},[4445,12340,12341],{},"Збір всіх посилань з початкової сторінки",[4445,12343,12344],{},"Рекурсивне проходження до глибини 2",[4445,12346,12347],{},"Статистика: успішні/невдалі запити, середній час",[4445,12349,12350],{},"Збереження результатів у JSON",[3192,12352,12354],{"id":12353},"рівень-3-resilient-service-з-circuit-breaker","Рівень 3: Resilient Service з Circuit Breaker",[2964,12356,12357],{},"Побудуйте resilient HTTP service wrapper:",[12263,12359,12360,12366,12372,12378,12384],{},[4445,12361,12362,12365],{},[2983,12363,12364],{},"Throttling:"," Максимум N одночасних запитів",[4445,12367,12368,12371],{},[2983,12369,12370],{},"Rate Limiting:"," Максимум M запитів на хвилину",[4445,12373,12374,12377],{},[2983,12375,12376],{},"Retry:"," Exponential backoff з jitter",[4445,12379,12380,12383],{},[2983,12381,12382],{},"Timeout:"," Configurable per-request timeout",[4445,12385,12386,12389],{},[2983,12387,12388],{},"Circuit Breaker:"," Після X невдалих запитів — відкрити circuit на Y секунд",[2964,12391,12392],{},[2983,12393,12394],{},"Circuit Breaker States:",[4442,12396,12397,12403,12409],{},[4445,12398,12399,12402],{},[2983,12400,12401],{},"Closed:"," Нормальна робота",[4445,12404,12405,12408],{},[2983,12406,12407],{},"Open:"," Всі запити одразу fail (circuit відкритий)",[4445,12410,12411,12414],{},[2983,12412,12413],{},"Half-Open:"," Пробний запит для перевірки відновлення",[2964,12416,12417],{},[2983,12418,12336],{},[4442,12420,12421,12424,12427,12430],{},[4445,12422,12423],{},"Metrics: success rate, average latency, circuit state",[4445,12425,12426],{},"Health check endpoint",[4445,12428,12429],{},"Configurable через JSON",[4445,12431,12432],{},"Unit tests для всіх станів circuit breaker",[3185,12434],{},[4434,12436,12437,3144,12440,12443,12444,2971,12447,12450],{},[2983,12438,12439],{},"Наступна тема:",[12441,12442,360],"a",{"href":361}," — низькорівневе програмування в C#, pointer arithmetic, ",[2968,12445,12446],{},"stackalloc",[2968,12448,12449],{},"Span\u003CT>",", та function pointers.",[12452,12453,12454],"style",{},"html pre.shiki code .su1O8, html code.shiki .su1O8{--shiki-light:#0000FF;--shiki-default:#569CD6;--shiki-dark:#569CD6}html pre.shiki code .siwwj, html code.shiki .siwwj{--shiki-light:#001080;--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}html pre.shiki code .sHH4Y, html code.shiki .sHH4Y{--shiki-light:#000000;--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .sN1BT, html code.shiki .sN1BT{--shiki-light:#267F99;--shiki-default:#4EC9B0;--shiki-dark:#4EC9B0}html pre.shiki code .s8Opu, html code.shiki .s8Opu{--shiki-light:#795E26;--shiki-default:#DCDCAA;--shiki-dark:#DCDCAA}html pre.shiki code .sCDza, html code.shiki .sCDza{--shiki-light:#AF00DB;--shiki-default:#CE92A4;--shiki-dark:#CE92A4}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 .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 .sbdoH, html code.shiki .sbdoH{--shiki-light:#A31515;--shiki-default:#CE9178;--shiki-dark:#CE9178}html pre.shiki code .sD7JJ, html code.shiki .sD7JJ{--shiki-light:#000000FF;--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .sjcCO, html code.shiki .sjcCO{--shiki-light:#EE0000;--shiki-default:#D7BA7D;--shiki-dark:#D7BA7D}",{"title":3013,"searchDepth":3047,"depth":3047,"links":12456},[12457,12458,12463,12469,12474,12481,12492,12500,12501,12502],{"id":2961,"depth":3047,"text":2962},{"id":3189,"depth":3047,"text":3190,"children":12459},[12460,12461,12462],{"id":3194,"depth":3054,"text":3195},{"id":3375,"depth":3054,"text":3376},{"id":3545,"depth":3054,"text":3546},{"id":3608,"depth":3047,"text":3609,"children":12464},[12465,12466,12467,12468],{"id":3612,"depth":3054,"text":3613},{"id":3642,"depth":3054,"text":3643},{"id":4023,"depth":3054,"text":4024},{"id":4315,"depth":3054,"text":4316},{"id":4464,"depth":3047,"text":4465,"children":12470},[12471,12472,12473],{"id":4468,"depth":3054,"text":4469},{"id":4488,"depth":3054,"text":4489},{"id":4987,"depth":3054,"text":4988},{"id":5767,"depth":3047,"text":5768,"children":12475},[12476,12477,12478,12479,12480],{"id":5771,"depth":3054,"text":5772},{"id":5781,"depth":3054,"text":5782},{"id":6186,"depth":3054,"text":6187},{"id":6531,"depth":3054,"text":6532},{"id":6904,"depth":3054,"text":6905},{"id":7547,"depth":3047,"text":7548,"children":12482},[12483,12484,12485,12486,12488,12490,12491],{"id":7551,"depth":3054,"text":7552},{"id":7586,"depth":3054,"text":7587},{"id":7764,"depth":3054,"text":7765},{"id":8134,"depth":3054,"text":12487},"AsyncCollection: Async Producer-Consumer",{"id":8373,"depth":3054,"text":12489},"AsyncLazy: Lazy Async Initialization",{"id":8667,"depth":3054,"text":8668},{"id":8989,"depth":3054,"text":8990},{"id":9115,"depth":3047,"text":9116,"children":12493},[12494,12495,12496,12497,12498,12499],{"id":9125,"depth":3054,"text":9126},{"id":9166,"depth":3054,"text":9167},{"id":9585,"depth":3054,"text":9586},{"id":10506,"depth":3054,"text":10507},{"id":11174,"depth":3054,"text":11175},{"id":11821,"depth":3054,"text":11822},{"id":11986,"depth":3047,"text":11987},{"id":12165,"depth":3047,"text":12166},{"id":12253,"depth":3047,"text":12254,"children":12503},[12504,12505,12506],{"id":12257,"depth":3054,"text":12258},{"id":12310,"depth":3054,"text":12311},{"id":12353,"depth":3054,"text":12354},"Повний розбір асинхронної синхронізації в C# — чому lock не працює з await, SemaphoreSlim.WaitAsync() як async mutex, throttling та rate limiting patterns, timeout strategies, та бібліотека Nito.AsyncEx для просунутих сценаріїв.","md",null,{},{"title":356,"description":12507},"HfCBnl4l8LW7aHfSIpk72BoFV7g2BF-R_qEK9SbC9jI",[12514,12516],{"title":352,"path":353,"stem":354,"description":12515,"children":-1},"Повний розбір System.Threading.Channels — async-native producer/consumer patterns для high-performance pipelines. Bounded та Unbounded channels, BoundedChannelFullMode, multi-stage pipelines, BackgroundService інтеграція та benchmarks проти BlockingCollection.",{"title":360,"path":361,"stem":362,"description":12517,"children":-1},"Повний розбір unsafe коду в C# — вказівники, pointer arithmetic, fixed statement для pinning, stackalloc та Span\u003CT>, sizeof, function pointers (C# 9+), та практичні сценарії використання для high-performance коду.",1777912545500]