[{"data":1,"prerenderedAt":23052},["ShallowReactive",2],{"navigation_docs":3,"-csharp-aspnet-web-api-hateoas-resource-expansion":2949,"-csharp-aspnet-web-api-hateoas-resource-expansion-surround":23047},[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":1323,"body":2951,"description":23041,"extension":23042,"links":23043,"meta":23044,"navigation":3287,"path":1324,"seo":23045,"stem":1325,"__hash__":23046},"docs/01.csharp/11.aspnet/12.web-api/08.hateoas-resource-expansion.md",{"type":2952,"value":2953,"toc":22994},"minimark",[2954,2958,2963,2967,2984,3071,3077,3088,3112,3117,3125,3130,3158,3163,3304,3321,3328,3333,3347,3352,3504,3509,3518,3702,3707,3716,3721,3858,3861,3881,3884,3888,3892,3899,3953,3958,3973,3978,3993,3998,4017,4022,4124,4135,4139,4144,4177,4182,4208,4212,4218,4370,4375,4417,4419,4423,4427,5318,5320,5324,5329,5334,5518,5522,5552,5556,5561,7201,7205,7237,7244,7246,7250,7254,7259,8067,8071,8104,8106,8110,8114,8119,8439,8444,8490,8492,8496,8501,9538,9540,9544,9549,14595,14599,14643,14645,14649,15075,15086,15088,15092,15597,15599,15603,15607,15610,15625,15629,16072,16076,16345,16350,16359,16402,16404,16408,16411,16792,16797,16835,16840,16899,16901,16905,16908,16971,17036,17039,17045,17047,17051,17054,17167,17170,17176,17178,17182,17186,17485,17487,17491,19796,19798,19802,22660,22662,22666,22674,22678,22683,22709,22714,22728,22733,22749,22754,22768,22773,22787,22791,22857,22861,22905,22932,22934,22938,22978,22980,22990],[2955,2956,1323],"h1",{"id":2957},"hateoas-та-resource-expansion",[2959,2960,2962],"h2",{"id":2961},"вступ-проблема-статичних-api","Вступ: Проблема статичних API",[2964,2965,2966],"p",{},"Уявіть, що ви створили REST API для блогу:",[2968,2969,2974],"pre",{"className":2970,"code":2971,"language":2972,"meta":2973,"style":2973},"language-http shiki shiki-themes light-plus dark-plus dark-plus","GET /api/articles/5\n","http","",[2975,2976,2977],"code",{"__ignoreMap":2973},[2978,2979,2982],"span",{"class":2980,"line":2981},"line",1,[2978,2983,2971],{},[2968,2985,2989],{"className":2986,"code":2987,"language":2988,"meta":2973,"style":2973},"language-json shiki shiki-themes light-plus dark-plus dark-plus","{\n  \"id\": 5,\n  \"title\": \"Introduction to ASP.NET Core\",\n  \"authorId\": 42,\n  \"categoryId\": 3,\n  \"publishedAt\": \"2024-01-15T10:00:00Z\"\n}\n","json",[2975,2990,2991,2997,3014,3028,3041,3054,3065],{"__ignoreMap":2973},[2978,2992,2993],{"class":2980,"line":2981},[2978,2994,2996],{"class":2995},"sHH4Y","{\n",[2978,2998,3000,3004,3007,3011],{"class":2980,"line":2999},2,[2978,3001,3003],{"class":3002},"sLwNe","  \"id\"",[2978,3005,3006],{"class":2995},": ",[2978,3008,3010],{"class":3009},"sJj4R","5",[2978,3012,3013],{"class":2995},",\n",[2978,3015,3017,3020,3022,3026],{"class":2980,"line":3016},3,[2978,3018,3019],{"class":3002},"  \"title\"",[2978,3021,3006],{"class":2995},[2978,3023,3025],{"class":3024},"sbdoH","\"Introduction to ASP.NET Core\"",[2978,3027,3013],{"class":2995},[2978,3029,3031,3034,3036,3039],{"class":2980,"line":3030},4,[2978,3032,3033],{"class":3002},"  \"authorId\"",[2978,3035,3006],{"class":2995},[2978,3037,3038],{"class":3009},"42",[2978,3040,3013],{"class":2995},[2978,3042,3044,3047,3049,3052],{"class":2980,"line":3043},5,[2978,3045,3046],{"class":3002},"  \"categoryId\"",[2978,3048,3006],{"class":2995},[2978,3050,3051],{"class":3009},"3",[2978,3053,3013],{"class":2995},[2978,3055,3057,3060,3062],{"class":2980,"line":3056},6,[2978,3058,3059],{"class":3002},"  \"publishedAt\"",[2978,3061,3006],{"class":2995},[2978,3063,3064],{"class":3024},"\"2024-01-15T10:00:00Z\"\n",[2978,3066,3068],{"class":2980,"line":3067},7,[2978,3069,3070],{"class":2995},"}\n",[2964,3072,3073],{},[3074,3075,3076],"strong",{},"Що має зробити клієнт далі?",[2964,3078,3079,3080,3083,3084,3087],{},"Клієнт бачить ",[2975,3081,3082],{},"authorId: 42",", але ",[3074,3085,3086],{},"не знає",":",[3089,3090,3091,3095,3106,3109],"ul",{},[3092,3093,3094],"li",{},"❌ Як отримати інформацію про автора?",[3092,3096,3097,3098,3101,3102,3105],{},"❌ Який URL використовувати? ",[2975,3099,3100],{},"/api/authors/42","? ",[2975,3103,3104],{},"/api/users/42","?",[3092,3107,3108],{},"❌ Які дії доступні? Можна редагувати? Видалити?",[3092,3110,3111],{},"❌ Як отримати коментарі до статті?",[2964,3113,3114],{},[3074,3115,3116],{},"Типовий підхід — документація:",[2968,3118,3123],{"className":3119,"code":3121,"language":3122},[3120],"language-text","Документація API:\n- Отримати автора: GET /api/authors/{id}\n- Отримати коментарі: GET /api/articles/{id}/comments\n- Редагувати статтю: PUT /api/articles/{id} (потрібна роль Editor)\n- Видалити статтю: DELETE /api/articles/{id} (потрібна роль Admin)\n","text",[2975,3124,3121],{"__ignoreMap":2973},[2964,3126,3127],{},[3074,3128,3129],{},"Проблеми цього підходу:",[3089,3131,3132,3139,3145,3152],{},[3092,3133,3134,3135,3138],{},"❌ Клієнт має ",[3074,3136,3137],{},"хардкодити"," URL-и",[3092,3140,3141,3142],{},"❌ Документація може ",[3074,3143,3144],{},"застаріти",[3092,3146,3147,3148,3151],{},"❌ Клієнт не знає, ",[3074,3149,3150],{},"які дії доступні"," для конкретного користувача",[3092,3153,3154,3155],{},"❌ Зміна URL-структури ",[3074,3156,3157],{},"ламає всіх клієнтів",[2964,3159,3160],{},[3074,3161,3162],{},"Реальний сценарій:",[2968,3164,3168],{"className":3165,"code":3166,"language":3167,"meta":2973,"style":2973},"language-javascript shiki shiki-themes light-plus dark-plus dark-plus","// Клієнтський код (хардкод URL)\nconst article = await fetch('/api/articles/5').then(r => r.json());\nconst author = await fetch(`/api/authors/${article.authorId}`).then(r => r.json());\n\n// ❌ Що якщо API змінить URL на /api/users/{id}?\n// ❌ Що якщо authorId більше не повертається?\n// ❌ Клієнт зламається!\n","javascript",[2975,3169,3170,3176,3229,3283,3289,3294,3299],{"__ignoreMap":2973},[2978,3171,3172],{"class":2980,"line":2981},[2978,3173,3175],{"class":3174},"spJ8K","// Клієнтський код (хардкод URL)\n",[2978,3177,3178,3182,3186,3189,3193,3197,3200,3203,3206,3209,3211,3215,3218,3221,3224,3226],{"class":2980,"line":2999},[2978,3179,3181],{"class":3180},"su1O8","const",[2978,3183,3185],{"class":3184},"s-QsJ"," article",[2978,3187,3188],{"class":2995}," = ",[2978,3190,3192],{"class":3191},"sCDza","await",[2978,3194,3196],{"class":3195},"s8Opu"," fetch",[2978,3198,3199],{"class":2995},"(",[2978,3201,3202],{"class":3024},"'/api/articles/5'",[2978,3204,3205],{"class":2995},").",[2978,3207,3208],{"class":3195},"then",[2978,3210,3199],{"class":2995},[2978,3212,3214],{"class":3213},"siwwj","r",[2978,3216,3217],{"class":3180}," =>",[2978,3219,3220],{"class":3213}," r",[2978,3222,3223],{"class":2995},".",[2978,3225,2988],{"class":3195},[2978,3227,3228],{"class":2995},"());\n",[2978,3230,3231,3233,3236,3238,3240,3242,3244,3247,3250,3253,3256,3259,3262,3265,3267,3269,3271,3273,3275,3277,3279,3281],{"class":2980,"line":3016},[2978,3232,3181],{"class":3180},[2978,3234,3235],{"class":3184}," author",[2978,3237,3188],{"class":2995},[2978,3239,3192],{"class":3191},[2978,3241,3196],{"class":3195},[2978,3243,3199],{"class":2995},[2978,3245,3246],{"class":3024},"`/api/authors/",[2978,3248,3249],{"class":3180},"${",[2978,3251,3252],{"class":3213},"article",[2978,3254,3223],{"class":3255},"sD7JJ",[2978,3257,3258],{"class":3213},"authorId",[2978,3260,3261],{"class":3180},"}",[2978,3263,3264],{"class":3024},"`",[2978,3266,3205],{"class":2995},[2978,3268,3208],{"class":3195},[2978,3270,3199],{"class":2995},[2978,3272,3214],{"class":3213},[2978,3274,3217],{"class":3180},[2978,3276,3220],{"class":3213},[2978,3278,3223],{"class":2995},[2978,3280,2988],{"class":3195},[2978,3282,3228],{"class":2995},[2978,3284,3285],{"class":2980,"line":3030},[2978,3286,3288],{"emptyLinePlaceholder":3287},true,"\n",[2978,3290,3291],{"class":2980,"line":3043},[2978,3292,3293],{"class":3174},"// ❌ Що якщо API змінить URL на /api/users/{id}?\n",[2978,3295,3296],{"class":2980,"line":3056},[2978,3297,3298],{"class":3174},"// ❌ Що якщо authorId більше не повертається?\n",[2978,3300,3301],{"class":2980,"line":3067},[2978,3302,3303],{"class":3174},"// ❌ Клієнт зламається!\n",[2964,3305,3306,3309,3310,3313,3314,3317,3318,3223],{},[3074,3307,3308],{},"Рішення"," — ",[3074,3311,3312],{},"HATEOAS (Hypermedia as the Engine of Application State)"," — принцип REST, де API ",[3074,3315,3316],{},"сам повідомляє клієнту",", які дії та ресурси доступні через ",[3074,3319,3320],{},"гіперпосилання",[3322,3323,3324,3327],"note",{},[3074,3325,3326],{},"Передумови:"," Ця стаття базується на знаннях з попередніх статей (01-07 Web API Controllers), а також на розумінні REST теорії з курсу API Design (статті 01-06).",[3329,3330,3332],"h3",{"id":3331},"що-ви-створите-в-цій-статті","Що ви створите в цій статті",[2964,3334,3335,3336,3339,3340,3343,3344,3087],{},"Ми побудуємо ",[3074,3337,3338],{},"Blog API"," з ",[3074,3341,3342],{},"HATEOAS"," та ",[3074,3345,3346],{},"Resource Expansion",[2964,3348,3349],{},[3074,3350,3351],{},"1. HATEOAS Links — Self-Discoverable API:",[2968,3353,3355],{"className":2986,"code":3354,"language":2988,"meta":2973,"style":2973},"{\n  \"id\": 5,\n  \"title\": \"Introduction to ASP.NET Core\",\n  \"_links\": {\n    \"self\": { \"href\": \"/api/articles/5\" },\n    \"author\": { \"href\": \"/api/authors/42\" },\n    \"comments\": { \"href\": \"/api/articles/5/comments\" },\n    \"edit\": { \"href\": \"/api/articles/5\", \"method\": \"PUT\" },\n    \"delete\": { \"href\": \"/api/articles/5\", \"method\": \"DELETE\" }\n  }\n}\n",[2975,3356,3357,3361,3371,3381,3389,3408,3424,3440,3467,3493,3499],{"__ignoreMap":2973},[2978,3358,3359],{"class":2980,"line":2981},[2978,3360,2996],{"class":2995},[2978,3362,3363,3365,3367,3369],{"class":2980,"line":2999},[2978,3364,3003],{"class":3002},[2978,3366,3006],{"class":2995},[2978,3368,3010],{"class":3009},[2978,3370,3013],{"class":2995},[2978,3372,3373,3375,3377,3379],{"class":2980,"line":3016},[2978,3374,3019],{"class":3002},[2978,3376,3006],{"class":2995},[2978,3378,3025],{"class":3024},[2978,3380,3013],{"class":2995},[2978,3382,3383,3386],{"class":2980,"line":3030},[2978,3384,3385],{"class":3002},"  \"_links\"",[2978,3387,3388],{"class":2995},": {\n",[2978,3390,3391,3394,3397,3400,3402,3405],{"class":2980,"line":3043},[2978,3392,3393],{"class":3002},"    \"self\"",[2978,3395,3396],{"class":2995},": { ",[2978,3398,3399],{"class":3002},"\"href\"",[2978,3401,3006],{"class":2995},[2978,3403,3404],{"class":3024},"\"/api/articles/5\"",[2978,3406,3407],{"class":2995}," },\n",[2978,3409,3410,3413,3415,3417,3419,3422],{"class":2980,"line":3056},[2978,3411,3412],{"class":3002},"    \"author\"",[2978,3414,3396],{"class":2995},[2978,3416,3399],{"class":3002},[2978,3418,3006],{"class":2995},[2978,3420,3421],{"class":3024},"\"/api/authors/42\"",[2978,3423,3407],{"class":2995},[2978,3425,3426,3429,3431,3433,3435,3438],{"class":2980,"line":3067},[2978,3427,3428],{"class":3002},"    \"comments\"",[2978,3430,3396],{"class":2995},[2978,3432,3399],{"class":3002},[2978,3434,3006],{"class":2995},[2978,3436,3437],{"class":3024},"\"/api/articles/5/comments\"",[2978,3439,3407],{"class":2995},[2978,3441,3443,3446,3448,3450,3452,3454,3457,3460,3462,3465],{"class":2980,"line":3442},8,[2978,3444,3445],{"class":3002},"    \"edit\"",[2978,3447,3396],{"class":2995},[2978,3449,3399],{"class":3002},[2978,3451,3006],{"class":2995},[2978,3453,3404],{"class":3024},[2978,3455,3456],{"class":2995},", ",[2978,3458,3459],{"class":3002},"\"method\"",[2978,3461,3006],{"class":2995},[2978,3463,3464],{"class":3024},"\"PUT\"",[2978,3466,3407],{"class":2995},[2978,3468,3470,3473,3475,3477,3479,3481,3483,3485,3487,3490],{"class":2980,"line":3469},9,[2978,3471,3472],{"class":3002},"    \"delete\"",[2978,3474,3396],{"class":2995},[2978,3476,3399],{"class":3002},[2978,3478,3006],{"class":2995},[2978,3480,3404],{"class":3024},[2978,3482,3456],{"class":2995},[2978,3484,3459],{"class":3002},[2978,3486,3006],{"class":2995},[2978,3488,3489],{"class":3024},"\"DELETE\"",[2978,3491,3492],{"class":2995}," }\n",[2978,3494,3496],{"class":2980,"line":3495},10,[2978,3497,3498],{"class":2995},"  }\n",[2978,3500,3502],{"class":2980,"line":3501},11,[2978,3503,3070],{"class":2995},[2964,3505,3506],{},[3074,3507,3508],{},"2. Resource Expansion — Embedded Resources:",[2968,3510,3512],{"className":2970,"code":3511,"language":2972,"meta":2973,"style":2973},"GET /api/articles/5?expand=author,comments\n",[2975,3513,3514],{"__ignoreMap":2973},[2978,3515,3516],{"class":2980,"line":2981},[2978,3517,3511],{},[2968,3519,3521],{"className":2986,"code":3520,"language":2988,"meta":2973,"style":2973},"{\n  \"id\": 5,\n  \"title\": \"Introduction to ASP.NET Core\",\n  \"_embedded\": {\n    \"author\": {\n      \"id\": 42,\n      \"name\": \"John Doe\",\n      \"email\": \"john@example.com\"\n    },\n    \"comments\": [\n      { \"id\": 1, \"text\": \"Great article!\", \"author\": \"Jane\" },\n      { \"id\": 2, \"text\": \"Thanks for sharing\", \"author\": \"Bob\" }\n    ]\n  },\n  \"_links\": { ... }\n}\n",[2975,3522,3523,3527,3537,3547,3554,3560,3571,3583,3593,3598,3605,3640,3672,3678,3684,3697],{"__ignoreMap":2973},[2978,3524,3525],{"class":2980,"line":2981},[2978,3526,2996],{"class":2995},[2978,3528,3529,3531,3533,3535],{"class":2980,"line":2999},[2978,3530,3003],{"class":3002},[2978,3532,3006],{"class":2995},[2978,3534,3010],{"class":3009},[2978,3536,3013],{"class":2995},[2978,3538,3539,3541,3543,3545],{"class":2980,"line":3016},[2978,3540,3019],{"class":3002},[2978,3542,3006],{"class":2995},[2978,3544,3025],{"class":3024},[2978,3546,3013],{"class":2995},[2978,3548,3549,3552],{"class":2980,"line":3030},[2978,3550,3551],{"class":3002},"  \"_embedded\"",[2978,3553,3388],{"class":2995},[2978,3555,3556,3558],{"class":2980,"line":3043},[2978,3557,3412],{"class":3002},[2978,3559,3388],{"class":2995},[2978,3561,3562,3565,3567,3569],{"class":2980,"line":3056},[2978,3563,3564],{"class":3002},"      \"id\"",[2978,3566,3006],{"class":2995},[2978,3568,3038],{"class":3009},[2978,3570,3013],{"class":2995},[2978,3572,3573,3576,3578,3581],{"class":2980,"line":3067},[2978,3574,3575],{"class":3002},"      \"name\"",[2978,3577,3006],{"class":2995},[2978,3579,3580],{"class":3024},"\"John Doe\"",[2978,3582,3013],{"class":2995},[2978,3584,3585,3588,3590],{"class":2980,"line":3442},[2978,3586,3587],{"class":3002},"      \"email\"",[2978,3589,3006],{"class":2995},[2978,3591,3592],{"class":3024},"\"john@example.com\"\n",[2978,3594,3595],{"class":2980,"line":3469},[2978,3596,3597],{"class":2995},"    },\n",[2978,3599,3600,3602],{"class":2980,"line":3495},[2978,3601,3428],{"class":3002},[2978,3603,3604],{"class":2995},": [\n",[2978,3606,3607,3610,3613,3615,3618,3620,3623,3625,3628,3630,3633,3635,3638],{"class":2980,"line":3501},[2978,3608,3609],{"class":2995},"      { ",[2978,3611,3612],{"class":3002},"\"id\"",[2978,3614,3006],{"class":2995},[2978,3616,3617],{"class":3009},"1",[2978,3619,3456],{"class":2995},[2978,3621,3622],{"class":3002},"\"text\"",[2978,3624,3006],{"class":2995},[2978,3626,3627],{"class":3024},"\"Great article!\"",[2978,3629,3456],{"class":2995},[2978,3631,3632],{"class":3002},"\"author\"",[2978,3634,3006],{"class":2995},[2978,3636,3637],{"class":3024},"\"Jane\"",[2978,3639,3407],{"class":2995},[2978,3641,3643,3645,3647,3649,3652,3654,3656,3658,3661,3663,3665,3667,3670],{"class":2980,"line":3642},12,[2978,3644,3609],{"class":2995},[2978,3646,3612],{"class":3002},[2978,3648,3006],{"class":2995},[2978,3650,3651],{"class":3009},"2",[2978,3653,3456],{"class":2995},[2978,3655,3622],{"class":3002},[2978,3657,3006],{"class":2995},[2978,3659,3660],{"class":3024},"\"Thanks for sharing\"",[2978,3662,3456],{"class":2995},[2978,3664,3632],{"class":3002},[2978,3666,3006],{"class":2995},[2978,3668,3669],{"class":3024},"\"Bob\"",[2978,3671,3492],{"class":2995},[2978,3673,3675],{"class":2980,"line":3674},13,[2978,3676,3677],{"class":2995},"    ]\n",[2978,3679,3681],{"class":2980,"line":3680},14,[2978,3682,3683],{"class":2995},"  },\n",[2978,3685,3687,3689,3691,3695],{"class":2980,"line":3686},15,[2978,3688,3385],{"class":3002},[2978,3690,3396],{"class":2995},[2978,3692,3694],{"class":3693},"se1LK","...",[2978,3696,3492],{"class":2995},[2978,3698,3700],{"class":2980,"line":3699},16,[2978,3701,3070],{"class":2995},[2964,3703,3704],{},[3074,3705,3706],{},"3. Sparse Fieldsets — Вибіркові поля:",[2968,3708,3710],{"className":2970,"code":3709,"language":2972,"meta":2973,"style":2973},"GET /api/articles?fields=id,title,author\n",[2975,3711,3712],{"__ignoreMap":2973},[2978,3713,3714],{"class":2980,"line":2981},[2978,3715,3709],{},[2964,3717,3718],{},[3074,3719,3720],{},"4. HAL (Hypertext Application Language) формат:",[2968,3722,3724],{"className":2986,"code":3723,"language":2988,"meta":2973,"style":2973},"{\n  \"_links\": { \"self\": { \"href\": \"/api/articles\" } },\n  \"_embedded\": {\n    \"articles\": [\n      { \"id\": 1, \"title\": \"Article 1\", \"_links\": { ... } },\n      { \"id\": 2, \"title\": \"Article 2\", \"_links\": { ... } }\n    ]\n  },\n  \"page\": 1,\n  \"totalPages\": 10\n}\n",[2975,3725,3726,3730,3751,3757,3764,3795,3825,3829,3833,3844,3854],{"__ignoreMap":2973},[2978,3727,3728],{"class":2980,"line":2981},[2978,3729,2996],{"class":2995},[2978,3731,3732,3734,3736,3739,3741,3743,3745,3748],{"class":2980,"line":2999},[2978,3733,3385],{"class":3002},[2978,3735,3396],{"class":2995},[2978,3737,3738],{"class":3002},"\"self\"",[2978,3740,3396],{"class":2995},[2978,3742,3399],{"class":3002},[2978,3744,3006],{"class":2995},[2978,3746,3747],{"class":3024},"\"/api/articles\"",[2978,3749,3750],{"class":2995}," } },\n",[2978,3752,3753,3755],{"class":2980,"line":3016},[2978,3754,3551],{"class":3002},[2978,3756,3388],{"class":2995},[2978,3758,3759,3762],{"class":2980,"line":3030},[2978,3760,3761],{"class":3002},"    \"articles\"",[2978,3763,3604],{"class":2995},[2978,3765,3766,3768,3770,3772,3774,3776,3779,3781,3784,3786,3789,3791,3793],{"class":2980,"line":3043},[2978,3767,3609],{"class":2995},[2978,3769,3612],{"class":3002},[2978,3771,3006],{"class":2995},[2978,3773,3617],{"class":3009},[2978,3775,3456],{"class":2995},[2978,3777,3778],{"class":3002},"\"title\"",[2978,3780,3006],{"class":2995},[2978,3782,3783],{"class":3024},"\"Article 1\"",[2978,3785,3456],{"class":2995},[2978,3787,3788],{"class":3002},"\"_links\"",[2978,3790,3396],{"class":2995},[2978,3792,3694],{"class":3693},[2978,3794,3750],{"class":2995},[2978,3796,3797,3799,3801,3803,3805,3807,3809,3811,3814,3816,3818,3820,3822],{"class":2980,"line":3056},[2978,3798,3609],{"class":2995},[2978,3800,3612],{"class":3002},[2978,3802,3006],{"class":2995},[2978,3804,3651],{"class":3009},[2978,3806,3456],{"class":2995},[2978,3808,3778],{"class":3002},[2978,3810,3006],{"class":2995},[2978,3812,3813],{"class":3024},"\"Article 2\"",[2978,3815,3456],{"class":2995},[2978,3817,3788],{"class":3002},[2978,3819,3396],{"class":2995},[2978,3821,3694],{"class":3693},[2978,3823,3824],{"class":2995}," } }\n",[2978,3826,3827],{"class":2980,"line":3067},[2978,3828,3677],{"class":2995},[2978,3830,3831],{"class":2980,"line":3442},[2978,3832,3683],{"class":2995},[2978,3834,3835,3838,3840,3842],{"class":2980,"line":3469},[2978,3836,3837],{"class":3002},"  \"page\"",[2978,3839,3006],{"class":2995},[2978,3841,3617],{"class":3009},[2978,3843,3013],{"class":2995},[2978,3845,3846,3849,3851],{"class":2980,"line":3495},[2978,3847,3848],{"class":3002},"  \"totalPages\"",[2978,3850,3006],{"class":2995},[2978,3852,3853],{"class":3009},"10\n",[2978,3855,3856],{"class":2980,"line":3501},[2978,3857,3070],{"class":2995},[2964,3859,3860],{},"До кінця статті ви зможете:",[3089,3862,3863,3869,3872,3875,3878],{},[3092,3864,3865,3866],{},"Реалізувати HATEOAS links через ",[2975,3867,3868],{},"LinkGenerator",[3092,3870,3871],{},"Створювати self-discoverable API",[3092,3873,3874],{},"Використовувати resource expansion для зменшення кількості запитів",[3092,3876,3877],{},"Реалізувати HAL формат",[3092,3879,3880],{},"Застосовувати sparse fieldsets для оптимізації",[3882,3883],"hr",{},[2959,3885,3887],{"id":3886},"фундаментальні-концепції","Фундаментальні концепції",[3329,3889,3891],{"id":3890},"richardson-maturity-model","Richardson Maturity Model",[2964,3893,3894,3895,3898],{},"REST API має ",[3074,3896,3897],{},"4 рівні зрілості"," (Richardson Maturity Model):",[3900,3901,3902],"mermaid",{},[2968,3903,3906],{"className":3904,"code":3905,"language":3900,"meta":2973,"style":2973},"language-mermaid shiki shiki-themes light-plus dark-plus dark-plus","graph TD\n    A[Level 0: The Swamp of POX\u003Cbr/>Один endpoint, POST для всього] --> B[Level 1: Resources\u003Cbr/>Множина endpoints, але тільки POST]\n    B --> C[Level 2: HTTP Verbs\u003Cbr/>GET, POST, PUT, DELETE + статус-коди]\n    C --> D[Level 3: Hypermedia Controls\u003Cbr/>HATEOAS - links у відповідях]\n    \n    style A fill:#ef4444,stroke:#b91c1c,color:#ffffff\n    style B fill:#f59e0b,stroke:#b45309,color:#ffffff\n    style C fill:#3b82f6,stroke:#1d4ed8,color:#ffffff\n    style D fill:#10b981,stroke:#059669,color:#ffffff\n",[2975,3907,3908,3913,3918,3923,3928,3933,3938,3943,3948],{"__ignoreMap":2973},[2978,3909,3910],{"class":2980,"line":2981},[2978,3911,3912],{},"graph TD\n",[2978,3914,3915],{"class":2980,"line":2999},[2978,3916,3917],{},"    A[Level 0: The Swamp of POX\u003Cbr/>Один endpoint, POST для всього] --> B[Level 1: Resources\u003Cbr/>Множина endpoints, але тільки POST]\n",[2978,3919,3920],{"class":2980,"line":3016},[2978,3921,3922],{},"    B --> C[Level 2: HTTP Verbs\u003Cbr/>GET, POST, PUT, DELETE + статус-коди]\n",[2978,3924,3925],{"class":2980,"line":3030},[2978,3926,3927],{},"    C --> D[Level 3: Hypermedia Controls\u003Cbr/>HATEOAS - links у відповідях]\n",[2978,3929,3930],{"class":2980,"line":3043},[2978,3931,3932],{},"    \n",[2978,3934,3935],{"class":2980,"line":3056},[2978,3936,3937],{},"    style A fill:#ef4444,stroke:#b91c1c,color:#ffffff\n",[2978,3939,3940],{"class":2980,"line":3067},[2978,3941,3942],{},"    style B fill:#f59e0b,stroke:#b45309,color:#ffffff\n",[2978,3944,3945],{"class":2980,"line":3442},[2978,3946,3947],{},"    style C fill:#3b82f6,stroke:#1d4ed8,color:#ffffff\n",[2978,3949,3950],{"class":2980,"line":3469},[2978,3951,3952],{},"    style D fill:#10b981,stroke:#059669,color:#ffffff\n",[2964,3954,3955],{},[3074,3956,3957],{},"Level 0 — The Swamp of POX (Plain Old XML):",[2968,3959,3961],{"className":2970,"code":3960,"language":2972,"meta":2973,"style":2973},"POST /api\n{ \"action\": \"getArticle\", \"id\": 5 }\n",[2975,3962,3963,3968],{"__ignoreMap":2973},[2978,3964,3965],{"class":2980,"line":2981},[2978,3966,3967],{},"POST /api\n",[2978,3969,3970],{"class":2980,"line":2999},[2978,3971,3972],{},"{ \"action\": \"getArticle\", \"id\": 5 }\n",[2964,3974,3975],{},[3074,3976,3977],{},"Level 1 — Resources:",[2968,3979,3981],{"className":2970,"code":3980,"language":2972,"meta":2973,"style":2973},"POST /api/articles/5\n{ \"action\": \"get\" }\n",[2975,3982,3983,3988],{"__ignoreMap":2973},[2978,3984,3985],{"class":2980,"line":2981},[2978,3986,3987],{},"POST /api/articles/5\n",[2978,3989,3990],{"class":2980,"line":2999},[2978,3991,3992],{},"{ \"action\": \"get\" }\n",[2964,3994,3995],{},[3074,3996,3997],{},"Level 2 — HTTP Verbs (більшість сучасних API):",[2968,3999,4001],{"className":2970,"code":4000,"language":2972,"meta":2973,"style":2973},"GET /api/articles/5\nPUT /api/articles/5\nDELETE /api/articles/5\n",[2975,4002,4003,4007,4012],{"__ignoreMap":2973},[2978,4004,4005],{"class":2980,"line":2981},[2978,4006,2971],{},[2978,4008,4009],{"class":2980,"line":2999},[2978,4010,4011],{},"PUT /api/articles/5\n",[2978,4013,4014],{"class":2980,"line":3016},[2978,4015,4016],{},"DELETE /api/articles/5\n",[2964,4018,4019],{},[3074,4020,4021],{},"Level 3 — Hypermedia Controls (HATEOAS):",[2968,4023,4025],{"className":2986,"code":4024,"language":2988,"meta":2973,"style":2973},"{\n  \"id\": 5,\n  \"title\": \"Article\",\n  \"_links\": {\n    \"self\": { \"href\": \"/api/articles/5\" },\n    \"edit\": { \"href\": \"/api/articles/5\", \"method\": \"PUT\" },\n    \"delete\": { \"href\": \"/api/articles/5\", \"method\": \"DELETE\" }\n  }\n}\n",[2975,4026,4027,4031,4041,4052,4058,4072,4094,4116,4120],{"__ignoreMap":2973},[2978,4028,4029],{"class":2980,"line":2981},[2978,4030,2996],{"class":2995},[2978,4032,4033,4035,4037,4039],{"class":2980,"line":2999},[2978,4034,3003],{"class":3002},[2978,4036,3006],{"class":2995},[2978,4038,3010],{"class":3009},[2978,4040,3013],{"class":2995},[2978,4042,4043,4045,4047,4050],{"class":2980,"line":3016},[2978,4044,3019],{"class":3002},[2978,4046,3006],{"class":2995},[2978,4048,4049],{"class":3024},"\"Article\"",[2978,4051,3013],{"class":2995},[2978,4053,4054,4056],{"class":2980,"line":3030},[2978,4055,3385],{"class":3002},[2978,4057,3388],{"class":2995},[2978,4059,4060,4062,4064,4066,4068,4070],{"class":2980,"line":3043},[2978,4061,3393],{"class":3002},[2978,4063,3396],{"class":2995},[2978,4065,3399],{"class":3002},[2978,4067,3006],{"class":2995},[2978,4069,3404],{"class":3024},[2978,4071,3407],{"class":2995},[2978,4073,4074,4076,4078,4080,4082,4084,4086,4088,4090,4092],{"class":2980,"line":3056},[2978,4075,3445],{"class":3002},[2978,4077,3396],{"class":2995},[2978,4079,3399],{"class":3002},[2978,4081,3006],{"class":2995},[2978,4083,3404],{"class":3024},[2978,4085,3456],{"class":2995},[2978,4087,3459],{"class":3002},[2978,4089,3006],{"class":2995},[2978,4091,3464],{"class":3024},[2978,4093,3407],{"class":2995},[2978,4095,4096,4098,4100,4102,4104,4106,4108,4110,4112,4114],{"class":2980,"line":3067},[2978,4097,3472],{"class":3002},[2978,4099,3396],{"class":2995},[2978,4101,3399],{"class":3002},[2978,4103,3006],{"class":2995},[2978,4105,3404],{"class":3024},[2978,4107,3456],{"class":2995},[2978,4109,3459],{"class":3002},[2978,4111,3006],{"class":2995},[2978,4113,3489],{"class":3024},[2978,4115,3492],{"class":2995},[2978,4117,4118],{"class":2980,"line":3442},[2978,4119,3498],{"class":2995},[2978,4121,4122],{"class":2980,"line":3469},[2978,4123,3070],{"class":2995},[4125,4126,4127,4130,4131,4134],"tip",{},[3074,4128,4129],{},"Більшість API знаходяться на Level 2."," Level 3 (HATEOAS) — це ",[3074,4132,4133],{},"ідеал REST",", але він вимагає більше зусиль і не завжди виправданий для простих API.",[3329,4136,4138],{"id":4137},"hateoas-переваги-та-недоліки","HATEOAS: Переваги та недоліки",[2964,4140,4141],{},[3074,4142,4143],{},"Переваги:",[2964,4145,4146,4147,4150,4151,4154,4155,4158,4159,4154,4161,4164,4165,4154,4167,4170,4171,4154,4173,4176],{},"✅ ",[3074,4148,4149],{},"Decoupling"," — клієнт не хардкодить URL-и",[4152,4153],"br",{},"\n✅ ",[3074,4156,4157],{},"Evolvability"," — можна змінювати URL-структуру без ламання клієнтів",[4152,4160],{},[3074,4162,4163],{},"Discoverability"," — API самодокументується",[4152,4166],{},[3074,4168,4169],{},"Dynamic behavior"," — сервер контролює, які дії доступні",[4152,4172],{},[3074,4174,4175],{},"Versioning"," — легше підтримувати кілька версій API",[2964,4178,4179],{},[3074,4180,4181],{},"Недоліки:",[2964,4183,4184,4185,4188,4189,4191,4192,4195,4196,4191,4198,4201,4202,4191,4204,4207],{},"❌ ",[3074,4186,4187],{},"Складність"," — більше коду на сервері та клієнті",[4152,4190],{},"\n❌ ",[3074,4193,4194],{},"Розмір відповіді"," — links збільшують payload",[4152,4197],{},[3074,4199,4200],{},"Підтримка клієнтів"," — не всі клієнти вміють працювати з HATEOAS",[4152,4203],{},[3074,4205,4206],{},"Overkill"," — для простих CRUD API може бути надмірним",[3329,4209,4211],{"id":4210},"hal-hypertext-application-language","HAL (Hypertext Application Language)",[2964,4213,4214,4217],{},[3074,4215,4216],{},"HAL"," — стандартний формат для HATEOAS API:",[2968,4219,4221],{"className":2986,"code":4220,"language":2988,"meta":2973,"style":2973},"{\n  \"_links\": {\n    \"self\": { \"href\": \"/api/articles/5\" },\n    \"author\": { \"href\": \"/api/authors/42\", \"title\": \"John Doe\" }\n  },\n  \"_embedded\": {\n    \"comments\": [\n      {\n        \"id\": 1,\n        \"text\": \"Great!\",\n        \"_links\": { \"self\": { \"href\": \"/api/comments/1\" } }\n      }\n    ]\n  },\n  \"id\": 5,\n  \"title\": \"Article Title\"\n}\n",[2975,4222,4223,4227,4233,4247,4269,4273,4279,4285,4290,4301,4313,4333,4338,4342,4346,4356,4365],{"__ignoreMap":2973},[2978,4224,4225],{"class":2980,"line":2981},[2978,4226,2996],{"class":2995},[2978,4228,4229,4231],{"class":2980,"line":2999},[2978,4230,3385],{"class":3002},[2978,4232,3388],{"class":2995},[2978,4234,4235,4237,4239,4241,4243,4245],{"class":2980,"line":3016},[2978,4236,3393],{"class":3002},[2978,4238,3396],{"class":2995},[2978,4240,3399],{"class":3002},[2978,4242,3006],{"class":2995},[2978,4244,3404],{"class":3024},[2978,4246,3407],{"class":2995},[2978,4248,4249,4251,4253,4255,4257,4259,4261,4263,4265,4267],{"class":2980,"line":3030},[2978,4250,3412],{"class":3002},[2978,4252,3396],{"class":2995},[2978,4254,3399],{"class":3002},[2978,4256,3006],{"class":2995},[2978,4258,3421],{"class":3024},[2978,4260,3456],{"class":2995},[2978,4262,3778],{"class":3002},[2978,4264,3006],{"class":2995},[2978,4266,3580],{"class":3024},[2978,4268,3492],{"class":2995},[2978,4270,4271],{"class":2980,"line":3043},[2978,4272,3683],{"class":2995},[2978,4274,4275,4277],{"class":2980,"line":3056},[2978,4276,3551],{"class":3002},[2978,4278,3388],{"class":2995},[2978,4280,4281,4283],{"class":2980,"line":3067},[2978,4282,3428],{"class":3002},[2978,4284,3604],{"class":2995},[2978,4286,4287],{"class":2980,"line":3442},[2978,4288,4289],{"class":2995},"      {\n",[2978,4291,4292,4295,4297,4299],{"class":2980,"line":3469},[2978,4293,4294],{"class":3002},"        \"id\"",[2978,4296,3006],{"class":2995},[2978,4298,3617],{"class":3009},[2978,4300,3013],{"class":2995},[2978,4302,4303,4306,4308,4311],{"class":2980,"line":3495},[2978,4304,4305],{"class":3002},"        \"text\"",[2978,4307,3006],{"class":2995},[2978,4309,4310],{"class":3024},"\"Great!\"",[2978,4312,3013],{"class":2995},[2978,4314,4315,4318,4320,4322,4324,4326,4328,4331],{"class":2980,"line":3501},[2978,4316,4317],{"class":3002},"        \"_links\"",[2978,4319,3396],{"class":2995},[2978,4321,3738],{"class":3002},[2978,4323,3396],{"class":2995},[2978,4325,3399],{"class":3002},[2978,4327,3006],{"class":2995},[2978,4329,4330],{"class":3024},"\"/api/comments/1\"",[2978,4332,3824],{"class":2995},[2978,4334,4335],{"class":2980,"line":3642},[2978,4336,4337],{"class":2995},"      }\n",[2978,4339,4340],{"class":2980,"line":3674},[2978,4341,3677],{"class":2995},[2978,4343,4344],{"class":2980,"line":3680},[2978,4345,3683],{"class":2995},[2978,4347,4348,4350,4352,4354],{"class":2980,"line":3686},[2978,4349,3003],{"class":3002},[2978,4351,3006],{"class":2995},[2978,4353,3010],{"class":3009},[2978,4355,3013],{"class":2995},[2978,4357,4358,4360,4362],{"class":2980,"line":3699},[2978,4359,3019],{"class":3002},[2978,4361,3006],{"class":2995},[2978,4363,4364],{"class":3024},"\"Article Title\"\n",[2978,4366,4368],{"class":2980,"line":4367},17,[2978,4369,3070],{"class":2995},[2964,4371,4372],{},[3074,4373,4374],{},"Ключові елементи:",[3089,4376,4377,4385,4393,4401,4409],{},[3092,4378,4379,4384],{},[3074,4380,4381],{},[2975,4382,4383],{},"_links"," — навігаційні посилання",[3092,4386,4387,4392],{},[3074,4388,4389],{},[2975,4390,4391],{},"_embedded"," — вбудовані ресурси (для зменшення кількості запитів)",[3092,4394,4395,4400],{},[3074,4396,4397],{},[2975,4398,4399],{},"self"," — обов'язкове посилання на сам ресурс",[3092,4402,4403,4408],{},[3074,4404,4405],{},[2975,4406,4407],{},"href"," — URL ресурсу",[3092,4410,4411,4416],{},[3074,4412,4413],{},[2975,4414,4415],{},"title"," — опис посилання (опціонально)",[3882,4418],{},[2959,4420,4422],{"id":4421},"практична-реалізація-blog-api-з-hateoas","Практична реалізація: Blog API з HATEOAS",[3329,4424,4426],{"id":4425},"крок-1-налаштування-проєкту","Крок 1: Налаштування проєкту",[4428,4429,4430,4434,4493,4497,4503,5281,5286],"steps",{},[3329,4431,4433],{"id":4432},"створення-проєкту","Створення проєкту",[4435,4436,4438,4453,4461,4464,4474,4484],"terminal-preview",{"title":4437},"bash",[4439,4440,4442,4447,4448],"div",{"className":4441},[2980],[2978,4443,4446],{"className":4444},[4445],"opacity-40","$"," ",[3074,4449,4452],{"className":4450},[4451],"font-bold","dotnet new webapi -n BlogHateoasApi",[4439,4454,4456],{"className":4455},[2980],[2978,4457,4460],{"className":4458},[4459,4451],"text-green-400","The template \"ASP.NET Core Web API\" was created successfully.",[4439,4462],{"className":4463},[2980],[4439,4465,4467,4447,4470],{"className":4466},[2980],[2978,4468,4446],{"className":4469},[4445],[3074,4471,4473],{"className":4472},[4451],"cd BlogHateoasApi",[4439,4475,4477,4447,4480],{"className":4476},[2980],[2978,4478,4446],{"className":4479},[4445],[3074,4481,4483],{"className":4482},[4451],"dotnet add package Microsoft.EntityFrameworkCore.InMemory",[4439,4485,4487,4492],{"className":4486},[2980],[2978,4488,4491],{"className":4489},[4490],"text-blue-400","info"," : PackageReference added successfully",[3329,4494,4496],{"id":4495},"створення-моделей","Створення моделей",[2964,4498,4499,4500,3087],{},"Створіть файл ",[2975,4501,4502],{},"Models/Article.cs",[2968,4504,4508],{"className":4505,"code":4506,"language":4507,"meta":2973,"style":2973},"language-csharp shiki shiki-themes light-plus dark-plus dark-plus","namespace BlogHateoasApi.Models;\n\npublic class Article\n{\n    public int Id { get; set; }\n    public required string Title { get; set; }\n    public required string Content { get; set; }\n    public int AuthorId { get; set; }\n    public Author? Author { get; set; }\n    public int CategoryId { get; set; }\n    public Category? Category { get; set; }\n    public List\u003CComment> Comments { get; set; } = new();\n    public DateTime PublishedAt { get; set; } = DateTime.UtcNow;\n    public DateTime? UpdatedAt { get; set; }\n    public ArticleStatus Status { get; set; } = ArticleStatus.Draft;\n}\n\npublic enum ArticleStatus\n{\n    Draft,\n    Published,\n    Archived\n}\n\npublic class Author\n{\n    public int Id { get; set; }\n    public required string Name { get; set; }\n    public required string Email { get; set; }\n    public string? Bio { get; set; }\n    public List\u003CArticle> Articles { get; set; } = new();\n}\n\npublic class Category\n{\n    public int Id { get; set; }\n    public required string Name { get; set; }\n    public string? Description { get; set; }\n    public List\u003CArticle> Articles { get; set; } = new();\n}\n\npublic class Comment\n{\n    public int Id { get; set; }\n    public required string Text { get; set; }\n    public required string AuthorName { get; set; }\n    public int ArticleId { get; set; }\n    public Article? Article { get; set; }\n    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;\n}\n","csharp",[2975,4509,4510,4527,4531,4542,4546,4572,4595,4616,4635,4657,4676,4698,4734,4764,4785,4815,4819,4823,4834,4839,4847,4855,4861,4866,4871,4881,4886,4905,4927,4949,4971,5002,5007,5012,5022,5027,5046,5067,5089,5118,5123,5128,5138,5143,5162,5184,5206,5226,5248,5276],{"__ignoreMap":2973},[2978,4511,4512,4515,4519,4521,4524],{"class":2980,"line":2981},[2978,4513,4514],{"class":3180},"namespace",[2978,4516,4518],{"class":4517},"sN1BT"," BlogHateoasApi",[2978,4520,3223],{"class":2995},[2978,4522,4523],{"class":4517},"Models",[2978,4525,4526],{"class":2995},";\n",[2978,4528,4529],{"class":2980,"line":2999},[2978,4530,3288],{"emptyLinePlaceholder":3287},[2978,4532,4533,4536,4539],{"class":2980,"line":3016},[2978,4534,4535],{"class":3180},"public",[2978,4537,4538],{"class":3180}," class",[2978,4540,4541],{"class":4517}," Article\n",[2978,4543,4544],{"class":2980,"line":3030},[2978,4545,2996],{"class":2995},[2978,4547,4548,4551,4554,4557,4560,4563,4566,4569],{"class":2980,"line":3043},[2978,4549,4550],{"class":3180},"    public",[2978,4552,4553],{"class":3180}," int",[2978,4555,4556],{"class":3213}," Id",[2978,4558,4559],{"class":2995}," { ",[2978,4561,4562],{"class":3180},"get",[2978,4564,4565],{"class":2995},"; ",[2978,4567,4568],{"class":3180},"set",[2978,4570,4571],{"class":2995},"; }\n",[2978,4573,4574,4576,4579,4582,4585,4587,4589,4591,4593],{"class":2980,"line":3056},[2978,4575,4550],{"class":3180},[2978,4577,4578],{"class":3180}," required",[2978,4580,4581],{"class":3180}," string",[2978,4583,4584],{"class":3213}," Title",[2978,4586,4559],{"class":2995},[2978,4588,4562],{"class":3180},[2978,4590,4565],{"class":2995},[2978,4592,4568],{"class":3180},[2978,4594,4571],{"class":2995},[2978,4596,4597,4599,4601,4603,4606,4608,4610,4612,4614],{"class":2980,"line":3067},[2978,4598,4550],{"class":3180},[2978,4600,4578],{"class":3180},[2978,4602,4581],{"class":3180},[2978,4604,4605],{"class":3213}," Content",[2978,4607,4559],{"class":2995},[2978,4609,4562],{"class":3180},[2978,4611,4565],{"class":2995},[2978,4613,4568],{"class":3180},[2978,4615,4571],{"class":2995},[2978,4617,4618,4620,4622,4625,4627,4629,4631,4633],{"class":2980,"line":3442},[2978,4619,4550],{"class":3180},[2978,4621,4553],{"class":3180},[2978,4623,4624],{"class":3213}," AuthorId",[2978,4626,4559],{"class":2995},[2978,4628,4562],{"class":3180},[2978,4630,4565],{"class":2995},[2978,4632,4568],{"class":3180},[2978,4634,4571],{"class":2995},[2978,4636,4637,4639,4642,4644,4647,4649,4651,4653,4655],{"class":2980,"line":3469},[2978,4638,4550],{"class":3180},[2978,4640,4641],{"class":4517}," Author",[2978,4643,3101],{"class":2995},[2978,4645,4646],{"class":3213},"Author",[2978,4648,4559],{"class":2995},[2978,4650,4562],{"class":3180},[2978,4652,4565],{"class":2995},[2978,4654,4568],{"class":3180},[2978,4656,4571],{"class":2995},[2978,4658,4659,4661,4663,4666,4668,4670,4672,4674],{"class":2980,"line":3495},[2978,4660,4550],{"class":3180},[2978,4662,4553],{"class":3180},[2978,4664,4665],{"class":3213}," CategoryId",[2978,4667,4559],{"class":2995},[2978,4669,4562],{"class":3180},[2978,4671,4565],{"class":2995},[2978,4673,4568],{"class":3180},[2978,4675,4571],{"class":2995},[2978,4677,4678,4680,4683,4685,4688,4690,4692,4694,4696],{"class":2980,"line":3501},[2978,4679,4550],{"class":3180},[2978,4681,4682],{"class":4517}," Category",[2978,4684,3101],{"class":2995},[2978,4686,4687],{"class":3213},"Category",[2978,4689,4559],{"class":2995},[2978,4691,4562],{"class":3180},[2978,4693,4565],{"class":2995},[2978,4695,4568],{"class":3180},[2978,4697,4571],{"class":2995},[2978,4699,4700,4702,4705,4708,4711,4714,4717,4719,4721,4723,4725,4728,4731],{"class":2980,"line":3642},[2978,4701,4550],{"class":3180},[2978,4703,4704],{"class":4517}," List",[2978,4706,4707],{"class":2995},"\u003C",[2978,4709,4710],{"class":4517},"Comment",[2978,4712,4713],{"class":2995},"> ",[2978,4715,4716],{"class":3213},"Comments",[2978,4718,4559],{"class":2995},[2978,4720,4562],{"class":3180},[2978,4722,4565],{"class":2995},[2978,4724,4568],{"class":3180},[2978,4726,4727],{"class":2995},"; } = ",[2978,4729,4730],{"class":3180},"new",[2978,4732,4733],{"class":2995},"();\n",[2978,4735,4736,4738,4741,4744,4746,4748,4750,4752,4754,4757,4759,4762],{"class":2980,"line":3674},[2978,4737,4550],{"class":3180},[2978,4739,4740],{"class":4517}," DateTime",[2978,4742,4743],{"class":3213}," PublishedAt",[2978,4745,4559],{"class":2995},[2978,4747,4562],{"class":3180},[2978,4749,4565],{"class":2995},[2978,4751,4568],{"class":3180},[2978,4753,4727],{"class":2995},[2978,4755,4756],{"class":3213},"DateTime",[2978,4758,3223],{"class":2995},[2978,4760,4761],{"class":3213},"UtcNow",[2978,4763,4526],{"class":2995},[2978,4765,4766,4768,4770,4772,4775,4777,4779,4781,4783],{"class":2980,"line":3680},[2978,4767,4550],{"class":3180},[2978,4769,4740],{"class":4517},[2978,4771,3101],{"class":2995},[2978,4773,4774],{"class":3213},"UpdatedAt",[2978,4776,4559],{"class":2995},[2978,4778,4562],{"class":3180},[2978,4780,4565],{"class":2995},[2978,4782,4568],{"class":3180},[2978,4784,4571],{"class":2995},[2978,4786,4787,4789,4792,4795,4797,4799,4801,4803,4805,4808,4810,4813],{"class":2980,"line":3686},[2978,4788,4550],{"class":3180},[2978,4790,4791],{"class":4517}," ArticleStatus",[2978,4793,4794],{"class":3213}," Status",[2978,4796,4559],{"class":2995},[2978,4798,4562],{"class":3180},[2978,4800,4565],{"class":2995},[2978,4802,4568],{"class":3180},[2978,4804,4727],{"class":2995},[2978,4806,4807],{"class":3213},"ArticleStatus",[2978,4809,3223],{"class":2995},[2978,4811,4812],{"class":3213},"Draft",[2978,4814,4526],{"class":2995},[2978,4816,4817],{"class":2980,"line":3699},[2978,4818,3070],{"class":2995},[2978,4820,4821],{"class":2980,"line":4367},[2978,4822,3288],{"emptyLinePlaceholder":3287},[2978,4824,4826,4828,4831],{"class":2980,"line":4825},18,[2978,4827,4535],{"class":3180},[2978,4829,4830],{"class":3180}," enum",[2978,4832,4833],{"class":4517}," ArticleStatus\n",[2978,4835,4837],{"class":2980,"line":4836},19,[2978,4838,2996],{"class":2995},[2978,4840,4842,4845],{"class":2980,"line":4841},20,[2978,4843,4844],{"class":3213},"    Draft",[2978,4846,3013],{"class":2995},[2978,4848,4850,4853],{"class":2980,"line":4849},21,[2978,4851,4852],{"class":3213},"    Published",[2978,4854,3013],{"class":2995},[2978,4856,4858],{"class":2980,"line":4857},22,[2978,4859,4860],{"class":3213},"    Archived\n",[2978,4862,4864],{"class":2980,"line":4863},23,[2978,4865,3070],{"class":2995},[2978,4867,4869],{"class":2980,"line":4868},24,[2978,4870,3288],{"emptyLinePlaceholder":3287},[2978,4872,4874,4876,4878],{"class":2980,"line":4873},25,[2978,4875,4535],{"class":3180},[2978,4877,4538],{"class":3180},[2978,4879,4880],{"class":4517}," Author\n",[2978,4882,4884],{"class":2980,"line":4883},26,[2978,4885,2996],{"class":2995},[2978,4887,4889,4891,4893,4895,4897,4899,4901,4903],{"class":2980,"line":4888},27,[2978,4890,4550],{"class":3180},[2978,4892,4553],{"class":3180},[2978,4894,4556],{"class":3213},[2978,4896,4559],{"class":2995},[2978,4898,4562],{"class":3180},[2978,4900,4565],{"class":2995},[2978,4902,4568],{"class":3180},[2978,4904,4571],{"class":2995},[2978,4906,4908,4910,4912,4914,4917,4919,4921,4923,4925],{"class":2980,"line":4907},28,[2978,4909,4550],{"class":3180},[2978,4911,4578],{"class":3180},[2978,4913,4581],{"class":3180},[2978,4915,4916],{"class":3213}," Name",[2978,4918,4559],{"class":2995},[2978,4920,4562],{"class":3180},[2978,4922,4565],{"class":2995},[2978,4924,4568],{"class":3180},[2978,4926,4571],{"class":2995},[2978,4928,4930,4932,4934,4936,4939,4941,4943,4945,4947],{"class":2980,"line":4929},29,[2978,4931,4550],{"class":3180},[2978,4933,4578],{"class":3180},[2978,4935,4581],{"class":3180},[2978,4937,4938],{"class":3213}," Email",[2978,4940,4559],{"class":2995},[2978,4942,4562],{"class":3180},[2978,4944,4565],{"class":2995},[2978,4946,4568],{"class":3180},[2978,4948,4571],{"class":2995},[2978,4950,4952,4954,4956,4958,4961,4963,4965,4967,4969],{"class":2980,"line":4951},30,[2978,4953,4550],{"class":3180},[2978,4955,4581],{"class":3180},[2978,4957,3101],{"class":2995},[2978,4959,4960],{"class":3213},"Bio",[2978,4962,4559],{"class":2995},[2978,4964,4562],{"class":3180},[2978,4966,4565],{"class":2995},[2978,4968,4568],{"class":3180},[2978,4970,4571],{"class":2995},[2978,4972,4974,4976,4978,4980,4983,4985,4988,4990,4992,4994,4996,4998,5000],{"class":2980,"line":4973},31,[2978,4975,4550],{"class":3180},[2978,4977,4704],{"class":4517},[2978,4979,4707],{"class":2995},[2978,4981,4982],{"class":4517},"Article",[2978,4984,4713],{"class":2995},[2978,4986,4987],{"class":3213},"Articles",[2978,4989,4559],{"class":2995},[2978,4991,4562],{"class":3180},[2978,4993,4565],{"class":2995},[2978,4995,4568],{"class":3180},[2978,4997,4727],{"class":2995},[2978,4999,4730],{"class":3180},[2978,5001,4733],{"class":2995},[2978,5003,5005],{"class":2980,"line":5004},32,[2978,5006,3070],{"class":2995},[2978,5008,5010],{"class":2980,"line":5009},33,[2978,5011,3288],{"emptyLinePlaceholder":3287},[2978,5013,5015,5017,5019],{"class":2980,"line":5014},34,[2978,5016,4535],{"class":3180},[2978,5018,4538],{"class":3180},[2978,5020,5021],{"class":4517}," Category\n",[2978,5023,5025],{"class":2980,"line":5024},35,[2978,5026,2996],{"class":2995},[2978,5028,5030,5032,5034,5036,5038,5040,5042,5044],{"class":2980,"line":5029},36,[2978,5031,4550],{"class":3180},[2978,5033,4553],{"class":3180},[2978,5035,4556],{"class":3213},[2978,5037,4559],{"class":2995},[2978,5039,4562],{"class":3180},[2978,5041,4565],{"class":2995},[2978,5043,4568],{"class":3180},[2978,5045,4571],{"class":2995},[2978,5047,5049,5051,5053,5055,5057,5059,5061,5063,5065],{"class":2980,"line":5048},37,[2978,5050,4550],{"class":3180},[2978,5052,4578],{"class":3180},[2978,5054,4581],{"class":3180},[2978,5056,4916],{"class":3213},[2978,5058,4559],{"class":2995},[2978,5060,4562],{"class":3180},[2978,5062,4565],{"class":2995},[2978,5064,4568],{"class":3180},[2978,5066,4571],{"class":2995},[2978,5068,5070,5072,5074,5076,5079,5081,5083,5085,5087],{"class":2980,"line":5069},38,[2978,5071,4550],{"class":3180},[2978,5073,4581],{"class":3180},[2978,5075,3101],{"class":2995},[2978,5077,5078],{"class":3213},"Description",[2978,5080,4559],{"class":2995},[2978,5082,4562],{"class":3180},[2978,5084,4565],{"class":2995},[2978,5086,4568],{"class":3180},[2978,5088,4571],{"class":2995},[2978,5090,5092,5094,5096,5098,5100,5102,5104,5106,5108,5110,5112,5114,5116],{"class":2980,"line":5091},39,[2978,5093,4550],{"class":3180},[2978,5095,4704],{"class":4517},[2978,5097,4707],{"class":2995},[2978,5099,4982],{"class":4517},[2978,5101,4713],{"class":2995},[2978,5103,4987],{"class":3213},[2978,5105,4559],{"class":2995},[2978,5107,4562],{"class":3180},[2978,5109,4565],{"class":2995},[2978,5111,4568],{"class":3180},[2978,5113,4727],{"class":2995},[2978,5115,4730],{"class":3180},[2978,5117,4733],{"class":2995},[2978,5119,5121],{"class":2980,"line":5120},40,[2978,5122,3070],{"class":2995},[2978,5124,5126],{"class":2980,"line":5125},41,[2978,5127,3288],{"emptyLinePlaceholder":3287},[2978,5129,5131,5133,5135],{"class":2980,"line":5130},42,[2978,5132,4535],{"class":3180},[2978,5134,4538],{"class":3180},[2978,5136,5137],{"class":4517}," Comment\n",[2978,5139,5141],{"class":2980,"line":5140},43,[2978,5142,2996],{"class":2995},[2978,5144,5146,5148,5150,5152,5154,5156,5158,5160],{"class":2980,"line":5145},44,[2978,5147,4550],{"class":3180},[2978,5149,4553],{"class":3180},[2978,5151,4556],{"class":3213},[2978,5153,4559],{"class":2995},[2978,5155,4562],{"class":3180},[2978,5157,4565],{"class":2995},[2978,5159,4568],{"class":3180},[2978,5161,4571],{"class":2995},[2978,5163,5165,5167,5169,5171,5174,5176,5178,5180,5182],{"class":2980,"line":5164},45,[2978,5166,4550],{"class":3180},[2978,5168,4578],{"class":3180},[2978,5170,4581],{"class":3180},[2978,5172,5173],{"class":3213}," Text",[2978,5175,4559],{"class":2995},[2978,5177,4562],{"class":3180},[2978,5179,4565],{"class":2995},[2978,5181,4568],{"class":3180},[2978,5183,4571],{"class":2995},[2978,5185,5187,5189,5191,5193,5196,5198,5200,5202,5204],{"class":2980,"line":5186},46,[2978,5188,4550],{"class":3180},[2978,5190,4578],{"class":3180},[2978,5192,4581],{"class":3180},[2978,5194,5195],{"class":3213}," AuthorName",[2978,5197,4559],{"class":2995},[2978,5199,4562],{"class":3180},[2978,5201,4565],{"class":2995},[2978,5203,4568],{"class":3180},[2978,5205,4571],{"class":2995},[2978,5207,5209,5211,5213,5216,5218,5220,5222,5224],{"class":2980,"line":5208},47,[2978,5210,4550],{"class":3180},[2978,5212,4553],{"class":3180},[2978,5214,5215],{"class":3213}," ArticleId",[2978,5217,4559],{"class":2995},[2978,5219,4562],{"class":3180},[2978,5221,4565],{"class":2995},[2978,5223,4568],{"class":3180},[2978,5225,4571],{"class":2995},[2978,5227,5229,5231,5234,5236,5238,5240,5242,5244,5246],{"class":2980,"line":5228},48,[2978,5230,4550],{"class":3180},[2978,5232,5233],{"class":4517}," Article",[2978,5235,3101],{"class":2995},[2978,5237,4982],{"class":3213},[2978,5239,4559],{"class":2995},[2978,5241,4562],{"class":3180},[2978,5243,4565],{"class":2995},[2978,5245,4568],{"class":3180},[2978,5247,4571],{"class":2995},[2978,5249,5251,5253,5255,5258,5260,5262,5264,5266,5268,5270,5272,5274],{"class":2980,"line":5250},49,[2978,5252,4550],{"class":3180},[2978,5254,4740],{"class":4517},[2978,5256,5257],{"class":3213}," CreatedAt",[2978,5259,4559],{"class":2995},[2978,5261,4562],{"class":3180},[2978,5263,4565],{"class":2995},[2978,5265,4568],{"class":3180},[2978,5267,4727],{"class":2995},[2978,5269,4756],{"class":3213},[2978,5271,3223],{"class":2995},[2978,5273,4761],{"class":3213},[2978,5275,4526],{"class":2995},[2978,5277,5279],{"class":2980,"line":5278},50,[2978,5280,3070],{"class":2995},[2964,5282,5283],{},[3074,5284,5285],{},"Декомпозиція:",[3089,5287,5288,5295,5304,5311],{},[3092,5289,5290,5294],{},[3074,5291,5292],{},[2975,5293,4982],{}," — основна сутність з навігаційними властивостями",[3092,5296,5297,5303],{},[3074,5298,5299,3456,5301],{},[2975,5300,4646],{},[2975,5302,4687],{}," — пов'язані ресурси для expansion",[3092,5305,5306,5310],{},[3074,5307,5308],{},[2975,5309,4710],{}," — вкладений ресурс (один-до-багатьох)",[3092,5312,5313,5317],{},[3074,5314,5315],{},[2975,5316,4807],{}," — для демонстрації conditional links (draft можна редагувати, archived — ні)",[3882,5319],{},[3329,5321,5323],{"id":5322},"крок-2-hateoas-infrastructure","Крок 2: HATEOAS Infrastructure",[5325,5326,5328],"h4",{"id":5327},"_1-link-dto","1. Link DTO",[2964,5330,4499,5331,3087],{},[2975,5332,5333],{},"Models/Link.cs",[2968,5335,5337],{"className":4505,"code":5336,"language":4507,"meta":2973,"style":2973},"namespace BlogHateoasApi.Models;\n\npublic class Link\n{\n    public required string Href { get; set; }\n    public string? Rel { get; set; }\n    public string? Method { get; set; } = \"GET\";\n    public string? Title { get; set; }\n}\n\npublic class ResourceWithLinks\n{\n    public Dictionary\u003Cstring, Link> Links { get; set; } = new();\n}\n",[2975,5338,5339,5351,5355,5364,5368,5389,5410,5436,5457,5461,5465,5474,5478,5514],{"__ignoreMap":2973},[2978,5340,5341,5343,5345,5347,5349],{"class":2980,"line":2981},[2978,5342,4514],{"class":3180},[2978,5344,4518],{"class":4517},[2978,5346,3223],{"class":2995},[2978,5348,4523],{"class":4517},[2978,5350,4526],{"class":2995},[2978,5352,5353],{"class":2980,"line":2999},[2978,5354,3288],{"emptyLinePlaceholder":3287},[2978,5356,5357,5359,5361],{"class":2980,"line":3016},[2978,5358,4535],{"class":3180},[2978,5360,4538],{"class":3180},[2978,5362,5363],{"class":4517}," Link\n",[2978,5365,5366],{"class":2980,"line":3030},[2978,5367,2996],{"class":2995},[2978,5369,5370,5372,5374,5376,5379,5381,5383,5385,5387],{"class":2980,"line":3043},[2978,5371,4550],{"class":3180},[2978,5373,4578],{"class":3180},[2978,5375,4581],{"class":3180},[2978,5377,5378],{"class":3213}," Href",[2978,5380,4559],{"class":2995},[2978,5382,4562],{"class":3180},[2978,5384,4565],{"class":2995},[2978,5386,4568],{"class":3180},[2978,5388,4571],{"class":2995},[2978,5390,5391,5393,5395,5397,5400,5402,5404,5406,5408],{"class":2980,"line":3056},[2978,5392,4550],{"class":3180},[2978,5394,4581],{"class":3180},[2978,5396,3101],{"class":2995},[2978,5398,5399],{"class":3213},"Rel",[2978,5401,4559],{"class":2995},[2978,5403,4562],{"class":3180},[2978,5405,4565],{"class":2995},[2978,5407,4568],{"class":3180},[2978,5409,4571],{"class":2995},[2978,5411,5412,5414,5416,5418,5421,5423,5425,5427,5429,5431,5434],{"class":2980,"line":3067},[2978,5413,4550],{"class":3180},[2978,5415,4581],{"class":3180},[2978,5417,3101],{"class":2995},[2978,5419,5420],{"class":3213},"Method",[2978,5422,4559],{"class":2995},[2978,5424,4562],{"class":3180},[2978,5426,4565],{"class":2995},[2978,5428,4568],{"class":3180},[2978,5430,4727],{"class":2995},[2978,5432,5433],{"class":3024},"\"GET\"",[2978,5435,4526],{"class":2995},[2978,5437,5438,5440,5442,5444,5447,5449,5451,5453,5455],{"class":2980,"line":3442},[2978,5439,4550],{"class":3180},[2978,5441,4581],{"class":3180},[2978,5443,3101],{"class":2995},[2978,5445,5446],{"class":3213},"Title",[2978,5448,4559],{"class":2995},[2978,5450,4562],{"class":3180},[2978,5452,4565],{"class":2995},[2978,5454,4568],{"class":3180},[2978,5456,4571],{"class":2995},[2978,5458,5459],{"class":2980,"line":3469},[2978,5460,3070],{"class":2995},[2978,5462,5463],{"class":2980,"line":3495},[2978,5464,3288],{"emptyLinePlaceholder":3287},[2978,5466,5467,5469,5471],{"class":2980,"line":3501},[2978,5468,4535],{"class":3180},[2978,5470,4538],{"class":3180},[2978,5472,5473],{"class":4517}," ResourceWithLinks\n",[2978,5475,5476],{"class":2980,"line":3642},[2978,5477,2996],{"class":2995},[2978,5479,5480,5482,5485,5487,5490,5492,5495,5497,5500,5502,5504,5506,5508,5510,5512],{"class":2980,"line":3674},[2978,5481,4550],{"class":3180},[2978,5483,5484],{"class":4517}," Dictionary",[2978,5486,4707],{"class":2995},[2978,5488,5489],{"class":3180},"string",[2978,5491,3456],{"class":2995},[2978,5493,5494],{"class":4517},"Link",[2978,5496,4713],{"class":2995},[2978,5498,5499],{"class":3213},"Links",[2978,5501,4559],{"class":2995},[2978,5503,4562],{"class":3180},[2978,5505,4565],{"class":2995},[2978,5507,4568],{"class":3180},[2978,5509,4727],{"class":2995},[2978,5511,4730],{"class":3180},[2978,5513,4733],{"class":2995},[2978,5515,5516],{"class":2980,"line":3680},[2978,5517,3070],{"class":2995},[2964,5519,5520],{},[3074,5521,5285],{},[3089,5523,5524,5531,5538,5545],{},[3092,5525,5526,4408],{},[3074,5527,5528],{},[2975,5529,5530],{},"Href",[3092,5532,5533,5537],{},[3074,5534,5535],{},[2975,5536,5399],{}," — тип зв'язку (self, author, edit, delete)",[3092,5539,5540,5544],{},[3074,5541,5542],{},[2975,5543,5420],{}," — HTTP метод (GET, POST, PUT, DELETE)",[3092,5546,5547,5551],{},[3074,5548,5549],{},[2975,5550,5446],{}," — опис посилання (для UI)",[5325,5553,5555],{"id":5554},"_2-linkgenerator-helper","2. LinkGenerator Helper",[2964,5557,4499,5558,3087],{},[2975,5559,5560],{},"Helpers/LinkGeneratorHelper.cs",[2968,5562,5564],{"className":4505,"code":5563,"language":4507,"meta":2973,"style":2973},"using BlogHateoasApi.Models;\nusing Microsoft.AspNetCore.Mvc;\n\nnamespace BlogHateoasApi.Helpers;\n\npublic static class LinkGeneratorHelper\n{\n    public static Dictionary\u003Cstring, Link> GenerateArticleLinks(\n        int articleId,\n        ArticleStatus status,\n        IUrlHelper urlHelper,\n        bool isOwner = false)\n    {\n        var links = new Dictionary\u003Cstring, Link>\n        {\n            [\"self\"] = new Link\n            {\n                Href = urlHelper.Action(\"GetById\", \"Articles\", new { id = articleId })!,\n                Rel = \"self\",\n                Method = \"GET\",\n                Title = \"Get article details\"\n            },\n            [\"author\"] = new Link\n            {\n                Href = urlHelper.Action(\"GetById\", \"Authors\", new { id = \"{authorId}\" })!,\n                Rel = \"author\",\n                Method = \"GET\",\n                Title = \"Get article author\"\n            },\n            [\"comments\"] = new Link\n            {\n                Href = urlHelper.Action(\"GetComments\", \"Articles\", new { id = articleId })!,\n                Rel = \"comments\",\n                Method = \"GET\",\n                Title = \"Get article comments\"\n            },\n            [\"category\"] = new Link\n            {\n                Href = urlHelper.Action(\"GetById\", \"Categories\", new { id = \"{categoryId}\" })!,\n                Rel = \"category\",\n                Method = \"GET\",\n                Title = \"Get article category\"\n            }\n        };\n\n        // Conditional links based on status and ownership\n        if (status == ArticleStatus.Draft && isOwner)\n        {\n            links[\"publish\"] = new Link\n            {\n                Href = urlHelper.Action(\"Publish\", \"Articles\", new { id = articleId })!,\n                Rel = \"publish\",\n                Method = \"POST\",\n                Title = \"Publish article\"\n            };\n        }\n\n        if (status != ArticleStatus.Archived && isOwner)\n        {\n            links[\"edit\"] = new Link\n            {\n                Href = urlHelper.Action(\"Update\", \"Articles\", new { id = articleId })!,\n                Rel = \"edit\",\n                Method = \"PUT\",\n                Title = \"Update article\"\n            };\n\n            links[\"delete\"] = new Link\n            {\n                Href = urlHelper.Action(\"Delete\", \"Articles\", new { id = articleId })!,\n                Rel = \"delete\",\n                Method = \"DELETE\",\n                Title = \"Delete article\"\n            };\n        }\n\n        if (status == ArticleStatus.Published)\n        {\n            links[\"archive\"] = new Link\n            {\n                Href = urlHelper.Action(\"Archive\", \"Articles\", new { id = articleId })!,\n                Rel = \"archive\",\n                Method = \"POST\",\n                Title = \"Archive article\"\n            };\n        }\n\n        return links;\n    }\n\n    public static Dictionary\u003Cstring, Link> GenerateCollectionLinks(\n        IUrlHelper urlHelper,\n        string action,\n        string controller,\n        int page,\n        int totalPages)\n    {\n        var links = new Dictionary\u003Cstring, Link>\n        {\n            [\"self\"] = new Link\n            {\n                Href = urlHelper.Action(action, controller, new { page })!,\n                Rel = \"self\"\n            }\n        };\n\n        if (page > 1)\n        {\n            links[\"first\"] = new Link\n            {\n                Href = urlHelper.Action(action, controller, new { page = 1 })!,\n                Rel = \"first\"\n            };\n\n            links[\"prev\"] = new Link\n            {\n                Href = urlHelper.Action(action, controller, new { page = page - 1 })!,\n                Rel = \"prev\"\n            };\n        }\n\n        if (page \u003C totalPages)\n        {\n            links[\"next\"] = new Link\n            {\n                Href = urlHelper.Action(action, controller, new { page = page + 1 })!,\n                Rel = \"next\"\n            };\n\n            links[\"last\"] = new Link\n            {\n                Href = urlHelper.Action(action, controller, new { page = totalPages })!,\n                Rel = \"last\"\n            };\n        }\n\n        return links;\n    }\n}\n",[2975,5565,5566,5579,5598,5602,5615,5619,5631,5635,5659,5669,5679,5689,5705,5710,5735,5740,5754,5759,5801,5812,5823,5833,5838,5850,5854,5890,5900,5910,5919,5923,5936,5940,5975,5985,5995,6004,6008,6021,6025,6061,6071,6081,6090,6095,6100,6104,6109,6137,6141,6158,6162,6198,6209,6221,6231,6237,6243,6248,6273,6278,6294,6299,6335,6346,6357,6367,6372,6377,6393,6398,6434,6445,6456,6466,6471,6476,6481,6501,6506,6522,6527,6563,6574,6585,6595,6600,6605,6610,6620,6626,6631,6655,6664,6675,6685,6695,6705,6710,6733,6738,6751,6756,6790,6800,6805,6810,6815,6831,6836,6852,6857,6892,6902,6907,6912,6928,6933,6973,6983,6988,6993,6998,7015,7020,7036,7041,7081,7091,7096,7101,7117,7122,7157,7167,7172,7177,7182,7191,7196],{"__ignoreMap":2973},[2978,5567,5568,5571,5573,5575,5577],{"class":2980,"line":2981},[2978,5569,5570],{"class":3191},"using",[2978,5572,4518],{"class":4517},[2978,5574,3223],{"class":2995},[2978,5576,4523],{"class":4517},[2978,5578,4526],{"class":2995},[2978,5580,5581,5583,5586,5588,5591,5593,5596],{"class":2980,"line":2999},[2978,5582,5570],{"class":3191},[2978,5584,5585],{"class":4517}," Microsoft",[2978,5587,3223],{"class":2995},[2978,5589,5590],{"class":4517},"AspNetCore",[2978,5592,3223],{"class":2995},[2978,5594,5595],{"class":4517},"Mvc",[2978,5597,4526],{"class":2995},[2978,5599,5600],{"class":2980,"line":3016},[2978,5601,3288],{"emptyLinePlaceholder":3287},[2978,5603,5604,5606,5608,5610,5613],{"class":2980,"line":3030},[2978,5605,4514],{"class":3180},[2978,5607,4518],{"class":4517},[2978,5609,3223],{"class":2995},[2978,5611,5612],{"class":4517},"Helpers",[2978,5614,4526],{"class":2995},[2978,5616,5617],{"class":2980,"line":3043},[2978,5618,3288],{"emptyLinePlaceholder":3287},[2978,5620,5621,5623,5626,5628],{"class":2980,"line":3056},[2978,5622,4535],{"class":3180},[2978,5624,5625],{"class":3180}," static",[2978,5627,4538],{"class":3180},[2978,5629,5630],{"class":4517}," LinkGeneratorHelper\n",[2978,5632,5633],{"class":2980,"line":3067},[2978,5634,2996],{"class":2995},[2978,5636,5637,5639,5641,5643,5645,5647,5649,5651,5653,5656],{"class":2980,"line":3442},[2978,5638,4550],{"class":3180},[2978,5640,5625],{"class":3180},[2978,5642,5484],{"class":4517},[2978,5644,4707],{"class":2995},[2978,5646,5489],{"class":3180},[2978,5648,3456],{"class":2995},[2978,5650,5494],{"class":4517},[2978,5652,4713],{"class":2995},[2978,5654,5655],{"class":3195},"GenerateArticleLinks",[2978,5657,5658],{"class":2995},"(\n",[2978,5660,5661,5664,5667],{"class":2980,"line":3469},[2978,5662,5663],{"class":3180},"        int",[2978,5665,5666],{"class":3213}," articleId",[2978,5668,3013],{"class":2995},[2978,5670,5671,5674,5677],{"class":2980,"line":3495},[2978,5672,5673],{"class":4517},"        ArticleStatus",[2978,5675,5676],{"class":3213}," status",[2978,5678,3013],{"class":2995},[2978,5680,5681,5684,5687],{"class":2980,"line":3501},[2978,5682,5683],{"class":4517},"        IUrlHelper",[2978,5685,5686],{"class":3213}," urlHelper",[2978,5688,3013],{"class":2995},[2978,5690,5691,5694,5697,5699,5702],{"class":2980,"line":3642},[2978,5692,5693],{"class":3180},"        bool",[2978,5695,5696],{"class":3213}," isOwner",[2978,5698,3188],{"class":2995},[2978,5700,5701],{"class":3180},"false",[2978,5703,5704],{"class":2995},")\n",[2978,5706,5707],{"class":2980,"line":3674},[2978,5708,5709],{"class":2995},"    {\n",[2978,5711,5712,5715,5718,5720,5722,5724,5726,5728,5730,5732],{"class":2980,"line":3680},[2978,5713,5714],{"class":3180},"        var",[2978,5716,5717],{"class":3213}," links",[2978,5719,3188],{"class":2995},[2978,5721,4730],{"class":3180},[2978,5723,5484],{"class":4517},[2978,5725,4707],{"class":2995},[2978,5727,5489],{"class":3180},[2978,5729,3456],{"class":2995},[2978,5731,5494],{"class":4517},[2978,5733,5734],{"class":2995},">\n",[2978,5736,5737],{"class":2980,"line":3686},[2978,5738,5739],{"class":2995},"        {\n",[2978,5741,5742,5745,5747,5750,5752],{"class":2980,"line":3699},[2978,5743,5744],{"class":2995},"            [",[2978,5746,3738],{"class":3024},[2978,5748,5749],{"class":2995},"] = ",[2978,5751,4730],{"class":3180},[2978,5753,5363],{"class":4517},[2978,5755,5756],{"class":2980,"line":4367},[2978,5757,5758],{"class":2995},"            {\n",[2978,5760,5761,5764,5766,5769,5771,5774,5776,5779,5781,5784,5786,5788,5790,5793,5795,5798],{"class":2980,"line":4825},[2978,5762,5763],{"class":3213},"                Href",[2978,5765,3188],{"class":2995},[2978,5767,5768],{"class":3213},"urlHelper",[2978,5770,3223],{"class":2995},[2978,5772,5773],{"class":3195},"Action",[2978,5775,3199],{"class":2995},[2978,5777,5778],{"class":3024},"\"GetById\"",[2978,5780,3456],{"class":2995},[2978,5782,5783],{"class":3024},"\"Articles\"",[2978,5785,3456],{"class":2995},[2978,5787,4730],{"class":3180},[2978,5789,4559],{"class":2995},[2978,5791,5792],{"class":3213},"id",[2978,5794,3188],{"class":2995},[2978,5796,5797],{"class":3213},"articleId",[2978,5799,5800],{"class":2995}," })!,\n",[2978,5802,5803,5806,5808,5810],{"class":2980,"line":4836},[2978,5804,5805],{"class":3213},"                Rel",[2978,5807,3188],{"class":2995},[2978,5809,3738],{"class":3024},[2978,5811,3013],{"class":2995},[2978,5813,5814,5817,5819,5821],{"class":2980,"line":4841},[2978,5815,5816],{"class":3213},"                Method",[2978,5818,3188],{"class":2995},[2978,5820,5433],{"class":3024},[2978,5822,3013],{"class":2995},[2978,5824,5825,5828,5830],{"class":2980,"line":4849},[2978,5826,5827],{"class":3213},"                Title",[2978,5829,3188],{"class":2995},[2978,5831,5832],{"class":3024},"\"Get article details\"\n",[2978,5834,5835],{"class":2980,"line":4857},[2978,5836,5837],{"class":2995},"            },\n",[2978,5839,5840,5842,5844,5846,5848],{"class":2980,"line":4863},[2978,5841,5744],{"class":2995},[2978,5843,3632],{"class":3024},[2978,5845,5749],{"class":2995},[2978,5847,4730],{"class":3180},[2978,5849,5363],{"class":4517},[2978,5851,5852],{"class":2980,"line":4868},[2978,5853,5758],{"class":2995},[2978,5855,5856,5858,5860,5862,5864,5866,5868,5870,5872,5875,5877,5879,5881,5883,5885,5888],{"class":2980,"line":4873},[2978,5857,5763],{"class":3213},[2978,5859,3188],{"class":2995},[2978,5861,5768],{"class":3213},[2978,5863,3223],{"class":2995},[2978,5865,5773],{"class":3195},[2978,5867,3199],{"class":2995},[2978,5869,5778],{"class":3024},[2978,5871,3456],{"class":2995},[2978,5873,5874],{"class":3024},"\"Authors\"",[2978,5876,3456],{"class":2995},[2978,5878,4730],{"class":3180},[2978,5880,4559],{"class":2995},[2978,5882,5792],{"class":3213},[2978,5884,3188],{"class":2995},[2978,5886,5887],{"class":3024},"\"{authorId}\"",[2978,5889,5800],{"class":2995},[2978,5891,5892,5894,5896,5898],{"class":2980,"line":4883},[2978,5893,5805],{"class":3213},[2978,5895,3188],{"class":2995},[2978,5897,3632],{"class":3024},[2978,5899,3013],{"class":2995},[2978,5901,5902,5904,5906,5908],{"class":2980,"line":4888},[2978,5903,5816],{"class":3213},[2978,5905,3188],{"class":2995},[2978,5907,5433],{"class":3024},[2978,5909,3013],{"class":2995},[2978,5911,5912,5914,5916],{"class":2980,"line":4907},[2978,5913,5827],{"class":3213},[2978,5915,3188],{"class":2995},[2978,5917,5918],{"class":3024},"\"Get article author\"\n",[2978,5920,5921],{"class":2980,"line":4929},[2978,5922,5837],{"class":2995},[2978,5924,5925,5927,5930,5932,5934],{"class":2980,"line":4951},[2978,5926,5744],{"class":2995},[2978,5928,5929],{"class":3024},"\"comments\"",[2978,5931,5749],{"class":2995},[2978,5933,4730],{"class":3180},[2978,5935,5363],{"class":4517},[2978,5937,5938],{"class":2980,"line":4973},[2978,5939,5758],{"class":2995},[2978,5941,5942,5944,5946,5948,5950,5952,5954,5957,5959,5961,5963,5965,5967,5969,5971,5973],{"class":2980,"line":5004},[2978,5943,5763],{"class":3213},[2978,5945,3188],{"class":2995},[2978,5947,5768],{"class":3213},[2978,5949,3223],{"class":2995},[2978,5951,5773],{"class":3195},[2978,5953,3199],{"class":2995},[2978,5955,5956],{"class":3024},"\"GetComments\"",[2978,5958,3456],{"class":2995},[2978,5960,5783],{"class":3024},[2978,5962,3456],{"class":2995},[2978,5964,4730],{"class":3180},[2978,5966,4559],{"class":2995},[2978,5968,5792],{"class":3213},[2978,5970,3188],{"class":2995},[2978,5972,5797],{"class":3213},[2978,5974,5800],{"class":2995},[2978,5976,5977,5979,5981,5983],{"class":2980,"line":5009},[2978,5978,5805],{"class":3213},[2978,5980,3188],{"class":2995},[2978,5982,5929],{"class":3024},[2978,5984,3013],{"class":2995},[2978,5986,5987,5989,5991,5993],{"class":2980,"line":5014},[2978,5988,5816],{"class":3213},[2978,5990,3188],{"class":2995},[2978,5992,5433],{"class":3024},[2978,5994,3013],{"class":2995},[2978,5996,5997,5999,6001],{"class":2980,"line":5024},[2978,5998,5827],{"class":3213},[2978,6000,3188],{"class":2995},[2978,6002,6003],{"class":3024},"\"Get article comments\"\n",[2978,6005,6006],{"class":2980,"line":5029},[2978,6007,5837],{"class":2995},[2978,6009,6010,6012,6015,6017,6019],{"class":2980,"line":5048},[2978,6011,5744],{"class":2995},[2978,6013,6014],{"class":3024},"\"category\"",[2978,6016,5749],{"class":2995},[2978,6018,4730],{"class":3180},[2978,6020,5363],{"class":4517},[2978,6022,6023],{"class":2980,"line":5069},[2978,6024,5758],{"class":2995},[2978,6026,6027,6029,6031,6033,6035,6037,6039,6041,6043,6046,6048,6050,6052,6054,6056,6059],{"class":2980,"line":5091},[2978,6028,5763],{"class":3213},[2978,6030,3188],{"class":2995},[2978,6032,5768],{"class":3213},[2978,6034,3223],{"class":2995},[2978,6036,5773],{"class":3195},[2978,6038,3199],{"class":2995},[2978,6040,5778],{"class":3024},[2978,6042,3456],{"class":2995},[2978,6044,6045],{"class":3024},"\"Categories\"",[2978,6047,3456],{"class":2995},[2978,6049,4730],{"class":3180},[2978,6051,4559],{"class":2995},[2978,6053,5792],{"class":3213},[2978,6055,3188],{"class":2995},[2978,6057,6058],{"class":3024},"\"{categoryId}\"",[2978,6060,5800],{"class":2995},[2978,6062,6063,6065,6067,6069],{"class":2980,"line":5120},[2978,6064,5805],{"class":3213},[2978,6066,3188],{"class":2995},[2978,6068,6014],{"class":3024},[2978,6070,3013],{"class":2995},[2978,6072,6073,6075,6077,6079],{"class":2980,"line":5125},[2978,6074,5816],{"class":3213},[2978,6076,3188],{"class":2995},[2978,6078,5433],{"class":3024},[2978,6080,3013],{"class":2995},[2978,6082,6083,6085,6087],{"class":2980,"line":5130},[2978,6084,5827],{"class":3213},[2978,6086,3188],{"class":2995},[2978,6088,6089],{"class":3024},"\"Get article category\"\n",[2978,6091,6092],{"class":2980,"line":5140},[2978,6093,6094],{"class":2995},"            }\n",[2978,6096,6097],{"class":2980,"line":5145},[2978,6098,6099],{"class":2995},"        };\n",[2978,6101,6102],{"class":2980,"line":5164},[2978,6103,3288],{"emptyLinePlaceholder":3287},[2978,6105,6106],{"class":2980,"line":5186},[2978,6107,6108],{"class":3174},"        // Conditional links based on status and ownership\n",[2978,6110,6111,6114,6117,6120,6123,6125,6127,6129,6132,6135],{"class":2980,"line":5208},[2978,6112,6113],{"class":3191},"        if",[2978,6115,6116],{"class":2995}," (",[2978,6118,6119],{"class":3213},"status",[2978,6121,6122],{"class":2995}," == ",[2978,6124,4807],{"class":3213},[2978,6126,3223],{"class":2995},[2978,6128,4812],{"class":3213},[2978,6130,6131],{"class":2995}," && ",[2978,6133,6134],{"class":3213},"isOwner",[2978,6136,5704],{"class":2995},[2978,6138,6139],{"class":2980,"line":5228},[2978,6140,5739],{"class":2995},[2978,6142,6143,6146,6149,6152,6154,6156],{"class":2980,"line":5250},[2978,6144,6145],{"class":3213},"            links",[2978,6147,6148],{"class":2995},"[",[2978,6150,6151],{"class":3024},"\"publish\"",[2978,6153,5749],{"class":2995},[2978,6155,4730],{"class":3180},[2978,6157,5363],{"class":4517},[2978,6159,6160],{"class":2980,"line":5278},[2978,6161,5758],{"class":2995},[2978,6163,6165,6167,6169,6171,6173,6175,6177,6180,6182,6184,6186,6188,6190,6192,6194,6196],{"class":2980,"line":6164},51,[2978,6166,5763],{"class":3213},[2978,6168,3188],{"class":2995},[2978,6170,5768],{"class":3213},[2978,6172,3223],{"class":2995},[2978,6174,5773],{"class":3195},[2978,6176,3199],{"class":2995},[2978,6178,6179],{"class":3024},"\"Publish\"",[2978,6181,3456],{"class":2995},[2978,6183,5783],{"class":3024},[2978,6185,3456],{"class":2995},[2978,6187,4730],{"class":3180},[2978,6189,4559],{"class":2995},[2978,6191,5792],{"class":3213},[2978,6193,3188],{"class":2995},[2978,6195,5797],{"class":3213},[2978,6197,5800],{"class":2995},[2978,6199,6201,6203,6205,6207],{"class":2980,"line":6200},52,[2978,6202,5805],{"class":3213},[2978,6204,3188],{"class":2995},[2978,6206,6151],{"class":3024},[2978,6208,3013],{"class":2995},[2978,6210,6212,6214,6216,6219],{"class":2980,"line":6211},53,[2978,6213,5816],{"class":3213},[2978,6215,3188],{"class":2995},[2978,6217,6218],{"class":3024},"\"POST\"",[2978,6220,3013],{"class":2995},[2978,6222,6224,6226,6228],{"class":2980,"line":6223},54,[2978,6225,5827],{"class":3213},[2978,6227,3188],{"class":2995},[2978,6229,6230],{"class":3024},"\"Publish article\"\n",[2978,6232,6234],{"class":2980,"line":6233},55,[2978,6235,6236],{"class":2995},"            };\n",[2978,6238,6240],{"class":2980,"line":6239},56,[2978,6241,6242],{"class":2995},"        }\n",[2978,6244,6246],{"class":2980,"line":6245},57,[2978,6247,3288],{"emptyLinePlaceholder":3287},[2978,6249,6251,6253,6255,6257,6260,6262,6264,6267,6269,6271],{"class":2980,"line":6250},58,[2978,6252,6113],{"class":3191},[2978,6254,6116],{"class":2995},[2978,6256,6119],{"class":3213},[2978,6258,6259],{"class":2995}," != ",[2978,6261,4807],{"class":3213},[2978,6263,3223],{"class":2995},[2978,6265,6266],{"class":3213},"Archived",[2978,6268,6131],{"class":2995},[2978,6270,6134],{"class":3213},[2978,6272,5704],{"class":2995},[2978,6274,6276],{"class":2980,"line":6275},59,[2978,6277,5739],{"class":2995},[2978,6279,6281,6283,6285,6288,6290,6292],{"class":2980,"line":6280},60,[2978,6282,6145],{"class":3213},[2978,6284,6148],{"class":2995},[2978,6286,6287],{"class":3024},"\"edit\"",[2978,6289,5749],{"class":2995},[2978,6291,4730],{"class":3180},[2978,6293,5363],{"class":4517},[2978,6295,6297],{"class":2980,"line":6296},61,[2978,6298,5758],{"class":2995},[2978,6300,6302,6304,6306,6308,6310,6312,6314,6317,6319,6321,6323,6325,6327,6329,6331,6333],{"class":2980,"line":6301},62,[2978,6303,5763],{"class":3213},[2978,6305,3188],{"class":2995},[2978,6307,5768],{"class":3213},[2978,6309,3223],{"class":2995},[2978,6311,5773],{"class":3195},[2978,6313,3199],{"class":2995},[2978,6315,6316],{"class":3024},"\"Update\"",[2978,6318,3456],{"class":2995},[2978,6320,5783],{"class":3024},[2978,6322,3456],{"class":2995},[2978,6324,4730],{"class":3180},[2978,6326,4559],{"class":2995},[2978,6328,5792],{"class":3213},[2978,6330,3188],{"class":2995},[2978,6332,5797],{"class":3213},[2978,6334,5800],{"class":2995},[2978,6336,6338,6340,6342,6344],{"class":2980,"line":6337},63,[2978,6339,5805],{"class":3213},[2978,6341,3188],{"class":2995},[2978,6343,6287],{"class":3024},[2978,6345,3013],{"class":2995},[2978,6347,6349,6351,6353,6355],{"class":2980,"line":6348},64,[2978,6350,5816],{"class":3213},[2978,6352,3188],{"class":2995},[2978,6354,3464],{"class":3024},[2978,6356,3013],{"class":2995},[2978,6358,6360,6362,6364],{"class":2980,"line":6359},65,[2978,6361,5827],{"class":3213},[2978,6363,3188],{"class":2995},[2978,6365,6366],{"class":3024},"\"Update article\"\n",[2978,6368,6370],{"class":2980,"line":6369},66,[2978,6371,6236],{"class":2995},[2978,6373,6375],{"class":2980,"line":6374},67,[2978,6376,3288],{"emptyLinePlaceholder":3287},[2978,6378,6380,6382,6384,6387,6389,6391],{"class":2980,"line":6379},68,[2978,6381,6145],{"class":3213},[2978,6383,6148],{"class":2995},[2978,6385,6386],{"class":3024},"\"delete\"",[2978,6388,5749],{"class":2995},[2978,6390,4730],{"class":3180},[2978,6392,5363],{"class":4517},[2978,6394,6396],{"class":2980,"line":6395},69,[2978,6397,5758],{"class":2995},[2978,6399,6401,6403,6405,6407,6409,6411,6413,6416,6418,6420,6422,6424,6426,6428,6430,6432],{"class":2980,"line":6400},70,[2978,6402,5763],{"class":3213},[2978,6404,3188],{"class":2995},[2978,6406,5768],{"class":3213},[2978,6408,3223],{"class":2995},[2978,6410,5773],{"class":3195},[2978,6412,3199],{"class":2995},[2978,6414,6415],{"class":3024},"\"Delete\"",[2978,6417,3456],{"class":2995},[2978,6419,5783],{"class":3024},[2978,6421,3456],{"class":2995},[2978,6423,4730],{"class":3180},[2978,6425,4559],{"class":2995},[2978,6427,5792],{"class":3213},[2978,6429,3188],{"class":2995},[2978,6431,5797],{"class":3213},[2978,6433,5800],{"class":2995},[2978,6435,6437,6439,6441,6443],{"class":2980,"line":6436},71,[2978,6438,5805],{"class":3213},[2978,6440,3188],{"class":2995},[2978,6442,6386],{"class":3024},[2978,6444,3013],{"class":2995},[2978,6446,6448,6450,6452,6454],{"class":2980,"line":6447},72,[2978,6449,5816],{"class":3213},[2978,6451,3188],{"class":2995},[2978,6453,3489],{"class":3024},[2978,6455,3013],{"class":2995},[2978,6457,6459,6461,6463],{"class":2980,"line":6458},73,[2978,6460,5827],{"class":3213},[2978,6462,3188],{"class":2995},[2978,6464,6465],{"class":3024},"\"Delete article\"\n",[2978,6467,6469],{"class":2980,"line":6468},74,[2978,6470,6236],{"class":2995},[2978,6472,6474],{"class":2980,"line":6473},75,[2978,6475,6242],{"class":2995},[2978,6477,6479],{"class":2980,"line":6478},76,[2978,6480,3288],{"emptyLinePlaceholder":3287},[2978,6482,6484,6486,6488,6490,6492,6494,6496,6499],{"class":2980,"line":6483},77,[2978,6485,6113],{"class":3191},[2978,6487,6116],{"class":2995},[2978,6489,6119],{"class":3213},[2978,6491,6122],{"class":2995},[2978,6493,4807],{"class":3213},[2978,6495,3223],{"class":2995},[2978,6497,6498],{"class":3213},"Published",[2978,6500,5704],{"class":2995},[2978,6502,6504],{"class":2980,"line":6503},78,[2978,6505,5739],{"class":2995},[2978,6507,6509,6511,6513,6516,6518,6520],{"class":2980,"line":6508},79,[2978,6510,6145],{"class":3213},[2978,6512,6148],{"class":2995},[2978,6514,6515],{"class":3024},"\"archive\"",[2978,6517,5749],{"class":2995},[2978,6519,4730],{"class":3180},[2978,6521,5363],{"class":4517},[2978,6523,6525],{"class":2980,"line":6524},80,[2978,6526,5758],{"class":2995},[2978,6528,6530,6532,6534,6536,6538,6540,6542,6545,6547,6549,6551,6553,6555,6557,6559,6561],{"class":2980,"line":6529},81,[2978,6531,5763],{"class":3213},[2978,6533,3188],{"class":2995},[2978,6535,5768],{"class":3213},[2978,6537,3223],{"class":2995},[2978,6539,5773],{"class":3195},[2978,6541,3199],{"class":2995},[2978,6543,6544],{"class":3024},"\"Archive\"",[2978,6546,3456],{"class":2995},[2978,6548,5783],{"class":3024},[2978,6550,3456],{"class":2995},[2978,6552,4730],{"class":3180},[2978,6554,4559],{"class":2995},[2978,6556,5792],{"class":3213},[2978,6558,3188],{"class":2995},[2978,6560,5797],{"class":3213},[2978,6562,5800],{"class":2995},[2978,6564,6566,6568,6570,6572],{"class":2980,"line":6565},82,[2978,6567,5805],{"class":3213},[2978,6569,3188],{"class":2995},[2978,6571,6515],{"class":3024},[2978,6573,3013],{"class":2995},[2978,6575,6577,6579,6581,6583],{"class":2980,"line":6576},83,[2978,6578,5816],{"class":3213},[2978,6580,3188],{"class":2995},[2978,6582,6218],{"class":3024},[2978,6584,3013],{"class":2995},[2978,6586,6588,6590,6592],{"class":2980,"line":6587},84,[2978,6589,5827],{"class":3213},[2978,6591,3188],{"class":2995},[2978,6593,6594],{"class":3024},"\"Archive article\"\n",[2978,6596,6598],{"class":2980,"line":6597},85,[2978,6599,6236],{"class":2995},[2978,6601,6603],{"class":2980,"line":6602},86,[2978,6604,6242],{"class":2995},[2978,6606,6608],{"class":2980,"line":6607},87,[2978,6609,3288],{"emptyLinePlaceholder":3287},[2978,6611,6613,6616,6618],{"class":2980,"line":6612},88,[2978,6614,6615],{"class":3191},"        return",[2978,6617,5717],{"class":3213},[2978,6619,4526],{"class":2995},[2978,6621,6623],{"class":2980,"line":6622},89,[2978,6624,6625],{"class":2995},"    }\n",[2978,6627,6629],{"class":2980,"line":6628},90,[2978,6630,3288],{"emptyLinePlaceholder":3287},[2978,6632,6634,6636,6638,6640,6642,6644,6646,6648,6650,6653],{"class":2980,"line":6633},91,[2978,6635,4550],{"class":3180},[2978,6637,5625],{"class":3180},[2978,6639,5484],{"class":4517},[2978,6641,4707],{"class":2995},[2978,6643,5489],{"class":3180},[2978,6645,3456],{"class":2995},[2978,6647,5494],{"class":4517},[2978,6649,4713],{"class":2995},[2978,6651,6652],{"class":3195},"GenerateCollectionLinks",[2978,6654,5658],{"class":2995},[2978,6656,6658,6660,6662],{"class":2980,"line":6657},92,[2978,6659,5683],{"class":4517},[2978,6661,5686],{"class":3213},[2978,6663,3013],{"class":2995},[2978,6665,6667,6670,6673],{"class":2980,"line":6666},93,[2978,6668,6669],{"class":3180},"        string",[2978,6671,6672],{"class":3213}," action",[2978,6674,3013],{"class":2995},[2978,6676,6678,6680,6683],{"class":2980,"line":6677},94,[2978,6679,6669],{"class":3180},[2978,6681,6682],{"class":3213}," controller",[2978,6684,3013],{"class":2995},[2978,6686,6688,6690,6693],{"class":2980,"line":6687},95,[2978,6689,5663],{"class":3180},[2978,6691,6692],{"class":3213}," page",[2978,6694,3013],{"class":2995},[2978,6696,6698,6700,6703],{"class":2980,"line":6697},96,[2978,6699,5663],{"class":3180},[2978,6701,6702],{"class":3213}," totalPages",[2978,6704,5704],{"class":2995},[2978,6706,6708],{"class":2980,"line":6707},97,[2978,6709,5709],{"class":2995},[2978,6711,6713,6715,6717,6719,6721,6723,6725,6727,6729,6731],{"class":2980,"line":6712},98,[2978,6714,5714],{"class":3180},[2978,6716,5717],{"class":3213},[2978,6718,3188],{"class":2995},[2978,6720,4730],{"class":3180},[2978,6722,5484],{"class":4517},[2978,6724,4707],{"class":2995},[2978,6726,5489],{"class":3180},[2978,6728,3456],{"class":2995},[2978,6730,5494],{"class":4517},[2978,6732,5734],{"class":2995},[2978,6734,6736],{"class":2980,"line":6735},99,[2978,6737,5739],{"class":2995},[2978,6739,6741,6743,6745,6747,6749],{"class":2980,"line":6740},100,[2978,6742,5744],{"class":2995},[2978,6744,3738],{"class":3024},[2978,6746,5749],{"class":2995},[2978,6748,4730],{"class":3180},[2978,6750,5363],{"class":4517},[2978,6752,6754],{"class":2980,"line":6753},101,[2978,6755,5758],{"class":2995},[2978,6757,6759,6761,6763,6765,6767,6769,6771,6774,6776,6779,6781,6783,6785,6788],{"class":2980,"line":6758},102,[2978,6760,5763],{"class":3213},[2978,6762,3188],{"class":2995},[2978,6764,5768],{"class":3213},[2978,6766,3223],{"class":2995},[2978,6768,5773],{"class":3195},[2978,6770,3199],{"class":2995},[2978,6772,6773],{"class":3213},"action",[2978,6775,3456],{"class":2995},[2978,6777,6778],{"class":3213},"controller",[2978,6780,3456],{"class":2995},[2978,6782,4730],{"class":3180},[2978,6784,4559],{"class":2995},[2978,6786,6787],{"class":3213},"page",[2978,6789,5800],{"class":2995},[2978,6791,6793,6795,6797],{"class":2980,"line":6792},103,[2978,6794,5805],{"class":3213},[2978,6796,3188],{"class":2995},[2978,6798,6799],{"class":3024},"\"self\"\n",[2978,6801,6803],{"class":2980,"line":6802},104,[2978,6804,6094],{"class":2995},[2978,6806,6808],{"class":2980,"line":6807},105,[2978,6809,6099],{"class":2995},[2978,6811,6813],{"class":2980,"line":6812},106,[2978,6814,3288],{"emptyLinePlaceholder":3287},[2978,6816,6818,6820,6822,6824,6827,6829],{"class":2980,"line":6817},107,[2978,6819,6113],{"class":3191},[2978,6821,6116],{"class":2995},[2978,6823,6787],{"class":3213},[2978,6825,6826],{"class":2995}," > ",[2978,6828,3617],{"class":3009},[2978,6830,5704],{"class":2995},[2978,6832,6834],{"class":2980,"line":6833},108,[2978,6835,5739],{"class":2995},[2978,6837,6839,6841,6843,6846,6848,6850],{"class":2980,"line":6838},109,[2978,6840,6145],{"class":3213},[2978,6842,6148],{"class":2995},[2978,6844,6845],{"class":3024},"\"first\"",[2978,6847,5749],{"class":2995},[2978,6849,4730],{"class":3180},[2978,6851,5363],{"class":4517},[2978,6853,6855],{"class":2980,"line":6854},110,[2978,6856,5758],{"class":2995},[2978,6858,6860,6862,6864,6866,6868,6870,6872,6874,6876,6878,6880,6882,6884,6886,6888,6890],{"class":2980,"line":6859},111,[2978,6861,5763],{"class":3213},[2978,6863,3188],{"class":2995},[2978,6865,5768],{"class":3213},[2978,6867,3223],{"class":2995},[2978,6869,5773],{"class":3195},[2978,6871,3199],{"class":2995},[2978,6873,6773],{"class":3213},[2978,6875,3456],{"class":2995},[2978,6877,6778],{"class":3213},[2978,6879,3456],{"class":2995},[2978,6881,4730],{"class":3180},[2978,6883,4559],{"class":2995},[2978,6885,6787],{"class":3213},[2978,6887,3188],{"class":2995},[2978,6889,3617],{"class":3009},[2978,6891,5800],{"class":2995},[2978,6893,6895,6897,6899],{"class":2980,"line":6894},112,[2978,6896,5805],{"class":3213},[2978,6898,3188],{"class":2995},[2978,6900,6901],{"class":3024},"\"first\"\n",[2978,6903,6905],{"class":2980,"line":6904},113,[2978,6906,6236],{"class":2995},[2978,6908,6910],{"class":2980,"line":6909},114,[2978,6911,3288],{"emptyLinePlaceholder":3287},[2978,6913,6915,6917,6919,6922,6924,6926],{"class":2980,"line":6914},115,[2978,6916,6145],{"class":3213},[2978,6918,6148],{"class":2995},[2978,6920,6921],{"class":3024},"\"prev\"",[2978,6923,5749],{"class":2995},[2978,6925,4730],{"class":3180},[2978,6927,5363],{"class":4517},[2978,6929,6931],{"class":2980,"line":6930},116,[2978,6932,5758],{"class":2995},[2978,6934,6936,6938,6940,6942,6944,6946,6948,6950,6952,6954,6956,6958,6960,6962,6964,6966,6969,6971],{"class":2980,"line":6935},117,[2978,6937,5763],{"class":3213},[2978,6939,3188],{"class":2995},[2978,6941,5768],{"class":3213},[2978,6943,3223],{"class":2995},[2978,6945,5773],{"class":3195},[2978,6947,3199],{"class":2995},[2978,6949,6773],{"class":3213},[2978,6951,3456],{"class":2995},[2978,6953,6778],{"class":3213},[2978,6955,3456],{"class":2995},[2978,6957,4730],{"class":3180},[2978,6959,4559],{"class":2995},[2978,6961,6787],{"class":3213},[2978,6963,3188],{"class":2995},[2978,6965,6787],{"class":3213},[2978,6967,6968],{"class":2995}," - ",[2978,6970,3617],{"class":3009},[2978,6972,5800],{"class":2995},[2978,6974,6976,6978,6980],{"class":2980,"line":6975},118,[2978,6977,5805],{"class":3213},[2978,6979,3188],{"class":2995},[2978,6981,6982],{"class":3024},"\"prev\"\n",[2978,6984,6986],{"class":2980,"line":6985},119,[2978,6987,6236],{"class":2995},[2978,6989,6991],{"class":2980,"line":6990},120,[2978,6992,6242],{"class":2995},[2978,6994,6996],{"class":2980,"line":6995},121,[2978,6997,3288],{"emptyLinePlaceholder":3287},[2978,6999,7001,7003,7005,7007,7010,7013],{"class":2980,"line":7000},122,[2978,7002,6113],{"class":3191},[2978,7004,6116],{"class":2995},[2978,7006,6787],{"class":3213},[2978,7008,7009],{"class":2995}," \u003C ",[2978,7011,7012],{"class":3213},"totalPages",[2978,7014,5704],{"class":2995},[2978,7016,7018],{"class":2980,"line":7017},123,[2978,7019,5739],{"class":2995},[2978,7021,7023,7025,7027,7030,7032,7034],{"class":2980,"line":7022},124,[2978,7024,6145],{"class":3213},[2978,7026,6148],{"class":2995},[2978,7028,7029],{"class":3024},"\"next\"",[2978,7031,5749],{"class":2995},[2978,7033,4730],{"class":3180},[2978,7035,5363],{"class":4517},[2978,7037,7039],{"class":2980,"line":7038},125,[2978,7040,5758],{"class":2995},[2978,7042,7044,7046,7048,7050,7052,7054,7056,7058,7060,7062,7064,7066,7068,7070,7072,7074,7077,7079],{"class":2980,"line":7043},126,[2978,7045,5763],{"class":3213},[2978,7047,3188],{"class":2995},[2978,7049,5768],{"class":3213},[2978,7051,3223],{"class":2995},[2978,7053,5773],{"class":3195},[2978,7055,3199],{"class":2995},[2978,7057,6773],{"class":3213},[2978,7059,3456],{"class":2995},[2978,7061,6778],{"class":3213},[2978,7063,3456],{"class":2995},[2978,7065,4730],{"class":3180},[2978,7067,4559],{"class":2995},[2978,7069,6787],{"class":3213},[2978,7071,3188],{"class":2995},[2978,7073,6787],{"class":3213},[2978,7075,7076],{"class":2995}," + ",[2978,7078,3617],{"class":3009},[2978,7080,5800],{"class":2995},[2978,7082,7084,7086,7088],{"class":2980,"line":7083},127,[2978,7085,5805],{"class":3213},[2978,7087,3188],{"class":2995},[2978,7089,7090],{"class":3024},"\"next\"\n",[2978,7092,7094],{"class":2980,"line":7093},128,[2978,7095,6236],{"class":2995},[2978,7097,7099],{"class":2980,"line":7098},129,[2978,7100,3288],{"emptyLinePlaceholder":3287},[2978,7102,7104,7106,7108,7111,7113,7115],{"class":2980,"line":7103},130,[2978,7105,6145],{"class":3213},[2978,7107,6148],{"class":2995},[2978,7109,7110],{"class":3024},"\"last\"",[2978,7112,5749],{"class":2995},[2978,7114,4730],{"class":3180},[2978,7116,5363],{"class":4517},[2978,7118,7120],{"class":2980,"line":7119},131,[2978,7121,5758],{"class":2995},[2978,7123,7125,7127,7129,7131,7133,7135,7137,7139,7141,7143,7145,7147,7149,7151,7153,7155],{"class":2980,"line":7124},132,[2978,7126,5763],{"class":3213},[2978,7128,3188],{"class":2995},[2978,7130,5768],{"class":3213},[2978,7132,3223],{"class":2995},[2978,7134,5773],{"class":3195},[2978,7136,3199],{"class":2995},[2978,7138,6773],{"class":3213},[2978,7140,3456],{"class":2995},[2978,7142,6778],{"class":3213},[2978,7144,3456],{"class":2995},[2978,7146,4730],{"class":3180},[2978,7148,4559],{"class":2995},[2978,7150,6787],{"class":3213},[2978,7152,3188],{"class":2995},[2978,7154,7012],{"class":3213},[2978,7156,5800],{"class":2995},[2978,7158,7160,7162,7164],{"class":2980,"line":7159},133,[2978,7161,5805],{"class":3213},[2978,7163,3188],{"class":2995},[2978,7165,7166],{"class":3024},"\"last\"\n",[2978,7168,7170],{"class":2980,"line":7169},134,[2978,7171,6236],{"class":2995},[2978,7173,7175],{"class":2980,"line":7174},135,[2978,7176,6242],{"class":2995},[2978,7178,7180],{"class":2980,"line":7179},136,[2978,7181,3288],{"emptyLinePlaceholder":3287},[2978,7183,7185,7187,7189],{"class":2980,"line":7184},137,[2978,7186,6615],{"class":3191},[2978,7188,5717],{"class":3213},[2978,7190,4526],{"class":2995},[2978,7192,7194],{"class":2980,"line":7193},138,[2978,7195,6625],{"class":2995},[2978,7197,7199],{"class":2980,"line":7198},139,[2978,7200,3070],{"class":2995},[2964,7202,7203],{},[3074,7204,5285],{},[7206,7207,7208,7216,7222,7231],"ol",{},[3092,7209,7210,7215],{},[3074,7211,7212],{},[2975,7213,7214],{},"IUrlHelper"," — ASP.NET Core сервіс для генерації URL-ів",[3092,7217,7218,7221],{},[3074,7219,7220],{},"Conditional links"," — різні links залежно від статусу та прав",[3092,7223,7224,7230],{},[3074,7225,7226,7229],{},[2975,7227,7228],{},"{authorId}"," placeholder"," — буде замінено на фактичний ID",[3092,7232,7233,7236],{},[3074,7234,7235],{},"Collection links"," — для пагінованих списків",[4125,7238,7239,7243],{},[3074,7240,7241],{},[2975,7242,7214],{}," автоматично генерує правильні URL-и з урахуванням routing конфігурації. Якщо змінити маршрут, links оновляться автоматично.",[3882,7245],{},[3329,7247,7249],{"id":7248},"крок-3-resource-dtos-з-hateoas","Крок 3: Resource DTOs з HATEOAS",[5325,7251,7253],{"id":7252},"articledto-з-links","ArticleDto з Links",[2964,7255,4499,7256,3087],{},[2975,7257,7258],{},"Models/DTOs/ArticleDto.cs",[2968,7260,7262],{"className":4505,"code":7261,"language":4507,"meta":2973,"style":2973},"using System.Text.Json.Serialization;\n\nnamespace BlogHateoasApi.Models.DTOs;\n\npublic class ArticleDto\n{\n    public int Id { get; set; }\n    public required string Title { get; set; }\n    public required string Content { get; set; }\n    public int AuthorId { get; set; }\n    public int CategoryId { get; set; }\n    public DateTime PublishedAt { get; set; }\n    public DateTime? UpdatedAt { get; set; }\n    public string Status { get; set; } = \"\";\n\n    [JsonPropertyName(\"_links\")]\n    public Dictionary\u003Cstring, Link>? Links { get; set; }\n\n    [JsonPropertyName(\"_embedded\")]\n    public EmbeddedResources? Embedded { get; set; }\n}\n\npublic class EmbeddedResources\n{\n    public AuthorDto? Author { get; set; }\n    public CategoryDto? Category { get; set; }\n    public List\u003CCommentDto>? Comments { get; set; }\n}\n\npublic class AuthorDto\n{\n    public int Id { get; set; }\n    public required string Name { get; set; }\n    public required string Email { get; set; }\n    public string? Bio { get; set; }\n\n    [JsonPropertyName(\"_links\")]\n    public Dictionary\u003Cstring, Link>? Links { get; set; }\n}\n\npublic class CategoryDto\n{\n    public int Id { get; set; }\n    public required string Name { get; set; }\n    public string? Description { get; set; }\n\n    [JsonPropertyName(\"_links\")]\n    public Dictionary\u003Cstring, Link>? Links { get; set; }\n}\n\npublic class CommentDto\n{\n    public int Id { get; set; }\n    public required string Text { get; set; }\n    public required string AuthorName { get; set; }\n    public DateTime CreatedAt { get; set; }\n\n    [JsonPropertyName(\"_links\")]\n    public Dictionary\u003Cstring, Link>? Links { get; set; }\n}\n",[2975,7263,7264,7288,7292,7309,7313,7322,7326,7344,7364,7384,7402,7420,7438,7458,7481,7485,7500,7529,7533,7546,7568,7572,7576,7585,7589,7610,7631,7656,7660,7664,7673,7677,7695,7715,7735,7755,7759,7771,7799,7803,7807,7816,7820,7838,7858,7878,7882,7894,7922,7926,7930,7939,7943,7961,7981,8001,8019,8023,8035,8063],{"__ignoreMap":2973},[2978,7265,7266,7268,7271,7273,7276,7278,7281,7283,7286],{"class":2980,"line":2981},[2978,7267,5570],{"class":3191},[2978,7269,7270],{"class":4517}," System",[2978,7272,3223],{"class":2995},[2978,7274,7275],{"class":4517},"Text",[2978,7277,3223],{"class":2995},[2978,7279,7280],{"class":4517},"Json",[2978,7282,3223],{"class":2995},[2978,7284,7285],{"class":4517},"Serialization",[2978,7287,4526],{"class":2995},[2978,7289,7290],{"class":2980,"line":2999},[2978,7291,3288],{"emptyLinePlaceholder":3287},[2978,7293,7294,7296,7298,7300,7302,7304,7307],{"class":2980,"line":3016},[2978,7295,4514],{"class":3180},[2978,7297,4518],{"class":4517},[2978,7299,3223],{"class":2995},[2978,7301,4523],{"class":4517},[2978,7303,3223],{"class":2995},[2978,7305,7306],{"class":4517},"DTOs",[2978,7308,4526],{"class":2995},[2978,7310,7311],{"class":2980,"line":3030},[2978,7312,3288],{"emptyLinePlaceholder":3287},[2978,7314,7315,7317,7319],{"class":2980,"line":3043},[2978,7316,4535],{"class":3180},[2978,7318,4538],{"class":3180},[2978,7320,7321],{"class":4517}," ArticleDto\n",[2978,7323,7324],{"class":2980,"line":3056},[2978,7325,2996],{"class":2995},[2978,7327,7328,7330,7332,7334,7336,7338,7340,7342],{"class":2980,"line":3067},[2978,7329,4550],{"class":3180},[2978,7331,4553],{"class":3180},[2978,7333,4556],{"class":3213},[2978,7335,4559],{"class":2995},[2978,7337,4562],{"class":3180},[2978,7339,4565],{"class":2995},[2978,7341,4568],{"class":3180},[2978,7343,4571],{"class":2995},[2978,7345,7346,7348,7350,7352,7354,7356,7358,7360,7362],{"class":2980,"line":3442},[2978,7347,4550],{"class":3180},[2978,7349,4578],{"class":3180},[2978,7351,4581],{"class":3180},[2978,7353,4584],{"class":3213},[2978,7355,4559],{"class":2995},[2978,7357,4562],{"class":3180},[2978,7359,4565],{"class":2995},[2978,7361,4568],{"class":3180},[2978,7363,4571],{"class":2995},[2978,7365,7366,7368,7370,7372,7374,7376,7378,7380,7382],{"class":2980,"line":3469},[2978,7367,4550],{"class":3180},[2978,7369,4578],{"class":3180},[2978,7371,4581],{"class":3180},[2978,7373,4605],{"class":3213},[2978,7375,4559],{"class":2995},[2978,7377,4562],{"class":3180},[2978,7379,4565],{"class":2995},[2978,7381,4568],{"class":3180},[2978,7383,4571],{"class":2995},[2978,7385,7386,7388,7390,7392,7394,7396,7398,7400],{"class":2980,"line":3495},[2978,7387,4550],{"class":3180},[2978,7389,4553],{"class":3180},[2978,7391,4624],{"class":3213},[2978,7393,4559],{"class":2995},[2978,7395,4562],{"class":3180},[2978,7397,4565],{"class":2995},[2978,7399,4568],{"class":3180},[2978,7401,4571],{"class":2995},[2978,7403,7404,7406,7408,7410,7412,7414,7416,7418],{"class":2980,"line":3501},[2978,7405,4550],{"class":3180},[2978,7407,4553],{"class":3180},[2978,7409,4665],{"class":3213},[2978,7411,4559],{"class":2995},[2978,7413,4562],{"class":3180},[2978,7415,4565],{"class":2995},[2978,7417,4568],{"class":3180},[2978,7419,4571],{"class":2995},[2978,7421,7422,7424,7426,7428,7430,7432,7434,7436],{"class":2980,"line":3642},[2978,7423,4550],{"class":3180},[2978,7425,4740],{"class":4517},[2978,7427,4743],{"class":3213},[2978,7429,4559],{"class":2995},[2978,7431,4562],{"class":3180},[2978,7433,4565],{"class":2995},[2978,7435,4568],{"class":3180},[2978,7437,4571],{"class":2995},[2978,7439,7440,7442,7444,7446,7448,7450,7452,7454,7456],{"class":2980,"line":3674},[2978,7441,4550],{"class":3180},[2978,7443,4740],{"class":4517},[2978,7445,3101],{"class":2995},[2978,7447,4774],{"class":3213},[2978,7449,4559],{"class":2995},[2978,7451,4562],{"class":3180},[2978,7453,4565],{"class":2995},[2978,7455,4568],{"class":3180},[2978,7457,4571],{"class":2995},[2978,7459,7460,7462,7464,7466,7468,7470,7472,7474,7476,7479],{"class":2980,"line":3680},[2978,7461,4550],{"class":3180},[2978,7463,4581],{"class":3180},[2978,7465,4794],{"class":3213},[2978,7467,4559],{"class":2995},[2978,7469,4562],{"class":3180},[2978,7471,4565],{"class":2995},[2978,7473,4568],{"class":3180},[2978,7475,4727],{"class":2995},[2978,7477,7478],{"class":3024},"\"\"",[2978,7480,4526],{"class":2995},[2978,7482,7483],{"class":2980,"line":3686},[2978,7484,3288],{"emptyLinePlaceholder":3287},[2978,7486,7487,7490,7493,7495,7497],{"class":2980,"line":3699},[2978,7488,7489],{"class":2995},"    [",[2978,7491,7492],{"class":4517},"JsonPropertyName",[2978,7494,3199],{"class":2995},[2978,7496,3788],{"class":3024},[2978,7498,7499],{"class":2995},")]\n",[2978,7501,7502,7504,7506,7508,7510,7512,7514,7517,7519,7521,7523,7525,7527],{"class":2980,"line":4367},[2978,7503,4550],{"class":3180},[2978,7505,5484],{"class":4517},[2978,7507,4707],{"class":2995},[2978,7509,5489],{"class":3180},[2978,7511,3456],{"class":2995},[2978,7513,5494],{"class":4517},[2978,7515,7516],{"class":2995},">? ",[2978,7518,5499],{"class":3213},[2978,7520,4559],{"class":2995},[2978,7522,4562],{"class":3180},[2978,7524,4565],{"class":2995},[2978,7526,4568],{"class":3180},[2978,7528,4571],{"class":2995},[2978,7530,7531],{"class":2980,"line":4825},[2978,7532,3288],{"emptyLinePlaceholder":3287},[2978,7534,7535,7537,7539,7541,7544],{"class":2980,"line":4836},[2978,7536,7489],{"class":2995},[2978,7538,7492],{"class":4517},[2978,7540,3199],{"class":2995},[2978,7542,7543],{"class":3024},"\"_embedded\"",[2978,7545,7499],{"class":2995},[2978,7547,7548,7550,7553,7555,7558,7560,7562,7564,7566],{"class":2980,"line":4841},[2978,7549,4550],{"class":3180},[2978,7551,7552],{"class":4517}," EmbeddedResources",[2978,7554,3101],{"class":2995},[2978,7556,7557],{"class":3213},"Embedded",[2978,7559,4559],{"class":2995},[2978,7561,4562],{"class":3180},[2978,7563,4565],{"class":2995},[2978,7565,4568],{"class":3180},[2978,7567,4571],{"class":2995},[2978,7569,7570],{"class":2980,"line":4849},[2978,7571,3070],{"class":2995},[2978,7573,7574],{"class":2980,"line":4857},[2978,7575,3288],{"emptyLinePlaceholder":3287},[2978,7577,7578,7580,7582],{"class":2980,"line":4863},[2978,7579,4535],{"class":3180},[2978,7581,4538],{"class":3180},[2978,7583,7584],{"class":4517}," EmbeddedResources\n",[2978,7586,7587],{"class":2980,"line":4868},[2978,7588,2996],{"class":2995},[2978,7590,7591,7593,7596,7598,7600,7602,7604,7606,7608],{"class":2980,"line":4873},[2978,7592,4550],{"class":3180},[2978,7594,7595],{"class":4517}," AuthorDto",[2978,7597,3101],{"class":2995},[2978,7599,4646],{"class":3213},[2978,7601,4559],{"class":2995},[2978,7603,4562],{"class":3180},[2978,7605,4565],{"class":2995},[2978,7607,4568],{"class":3180},[2978,7609,4571],{"class":2995},[2978,7611,7612,7614,7617,7619,7621,7623,7625,7627,7629],{"class":2980,"line":4883},[2978,7613,4550],{"class":3180},[2978,7615,7616],{"class":4517}," CategoryDto",[2978,7618,3101],{"class":2995},[2978,7620,4687],{"class":3213},[2978,7622,4559],{"class":2995},[2978,7624,4562],{"class":3180},[2978,7626,4565],{"class":2995},[2978,7628,4568],{"class":3180},[2978,7630,4571],{"class":2995},[2978,7632,7633,7635,7637,7639,7642,7644,7646,7648,7650,7652,7654],{"class":2980,"line":4888},[2978,7634,4550],{"class":3180},[2978,7636,4704],{"class":4517},[2978,7638,4707],{"class":2995},[2978,7640,7641],{"class":4517},"CommentDto",[2978,7643,7516],{"class":2995},[2978,7645,4716],{"class":3213},[2978,7647,4559],{"class":2995},[2978,7649,4562],{"class":3180},[2978,7651,4565],{"class":2995},[2978,7653,4568],{"class":3180},[2978,7655,4571],{"class":2995},[2978,7657,7658],{"class":2980,"line":4907},[2978,7659,3070],{"class":2995},[2978,7661,7662],{"class":2980,"line":4929},[2978,7663,3288],{"emptyLinePlaceholder":3287},[2978,7665,7666,7668,7670],{"class":2980,"line":4951},[2978,7667,4535],{"class":3180},[2978,7669,4538],{"class":3180},[2978,7671,7672],{"class":4517}," AuthorDto\n",[2978,7674,7675],{"class":2980,"line":4973},[2978,7676,2996],{"class":2995},[2978,7678,7679,7681,7683,7685,7687,7689,7691,7693],{"class":2980,"line":5004},[2978,7680,4550],{"class":3180},[2978,7682,4553],{"class":3180},[2978,7684,4556],{"class":3213},[2978,7686,4559],{"class":2995},[2978,7688,4562],{"class":3180},[2978,7690,4565],{"class":2995},[2978,7692,4568],{"class":3180},[2978,7694,4571],{"class":2995},[2978,7696,7697,7699,7701,7703,7705,7707,7709,7711,7713],{"class":2980,"line":5009},[2978,7698,4550],{"class":3180},[2978,7700,4578],{"class":3180},[2978,7702,4581],{"class":3180},[2978,7704,4916],{"class":3213},[2978,7706,4559],{"class":2995},[2978,7708,4562],{"class":3180},[2978,7710,4565],{"class":2995},[2978,7712,4568],{"class":3180},[2978,7714,4571],{"class":2995},[2978,7716,7717,7719,7721,7723,7725,7727,7729,7731,7733],{"class":2980,"line":5014},[2978,7718,4550],{"class":3180},[2978,7720,4578],{"class":3180},[2978,7722,4581],{"class":3180},[2978,7724,4938],{"class":3213},[2978,7726,4559],{"class":2995},[2978,7728,4562],{"class":3180},[2978,7730,4565],{"class":2995},[2978,7732,4568],{"class":3180},[2978,7734,4571],{"class":2995},[2978,7736,7737,7739,7741,7743,7745,7747,7749,7751,7753],{"class":2980,"line":5024},[2978,7738,4550],{"class":3180},[2978,7740,4581],{"class":3180},[2978,7742,3101],{"class":2995},[2978,7744,4960],{"class":3213},[2978,7746,4559],{"class":2995},[2978,7748,4562],{"class":3180},[2978,7750,4565],{"class":2995},[2978,7752,4568],{"class":3180},[2978,7754,4571],{"class":2995},[2978,7756,7757],{"class":2980,"line":5029},[2978,7758,3288],{"emptyLinePlaceholder":3287},[2978,7760,7761,7763,7765,7767,7769],{"class":2980,"line":5048},[2978,7762,7489],{"class":2995},[2978,7764,7492],{"class":4517},[2978,7766,3199],{"class":2995},[2978,7768,3788],{"class":3024},[2978,7770,7499],{"class":2995},[2978,7772,7773,7775,7777,7779,7781,7783,7785,7787,7789,7791,7793,7795,7797],{"class":2980,"line":5069},[2978,7774,4550],{"class":3180},[2978,7776,5484],{"class":4517},[2978,7778,4707],{"class":2995},[2978,7780,5489],{"class":3180},[2978,7782,3456],{"class":2995},[2978,7784,5494],{"class":4517},[2978,7786,7516],{"class":2995},[2978,7788,5499],{"class":3213},[2978,7790,4559],{"class":2995},[2978,7792,4562],{"class":3180},[2978,7794,4565],{"class":2995},[2978,7796,4568],{"class":3180},[2978,7798,4571],{"class":2995},[2978,7800,7801],{"class":2980,"line":5091},[2978,7802,3070],{"class":2995},[2978,7804,7805],{"class":2980,"line":5120},[2978,7806,3288],{"emptyLinePlaceholder":3287},[2978,7808,7809,7811,7813],{"class":2980,"line":5125},[2978,7810,4535],{"class":3180},[2978,7812,4538],{"class":3180},[2978,7814,7815],{"class":4517}," CategoryDto\n",[2978,7817,7818],{"class":2980,"line":5130},[2978,7819,2996],{"class":2995},[2978,7821,7822,7824,7826,7828,7830,7832,7834,7836],{"class":2980,"line":5140},[2978,7823,4550],{"class":3180},[2978,7825,4553],{"class":3180},[2978,7827,4556],{"class":3213},[2978,7829,4559],{"class":2995},[2978,7831,4562],{"class":3180},[2978,7833,4565],{"class":2995},[2978,7835,4568],{"class":3180},[2978,7837,4571],{"class":2995},[2978,7839,7840,7842,7844,7846,7848,7850,7852,7854,7856],{"class":2980,"line":5145},[2978,7841,4550],{"class":3180},[2978,7843,4578],{"class":3180},[2978,7845,4581],{"class":3180},[2978,7847,4916],{"class":3213},[2978,7849,4559],{"class":2995},[2978,7851,4562],{"class":3180},[2978,7853,4565],{"class":2995},[2978,7855,4568],{"class":3180},[2978,7857,4571],{"class":2995},[2978,7859,7860,7862,7864,7866,7868,7870,7872,7874,7876],{"class":2980,"line":5164},[2978,7861,4550],{"class":3180},[2978,7863,4581],{"class":3180},[2978,7865,3101],{"class":2995},[2978,7867,5078],{"class":3213},[2978,7869,4559],{"class":2995},[2978,7871,4562],{"class":3180},[2978,7873,4565],{"class":2995},[2978,7875,4568],{"class":3180},[2978,7877,4571],{"class":2995},[2978,7879,7880],{"class":2980,"line":5186},[2978,7881,3288],{"emptyLinePlaceholder":3287},[2978,7883,7884,7886,7888,7890,7892],{"class":2980,"line":5208},[2978,7885,7489],{"class":2995},[2978,7887,7492],{"class":4517},[2978,7889,3199],{"class":2995},[2978,7891,3788],{"class":3024},[2978,7893,7499],{"class":2995},[2978,7895,7896,7898,7900,7902,7904,7906,7908,7910,7912,7914,7916,7918,7920],{"class":2980,"line":5228},[2978,7897,4550],{"class":3180},[2978,7899,5484],{"class":4517},[2978,7901,4707],{"class":2995},[2978,7903,5489],{"class":3180},[2978,7905,3456],{"class":2995},[2978,7907,5494],{"class":4517},[2978,7909,7516],{"class":2995},[2978,7911,5499],{"class":3213},[2978,7913,4559],{"class":2995},[2978,7915,4562],{"class":3180},[2978,7917,4565],{"class":2995},[2978,7919,4568],{"class":3180},[2978,7921,4571],{"class":2995},[2978,7923,7924],{"class":2980,"line":5250},[2978,7925,3070],{"class":2995},[2978,7927,7928],{"class":2980,"line":5278},[2978,7929,3288],{"emptyLinePlaceholder":3287},[2978,7931,7932,7934,7936],{"class":2980,"line":6164},[2978,7933,4535],{"class":3180},[2978,7935,4538],{"class":3180},[2978,7937,7938],{"class":4517}," CommentDto\n",[2978,7940,7941],{"class":2980,"line":6200},[2978,7942,2996],{"class":2995},[2978,7944,7945,7947,7949,7951,7953,7955,7957,7959],{"class":2980,"line":6211},[2978,7946,4550],{"class":3180},[2978,7948,4553],{"class":3180},[2978,7950,4556],{"class":3213},[2978,7952,4559],{"class":2995},[2978,7954,4562],{"class":3180},[2978,7956,4565],{"class":2995},[2978,7958,4568],{"class":3180},[2978,7960,4571],{"class":2995},[2978,7962,7963,7965,7967,7969,7971,7973,7975,7977,7979],{"class":2980,"line":6223},[2978,7964,4550],{"class":3180},[2978,7966,4578],{"class":3180},[2978,7968,4581],{"class":3180},[2978,7970,5173],{"class":3213},[2978,7972,4559],{"class":2995},[2978,7974,4562],{"class":3180},[2978,7976,4565],{"class":2995},[2978,7978,4568],{"class":3180},[2978,7980,4571],{"class":2995},[2978,7982,7983,7985,7987,7989,7991,7993,7995,7997,7999],{"class":2980,"line":6233},[2978,7984,4550],{"class":3180},[2978,7986,4578],{"class":3180},[2978,7988,4581],{"class":3180},[2978,7990,5195],{"class":3213},[2978,7992,4559],{"class":2995},[2978,7994,4562],{"class":3180},[2978,7996,4565],{"class":2995},[2978,7998,4568],{"class":3180},[2978,8000,4571],{"class":2995},[2978,8002,8003,8005,8007,8009,8011,8013,8015,8017],{"class":2980,"line":6239},[2978,8004,4550],{"class":3180},[2978,8006,4740],{"class":4517},[2978,8008,5257],{"class":3213},[2978,8010,4559],{"class":2995},[2978,8012,4562],{"class":3180},[2978,8014,4565],{"class":2995},[2978,8016,4568],{"class":3180},[2978,8018,4571],{"class":2995},[2978,8020,8021],{"class":2980,"line":6245},[2978,8022,3288],{"emptyLinePlaceholder":3287},[2978,8024,8025,8027,8029,8031,8033],{"class":2980,"line":6250},[2978,8026,7489],{"class":2995},[2978,8028,7492],{"class":4517},[2978,8030,3199],{"class":2995},[2978,8032,3788],{"class":3024},[2978,8034,7499],{"class":2995},[2978,8036,8037,8039,8041,8043,8045,8047,8049,8051,8053,8055,8057,8059,8061],{"class":2980,"line":6275},[2978,8038,4550],{"class":3180},[2978,8040,5484],{"class":4517},[2978,8042,4707],{"class":2995},[2978,8044,5489],{"class":3180},[2978,8046,3456],{"class":2995},[2978,8048,5494],{"class":4517},[2978,8050,7516],{"class":2995},[2978,8052,5499],{"class":3213},[2978,8054,4559],{"class":2995},[2978,8056,4562],{"class":3180},[2978,8058,4565],{"class":2995},[2978,8060,4568],{"class":3180},[2978,8062,4571],{"class":2995},[2978,8064,8065],{"class":2980,"line":6280},[2978,8066,3070],{"class":2995},[2964,8068,8069],{},[3074,8070,5285],{},[7206,8072,8073,8083,8090,8098],{},[3092,8074,8075,8080,8081],{},[3074,8076,8077],{},[2975,8078,8079],{},"[JsonPropertyName(\"_links\")]"," — HAL стандарт використовує ",[2975,8082,4383],{},[3092,8084,8085,8089],{},[3074,8086,8087],{},[2975,8088,4391],{}," — вбудовані ресурси (для expansion)",[3092,8091,8092,8097],{},[3074,8093,8094,8095],{},"Nullable ",[2975,8096,5499],{}," — можна вимкнути HATEOAS для певних endpoints",[3092,8099,8100,8103],{},[3074,8101,8102],{},"Окремі DTO"," — для кожного типу ресурсу",[3882,8105],{},[3329,8107,8109],{"id":8108},"крок-4-resource-expansion-infrastructure","Крок 4: Resource Expansion Infrastructure",[5325,8111,8113],{"id":8112},"expansionhelper","ExpansionHelper",[2964,8115,4499,8116,3087],{},[2975,8117,8118],{},"Helpers/ExpansionHelper.cs",[2968,8120,8122],{"className":4505,"code":8121,"language":4507,"meta":2973,"style":2973},"namespace BlogHateoasApi.Helpers;\n\npublic class ExpansionOptions\n{\n    public bool IncludeAuthor { get; set; }\n    public bool IncludeCategory { get; set; }\n    public bool IncludeComments { get; set; }\n\n    public static ExpansionOptions Parse(string? expand)\n    {\n        if (string.IsNullOrWhiteSpace(expand))\n            return new ExpansionOptions();\n\n        var parts = expand.Split(',', StringSplitOptions.RemoveEmptyEntries)\n            .Select(p => p.Trim().ToLower())\n            .ToHashSet();\n\n        return new ExpansionOptions\n        {\n            IncludeAuthor = parts.Contains(\"author\"),\n            IncludeCategory = parts.Contains(\"category\"),\n            IncludeComments = parts.Contains(\"comments\")\n        };\n    }\n}\n",[2975,8123,8124,8136,8140,8149,8153,8173,8192,8211,8215,8238,8242,8262,8274,8278,8311,8342,8351,8355,8363,8367,8389,8408,8427,8431,8435],{"__ignoreMap":2973},[2978,8125,8126,8128,8130,8132,8134],{"class":2980,"line":2981},[2978,8127,4514],{"class":3180},[2978,8129,4518],{"class":4517},[2978,8131,3223],{"class":2995},[2978,8133,5612],{"class":4517},[2978,8135,4526],{"class":2995},[2978,8137,8138],{"class":2980,"line":2999},[2978,8139,3288],{"emptyLinePlaceholder":3287},[2978,8141,8142,8144,8146],{"class":2980,"line":3016},[2978,8143,4535],{"class":3180},[2978,8145,4538],{"class":3180},[2978,8147,8148],{"class":4517}," ExpansionOptions\n",[2978,8150,8151],{"class":2980,"line":3030},[2978,8152,2996],{"class":2995},[2978,8154,8155,8157,8160,8163,8165,8167,8169,8171],{"class":2980,"line":3043},[2978,8156,4550],{"class":3180},[2978,8158,8159],{"class":3180}," bool",[2978,8161,8162],{"class":3213}," IncludeAuthor",[2978,8164,4559],{"class":2995},[2978,8166,4562],{"class":3180},[2978,8168,4565],{"class":2995},[2978,8170,4568],{"class":3180},[2978,8172,4571],{"class":2995},[2978,8174,8175,8177,8179,8182,8184,8186,8188,8190],{"class":2980,"line":3056},[2978,8176,4550],{"class":3180},[2978,8178,8159],{"class":3180},[2978,8180,8181],{"class":3213}," IncludeCategory",[2978,8183,4559],{"class":2995},[2978,8185,4562],{"class":3180},[2978,8187,4565],{"class":2995},[2978,8189,4568],{"class":3180},[2978,8191,4571],{"class":2995},[2978,8193,8194,8196,8198,8201,8203,8205,8207,8209],{"class":2980,"line":3067},[2978,8195,4550],{"class":3180},[2978,8197,8159],{"class":3180},[2978,8199,8200],{"class":3213}," IncludeComments",[2978,8202,4559],{"class":2995},[2978,8204,4562],{"class":3180},[2978,8206,4565],{"class":2995},[2978,8208,4568],{"class":3180},[2978,8210,4571],{"class":2995},[2978,8212,8213],{"class":2980,"line":3442},[2978,8214,3288],{"emptyLinePlaceholder":3287},[2978,8216,8217,8219,8221,8224,8227,8229,8231,8233,8236],{"class":2980,"line":3469},[2978,8218,4550],{"class":3180},[2978,8220,5625],{"class":3180},[2978,8222,8223],{"class":4517}," ExpansionOptions",[2978,8225,8226],{"class":3195}," Parse",[2978,8228,3199],{"class":2995},[2978,8230,5489],{"class":3180},[2978,8232,3101],{"class":2995},[2978,8234,8235],{"class":3213},"expand",[2978,8237,5704],{"class":2995},[2978,8239,8240],{"class":2980,"line":3495},[2978,8241,5709],{"class":2995},[2978,8243,8244,8246,8248,8250,8252,8255,8257,8259],{"class":2980,"line":3501},[2978,8245,6113],{"class":3191},[2978,8247,6116],{"class":2995},[2978,8249,5489],{"class":3180},[2978,8251,3223],{"class":2995},[2978,8253,8254],{"class":3195},"IsNullOrWhiteSpace",[2978,8256,3199],{"class":2995},[2978,8258,8235],{"class":3213},[2978,8260,8261],{"class":2995},"))\n",[2978,8263,8264,8267,8270,8272],{"class":2980,"line":3642},[2978,8265,8266],{"class":3191},"            return",[2978,8268,8269],{"class":3180}," new",[2978,8271,8223],{"class":4517},[2978,8273,4733],{"class":2995},[2978,8275,8276],{"class":2980,"line":3674},[2978,8277,3288],{"emptyLinePlaceholder":3287},[2978,8279,8280,8282,8285,8287,8289,8291,8294,8296,8299,8301,8304,8306,8309],{"class":2980,"line":3680},[2978,8281,5714],{"class":3180},[2978,8283,8284],{"class":3213}," parts",[2978,8286,3188],{"class":2995},[2978,8288,8235],{"class":3213},[2978,8290,3223],{"class":2995},[2978,8292,8293],{"class":3195},"Split",[2978,8295,3199],{"class":2995},[2978,8297,8298],{"class":3024},"','",[2978,8300,3456],{"class":2995},[2978,8302,8303],{"class":3213},"StringSplitOptions",[2978,8305,3223],{"class":2995},[2978,8307,8308],{"class":3213},"RemoveEmptyEntries",[2978,8310,5704],{"class":2995},[2978,8312,8313,8316,8319,8321,8323,8326,8328,8330,8333,8336,8339],{"class":2980,"line":3686},[2978,8314,8315],{"class":2995},"            .",[2978,8317,8318],{"class":3195},"Select",[2978,8320,3199],{"class":2995},[2978,8322,2964],{"class":3213},[2978,8324,8325],{"class":2995}," => ",[2978,8327,2964],{"class":3213},[2978,8329,3223],{"class":2995},[2978,8331,8332],{"class":3195},"Trim",[2978,8334,8335],{"class":2995},"().",[2978,8337,8338],{"class":3195},"ToLower",[2978,8340,8341],{"class":2995},"())\n",[2978,8343,8344,8346,8349],{"class":2980,"line":3699},[2978,8345,8315],{"class":2995},[2978,8347,8348],{"class":3195},"ToHashSet",[2978,8350,4733],{"class":2995},[2978,8352,8353],{"class":2980,"line":4367},[2978,8354,3288],{"emptyLinePlaceholder":3287},[2978,8356,8357,8359,8361],{"class":2980,"line":4825},[2978,8358,6615],{"class":3191},[2978,8360,8269],{"class":3180},[2978,8362,8148],{"class":4517},[2978,8364,8365],{"class":2980,"line":4836},[2978,8366,5739],{"class":2995},[2978,8368,8369,8372,8374,8377,8379,8382,8384,8386],{"class":2980,"line":4841},[2978,8370,8371],{"class":3213},"            IncludeAuthor",[2978,8373,3188],{"class":2995},[2978,8375,8376],{"class":3213},"parts",[2978,8378,3223],{"class":2995},[2978,8380,8381],{"class":3195},"Contains",[2978,8383,3199],{"class":2995},[2978,8385,3632],{"class":3024},[2978,8387,8388],{"class":2995},"),\n",[2978,8390,8391,8394,8396,8398,8400,8402,8404,8406],{"class":2980,"line":4849},[2978,8392,8393],{"class":3213},"            IncludeCategory",[2978,8395,3188],{"class":2995},[2978,8397,8376],{"class":3213},[2978,8399,3223],{"class":2995},[2978,8401,8381],{"class":3195},[2978,8403,3199],{"class":2995},[2978,8405,6014],{"class":3024},[2978,8407,8388],{"class":2995},[2978,8409,8410,8413,8415,8417,8419,8421,8423,8425],{"class":2980,"line":4857},[2978,8411,8412],{"class":3213},"            IncludeComments",[2978,8414,3188],{"class":2995},[2978,8416,8376],{"class":3213},[2978,8418,3223],{"class":2995},[2978,8420,8381],{"class":3195},[2978,8422,3199],{"class":2995},[2978,8424,5929],{"class":3024},[2978,8426,5704],{"class":2995},[2978,8428,8429],{"class":2980,"line":4863},[2978,8430,6099],{"class":2995},[2978,8432,8433],{"class":2980,"line":4868},[2978,8434,6625],{"class":2995},[2978,8436,8437],{"class":2980,"line":4873},[2978,8438,3070],{"class":2995},[2964,8440,8441],{},[3074,8442,8443],{},"Використання:",[2968,8445,8447],{"className":4505,"code":8446,"language":4507,"meta":2973,"style":2973},"var options = ExpansionOptions.Parse(\"author,comments\");\n// options.IncludeAuthor = true\n// options.IncludeComments = true\n// options.IncludeCategory = false\n",[2975,8448,8449,8475,8480,8485],{"__ignoreMap":2973},[2978,8450,8451,8454,8457,8459,8462,8464,8467,8469,8472],{"class":2980,"line":2981},[2978,8452,8453],{"class":3180},"var",[2978,8455,8456],{"class":3213}," options",[2978,8458,3188],{"class":2995},[2978,8460,8461],{"class":3213},"ExpansionOptions",[2978,8463,3223],{"class":2995},[2978,8465,8466],{"class":3195},"Parse",[2978,8468,3199],{"class":2995},[2978,8470,8471],{"class":3024},"\"author,comments\"",[2978,8473,8474],{"class":2995},");\n",[2978,8476,8477],{"class":2980,"line":2999},[2978,8478,8479],{"class":3174},"// options.IncludeAuthor = true\n",[2978,8481,8482],{"class":2980,"line":3016},[2978,8483,8484],{"class":3174},"// options.IncludeComments = true\n",[2978,8486,8487],{"class":2980,"line":3030},[2978,8488,8489],{"class":3174},"// options.IncludeCategory = false\n",[3882,8491],{},[3329,8493,8495],{"id":8494},"крок-5-dbcontext-та-seed-data","Крок 5: DbContext та Seed Data",[2964,8497,4499,8498,3087],{},[2975,8499,8500],{},"Data/BlogDbContext.cs",[2968,8502,8504],{"className":4505,"code":8503,"language":4507,"meta":2973,"style":2973},"using Microsoft.EntityFrameworkCore;\nusing BlogHateoasApi.Models;\n\nnamespace BlogHateoasApi.Data;\n\npublic class BlogDbContext : DbContext\n{\n    public BlogDbContext(DbContextOptions\u003CBlogDbContext> options) : base(options) { }\n\n    public DbSet\u003CArticle> Articles => Set\u003CArticle>();\n    public DbSet\u003CAuthor> Authors => Set\u003CAuthor>();\n    public DbSet\u003CCategory> Categories => Set\u003CCategory>();\n    public DbSet\u003CComment> Comments => Set\u003CComment>();\n\n    protected override void OnModelCreating(ModelBuilder modelBuilder)\n    {\n        // Seed Authors\n        modelBuilder.Entity\u003CAuthor>().HasData(\n            new Author { Id = 1, Name = \"John Doe\", Email = \"john@example.com\", Bio = \"Senior Developer\" },\n            new Author { Id = 2, Name = \"Jane Smith\", Email = \"jane@example.com\", Bio = \"Tech Writer\" }\n        );\n\n        // Seed Categories\n        modelBuilder.Entity\u003CCategory>().HasData(\n            new Category { Id = 1, Name = \"Technology\", Description = \"Tech articles\" },\n            new Category { Id = 2, Name = \"Programming\", Description = \"Programming tutorials\" }\n        );\n\n        // Seed Articles\n        modelBuilder.Entity\u003CArticle>().HasData(\n            new Article\n            {\n                Id = 1,\n                Title = \"Introduction to ASP.NET Core\",\n                Content = \"ASP.NET Core is a cross-platform framework...\",\n                AuthorId = 1,\n                CategoryId = 2,\n                Status = ArticleStatus.Published,\n                PublishedAt = DateTime.UtcNow.AddDays(-10)\n            },\n            new Article\n            {\n                Id = 2,\n                Title = \"Getting Started with HATEOAS\",\n                Content = \"HATEOAS is a constraint of REST...\",\n                AuthorId = 2,\n                CategoryId = 1,\n                Status = ArticleStatus.Draft,\n                PublishedAt = DateTime.UtcNow.AddDays(-5)\n            },\n            new Article\n            {\n                Id = 3,\n                Title = \"REST API Best Practices\",\n                Content = \"Building great APIs requires...\",\n                AuthorId = 1,\n                CategoryId = 2,\n                Status = ArticleStatus.Published,\n                PublishedAt = DateTime.UtcNow.AddDays(-3)\n            }\n        );\n\n        // Seed Comments\n        modelBuilder.Entity\u003CComment>().HasData(\n            new Comment { Id = 1, ArticleId = 1, Text = \"Great article!\", AuthorName = \"Bob\", CreatedAt = DateTime.UtcNow.AddDays(-9) },\n            new Comment { Id = 2, ArticleId = 1, Text = \"Very helpful, thanks!\", AuthorName = \"Alice\", CreatedAt = DateTime.UtcNow.AddDays(-8) },\n            new Comment { Id = 3, ArticleId = 3, Text = \"Looking forward to more!\", AuthorName = \"Charlie\", CreatedAt = DateTime.UtcNow.AddDays(-2) }\n        );\n    }\n}\n",[2975,8505,8506,8519,8531,8535,8548,8552,8567,8571,8605,8609,8636,8661,8686,8710,8714,8738,8742,8747,8769,8815,8858,8863,8867,8872,8890,8924,8958,8962,8966,8971,8989,8995,8999,9010,9020,9032,9043,9054,9069,9095,9099,9105,9109,9119,9130,9141,9151,9161,9175,9197,9201,9207,9211,9221,9232,9243,9253,9263,9277,9299,9303,9307,9311,9316,9334,9400,9463,9526,9530,9534],{"__ignoreMap":2973},[2978,8507,8508,8510,8512,8514,8517],{"class":2980,"line":2981},[2978,8509,5570],{"class":3191},[2978,8511,5585],{"class":4517},[2978,8513,3223],{"class":2995},[2978,8515,8516],{"class":4517},"EntityFrameworkCore",[2978,8518,4526],{"class":2995},[2978,8520,8521,8523,8525,8527,8529],{"class":2980,"line":2999},[2978,8522,5570],{"class":3191},[2978,8524,4518],{"class":4517},[2978,8526,3223],{"class":2995},[2978,8528,4523],{"class":4517},[2978,8530,4526],{"class":2995},[2978,8532,8533],{"class":2980,"line":3016},[2978,8534,3288],{"emptyLinePlaceholder":3287},[2978,8536,8537,8539,8541,8543,8546],{"class":2980,"line":3030},[2978,8538,4514],{"class":3180},[2978,8540,4518],{"class":4517},[2978,8542,3223],{"class":2995},[2978,8544,8545],{"class":4517},"Data",[2978,8547,4526],{"class":2995},[2978,8549,8550],{"class":2980,"line":3043},[2978,8551,3288],{"emptyLinePlaceholder":3287},[2978,8553,8554,8556,8558,8561,8564],{"class":2980,"line":3056},[2978,8555,4535],{"class":3180},[2978,8557,4538],{"class":3180},[2978,8559,8560],{"class":4517}," BlogDbContext",[2978,8562,8563],{"class":2995}," : ",[2978,8565,8566],{"class":4517},"DbContext\n",[2978,8568,8569],{"class":2980,"line":3067},[2978,8570,2996],{"class":2995},[2978,8572,8573,8575,8577,8579,8582,8584,8587,8589,8592,8595,8598,8600,8602],{"class":2980,"line":3442},[2978,8574,4550],{"class":3180},[2978,8576,8560],{"class":3195},[2978,8578,3199],{"class":2995},[2978,8580,8581],{"class":4517},"DbContextOptions",[2978,8583,4707],{"class":2995},[2978,8585,8586],{"class":4517},"BlogDbContext",[2978,8588,4713],{"class":2995},[2978,8590,8591],{"class":3213},"options",[2978,8593,8594],{"class":2995},") : ",[2978,8596,8597],{"class":3180},"base",[2978,8599,3199],{"class":2995},[2978,8601,8591],{"class":3213},[2978,8603,8604],{"class":2995},") { }\n",[2978,8606,8607],{"class":2980,"line":3469},[2978,8608,3288],{"emptyLinePlaceholder":3287},[2978,8610,8611,8613,8616,8618,8620,8622,8624,8626,8629,8631,8633],{"class":2980,"line":3495},[2978,8612,4550],{"class":3180},[2978,8614,8615],{"class":4517}," DbSet",[2978,8617,4707],{"class":2995},[2978,8619,4982],{"class":4517},[2978,8621,4713],{"class":2995},[2978,8623,4987],{"class":3213},[2978,8625,8325],{"class":2995},[2978,8627,8628],{"class":3195},"Set",[2978,8630,4707],{"class":2995},[2978,8632,4982],{"class":4517},[2978,8634,8635],{"class":2995},">();\n",[2978,8637,8638,8640,8642,8644,8646,8648,8651,8653,8655,8657,8659],{"class":2980,"line":3501},[2978,8639,4550],{"class":3180},[2978,8641,8615],{"class":4517},[2978,8643,4707],{"class":2995},[2978,8645,4646],{"class":4517},[2978,8647,4713],{"class":2995},[2978,8649,8650],{"class":3213},"Authors",[2978,8652,8325],{"class":2995},[2978,8654,8628],{"class":3195},[2978,8656,4707],{"class":2995},[2978,8658,4646],{"class":4517},[2978,8660,8635],{"class":2995},[2978,8662,8663,8665,8667,8669,8671,8673,8676,8678,8680,8682,8684],{"class":2980,"line":3642},[2978,8664,4550],{"class":3180},[2978,8666,8615],{"class":4517},[2978,8668,4707],{"class":2995},[2978,8670,4687],{"class":4517},[2978,8672,4713],{"class":2995},[2978,8674,8675],{"class":3213},"Categories",[2978,8677,8325],{"class":2995},[2978,8679,8628],{"class":3195},[2978,8681,4707],{"class":2995},[2978,8683,4687],{"class":4517},[2978,8685,8635],{"class":2995},[2978,8687,8688,8690,8692,8694,8696,8698,8700,8702,8704,8706,8708],{"class":2980,"line":3674},[2978,8689,4550],{"class":3180},[2978,8691,8615],{"class":4517},[2978,8693,4707],{"class":2995},[2978,8695,4710],{"class":4517},[2978,8697,4713],{"class":2995},[2978,8699,4716],{"class":3213},[2978,8701,8325],{"class":2995},[2978,8703,8628],{"class":3195},[2978,8705,4707],{"class":2995},[2978,8707,4710],{"class":4517},[2978,8709,8635],{"class":2995},[2978,8711,8712],{"class":2980,"line":3680},[2978,8713,3288],{"emptyLinePlaceholder":3287},[2978,8715,8716,8719,8722,8725,8728,8730,8733,8736],{"class":2980,"line":3686},[2978,8717,8718],{"class":3180},"    protected",[2978,8720,8721],{"class":3180}," override",[2978,8723,8724],{"class":3180}," void",[2978,8726,8727],{"class":3195}," OnModelCreating",[2978,8729,3199],{"class":2995},[2978,8731,8732],{"class":4517},"ModelBuilder",[2978,8734,8735],{"class":3213}," modelBuilder",[2978,8737,5704],{"class":2995},[2978,8739,8740],{"class":2980,"line":3699},[2978,8741,5709],{"class":2995},[2978,8743,8744],{"class":2980,"line":4367},[2978,8745,8746],{"class":3174},"        // Seed Authors\n",[2978,8748,8749,8752,8754,8757,8759,8761,8764,8767],{"class":2980,"line":4825},[2978,8750,8751],{"class":3213},"        modelBuilder",[2978,8753,3223],{"class":2995},[2978,8755,8756],{"class":3195},"Entity",[2978,8758,4707],{"class":2995},[2978,8760,4646],{"class":4517},[2978,8762,8763],{"class":2995},">().",[2978,8765,8766],{"class":3195},"HasData",[2978,8768,5658],{"class":2995},[2978,8770,8771,8774,8776,8778,8781,8783,8785,8787,8790,8792,8794,8796,8799,8801,8804,8806,8808,8810,8813],{"class":2980,"line":4836},[2978,8772,8773],{"class":3180},"            new",[2978,8775,4641],{"class":4517},[2978,8777,4559],{"class":2995},[2978,8779,8780],{"class":3213},"Id",[2978,8782,3188],{"class":2995},[2978,8784,3617],{"class":3009},[2978,8786,3456],{"class":2995},[2978,8788,8789],{"class":3213},"Name",[2978,8791,3188],{"class":2995},[2978,8793,3580],{"class":3024},[2978,8795,3456],{"class":2995},[2978,8797,8798],{"class":3213},"Email",[2978,8800,3188],{"class":2995},[2978,8802,8803],{"class":3024},"\"john@example.com\"",[2978,8805,3456],{"class":2995},[2978,8807,4960],{"class":3213},[2978,8809,3188],{"class":2995},[2978,8811,8812],{"class":3024},"\"Senior Developer\"",[2978,8814,3407],{"class":2995},[2978,8816,8817,8819,8821,8823,8825,8827,8829,8831,8833,8835,8838,8840,8842,8844,8847,8849,8851,8853,8856],{"class":2980,"line":4841},[2978,8818,8773],{"class":3180},[2978,8820,4641],{"class":4517},[2978,8822,4559],{"class":2995},[2978,8824,8780],{"class":3213},[2978,8826,3188],{"class":2995},[2978,8828,3651],{"class":3009},[2978,8830,3456],{"class":2995},[2978,8832,8789],{"class":3213},[2978,8834,3188],{"class":2995},[2978,8836,8837],{"class":3024},"\"Jane Smith\"",[2978,8839,3456],{"class":2995},[2978,8841,8798],{"class":3213},[2978,8843,3188],{"class":2995},[2978,8845,8846],{"class":3024},"\"jane@example.com\"",[2978,8848,3456],{"class":2995},[2978,8850,4960],{"class":3213},[2978,8852,3188],{"class":2995},[2978,8854,8855],{"class":3024},"\"Tech Writer\"",[2978,8857,3492],{"class":2995},[2978,8859,8860],{"class":2980,"line":4849},[2978,8861,8862],{"class":2995},"        );\n",[2978,8864,8865],{"class":2980,"line":4857},[2978,8866,3288],{"emptyLinePlaceholder":3287},[2978,8868,8869],{"class":2980,"line":4863},[2978,8870,8871],{"class":3174},"        // Seed Categories\n",[2978,8873,8874,8876,8878,8880,8882,8884,8886,8888],{"class":2980,"line":4868},[2978,8875,8751],{"class":3213},[2978,8877,3223],{"class":2995},[2978,8879,8756],{"class":3195},[2978,8881,4707],{"class":2995},[2978,8883,4687],{"class":4517},[2978,8885,8763],{"class":2995},[2978,8887,8766],{"class":3195},[2978,8889,5658],{"class":2995},[2978,8891,8892,8894,8896,8898,8900,8902,8904,8906,8908,8910,8913,8915,8917,8919,8922],{"class":2980,"line":4873},[2978,8893,8773],{"class":3180},[2978,8895,4682],{"class":4517},[2978,8897,4559],{"class":2995},[2978,8899,8780],{"class":3213},[2978,8901,3188],{"class":2995},[2978,8903,3617],{"class":3009},[2978,8905,3456],{"class":2995},[2978,8907,8789],{"class":3213},[2978,8909,3188],{"class":2995},[2978,8911,8912],{"class":3024},"\"Technology\"",[2978,8914,3456],{"class":2995},[2978,8916,5078],{"class":3213},[2978,8918,3188],{"class":2995},[2978,8920,8921],{"class":3024},"\"Tech articles\"",[2978,8923,3407],{"class":2995},[2978,8925,8926,8928,8930,8932,8934,8936,8938,8940,8942,8944,8947,8949,8951,8953,8956],{"class":2980,"line":4883},[2978,8927,8773],{"class":3180},[2978,8929,4682],{"class":4517},[2978,8931,4559],{"class":2995},[2978,8933,8780],{"class":3213},[2978,8935,3188],{"class":2995},[2978,8937,3651],{"class":3009},[2978,8939,3456],{"class":2995},[2978,8941,8789],{"class":3213},[2978,8943,3188],{"class":2995},[2978,8945,8946],{"class":3024},"\"Programming\"",[2978,8948,3456],{"class":2995},[2978,8950,5078],{"class":3213},[2978,8952,3188],{"class":2995},[2978,8954,8955],{"class":3024},"\"Programming tutorials\"",[2978,8957,3492],{"class":2995},[2978,8959,8960],{"class":2980,"line":4888},[2978,8961,8862],{"class":2995},[2978,8963,8964],{"class":2980,"line":4907},[2978,8965,3288],{"emptyLinePlaceholder":3287},[2978,8967,8968],{"class":2980,"line":4929},[2978,8969,8970],{"class":3174},"        // Seed Articles\n",[2978,8972,8973,8975,8977,8979,8981,8983,8985,8987],{"class":2980,"line":4951},[2978,8974,8751],{"class":3213},[2978,8976,3223],{"class":2995},[2978,8978,8756],{"class":3195},[2978,8980,4707],{"class":2995},[2978,8982,4982],{"class":4517},[2978,8984,8763],{"class":2995},[2978,8986,8766],{"class":3195},[2978,8988,5658],{"class":2995},[2978,8990,8991,8993],{"class":2980,"line":4973},[2978,8992,8773],{"class":3180},[2978,8994,4541],{"class":4517},[2978,8996,8997],{"class":2980,"line":5004},[2978,8998,5758],{"class":2995},[2978,9000,9001,9004,9006,9008],{"class":2980,"line":5009},[2978,9002,9003],{"class":3213},"                Id",[2978,9005,3188],{"class":2995},[2978,9007,3617],{"class":3009},[2978,9009,3013],{"class":2995},[2978,9011,9012,9014,9016,9018],{"class":2980,"line":5014},[2978,9013,5827],{"class":3213},[2978,9015,3188],{"class":2995},[2978,9017,3025],{"class":3024},[2978,9019,3013],{"class":2995},[2978,9021,9022,9025,9027,9030],{"class":2980,"line":5024},[2978,9023,9024],{"class":3213},"                Content",[2978,9026,3188],{"class":2995},[2978,9028,9029],{"class":3024},"\"ASP.NET Core is a cross-platform framework...\"",[2978,9031,3013],{"class":2995},[2978,9033,9034,9037,9039,9041],{"class":2980,"line":5029},[2978,9035,9036],{"class":3213},"                AuthorId",[2978,9038,3188],{"class":2995},[2978,9040,3617],{"class":3009},[2978,9042,3013],{"class":2995},[2978,9044,9045,9048,9050,9052],{"class":2980,"line":5048},[2978,9046,9047],{"class":3213},"                CategoryId",[2978,9049,3188],{"class":2995},[2978,9051,3651],{"class":3009},[2978,9053,3013],{"class":2995},[2978,9055,9056,9059,9061,9063,9065,9067],{"class":2980,"line":5069},[2978,9057,9058],{"class":3213},"                Status",[2978,9060,3188],{"class":2995},[2978,9062,4807],{"class":3213},[2978,9064,3223],{"class":2995},[2978,9066,6498],{"class":3213},[2978,9068,3013],{"class":2995},[2978,9070,9071,9074,9076,9078,9080,9082,9084,9087,9090,9093],{"class":2980,"line":5091},[2978,9072,9073],{"class":3213},"                PublishedAt",[2978,9075,3188],{"class":2995},[2978,9077,4756],{"class":3213},[2978,9079,3223],{"class":2995},[2978,9081,4761],{"class":3213},[2978,9083,3223],{"class":2995},[2978,9085,9086],{"class":3195},"AddDays",[2978,9088,9089],{"class":2995},"(-",[2978,9091,9092],{"class":3009},"10",[2978,9094,5704],{"class":2995},[2978,9096,9097],{"class":2980,"line":5120},[2978,9098,5837],{"class":2995},[2978,9100,9101,9103],{"class":2980,"line":5125},[2978,9102,8773],{"class":3180},[2978,9104,4541],{"class":4517},[2978,9106,9107],{"class":2980,"line":5130},[2978,9108,5758],{"class":2995},[2978,9110,9111,9113,9115,9117],{"class":2980,"line":5140},[2978,9112,9003],{"class":3213},[2978,9114,3188],{"class":2995},[2978,9116,3651],{"class":3009},[2978,9118,3013],{"class":2995},[2978,9120,9121,9123,9125,9128],{"class":2980,"line":5145},[2978,9122,5827],{"class":3213},[2978,9124,3188],{"class":2995},[2978,9126,9127],{"class":3024},"\"Getting Started with HATEOAS\"",[2978,9129,3013],{"class":2995},[2978,9131,9132,9134,9136,9139],{"class":2980,"line":5164},[2978,9133,9024],{"class":3213},[2978,9135,3188],{"class":2995},[2978,9137,9138],{"class":3024},"\"HATEOAS is a constraint of REST...\"",[2978,9140,3013],{"class":2995},[2978,9142,9143,9145,9147,9149],{"class":2980,"line":5186},[2978,9144,9036],{"class":3213},[2978,9146,3188],{"class":2995},[2978,9148,3651],{"class":3009},[2978,9150,3013],{"class":2995},[2978,9152,9153,9155,9157,9159],{"class":2980,"line":5208},[2978,9154,9047],{"class":3213},[2978,9156,3188],{"class":2995},[2978,9158,3617],{"class":3009},[2978,9160,3013],{"class":2995},[2978,9162,9163,9165,9167,9169,9171,9173],{"class":2980,"line":5228},[2978,9164,9058],{"class":3213},[2978,9166,3188],{"class":2995},[2978,9168,4807],{"class":3213},[2978,9170,3223],{"class":2995},[2978,9172,4812],{"class":3213},[2978,9174,3013],{"class":2995},[2978,9176,9177,9179,9181,9183,9185,9187,9189,9191,9193,9195],{"class":2980,"line":5250},[2978,9178,9073],{"class":3213},[2978,9180,3188],{"class":2995},[2978,9182,4756],{"class":3213},[2978,9184,3223],{"class":2995},[2978,9186,4761],{"class":3213},[2978,9188,3223],{"class":2995},[2978,9190,9086],{"class":3195},[2978,9192,9089],{"class":2995},[2978,9194,3010],{"class":3009},[2978,9196,5704],{"class":2995},[2978,9198,9199],{"class":2980,"line":5278},[2978,9200,5837],{"class":2995},[2978,9202,9203,9205],{"class":2980,"line":6164},[2978,9204,8773],{"class":3180},[2978,9206,4541],{"class":4517},[2978,9208,9209],{"class":2980,"line":6200},[2978,9210,5758],{"class":2995},[2978,9212,9213,9215,9217,9219],{"class":2980,"line":6211},[2978,9214,9003],{"class":3213},[2978,9216,3188],{"class":2995},[2978,9218,3051],{"class":3009},[2978,9220,3013],{"class":2995},[2978,9222,9223,9225,9227,9230],{"class":2980,"line":6223},[2978,9224,5827],{"class":3213},[2978,9226,3188],{"class":2995},[2978,9228,9229],{"class":3024},"\"REST API Best Practices\"",[2978,9231,3013],{"class":2995},[2978,9233,9234,9236,9238,9241],{"class":2980,"line":6233},[2978,9235,9024],{"class":3213},[2978,9237,3188],{"class":2995},[2978,9239,9240],{"class":3024},"\"Building great APIs requires...\"",[2978,9242,3013],{"class":2995},[2978,9244,9245,9247,9249,9251],{"class":2980,"line":6239},[2978,9246,9036],{"class":3213},[2978,9248,3188],{"class":2995},[2978,9250,3617],{"class":3009},[2978,9252,3013],{"class":2995},[2978,9254,9255,9257,9259,9261],{"class":2980,"line":6245},[2978,9256,9047],{"class":3213},[2978,9258,3188],{"class":2995},[2978,9260,3651],{"class":3009},[2978,9262,3013],{"class":2995},[2978,9264,9265,9267,9269,9271,9273,9275],{"class":2980,"line":6250},[2978,9266,9058],{"class":3213},[2978,9268,3188],{"class":2995},[2978,9270,4807],{"class":3213},[2978,9272,3223],{"class":2995},[2978,9274,6498],{"class":3213},[2978,9276,3013],{"class":2995},[2978,9278,9279,9281,9283,9285,9287,9289,9291,9293,9295,9297],{"class":2980,"line":6275},[2978,9280,9073],{"class":3213},[2978,9282,3188],{"class":2995},[2978,9284,4756],{"class":3213},[2978,9286,3223],{"class":2995},[2978,9288,4761],{"class":3213},[2978,9290,3223],{"class":2995},[2978,9292,9086],{"class":3195},[2978,9294,9089],{"class":2995},[2978,9296,3051],{"class":3009},[2978,9298,5704],{"class":2995},[2978,9300,9301],{"class":2980,"line":6280},[2978,9302,6094],{"class":2995},[2978,9304,9305],{"class":2980,"line":6296},[2978,9306,8862],{"class":2995},[2978,9308,9309],{"class":2980,"line":6301},[2978,9310,3288],{"emptyLinePlaceholder":3287},[2978,9312,9313],{"class":2980,"line":6337},[2978,9314,9315],{"class":3174},"        // Seed Comments\n",[2978,9317,9318,9320,9322,9324,9326,9328,9330,9332],{"class":2980,"line":6348},[2978,9319,8751],{"class":3213},[2978,9321,3223],{"class":2995},[2978,9323,8756],{"class":3195},[2978,9325,4707],{"class":2995},[2978,9327,4710],{"class":4517},[2978,9329,8763],{"class":2995},[2978,9331,8766],{"class":3195},[2978,9333,5658],{"class":2995},[2978,9335,9336,9338,9341,9343,9345,9347,9349,9351,9354,9356,9358,9360,9362,9364,9366,9368,9371,9373,9375,9377,9380,9382,9384,9386,9388,9390,9392,9394,9397],{"class":2980,"line":6359},[2978,9337,8773],{"class":3180},[2978,9339,9340],{"class":4517}," Comment",[2978,9342,4559],{"class":2995},[2978,9344,8780],{"class":3213},[2978,9346,3188],{"class":2995},[2978,9348,3617],{"class":3009},[2978,9350,3456],{"class":2995},[2978,9352,9353],{"class":3213},"ArticleId",[2978,9355,3188],{"class":2995},[2978,9357,3617],{"class":3009},[2978,9359,3456],{"class":2995},[2978,9361,7275],{"class":3213},[2978,9363,3188],{"class":2995},[2978,9365,3627],{"class":3024},[2978,9367,3456],{"class":2995},[2978,9369,9370],{"class":3213},"AuthorName",[2978,9372,3188],{"class":2995},[2978,9374,3669],{"class":3024},[2978,9376,3456],{"class":2995},[2978,9378,9379],{"class":3213},"CreatedAt",[2978,9381,3188],{"class":2995},[2978,9383,4756],{"class":3213},[2978,9385,3223],{"class":2995},[2978,9387,4761],{"class":3213},[2978,9389,3223],{"class":2995},[2978,9391,9086],{"class":3195},[2978,9393,9089],{"class":2995},[2978,9395,9396],{"class":3009},"9",[2978,9398,9399],{"class":2995},") },\n",[2978,9401,9402,9404,9406,9408,9410,9412,9414,9416,9418,9420,9422,9424,9426,9428,9431,9433,9435,9437,9440,9442,9444,9446,9448,9450,9452,9454,9456,9458,9461],{"class":2980,"line":6369},[2978,9403,8773],{"class":3180},[2978,9405,9340],{"class":4517},[2978,9407,4559],{"class":2995},[2978,9409,8780],{"class":3213},[2978,9411,3188],{"class":2995},[2978,9413,3651],{"class":3009},[2978,9415,3456],{"class":2995},[2978,9417,9353],{"class":3213},[2978,9419,3188],{"class":2995},[2978,9421,3617],{"class":3009},[2978,9423,3456],{"class":2995},[2978,9425,7275],{"class":3213},[2978,9427,3188],{"class":2995},[2978,9429,9430],{"class":3024},"\"Very helpful, thanks!\"",[2978,9432,3456],{"class":2995},[2978,9434,9370],{"class":3213},[2978,9436,3188],{"class":2995},[2978,9438,9439],{"class":3024},"\"Alice\"",[2978,9441,3456],{"class":2995},[2978,9443,9379],{"class":3213},[2978,9445,3188],{"class":2995},[2978,9447,4756],{"class":3213},[2978,9449,3223],{"class":2995},[2978,9451,4761],{"class":3213},[2978,9453,3223],{"class":2995},[2978,9455,9086],{"class":3195},[2978,9457,9089],{"class":2995},[2978,9459,9460],{"class":3009},"8",[2978,9462,9399],{"class":2995},[2978,9464,9465,9467,9469,9471,9473,9475,9477,9479,9481,9483,9485,9487,9489,9491,9494,9496,9498,9500,9503,9505,9507,9509,9511,9513,9515,9517,9519,9521,9523],{"class":2980,"line":6374},[2978,9466,8773],{"class":3180},[2978,9468,9340],{"class":4517},[2978,9470,4559],{"class":2995},[2978,9472,8780],{"class":3213},[2978,9474,3188],{"class":2995},[2978,9476,3051],{"class":3009},[2978,9478,3456],{"class":2995},[2978,9480,9353],{"class":3213},[2978,9482,3188],{"class":2995},[2978,9484,3051],{"class":3009},[2978,9486,3456],{"class":2995},[2978,9488,7275],{"class":3213},[2978,9490,3188],{"class":2995},[2978,9492,9493],{"class":3024},"\"Looking forward to more!\"",[2978,9495,3456],{"class":2995},[2978,9497,9370],{"class":3213},[2978,9499,3188],{"class":2995},[2978,9501,9502],{"class":3024},"\"Charlie\"",[2978,9504,3456],{"class":2995},[2978,9506,9379],{"class":3213},[2978,9508,3188],{"class":2995},[2978,9510,4756],{"class":3213},[2978,9512,3223],{"class":2995},[2978,9514,4761],{"class":3213},[2978,9516,3223],{"class":2995},[2978,9518,9086],{"class":3195},[2978,9520,9089],{"class":2995},[2978,9522,3651],{"class":3009},[2978,9524,9525],{"class":2995},") }\n",[2978,9527,9528],{"class":2980,"line":6379},[2978,9529,8862],{"class":2995},[2978,9531,9532],{"class":2980,"line":6395},[2978,9533,6625],{"class":2995},[2978,9535,9536],{"class":2980,"line":6400},[2978,9537,3070],{"class":2995},[3882,9539],{},[3329,9541,9543],{"id":9542},"крок-6-articles-controller-з-hateoas","Крок 6: Articles Controller з HATEOAS",[2964,9545,4499,9546,3087],{},[2975,9547,9548],{},"Controllers/ArticlesController.cs",[2968,9550,9552],{"className":4505,"code":9551,"language":4507,"meta":2973,"style":2973},"using Microsoft.AspNetCore.Mvc;\nusing Microsoft.EntityFrameworkCore;\nusing BlogHateoasApi.Data;\nusing BlogHateoasApi.Models;\nusing BlogHateoasApi.Models.DTOs;\nusing BlogHateoasApi.Helpers;\n\nnamespace BlogHateoasApi.Controllers;\n\n[ApiController]\n[Route(\"api/[controller]\")]\npublic class ArticlesController : ControllerBase\n{\n    private readonly BlogDbContext _db;\n    private readonly ILogger\u003CArticlesController> _logger;\n    private readonly IUrlHelper _urlHelper;\n\n    public ArticlesController(\n        BlogDbContext db,\n        ILogger\u003CArticlesController> logger,\n        IUrlHelperFactory urlHelperFactory,\n        IActionContextAccessor actionContextAccessor)\n    {\n        _db = db;\n        _logger = logger;\n        _urlHelper = urlHelperFactory.GetUrlHelper(actionContextAccessor.ActionContext!);\n    }\n\n    /// \u003Csummary>\n    /// Отримати статтю за ID з HATEOAS links та опціональним expansion\n    /// \u003C/summary>\n    /// \u003Cparam name=\"id\">ID статті\u003C/param>\n    /// \u003Cparam name=\"expand\">Ресурси для expansion (author,category,comments)\u003C/param>\n    [HttpGet(\"{id:int}\", Name = \"GetArticleById\")]\n    [ProducesResponseType(typeof(ArticleDto), StatusCodes.Status200OK)]\n    [ProducesResponseType(StatusCodes.Status404NotFound)]\n    public async Task\u003CActionResult\u003CArticleDto>> GetById(\n        int id,\n        [FromQuery] string? expand = null)\n    {\n        var expansionOptions = ExpansionOptions.Parse(expand);\n\n        // Базовий query\n        var query = _db.Articles.AsQueryable();\n\n        // Eager loading залежно від expansion\n        if (expansionOptions.IncludeAuthor)\n            query = query.Include(a => a.Author);\n\n        if (expansionOptions.IncludeCategory)\n            query = query.Include(a => a.Category);\n\n        if (expansionOptions.IncludeComments)\n            query = query.Include(a => a.Comments);\n\n        var article = await query.FirstOrDefaultAsync(a => a.Id == id);\n\n        if (article is null)\n            return NotFound();\n\n        // Мапінг до DTO\n        var dto = MapToDto(article, expansionOptions);\n\n        // Генерація HATEOAS links\n        dto.Links = LinkGeneratorHelper.GenerateArticleLinks(\n            article.Id,\n            article.Status,\n            _urlHelper,\n            isOwner: true); // У production перевіряти реального користувача\n\n        // Заміна placeholders у links\n        dto.Links[\"author\"].Href = dto.Links[\"author\"].Href.Replace(\"{authorId}\", article.AuthorId.ToString());\n        dto.Links[\"category\"].Href = dto.Links[\"category\"].Href.Replace(\"{categoryId}\", article.CategoryId.ToString());\n\n        return Ok(dto);\n    }\n\n    /// \u003Csummary>\n    /// Отримати всі статті з пагінацією та HATEOAS\n    /// \u003C/summary>\n    [HttpGet(Name = \"GetArticles\")]\n    [ProducesResponseType(typeof(object), StatusCodes.Status200OK)]\n    public async Task\u003CIActionResult> GetAll(\n        [FromQuery] int page = 1,\n        [FromQuery] int pageSize = 10)\n    {\n        var totalCount = await _db.Articles.CountAsync();\n        var totalPages = (int)Math.Ceiling(totalCount / (double)pageSize);\n\n        var articles = await _db.Articles\n            .OrderByDescending(a => a.PublishedAt)\n            .Skip((page - 1) * pageSize)\n            .Take(pageSize)\n            .ToListAsync();\n\n        var dtos = articles.Select(a =>\n        {\n            var dto = MapToDto(a, new ExpansionOptions());\n            dto.Links = LinkGeneratorHelper.GenerateArticleLinks(\n                a.Id,\n                a.Status,\n                _urlHelper,\n                isOwner: true);\n            return dto;\n        }).ToList();\n\n        var collectionLinks = LinkGeneratorHelper.GenerateCollectionLinks(\n            _urlHelper,\n            \"GetArticles\",\n            \"Articles\",\n            page,\n            totalPages);\n\n        var response = new\n        {\n            _links = collectionLinks,\n            _embedded = new { articles = dtos },\n            page,\n            pageSize,\n            totalCount,\n            totalPages\n        };\n\n        return Ok(response);\n    }\n\n    /// \u003Csummary>\n    /// Отримати коментарі до статті\n    /// \u003C/summary>\n    [HttpGet(\"{id:int}/comments\", Name = \"GetArticleComments\")]\n    [ProducesResponseType(typeof(List\u003CCommentDto>), StatusCodes.Status200OK)]\n    public async Task\u003CActionResult\u003CList\u003CCommentDto>>> GetComments(int id)\n    {\n        var article = await _db.Articles\n            .Include(a => a.Comments)\n            .FirstOrDefaultAsync(a => a.Id == id);\n\n        if (article is null)\n            return NotFound();\n\n        var dtos = article.Comments.Select(c => new CommentDto\n        {\n            Id = c.Id,\n            Text = c.Text,\n            AuthorName = c.AuthorName,\n            CreatedAt = c.CreatedAt,\n            Links = new Dictionary\u003Cstring, Link>\n            {\n                [\"self\"] = new Link\n                {\n                    Href = _urlHelper.Action(\"GetCommentById\", \"Comments\", new { id = c.Id })!,\n                    Rel = \"self\"\n                },\n                [\"article\"] = new Link\n                {\n                    Href = _urlHelper.Action(\"GetById\", \"Articles\", new { id = article.Id })!,\n                    Rel = \"article\"\n                }\n            }\n        }).ToList();\n\n        return Ok(dtos);\n    }\n\n    /// \u003Csummary>\n    /// Створити нову статтю\n    /// \u003C/summary>\n    [HttpPost(Name = \"CreateArticle\")]\n    [ProducesResponseType(typeof(ArticleDto), StatusCodes.Status201Created)]\n    public async Task\u003CActionResult\u003CArticleDto>> Create([FromBody] CreateArticleDto dto)\n    {\n        var article = new Article\n        {\n            Title = dto.Title,\n            Content = dto.Content,\n            AuthorId = dto.AuthorId,\n            CategoryId = dto.CategoryId,\n            Status = ArticleStatus.Draft\n        };\n\n        _db.Articles.Add(article);\n        await _db.SaveChangesAsync();\n\n        var resultDto = MapToDto(article, new ExpansionOptions());\n        resultDto.Links = LinkGeneratorHelper.GenerateArticleLinks(\n            article.Id,\n            article.Status,\n            _urlHelper,\n            isOwner: true);\n\n        return CreatedAtAction(\n            nameof(GetById),\n            new { id = article.Id },\n            resultDto);\n    }\n\n    /// \u003Csummary>\n    /// Опублікувати статтю (змінити статус на Published)\n    /// \u003C/summary>\n    [HttpPost(\"{id:int}/publish\", Name = \"PublishArticle\")]\n    [ProducesResponseType(typeof(ArticleDto), StatusCodes.Status200OK)]\n    [ProducesResponseType(StatusCodes.Status404NotFound)]\n    [ProducesResponseType(StatusCodes.Status400BadRequest)]\n    public async Task\u003CActionResult\u003CArticleDto>> Publish(int id)\n    {\n        var article = await _db.Articles.FindAsync(id);\n\n        if (article is null)\n            return NotFound();\n\n        if (article.Status != ArticleStatus.Draft)\n            return BadRequest(new ProblemDetails\n            {\n                Title = \"Invalid Operation\",\n                Detail = \"Only draft articles can be published\"\n            });\n\n        article.Status = ArticleStatus.Published;\n        article.PublishedAt = DateTime.UtcNow;\n        await _db.SaveChangesAsync();\n\n        var dto = MapToDto(article, new ExpansionOptions());\n        dto.Links = LinkGeneratorHelper.GenerateArticleLinks(\n            article.Id,\n            article.Status,\n            _urlHelper,\n            isOwner: true);\n\n        return Ok(dto);\n    }\n\n    /// \u003Csummary>\n    /// Архівувати статтю\n    /// \u003C/summary>\n    [HttpPost(\"{id:int}/archive\", Name = \"ArchiveArticle\")]\n    [ProducesResponseType(typeof(ArticleDto), StatusCodes.Status200OK)]\n    public async Task\u003CActionResult\u003CArticleDto>> Archive(int id)\n    {\n        var article = await _db.Articles.FindAsync(id);\n\n        if (article is null)\n            return NotFound();\n\n        article.Status = ArticleStatus.Archived;\n        await _db.SaveChangesAsync();\n\n        var dto = MapToDto(article, new ExpansionOptions());\n        dto.Links = LinkGeneratorHelper.GenerateArticleLinks(\n            article.Id,\n            article.Status,\n            _urlHelper,\n            isOwner: true);\n\n        return Ok(dto);\n    }\n\n    /// \u003Csummary>\n    /// Оновити статтю\n    /// \u003C/summary>\n    [HttpPut(\"{id:int}\", Name = \"UpdateArticle\")]\n    [ProducesResponseType(typeof(ArticleDto), StatusCodes.Status200OK)]\n    public async Task\u003CActionResult\u003CArticleDto>> Update(int id, [FromBody] UpdateArticleDto dto)\n    {\n        var article = await _db.Articles.FindAsync(id);\n\n        if (article is null)\n            return NotFound();\n\n        article.Title = dto.Title;\n        article.Content = dto.Content;\n        article.UpdatedAt = DateTime.UtcNow;\n\n        await _db.SaveChangesAsync();\n\n        var resultDto = MapToDto(article, new ExpansionOptions());\n        resultDto.Links = LinkGeneratorHelper.GenerateArticleLinks(\n            article.Id,\n            article.Status,\n            _urlHelper,\n            isOwner: true);\n\n        return Ok(resultDto);\n    }\n\n    /// \u003Csummary>\n    /// Видалити статтю\n    /// \u003C/summary>\n    [HttpDelete(\"{id:int}\", Name = \"DeleteArticle\")]\n    [ProducesResponseType(StatusCodes.Status204NoContent)]\n    public async Task\u003CIActionResult> Delete(int id)\n    {\n        var article = await _db.Articles.FindAsync(id);\n\n        if (article is null)\n            return NotFound();\n\n        _db.Articles.Remove(article);\n        await _db.SaveChangesAsync();\n\n        return NoContent();\n    }\n\n    private ArticleDto MapToDto(Article article, ExpansionOptions options)\n    {\n        var dto = new ArticleDto\n        {\n            Id = article.Id,\n            Title = article.Title,\n            Content = article.Content,\n            AuthorId = article.AuthorId,\n            CategoryId = article.CategoryId,\n            PublishedAt = article.PublishedAt,\n            UpdatedAt = article.UpdatedAt,\n            Status = article.Status.ToString()\n        };\n\n        // Resource expansion\n        if (options.IncludeAuthor || options.IncludeCategory || options.IncludeComments)\n        {\n            dto.Embedded = new EmbeddedResources();\n\n            if (options.IncludeAuthor && article.Author != null)\n            {\n                dto.Embedded.Author = new AuthorDto\n                {\n                    Id = article.Author.Id,\n                    Name = article.Author.Name,\n                    Email = article.Author.Email,\n                    Bio = article.Author.Bio,\n                    Links = new Dictionary\u003Cstring, Link>\n                    {\n                        [\"self\"] = new Link\n                        {\n                            Href = _urlHelper.Action(\"GetById\", \"Authors\", new { id = article.Author.Id })!,\n                            Rel = \"self\"\n                        }\n                    }\n                };\n            }\n\n            if (options.IncludeCategory && article.Category != null)\n            {\n                dto.Embedded.Category = new CategoryDto\n                {\n                    Id = article.Category.Id,\n                    Name = article.Category.Name,\n                    Description = article.Category.Description,\n                    Links = new Dictionary\u003Cstring, Link>\n                    {\n                        [\"self\"] = new Link\n                        {\n                            Href = _urlHelper.Action(\"GetById\", \"Categories\", new { id = article.Category.Id })!,\n                            Rel = \"self\"\n                        }\n                    }\n                };\n            }\n\n            if (options.IncludeComments && article.Comments.Any())\n            {\n                dto.Embedded.Comments = article.Comments.Select(c => new CommentDto\n                {\n                    Id = c.Id,\n                    Text = c.Text,\n                    AuthorName = c.AuthorName,\n                    CreatedAt = c.CreatedAt\n                }).ToList();\n            }\n        }\n\n        return dto;\n    }\n}\n\n// DTOs для створення/оновлення\npublic record CreateArticleDto\n{\n    public required string Title { get; init; }\n    public required string Content { get; init; }\n    public int AuthorId { get; init; }\n    public int CategoryId { get; init; }\n}\n\npublic record UpdateArticleDto\n{\n    public required string Title { get; init; }\n    public required string Content { get; init; }\n}\n",[2975,9553,9554,9570,9582,9594,9606,9622,9634,9638,9651,9655,9665,9679,9693,9697,9712,9733,9747,9751,9759,9769,9785,9795,9805,9809,9821,9832,9860,9864,9868,9882,9887,9898,9928,9954,9977,10007,10024,10051,10060,10084,10088,10109,10113,10118,10141,10145,10150,10166,10196,10200,10215,10241,10245,10260,10286,10290,10325,10329,10345,10354,10358,10363,10385,10389,10394,10414,10425,10436,10443,10459,10463,10468,10527,10582,10586,10599,10603,10607,10617,10622,10632,10649,10674,10694,10713,10732,10736,10760,10800,10804,10822,10844,10867,10880,10889,10893,10916,10920,10943,10962,10973,10983,10990,11001,11009,11019,11023,11040,11046,11053,11060,11067,11074,11078,11090,11094,11106,11126,11132,11139,11146,11151,11155,11159,11172,11176,11180,11190,11195,11205,11227,11257,11291,11295,11311,11331,11355,11359,11373,11381,11386,11416,11421,11437,11453,11469,11485,11507,11512,11526,11532,11575,11585,11591,11605,11610,11649,11659,11665,11670,11679,11684,11697,11702,11707,11718,11724,11735,11754,11780,11817,11822,11835,11840,11856,11873,11889,11905,11920,11925,11930,11950,11965,11970,11994,12014,12025,12036,12043,12054,12059,12069,12081,12100,12108,12113,12118,12129,12135,12146,12169,12194,12211,12229,12259,12264,12292,12297,12312,12321,12326,12349,12364,12369,12381,12392,12398,12403,12423,12442,12455,12460,12483,12502,12513,12524,12531,12542,12547,12560,12565,12570,12581,12587,12598,12621,12646,12676,12681,12708,12713,12728,12737,12742,12761,12774,12779,12802,12821,12832,12843,12850,12861,12866,12879,12884,12889,12900,12906,12917,12940,12965,13007,13012,13039,13044,13059,13068,13073,13092,13111,13130,13135,13148,13153,13176,13195,13206,13217,13224,13235,13240,13254,13259,13264,13275,13281,13292,13315,13333,13359,13364,13391,13396,13411,13420,13425,13445,13458,13463,13473,13478,13483,13508,13513,13526,13531,13546,13561,13576,13591,13606,13622,13638,13658,13663,13668,13674,13706,13711,13728,13733,13761,13766,13786,13791,13811,13831,13851,13871,13893,13899,13913,13919,13963,13973,13979,13985,13991,13996,14001,14028,14033,14052,14057,14076,14095,14115,14136,14141,14154,14159,14202,14211,14216,14221,14226,14231,14236,14264,14269,14304,14309,14324,14340,14356,14371,14381,14386,14391,14396,14405,14410,14415,14420,14426,14437,14442,14464,14485,14504,14523,14528,14533,14543,14548,14569,14590],{"__ignoreMap":2973},[2978,9555,9556,9558,9560,9562,9564,9566,9568],{"class":2980,"line":2981},[2978,9557,5570],{"class":3191},[2978,9559,5585],{"class":4517},[2978,9561,3223],{"class":2995},[2978,9563,5590],{"class":4517},[2978,9565,3223],{"class":2995},[2978,9567,5595],{"class":4517},[2978,9569,4526],{"class":2995},[2978,9571,9572,9574,9576,9578,9580],{"class":2980,"line":2999},[2978,9573,5570],{"class":3191},[2978,9575,5585],{"class":4517},[2978,9577,3223],{"class":2995},[2978,9579,8516],{"class":4517},[2978,9581,4526],{"class":2995},[2978,9583,9584,9586,9588,9590,9592],{"class":2980,"line":3016},[2978,9585,5570],{"class":3191},[2978,9587,4518],{"class":4517},[2978,9589,3223],{"class":2995},[2978,9591,8545],{"class":4517},[2978,9593,4526],{"class":2995},[2978,9595,9596,9598,9600,9602,9604],{"class":2980,"line":3030},[2978,9597,5570],{"class":3191},[2978,9599,4518],{"class":4517},[2978,9601,3223],{"class":2995},[2978,9603,4523],{"class":4517},[2978,9605,4526],{"class":2995},[2978,9607,9608,9610,9612,9614,9616,9618,9620],{"class":2980,"line":3043},[2978,9609,5570],{"class":3191},[2978,9611,4518],{"class":4517},[2978,9613,3223],{"class":2995},[2978,9615,4523],{"class":4517},[2978,9617,3223],{"class":2995},[2978,9619,7306],{"class":4517},[2978,9621,4526],{"class":2995},[2978,9623,9624,9626,9628,9630,9632],{"class":2980,"line":3056},[2978,9625,5570],{"class":3191},[2978,9627,4518],{"class":4517},[2978,9629,3223],{"class":2995},[2978,9631,5612],{"class":4517},[2978,9633,4526],{"class":2995},[2978,9635,9636],{"class":2980,"line":3067},[2978,9637,3288],{"emptyLinePlaceholder":3287},[2978,9639,9640,9642,9644,9646,9649],{"class":2980,"line":3442},[2978,9641,4514],{"class":3180},[2978,9643,4518],{"class":4517},[2978,9645,3223],{"class":2995},[2978,9647,9648],{"class":4517},"Controllers",[2978,9650,4526],{"class":2995},[2978,9652,9653],{"class":2980,"line":3469},[2978,9654,3288],{"emptyLinePlaceholder":3287},[2978,9656,9657,9659,9662],{"class":2980,"line":3495},[2978,9658,6148],{"class":2995},[2978,9660,9661],{"class":4517},"ApiController",[2978,9663,9664],{"class":2995},"]\n",[2978,9666,9667,9669,9672,9674,9677],{"class":2980,"line":3501},[2978,9668,6148],{"class":2995},[2978,9670,9671],{"class":4517},"Route",[2978,9673,3199],{"class":2995},[2978,9675,9676],{"class":3024},"\"api/[controller]\"",[2978,9678,7499],{"class":2995},[2978,9680,9681,9683,9685,9688,9690],{"class":2980,"line":3642},[2978,9682,4535],{"class":3180},[2978,9684,4538],{"class":3180},[2978,9686,9687],{"class":4517}," ArticlesController",[2978,9689,8563],{"class":2995},[2978,9691,9692],{"class":4517},"ControllerBase\n",[2978,9694,9695],{"class":2980,"line":3674},[2978,9696,2996],{"class":2995},[2978,9698,9699,9702,9705,9707,9710],{"class":2980,"line":3680},[2978,9700,9701],{"class":3180},"    private",[2978,9703,9704],{"class":3180}," readonly",[2978,9706,8560],{"class":4517},[2978,9708,9709],{"class":3213}," _db",[2978,9711,4526],{"class":2995},[2978,9713,9714,9716,9718,9721,9723,9726,9728,9731],{"class":2980,"line":3686},[2978,9715,9701],{"class":3180},[2978,9717,9704],{"class":3180},[2978,9719,9720],{"class":4517}," ILogger",[2978,9722,4707],{"class":2995},[2978,9724,9725],{"class":4517},"ArticlesController",[2978,9727,4713],{"class":2995},[2978,9729,9730],{"class":3213},"_logger",[2978,9732,4526],{"class":2995},[2978,9734,9735,9737,9739,9742,9745],{"class":2980,"line":3699},[2978,9736,9701],{"class":3180},[2978,9738,9704],{"class":3180},[2978,9740,9741],{"class":4517}," IUrlHelper",[2978,9743,9744],{"class":3213}," _urlHelper",[2978,9746,4526],{"class":2995},[2978,9748,9749],{"class":2980,"line":4367},[2978,9750,3288],{"emptyLinePlaceholder":3287},[2978,9752,9753,9755,9757],{"class":2980,"line":4825},[2978,9754,4550],{"class":3180},[2978,9756,9687],{"class":3195},[2978,9758,5658],{"class":2995},[2978,9760,9761,9764,9767],{"class":2980,"line":4836},[2978,9762,9763],{"class":4517},"        BlogDbContext",[2978,9765,9766],{"class":3213}," db",[2978,9768,3013],{"class":2995},[2978,9770,9771,9774,9776,9778,9780,9783],{"class":2980,"line":4841},[2978,9772,9773],{"class":4517},"        ILogger",[2978,9775,4707],{"class":2995},[2978,9777,9725],{"class":4517},[2978,9779,4713],{"class":2995},[2978,9781,9782],{"class":3213},"logger",[2978,9784,3013],{"class":2995},[2978,9786,9787,9790,9793],{"class":2980,"line":4849},[2978,9788,9789],{"class":4517},"        IUrlHelperFactory",[2978,9791,9792],{"class":3213}," urlHelperFactory",[2978,9794,3013],{"class":2995},[2978,9796,9797,9800,9803],{"class":2980,"line":4857},[2978,9798,9799],{"class":4517},"        IActionContextAccessor",[2978,9801,9802],{"class":3213}," actionContextAccessor",[2978,9804,5704],{"class":2995},[2978,9806,9807],{"class":2980,"line":4863},[2978,9808,5709],{"class":2995},[2978,9810,9811,9814,9816,9819],{"class":2980,"line":4868},[2978,9812,9813],{"class":3213},"        _db",[2978,9815,3188],{"class":2995},[2978,9817,9818],{"class":3213},"db",[2978,9820,4526],{"class":2995},[2978,9822,9823,9826,9828,9830],{"class":2980,"line":4873},[2978,9824,9825],{"class":3213},"        _logger",[2978,9827,3188],{"class":2995},[2978,9829,9782],{"class":3213},[2978,9831,4526],{"class":2995},[2978,9833,9834,9837,9839,9842,9844,9847,9849,9852,9854,9857],{"class":2980,"line":4883},[2978,9835,9836],{"class":3213},"        _urlHelper",[2978,9838,3188],{"class":2995},[2978,9840,9841],{"class":3213},"urlHelperFactory",[2978,9843,3223],{"class":2995},[2978,9845,9846],{"class":3195},"GetUrlHelper",[2978,9848,3199],{"class":2995},[2978,9850,9851],{"class":3213},"actionContextAccessor",[2978,9853,3223],{"class":2995},[2978,9855,9856],{"class":3213},"ActionContext",[2978,9858,9859],{"class":2995},"!);\n",[2978,9861,9862],{"class":2980,"line":4888},[2978,9863,6625],{"class":2995},[2978,9865,9866],{"class":2980,"line":4907},[2978,9867,3288],{"emptyLinePlaceholder":3287},[2978,9869,9870,9873,9876,9880],{"class":2980,"line":4929},[2978,9871,9872],{"class":3174},"    /// ",[2978,9874,4707],{"class":9875},"s0P7L",[2978,9877,9879],{"class":9878},"sKtos","summary",[2978,9881,5734],{"class":9875},[2978,9883,9884],{"class":2980,"line":4951},[2978,9885,9886],{"class":3174},"    /// Отримати статтю за ID з HATEOAS links та опціональним expansion\n",[2978,9888,9889,9891,9894,9896],{"class":2980,"line":4973},[2978,9890,9872],{"class":3174},[2978,9892,9893],{"class":9875},"\u003C/",[2978,9895,9879],{"class":9878},[2978,9897,5734],{"class":9875},[2978,9899,9900,9902,9904,9907,9911,9914,9916,9919,9922,9924,9926],{"class":2980,"line":5004},[2978,9901,9872],{"class":3174},[2978,9903,4707],{"class":9875},[2978,9905,9906],{"class":9878},"param",[2978,9908,9910],{"class":9909},"sa4r_"," name",[2978,9912,9913],{"class":3174},"=",[2978,9915,3612],{"class":3024},[2978,9917,9918],{"class":9875},">",[2978,9920,9921],{"class":3174},"ID статті",[2978,9923,9893],{"class":9875},[2978,9925,9906],{"class":9878},[2978,9927,5734],{"class":9875},[2978,9929,9930,9932,9934,9936,9938,9940,9943,9945,9948,9950,9952],{"class":2980,"line":5009},[2978,9931,9872],{"class":3174},[2978,9933,4707],{"class":9875},[2978,9935,9906],{"class":9878},[2978,9937,9910],{"class":9909},[2978,9939,9913],{"class":3174},[2978,9941,9942],{"class":3024},"\"expand\"",[2978,9944,9918],{"class":9875},[2978,9946,9947],{"class":3174},"Ресурси для expansion (author,category,comments)",[2978,9949,9893],{"class":9875},[2978,9951,9906],{"class":9878},[2978,9953,5734],{"class":9875},[2978,9955,9956,9958,9961,9963,9966,9968,9970,9972,9975],{"class":2980,"line":5014},[2978,9957,7489],{"class":2995},[2978,9959,9960],{"class":4517},"HttpGet",[2978,9962,3199],{"class":2995},[2978,9964,9965],{"class":3024},"\"{id:int}\"",[2978,9967,3456],{"class":2995},[2978,9969,8789],{"class":3213},[2978,9971,3188],{"class":2995},[2978,9973,9974],{"class":3024},"\"GetArticleById\"",[2978,9976,7499],{"class":2995},[2978,9978,9979,9981,9984,9986,9989,9991,9994,9997,10000,10002,10005],{"class":2980,"line":5024},[2978,9980,7489],{"class":2995},[2978,9982,9983],{"class":4517},"ProducesResponseType",[2978,9985,3199],{"class":2995},[2978,9987,9988],{"class":3180},"typeof",[2978,9990,3199],{"class":2995},[2978,9992,9993],{"class":4517},"ArticleDto",[2978,9995,9996],{"class":2995},"), ",[2978,9998,9999],{"class":3213},"StatusCodes",[2978,10001,3223],{"class":2995},[2978,10003,10004],{"class":3213},"Status200OK",[2978,10006,7499],{"class":2995},[2978,10008,10009,10011,10013,10015,10017,10019,10022],{"class":2980,"line":5029},[2978,10010,7489],{"class":2995},[2978,10012,9983],{"class":4517},[2978,10014,3199],{"class":2995},[2978,10016,9999],{"class":3213},[2978,10018,3223],{"class":2995},[2978,10020,10021],{"class":3213},"Status404NotFound",[2978,10023,7499],{"class":2995},[2978,10025,10026,10028,10031,10034,10036,10039,10041,10043,10046,10049],{"class":2980,"line":5048},[2978,10027,4550],{"class":3180},[2978,10029,10030],{"class":3180}," async",[2978,10032,10033],{"class":4517}," Task",[2978,10035,4707],{"class":2995},[2978,10037,10038],{"class":4517},"ActionResult",[2978,10040,4707],{"class":2995},[2978,10042,9993],{"class":4517},[2978,10044,10045],{"class":2995},">> ",[2978,10047,10048],{"class":3195},"GetById",[2978,10050,5658],{"class":2995},[2978,10052,10053,10055,10058],{"class":2980,"line":5069},[2978,10054,5663],{"class":3180},[2978,10056,10057],{"class":3213}," id",[2978,10059,3013],{"class":2995},[2978,10061,10062,10065,10068,10071,10073,10075,10077,10079,10082],{"class":2980,"line":5091},[2978,10063,10064],{"class":2995},"        [",[2978,10066,10067],{"class":4517},"FromQuery",[2978,10069,10070],{"class":2995},"] ",[2978,10072,5489],{"class":3180},[2978,10074,3101],{"class":2995},[2978,10076,8235],{"class":3213},[2978,10078,3188],{"class":2995},[2978,10080,10081],{"class":3180},"null",[2978,10083,5704],{"class":2995},[2978,10085,10086],{"class":2980,"line":5120},[2978,10087,5709],{"class":2995},[2978,10089,10090,10092,10095,10097,10099,10101,10103,10105,10107],{"class":2980,"line":5125},[2978,10091,5714],{"class":3180},[2978,10093,10094],{"class":3213}," expansionOptions",[2978,10096,3188],{"class":2995},[2978,10098,8461],{"class":3213},[2978,10100,3223],{"class":2995},[2978,10102,8466],{"class":3195},[2978,10104,3199],{"class":2995},[2978,10106,8235],{"class":3213},[2978,10108,8474],{"class":2995},[2978,10110,10111],{"class":2980,"line":5130},[2978,10112,3288],{"emptyLinePlaceholder":3287},[2978,10114,10115],{"class":2980,"line":5140},[2978,10116,10117],{"class":3174},"        // Базовий query\n",[2978,10119,10120,10122,10125,10127,10130,10132,10134,10136,10139],{"class":2980,"line":5145},[2978,10121,5714],{"class":3180},[2978,10123,10124],{"class":3213}," query",[2978,10126,3188],{"class":2995},[2978,10128,10129],{"class":3213},"_db",[2978,10131,3223],{"class":2995},[2978,10133,4987],{"class":3213},[2978,10135,3223],{"class":2995},[2978,10137,10138],{"class":3195},"AsQueryable",[2978,10140,4733],{"class":2995},[2978,10142,10143],{"class":2980,"line":5164},[2978,10144,3288],{"emptyLinePlaceholder":3287},[2978,10146,10147],{"class":2980,"line":5186},[2978,10148,10149],{"class":3174},"        // Eager loading залежно від expansion\n",[2978,10151,10152,10154,10156,10159,10161,10164],{"class":2980,"line":5208},[2978,10153,6113],{"class":3191},[2978,10155,6116],{"class":2995},[2978,10157,10158],{"class":3213},"expansionOptions",[2978,10160,3223],{"class":2995},[2978,10162,10163],{"class":3213},"IncludeAuthor",[2978,10165,5704],{"class":2995},[2978,10167,10168,10171,10173,10176,10178,10181,10183,10186,10188,10190,10192,10194],{"class":2980,"line":5228},[2978,10169,10170],{"class":3213},"            query",[2978,10172,3188],{"class":2995},[2978,10174,10175],{"class":3213},"query",[2978,10177,3223],{"class":2995},[2978,10179,10180],{"class":3195},"Include",[2978,10182,3199],{"class":2995},[2978,10184,10185],{"class":3213},"a",[2978,10187,8325],{"class":2995},[2978,10189,10185],{"class":3213},[2978,10191,3223],{"class":2995},[2978,10193,4646],{"class":3213},[2978,10195,8474],{"class":2995},[2978,10197,10198],{"class":2980,"line":5250},[2978,10199,3288],{"emptyLinePlaceholder":3287},[2978,10201,10202,10204,10206,10208,10210,10213],{"class":2980,"line":5278},[2978,10203,6113],{"class":3191},[2978,10205,6116],{"class":2995},[2978,10207,10158],{"class":3213},[2978,10209,3223],{"class":2995},[2978,10211,10212],{"class":3213},"IncludeCategory",[2978,10214,5704],{"class":2995},[2978,10216,10217,10219,10221,10223,10225,10227,10229,10231,10233,10235,10237,10239],{"class":2980,"line":6164},[2978,10218,10170],{"class":3213},[2978,10220,3188],{"class":2995},[2978,10222,10175],{"class":3213},[2978,10224,3223],{"class":2995},[2978,10226,10180],{"class":3195},[2978,10228,3199],{"class":2995},[2978,10230,10185],{"class":3213},[2978,10232,8325],{"class":2995},[2978,10234,10185],{"class":3213},[2978,10236,3223],{"class":2995},[2978,10238,4687],{"class":3213},[2978,10240,8474],{"class":2995},[2978,10242,10243],{"class":2980,"line":6200},[2978,10244,3288],{"emptyLinePlaceholder":3287},[2978,10246,10247,10249,10251,10253,10255,10258],{"class":2980,"line":6211},[2978,10248,6113],{"class":3191},[2978,10250,6116],{"class":2995},[2978,10252,10158],{"class":3213},[2978,10254,3223],{"class":2995},[2978,10256,10257],{"class":3213},"IncludeComments",[2978,10259,5704],{"class":2995},[2978,10261,10262,10264,10266,10268,10270,10272,10274,10276,10278,10280,10282,10284],{"class":2980,"line":6223},[2978,10263,10170],{"class":3213},[2978,10265,3188],{"class":2995},[2978,10267,10175],{"class":3213},[2978,10269,3223],{"class":2995},[2978,10271,10180],{"class":3195},[2978,10273,3199],{"class":2995},[2978,10275,10185],{"class":3213},[2978,10277,8325],{"class":2995},[2978,10279,10185],{"class":3213},[2978,10281,3223],{"class":2995},[2978,10283,4716],{"class":3213},[2978,10285,8474],{"class":2995},[2978,10287,10288],{"class":2980,"line":6233},[2978,10289,3288],{"emptyLinePlaceholder":3287},[2978,10291,10292,10294,10296,10298,10300,10302,10304,10307,10309,10311,10313,10315,10317,10319,10321,10323],{"class":2980,"line":6239},[2978,10293,5714],{"class":3180},[2978,10295,3185],{"class":3213},[2978,10297,3188],{"class":2995},[2978,10299,3192],{"class":3180},[2978,10301,10124],{"class":3213},[2978,10303,3223],{"class":2995},[2978,10305,10306],{"class":3195},"FirstOrDefaultAsync",[2978,10308,3199],{"class":2995},[2978,10310,10185],{"class":3213},[2978,10312,8325],{"class":2995},[2978,10314,10185],{"class":3213},[2978,10316,3223],{"class":2995},[2978,10318,8780],{"class":3213},[2978,10320,6122],{"class":2995},[2978,10322,5792],{"class":3213},[2978,10324,8474],{"class":2995},[2978,10326,10327],{"class":2980,"line":6245},[2978,10328,3288],{"emptyLinePlaceholder":3287},[2978,10330,10331,10333,10335,10337,10340,10343],{"class":2980,"line":6250},[2978,10332,6113],{"class":3191},[2978,10334,6116],{"class":2995},[2978,10336,3252],{"class":3213},[2978,10338,10339],{"class":3180}," is",[2978,10341,10342],{"class":3180}," null",[2978,10344,5704],{"class":2995},[2978,10346,10347,10349,10352],{"class":2980,"line":6275},[2978,10348,8266],{"class":3191},[2978,10350,10351],{"class":3195}," NotFound",[2978,10353,4733],{"class":2995},[2978,10355,10356],{"class":2980,"line":6280},[2978,10357,3288],{"emptyLinePlaceholder":3287},[2978,10359,10360],{"class":2980,"line":6296},[2978,10361,10362],{"class":3174},"        // Мапінг до DTO\n",[2978,10364,10365,10367,10370,10372,10375,10377,10379,10381,10383],{"class":2980,"line":6301},[2978,10366,5714],{"class":3180},[2978,10368,10369],{"class":3213}," dto",[2978,10371,3188],{"class":2995},[2978,10373,10374],{"class":3195},"MapToDto",[2978,10376,3199],{"class":2995},[2978,10378,3252],{"class":3213},[2978,10380,3456],{"class":2995},[2978,10382,10158],{"class":3213},[2978,10384,8474],{"class":2995},[2978,10386,10387],{"class":2980,"line":6337},[2978,10388,3288],{"emptyLinePlaceholder":3287},[2978,10390,10391],{"class":2980,"line":6348},[2978,10392,10393],{"class":3174},"        // Генерація HATEOAS links\n",[2978,10395,10396,10399,10401,10403,10405,10408,10410,10412],{"class":2980,"line":6359},[2978,10397,10398],{"class":3213},"        dto",[2978,10400,3223],{"class":2995},[2978,10402,5499],{"class":3213},[2978,10404,3188],{"class":2995},[2978,10406,10407],{"class":3213},"LinkGeneratorHelper",[2978,10409,3223],{"class":2995},[2978,10411,5655],{"class":3195},[2978,10413,5658],{"class":2995},[2978,10415,10416,10419,10421,10423],{"class":2980,"line":6369},[2978,10417,10418],{"class":3213},"            article",[2978,10420,3223],{"class":2995},[2978,10422,8780],{"class":3213},[2978,10424,3013],{"class":2995},[2978,10426,10427,10429,10431,10434],{"class":2980,"line":6374},[2978,10428,10418],{"class":3213},[2978,10430,3223],{"class":2995},[2978,10432,10433],{"class":3213},"Status",[2978,10435,3013],{"class":2995},[2978,10437,10438,10441],{"class":2980,"line":6379},[2978,10439,10440],{"class":3213},"            _urlHelper",[2978,10442,3013],{"class":2995},[2978,10444,10445,10448,10450,10453,10456],{"class":2980,"line":6395},[2978,10446,10447],{"class":3213},"            isOwner",[2978,10449,3006],{"class":2995},[2978,10451,10452],{"class":3180},"true",[2978,10454,10455],{"class":2995},"); ",[2978,10457,10458],{"class":3174},"// У production перевіряти реального користувача\n",[2978,10460,10461],{"class":2980,"line":6400},[2978,10462,3288],{"emptyLinePlaceholder":3287},[2978,10464,10465],{"class":2980,"line":6436},[2978,10466,10467],{"class":3174},"        // Заміна placeholders у links\n",[2978,10469,10470,10472,10474,10476,10478,10480,10483,10485,10487,10490,10492,10494,10496,10498,10500,10502,10504,10507,10509,10511,10513,10515,10517,10520,10522,10525],{"class":2980,"line":6447},[2978,10471,10398],{"class":3213},[2978,10473,3223],{"class":2995},[2978,10475,5499],{"class":3213},[2978,10477,6148],{"class":2995},[2978,10479,3632],{"class":3024},[2978,10481,10482],{"class":2995},"].",[2978,10484,5530],{"class":3213},[2978,10486,3188],{"class":2995},[2978,10488,10489],{"class":3213},"dto",[2978,10491,3223],{"class":2995},[2978,10493,5499],{"class":3213},[2978,10495,6148],{"class":2995},[2978,10497,3632],{"class":3024},[2978,10499,10482],{"class":2995},[2978,10501,5530],{"class":3213},[2978,10503,3223],{"class":2995},[2978,10505,10506],{"class":3195},"Replace",[2978,10508,3199],{"class":2995},[2978,10510,5887],{"class":3024},[2978,10512,3456],{"class":2995},[2978,10514,3252],{"class":3213},[2978,10516,3223],{"class":2995},[2978,10518,10519],{"class":3213},"AuthorId",[2978,10521,3223],{"class":2995},[2978,10523,10524],{"class":3195},"ToString",[2978,10526,3228],{"class":2995},[2978,10528,10529,10531,10533,10535,10537,10539,10541,10543,10545,10547,10549,10551,10553,10555,10557,10559,10561,10563,10565,10567,10569,10571,10573,10576,10578,10580],{"class":2980,"line":6458},[2978,10530,10398],{"class":3213},[2978,10532,3223],{"class":2995},[2978,10534,5499],{"class":3213},[2978,10536,6148],{"class":2995},[2978,10538,6014],{"class":3024},[2978,10540,10482],{"class":2995},[2978,10542,5530],{"class":3213},[2978,10544,3188],{"class":2995},[2978,10546,10489],{"class":3213},[2978,10548,3223],{"class":2995},[2978,10550,5499],{"class":3213},[2978,10552,6148],{"class":2995},[2978,10554,6014],{"class":3024},[2978,10556,10482],{"class":2995},[2978,10558,5530],{"class":3213},[2978,10560,3223],{"class":2995},[2978,10562,10506],{"class":3195},[2978,10564,3199],{"class":2995},[2978,10566,6058],{"class":3024},[2978,10568,3456],{"class":2995},[2978,10570,3252],{"class":3213},[2978,10572,3223],{"class":2995},[2978,10574,10575],{"class":3213},"CategoryId",[2978,10577,3223],{"class":2995},[2978,10579,10524],{"class":3195},[2978,10581,3228],{"class":2995},[2978,10583,10584],{"class":2980,"line":6468},[2978,10585,3288],{"emptyLinePlaceholder":3287},[2978,10587,10588,10590,10593,10595,10597],{"class":2980,"line":6473},[2978,10589,6615],{"class":3191},[2978,10591,10592],{"class":3195}," Ok",[2978,10594,3199],{"class":2995},[2978,10596,10489],{"class":3213},[2978,10598,8474],{"class":2995},[2978,10600,10601],{"class":2980,"line":6478},[2978,10602,6625],{"class":2995},[2978,10604,10605],{"class":2980,"line":6483},[2978,10606,3288],{"emptyLinePlaceholder":3287},[2978,10608,10609,10611,10613,10615],{"class":2980,"line":6503},[2978,10610,9872],{"class":3174},[2978,10612,4707],{"class":9875},[2978,10614,9879],{"class":9878},[2978,10616,5734],{"class":9875},[2978,10618,10619],{"class":2980,"line":6508},[2978,10620,10621],{"class":3174},"    /// Отримати всі статті з пагінацією та HATEOAS\n",[2978,10623,10624,10626,10628,10630],{"class":2980,"line":6524},[2978,10625,9872],{"class":3174},[2978,10627,9893],{"class":9875},[2978,10629,9879],{"class":9878},[2978,10631,5734],{"class":9875},[2978,10633,10634,10636,10638,10640,10642,10644,10647],{"class":2980,"line":6529},[2978,10635,7489],{"class":2995},[2978,10637,9960],{"class":4517},[2978,10639,3199],{"class":2995},[2978,10641,8789],{"class":3213},[2978,10643,3188],{"class":2995},[2978,10645,10646],{"class":3024},"\"GetArticles\"",[2978,10648,7499],{"class":2995},[2978,10650,10651,10653,10655,10657,10659,10661,10664,10666,10668,10670,10672],{"class":2980,"line":6565},[2978,10652,7489],{"class":2995},[2978,10654,9983],{"class":4517},[2978,10656,3199],{"class":2995},[2978,10658,9988],{"class":3180},[2978,10660,3199],{"class":2995},[2978,10662,10663],{"class":3180},"object",[2978,10665,9996],{"class":2995},[2978,10667,9999],{"class":3213},[2978,10669,3223],{"class":2995},[2978,10671,10004],{"class":3213},[2978,10673,7499],{"class":2995},[2978,10675,10676,10678,10680,10682,10684,10687,10689,10692],{"class":2980,"line":6576},[2978,10677,4550],{"class":3180},[2978,10679,10030],{"class":3180},[2978,10681,10033],{"class":4517},[2978,10683,4707],{"class":2995},[2978,10685,10686],{"class":4517},"IActionResult",[2978,10688,4713],{"class":2995},[2978,10690,10691],{"class":3195},"GetAll",[2978,10693,5658],{"class":2995},[2978,10695,10696,10698,10700,10702,10705,10707,10709,10711],{"class":2980,"line":6587},[2978,10697,10064],{"class":2995},[2978,10699,10067],{"class":4517},[2978,10701,10070],{"class":2995},[2978,10703,10704],{"class":3180},"int",[2978,10706,6692],{"class":3213},[2978,10708,3188],{"class":2995},[2978,10710,3617],{"class":3009},[2978,10712,3013],{"class":2995},[2978,10714,10715,10717,10719,10721,10723,10726,10728,10730],{"class":2980,"line":6597},[2978,10716,10064],{"class":2995},[2978,10718,10067],{"class":4517},[2978,10720,10070],{"class":2995},[2978,10722,10704],{"class":3180},[2978,10724,10725],{"class":3213}," pageSize",[2978,10727,3188],{"class":2995},[2978,10729,9092],{"class":3009},[2978,10731,5704],{"class":2995},[2978,10733,10734],{"class":2980,"line":6602},[2978,10735,5709],{"class":2995},[2978,10737,10738,10740,10743,10745,10747,10749,10751,10753,10755,10758],{"class":2980,"line":6607},[2978,10739,5714],{"class":3180},[2978,10741,10742],{"class":3213}," totalCount",[2978,10744,3188],{"class":2995},[2978,10746,3192],{"class":3180},[2978,10748,9709],{"class":3213},[2978,10750,3223],{"class":2995},[2978,10752,4987],{"class":3213},[2978,10754,3223],{"class":2995},[2978,10756,10757],{"class":3195},"CountAsync",[2978,10759,4733],{"class":2995},[2978,10761,10762,10764,10766,10769,10771,10774,10777,10779,10782,10784,10787,10790,10793,10795,10798],{"class":2980,"line":6612},[2978,10763,5714],{"class":3180},[2978,10765,6702],{"class":3213},[2978,10767,10768],{"class":2995}," = (",[2978,10770,10704],{"class":3180},[2978,10772,10773],{"class":2995},")",[2978,10775,10776],{"class":3213},"Math",[2978,10778,3223],{"class":2995},[2978,10780,10781],{"class":3195},"Ceiling",[2978,10783,3199],{"class":2995},[2978,10785,10786],{"class":3213},"totalCount",[2978,10788,10789],{"class":2995}," / (",[2978,10791,10792],{"class":3180},"double",[2978,10794,10773],{"class":2995},[2978,10796,10797],{"class":3213},"pageSize",[2978,10799,8474],{"class":2995},[2978,10801,10802],{"class":2980,"line":6622},[2978,10803,3288],{"emptyLinePlaceholder":3287},[2978,10805,10806,10808,10811,10813,10815,10817,10819],{"class":2980,"line":6628},[2978,10807,5714],{"class":3180},[2978,10809,10810],{"class":3213}," articles",[2978,10812,3188],{"class":2995},[2978,10814,3192],{"class":3180},[2978,10816,9709],{"class":3213},[2978,10818,3223],{"class":2995},[2978,10820,10821],{"class":3213},"Articles\n",[2978,10823,10824,10826,10829,10831,10833,10835,10837,10839,10842],{"class":2980,"line":6633},[2978,10825,8315],{"class":2995},[2978,10827,10828],{"class":3195},"OrderByDescending",[2978,10830,3199],{"class":2995},[2978,10832,10185],{"class":3213},[2978,10834,8325],{"class":2995},[2978,10836,10185],{"class":3213},[2978,10838,3223],{"class":2995},[2978,10840,10841],{"class":3213},"PublishedAt",[2978,10843,5704],{"class":2995},[2978,10845,10846,10848,10851,10854,10856,10858,10860,10863,10865],{"class":2980,"line":6657},[2978,10847,8315],{"class":2995},[2978,10849,10850],{"class":3195},"Skip",[2978,10852,10853],{"class":2995},"((",[2978,10855,6787],{"class":3213},[2978,10857,6968],{"class":2995},[2978,10859,3617],{"class":3009},[2978,10861,10862],{"class":2995},") * ",[2978,10864,10797],{"class":3213},[2978,10866,5704],{"class":2995},[2978,10868,10869,10871,10874,10876,10878],{"class":2980,"line":6666},[2978,10870,8315],{"class":2995},[2978,10872,10873],{"class":3195},"Take",[2978,10875,3199],{"class":2995},[2978,10877,10797],{"class":3213},[2978,10879,5704],{"class":2995},[2978,10881,10882,10884,10887],{"class":2980,"line":6677},[2978,10883,8315],{"class":2995},[2978,10885,10886],{"class":3195},"ToListAsync",[2978,10888,4733],{"class":2995},[2978,10890,10891],{"class":2980,"line":6687},[2978,10892,3288],{"emptyLinePlaceholder":3287},[2978,10894,10895,10897,10900,10902,10905,10907,10909,10911,10913],{"class":2980,"line":6697},[2978,10896,5714],{"class":3180},[2978,10898,10899],{"class":3213}," dtos",[2978,10901,3188],{"class":2995},[2978,10903,10904],{"class":3213},"articles",[2978,10906,3223],{"class":2995},[2978,10908,8318],{"class":3195},[2978,10910,3199],{"class":2995},[2978,10912,10185],{"class":3213},[2978,10914,10915],{"class":2995}," =>\n",[2978,10917,10918],{"class":2980,"line":6707},[2978,10919,5739],{"class":2995},[2978,10921,10922,10925,10927,10929,10931,10933,10935,10937,10939,10941],{"class":2980,"line":6712},[2978,10923,10924],{"class":3180},"            var",[2978,10926,10369],{"class":3213},[2978,10928,3188],{"class":2995},[2978,10930,10374],{"class":3195},[2978,10932,3199],{"class":2995},[2978,10934,10185],{"class":3213},[2978,10936,3456],{"class":2995},[2978,10938,4730],{"class":3180},[2978,10940,8223],{"class":4517},[2978,10942,3228],{"class":2995},[2978,10944,10945,10948,10950,10952,10954,10956,10958,10960],{"class":2980,"line":6735},[2978,10946,10947],{"class":3213},"            dto",[2978,10949,3223],{"class":2995},[2978,10951,5499],{"class":3213},[2978,10953,3188],{"class":2995},[2978,10955,10407],{"class":3213},[2978,10957,3223],{"class":2995},[2978,10959,5655],{"class":3195},[2978,10961,5658],{"class":2995},[2978,10963,10964,10967,10969,10971],{"class":2980,"line":6740},[2978,10965,10966],{"class":3213},"                a",[2978,10968,3223],{"class":2995},[2978,10970,8780],{"class":3213},[2978,10972,3013],{"class":2995},[2978,10974,10975,10977,10979,10981],{"class":2980,"line":6753},[2978,10976,10966],{"class":3213},[2978,10978,3223],{"class":2995},[2978,10980,10433],{"class":3213},[2978,10982,3013],{"class":2995},[2978,10984,10985,10988],{"class":2980,"line":6758},[2978,10986,10987],{"class":3213},"                _urlHelper",[2978,10989,3013],{"class":2995},[2978,10991,10992,10995,10997,10999],{"class":2980,"line":6792},[2978,10993,10994],{"class":3213},"                isOwner",[2978,10996,3006],{"class":2995},[2978,10998,10452],{"class":3180},[2978,11000,8474],{"class":2995},[2978,11002,11003,11005,11007],{"class":2980,"line":6802},[2978,11004,8266],{"class":3191},[2978,11006,10369],{"class":3213},[2978,11008,4526],{"class":2995},[2978,11010,11011,11014,11017],{"class":2980,"line":6807},[2978,11012,11013],{"class":2995},"        }).",[2978,11015,11016],{"class":3195},"ToList",[2978,11018,4733],{"class":2995},[2978,11020,11021],{"class":2980,"line":6812},[2978,11022,3288],{"emptyLinePlaceholder":3287},[2978,11024,11025,11027,11030,11032,11034,11036,11038],{"class":2980,"line":6817},[2978,11026,5714],{"class":3180},[2978,11028,11029],{"class":3213}," collectionLinks",[2978,11031,3188],{"class":2995},[2978,11033,10407],{"class":3213},[2978,11035,3223],{"class":2995},[2978,11037,6652],{"class":3195},[2978,11039,5658],{"class":2995},[2978,11041,11042,11044],{"class":2980,"line":6833},[2978,11043,10440],{"class":3213},[2978,11045,3013],{"class":2995},[2978,11047,11048,11051],{"class":2980,"line":6838},[2978,11049,11050],{"class":3024},"            \"GetArticles\"",[2978,11052,3013],{"class":2995},[2978,11054,11055,11058],{"class":2980,"line":6854},[2978,11056,11057],{"class":3024},"            \"Articles\"",[2978,11059,3013],{"class":2995},[2978,11061,11062,11065],{"class":2980,"line":6859},[2978,11063,11064],{"class":3213},"            page",[2978,11066,3013],{"class":2995},[2978,11068,11069,11072],{"class":2980,"line":6894},[2978,11070,11071],{"class":3213},"            totalPages",[2978,11073,8474],{"class":2995},[2978,11075,11076],{"class":2980,"line":6904},[2978,11077,3288],{"emptyLinePlaceholder":3287},[2978,11079,11080,11082,11085,11087],{"class":2980,"line":6909},[2978,11081,5714],{"class":3180},[2978,11083,11084],{"class":3213}," response",[2978,11086,3188],{"class":2995},[2978,11088,11089],{"class":3180},"new\n",[2978,11091,11092],{"class":2980,"line":6914},[2978,11093,5739],{"class":2995},[2978,11095,11096,11099,11101,11104],{"class":2980,"line":6930},[2978,11097,11098],{"class":3213},"            _links",[2978,11100,3188],{"class":2995},[2978,11102,11103],{"class":3213},"collectionLinks",[2978,11105,3013],{"class":2995},[2978,11107,11108,11111,11113,11115,11117,11119,11121,11124],{"class":2980,"line":6935},[2978,11109,11110],{"class":3213},"            _embedded",[2978,11112,3188],{"class":2995},[2978,11114,4730],{"class":3180},[2978,11116,4559],{"class":2995},[2978,11118,10904],{"class":3213},[2978,11120,3188],{"class":2995},[2978,11122,11123],{"class":3213},"dtos",[2978,11125,3407],{"class":2995},[2978,11127,11128,11130],{"class":2980,"line":6975},[2978,11129,11064],{"class":3213},[2978,11131,3013],{"class":2995},[2978,11133,11134,11137],{"class":2980,"line":6985},[2978,11135,11136],{"class":3213},"            pageSize",[2978,11138,3013],{"class":2995},[2978,11140,11141,11144],{"class":2980,"line":6990},[2978,11142,11143],{"class":3213},"            totalCount",[2978,11145,3013],{"class":2995},[2978,11147,11148],{"class":2980,"line":6995},[2978,11149,11150],{"class":3213},"            totalPages\n",[2978,11152,11153],{"class":2980,"line":7000},[2978,11154,6099],{"class":2995},[2978,11156,11157],{"class":2980,"line":7017},[2978,11158,3288],{"emptyLinePlaceholder":3287},[2978,11160,11161,11163,11165,11167,11170],{"class":2980,"line":7022},[2978,11162,6615],{"class":3191},[2978,11164,10592],{"class":3195},[2978,11166,3199],{"class":2995},[2978,11168,11169],{"class":3213},"response",[2978,11171,8474],{"class":2995},[2978,11173,11174],{"class":2980,"line":7038},[2978,11175,6625],{"class":2995},[2978,11177,11178],{"class":2980,"line":7043},[2978,11179,3288],{"emptyLinePlaceholder":3287},[2978,11181,11182,11184,11186,11188],{"class":2980,"line":7083},[2978,11183,9872],{"class":3174},[2978,11185,4707],{"class":9875},[2978,11187,9879],{"class":9878},[2978,11189,5734],{"class":9875},[2978,11191,11192],{"class":2980,"line":7093},[2978,11193,11194],{"class":3174},"    /// Отримати коментарі до статті\n",[2978,11196,11197,11199,11201,11203],{"class":2980,"line":7098},[2978,11198,9872],{"class":3174},[2978,11200,9893],{"class":9875},[2978,11202,9879],{"class":9878},[2978,11204,5734],{"class":9875},[2978,11206,11207,11209,11211,11213,11216,11218,11220,11222,11225],{"class":2980,"line":7103},[2978,11208,7489],{"class":2995},[2978,11210,9960],{"class":4517},[2978,11212,3199],{"class":2995},[2978,11214,11215],{"class":3024},"\"{id:int}/comments\"",[2978,11217,3456],{"class":2995},[2978,11219,8789],{"class":3213},[2978,11221,3188],{"class":2995},[2978,11223,11224],{"class":3024},"\"GetArticleComments\"",[2978,11226,7499],{"class":2995},[2978,11228,11229,11231,11233,11235,11237,11239,11242,11244,11246,11249,11251,11253,11255],{"class":2980,"line":7119},[2978,11230,7489],{"class":2995},[2978,11232,9983],{"class":4517},[2978,11234,3199],{"class":2995},[2978,11236,9988],{"class":3180},[2978,11238,3199],{"class":2995},[2978,11240,11241],{"class":4517},"List",[2978,11243,4707],{"class":2995},[2978,11245,7641],{"class":4517},[2978,11247,11248],{"class":2995},">), ",[2978,11250,9999],{"class":3213},[2978,11252,3223],{"class":2995},[2978,11254,10004],{"class":3213},[2978,11256,7499],{"class":2995},[2978,11258,11259,11261,11263,11265,11267,11269,11271,11273,11275,11277,11280,11283,11285,11287,11289],{"class":2980,"line":7124},[2978,11260,4550],{"class":3180},[2978,11262,10030],{"class":3180},[2978,11264,10033],{"class":4517},[2978,11266,4707],{"class":2995},[2978,11268,10038],{"class":4517},[2978,11270,4707],{"class":2995},[2978,11272,11241],{"class":4517},[2978,11274,4707],{"class":2995},[2978,11276,7641],{"class":4517},[2978,11278,11279],{"class":2995},">>> ",[2978,11281,11282],{"class":3195},"GetComments",[2978,11284,3199],{"class":2995},[2978,11286,10704],{"class":3180},[2978,11288,10057],{"class":3213},[2978,11290,5704],{"class":2995},[2978,11292,11293],{"class":2980,"line":7159},[2978,11294,5709],{"class":2995},[2978,11296,11297,11299,11301,11303,11305,11307,11309],{"class":2980,"line":7169},[2978,11298,5714],{"class":3180},[2978,11300,3185],{"class":3213},[2978,11302,3188],{"class":2995},[2978,11304,3192],{"class":3180},[2978,11306,9709],{"class":3213},[2978,11308,3223],{"class":2995},[2978,11310,10821],{"class":3213},[2978,11312,11313,11315,11317,11319,11321,11323,11325,11327,11329],{"class":2980,"line":7174},[2978,11314,8315],{"class":2995},[2978,11316,10180],{"class":3195},[2978,11318,3199],{"class":2995},[2978,11320,10185],{"class":3213},[2978,11322,8325],{"class":2995},[2978,11324,10185],{"class":3213},[2978,11326,3223],{"class":2995},[2978,11328,4716],{"class":3213},[2978,11330,5704],{"class":2995},[2978,11332,11333,11335,11337,11339,11341,11343,11345,11347,11349,11351,11353],{"class":2980,"line":7179},[2978,11334,8315],{"class":2995},[2978,11336,10306],{"class":3195},[2978,11338,3199],{"class":2995},[2978,11340,10185],{"class":3213},[2978,11342,8325],{"class":2995},[2978,11344,10185],{"class":3213},[2978,11346,3223],{"class":2995},[2978,11348,8780],{"class":3213},[2978,11350,6122],{"class":2995},[2978,11352,5792],{"class":3213},[2978,11354,8474],{"class":2995},[2978,11356,11357],{"class":2980,"line":7184},[2978,11358,3288],{"emptyLinePlaceholder":3287},[2978,11360,11361,11363,11365,11367,11369,11371],{"class":2980,"line":7193},[2978,11362,6113],{"class":3191},[2978,11364,6116],{"class":2995},[2978,11366,3252],{"class":3213},[2978,11368,10339],{"class":3180},[2978,11370,10342],{"class":3180},[2978,11372,5704],{"class":2995},[2978,11374,11375,11377,11379],{"class":2980,"line":7198},[2978,11376,8266],{"class":3191},[2978,11378,10351],{"class":3195},[2978,11380,4733],{"class":2995},[2978,11382,11384],{"class":2980,"line":11383},140,[2978,11385,3288],{"emptyLinePlaceholder":3287},[2978,11387,11389,11391,11393,11395,11397,11399,11401,11403,11405,11407,11410,11412,11414],{"class":2980,"line":11388},141,[2978,11390,5714],{"class":3180},[2978,11392,10899],{"class":3213},[2978,11394,3188],{"class":2995},[2978,11396,3252],{"class":3213},[2978,11398,3223],{"class":2995},[2978,11400,4716],{"class":3213},[2978,11402,3223],{"class":2995},[2978,11404,8318],{"class":3195},[2978,11406,3199],{"class":2995},[2978,11408,11409],{"class":3213},"c",[2978,11411,8325],{"class":2995},[2978,11413,4730],{"class":3180},[2978,11415,7938],{"class":4517},[2978,11417,11419],{"class":2980,"line":11418},142,[2978,11420,5739],{"class":2995},[2978,11422,11424,11427,11429,11431,11433,11435],{"class":2980,"line":11423},143,[2978,11425,11426],{"class":3213},"            Id",[2978,11428,3188],{"class":2995},[2978,11430,11409],{"class":3213},[2978,11432,3223],{"class":2995},[2978,11434,8780],{"class":3213},[2978,11436,3013],{"class":2995},[2978,11438,11440,11443,11445,11447,11449,11451],{"class":2980,"line":11439},144,[2978,11441,11442],{"class":3213},"            Text",[2978,11444,3188],{"class":2995},[2978,11446,11409],{"class":3213},[2978,11448,3223],{"class":2995},[2978,11450,7275],{"class":3213},[2978,11452,3013],{"class":2995},[2978,11454,11456,11459,11461,11463,11465,11467],{"class":2980,"line":11455},145,[2978,11457,11458],{"class":3213},"            AuthorName",[2978,11460,3188],{"class":2995},[2978,11462,11409],{"class":3213},[2978,11464,3223],{"class":2995},[2978,11466,9370],{"class":3213},[2978,11468,3013],{"class":2995},[2978,11470,11472,11475,11477,11479,11481,11483],{"class":2980,"line":11471},146,[2978,11473,11474],{"class":3213},"            CreatedAt",[2978,11476,3188],{"class":2995},[2978,11478,11409],{"class":3213},[2978,11480,3223],{"class":2995},[2978,11482,9379],{"class":3213},[2978,11484,3013],{"class":2995},[2978,11486,11488,11491,11493,11495,11497,11499,11501,11503,11505],{"class":2980,"line":11487},147,[2978,11489,11490],{"class":3213},"            Links",[2978,11492,3188],{"class":2995},[2978,11494,4730],{"class":3180},[2978,11496,5484],{"class":4517},[2978,11498,4707],{"class":2995},[2978,11500,5489],{"class":3180},[2978,11502,3456],{"class":2995},[2978,11504,5494],{"class":4517},[2978,11506,5734],{"class":2995},[2978,11508,11510],{"class":2980,"line":11509},148,[2978,11511,5758],{"class":2995},[2978,11513,11515,11518,11520,11522,11524],{"class":2980,"line":11514},149,[2978,11516,11517],{"class":2995},"                [",[2978,11519,3738],{"class":3024},[2978,11521,5749],{"class":2995},[2978,11523,4730],{"class":3180},[2978,11525,5363],{"class":4517},[2978,11527,11529],{"class":2980,"line":11528},150,[2978,11530,11531],{"class":2995},"                {\n",[2978,11533,11535,11538,11540,11543,11545,11547,11549,11552,11554,11557,11559,11561,11563,11565,11567,11569,11571,11573],{"class":2980,"line":11534},151,[2978,11536,11537],{"class":3213},"                    Href",[2978,11539,3188],{"class":2995},[2978,11541,11542],{"class":3213},"_urlHelper",[2978,11544,3223],{"class":2995},[2978,11546,5773],{"class":3195},[2978,11548,3199],{"class":2995},[2978,11550,11551],{"class":3024},"\"GetCommentById\"",[2978,11553,3456],{"class":2995},[2978,11555,11556],{"class":3024},"\"Comments\"",[2978,11558,3456],{"class":2995},[2978,11560,4730],{"class":3180},[2978,11562,4559],{"class":2995},[2978,11564,5792],{"class":3213},[2978,11566,3188],{"class":2995},[2978,11568,11409],{"class":3213},[2978,11570,3223],{"class":2995},[2978,11572,8780],{"class":3213},[2978,11574,5800],{"class":2995},[2978,11576,11578,11581,11583],{"class":2980,"line":11577},152,[2978,11579,11580],{"class":3213},"                    Rel",[2978,11582,3188],{"class":2995},[2978,11584,6799],{"class":3024},[2978,11586,11588],{"class":2980,"line":11587},153,[2978,11589,11590],{"class":2995},"                },\n",[2978,11592,11594,11596,11599,11601,11603],{"class":2980,"line":11593},154,[2978,11595,11517],{"class":2995},[2978,11597,11598],{"class":3024},"\"article\"",[2978,11600,5749],{"class":2995},[2978,11602,4730],{"class":3180},[2978,11604,5363],{"class":4517},[2978,11606,11608],{"class":2980,"line":11607},155,[2978,11609,11531],{"class":2995},[2978,11611,11613,11615,11617,11619,11621,11623,11625,11627,11629,11631,11633,11635,11637,11639,11641,11643,11645,11647],{"class":2980,"line":11612},156,[2978,11614,11537],{"class":3213},[2978,11616,3188],{"class":2995},[2978,11618,11542],{"class":3213},[2978,11620,3223],{"class":2995},[2978,11622,5773],{"class":3195},[2978,11624,3199],{"class":2995},[2978,11626,5778],{"class":3024},[2978,11628,3456],{"class":2995},[2978,11630,5783],{"class":3024},[2978,11632,3456],{"class":2995},[2978,11634,4730],{"class":3180},[2978,11636,4559],{"class":2995},[2978,11638,5792],{"class":3213},[2978,11640,3188],{"class":2995},[2978,11642,3252],{"class":3213},[2978,11644,3223],{"class":2995},[2978,11646,8780],{"class":3213},[2978,11648,5800],{"class":2995},[2978,11650,11652,11654,11656],{"class":2980,"line":11651},157,[2978,11653,11580],{"class":3213},[2978,11655,3188],{"class":2995},[2978,11657,11658],{"class":3024},"\"article\"\n",[2978,11660,11662],{"class":2980,"line":11661},158,[2978,11663,11664],{"class":2995},"                }\n",[2978,11666,11668],{"class":2980,"line":11667},159,[2978,11669,6094],{"class":2995},[2978,11671,11673,11675,11677],{"class":2980,"line":11672},160,[2978,11674,11013],{"class":2995},[2978,11676,11016],{"class":3195},[2978,11678,4733],{"class":2995},[2978,11680,11682],{"class":2980,"line":11681},161,[2978,11683,3288],{"emptyLinePlaceholder":3287},[2978,11685,11687,11689,11691,11693,11695],{"class":2980,"line":11686},162,[2978,11688,6615],{"class":3191},[2978,11690,10592],{"class":3195},[2978,11692,3199],{"class":2995},[2978,11694,11123],{"class":3213},[2978,11696,8474],{"class":2995},[2978,11698,11700],{"class":2980,"line":11699},163,[2978,11701,6625],{"class":2995},[2978,11703,11705],{"class":2980,"line":11704},164,[2978,11706,3288],{"emptyLinePlaceholder":3287},[2978,11708,11710,11712,11714,11716],{"class":2980,"line":11709},165,[2978,11711,9872],{"class":3174},[2978,11713,4707],{"class":9875},[2978,11715,9879],{"class":9878},[2978,11717,5734],{"class":9875},[2978,11719,11721],{"class":2980,"line":11720},166,[2978,11722,11723],{"class":3174},"    /// Створити нову статтю\n",[2978,11725,11727,11729,11731,11733],{"class":2980,"line":11726},167,[2978,11728,9872],{"class":3174},[2978,11730,9893],{"class":9875},[2978,11732,9879],{"class":9878},[2978,11734,5734],{"class":9875},[2978,11736,11738,11740,11743,11745,11747,11749,11752],{"class":2980,"line":11737},168,[2978,11739,7489],{"class":2995},[2978,11741,11742],{"class":4517},"HttpPost",[2978,11744,3199],{"class":2995},[2978,11746,8789],{"class":3213},[2978,11748,3188],{"class":2995},[2978,11750,11751],{"class":3024},"\"CreateArticle\"",[2978,11753,7499],{"class":2995},[2978,11755,11757,11759,11761,11763,11765,11767,11769,11771,11773,11775,11778],{"class":2980,"line":11756},169,[2978,11758,7489],{"class":2995},[2978,11760,9983],{"class":4517},[2978,11762,3199],{"class":2995},[2978,11764,9988],{"class":3180},[2978,11766,3199],{"class":2995},[2978,11768,9993],{"class":4517},[2978,11770,9996],{"class":2995},[2978,11772,9999],{"class":3213},[2978,11774,3223],{"class":2995},[2978,11776,11777],{"class":3213},"Status201Created",[2978,11779,7499],{"class":2995},[2978,11781,11783,11785,11787,11789,11791,11793,11795,11797,11799,11802,11805,11808,11810,11813,11815],{"class":2980,"line":11782},170,[2978,11784,4550],{"class":3180},[2978,11786,10030],{"class":3180},[2978,11788,10033],{"class":4517},[2978,11790,4707],{"class":2995},[2978,11792,10038],{"class":4517},[2978,11794,4707],{"class":2995},[2978,11796,9993],{"class":4517},[2978,11798,10045],{"class":2995},[2978,11800,11801],{"class":3195},"Create",[2978,11803,11804],{"class":2995},"([",[2978,11806,11807],{"class":4517},"FromBody",[2978,11809,10070],{"class":2995},[2978,11811,11812],{"class":4517},"CreateArticleDto",[2978,11814,10369],{"class":3213},[2978,11816,5704],{"class":2995},[2978,11818,11820],{"class":2980,"line":11819},171,[2978,11821,5709],{"class":2995},[2978,11823,11825,11827,11829,11831,11833],{"class":2980,"line":11824},172,[2978,11826,5714],{"class":3180},[2978,11828,3185],{"class":3213},[2978,11830,3188],{"class":2995},[2978,11832,4730],{"class":3180},[2978,11834,4541],{"class":4517},[2978,11836,11838],{"class":2980,"line":11837},173,[2978,11839,5739],{"class":2995},[2978,11841,11843,11846,11848,11850,11852,11854],{"class":2980,"line":11842},174,[2978,11844,11845],{"class":3213},"            Title",[2978,11847,3188],{"class":2995},[2978,11849,10489],{"class":3213},[2978,11851,3223],{"class":2995},[2978,11853,5446],{"class":3213},[2978,11855,3013],{"class":2995},[2978,11857,11859,11862,11864,11866,11868,11871],{"class":2980,"line":11858},175,[2978,11860,11861],{"class":3213},"            Content",[2978,11863,3188],{"class":2995},[2978,11865,10489],{"class":3213},[2978,11867,3223],{"class":2995},[2978,11869,11870],{"class":3213},"Content",[2978,11872,3013],{"class":2995},[2978,11874,11876,11879,11881,11883,11885,11887],{"class":2980,"line":11875},176,[2978,11877,11878],{"class":3213},"            AuthorId",[2978,11880,3188],{"class":2995},[2978,11882,10489],{"class":3213},[2978,11884,3223],{"class":2995},[2978,11886,10519],{"class":3213},[2978,11888,3013],{"class":2995},[2978,11890,11892,11895,11897,11899,11901,11903],{"class":2980,"line":11891},177,[2978,11893,11894],{"class":3213},"            CategoryId",[2978,11896,3188],{"class":2995},[2978,11898,10489],{"class":3213},[2978,11900,3223],{"class":2995},[2978,11902,10575],{"class":3213},[2978,11904,3013],{"class":2995},[2978,11906,11908,11911,11913,11915,11917],{"class":2980,"line":11907},178,[2978,11909,11910],{"class":3213},"            Status",[2978,11912,3188],{"class":2995},[2978,11914,4807],{"class":3213},[2978,11916,3223],{"class":2995},[2978,11918,11919],{"class":3213},"Draft\n",[2978,11921,11923],{"class":2980,"line":11922},179,[2978,11924,6099],{"class":2995},[2978,11926,11928],{"class":2980,"line":11927},180,[2978,11929,3288],{"emptyLinePlaceholder":3287},[2978,11931,11933,11935,11937,11939,11941,11944,11946,11948],{"class":2980,"line":11932},181,[2978,11934,9813],{"class":3213},[2978,11936,3223],{"class":2995},[2978,11938,4987],{"class":3213},[2978,11940,3223],{"class":2995},[2978,11942,11943],{"class":3195},"Add",[2978,11945,3199],{"class":2995},[2978,11947,3252],{"class":3213},[2978,11949,8474],{"class":2995},[2978,11951,11953,11956,11958,11960,11963],{"class":2980,"line":11952},182,[2978,11954,11955],{"class":3180},"        await",[2978,11957,9709],{"class":3213},[2978,11959,3223],{"class":2995},[2978,11961,11962],{"class":3195},"SaveChangesAsync",[2978,11964,4733],{"class":2995},[2978,11966,11968],{"class":2980,"line":11967},183,[2978,11969,3288],{"emptyLinePlaceholder":3287},[2978,11971,11973,11975,11978,11980,11982,11984,11986,11988,11990,11992],{"class":2980,"line":11972},184,[2978,11974,5714],{"class":3180},[2978,11976,11977],{"class":3213}," resultDto",[2978,11979,3188],{"class":2995},[2978,11981,10374],{"class":3195},[2978,11983,3199],{"class":2995},[2978,11985,3252],{"class":3213},[2978,11987,3456],{"class":2995},[2978,11989,4730],{"class":3180},[2978,11991,8223],{"class":4517},[2978,11993,3228],{"class":2995},[2978,11995,11997,12000,12002,12004,12006,12008,12010,12012],{"class":2980,"line":11996},185,[2978,11998,11999],{"class":3213},"        resultDto",[2978,12001,3223],{"class":2995},[2978,12003,5499],{"class":3213},[2978,12005,3188],{"class":2995},[2978,12007,10407],{"class":3213},[2978,12009,3223],{"class":2995},[2978,12011,5655],{"class":3195},[2978,12013,5658],{"class":2995},[2978,12015,12017,12019,12021,12023],{"class":2980,"line":12016},186,[2978,12018,10418],{"class":3213},[2978,12020,3223],{"class":2995},[2978,12022,8780],{"class":3213},[2978,12024,3013],{"class":2995},[2978,12026,12028,12030,12032,12034],{"class":2980,"line":12027},187,[2978,12029,10418],{"class":3213},[2978,12031,3223],{"class":2995},[2978,12033,10433],{"class":3213},[2978,12035,3013],{"class":2995},[2978,12037,12039,12041],{"class":2980,"line":12038},188,[2978,12040,10440],{"class":3213},[2978,12042,3013],{"class":2995},[2978,12044,12046,12048,12050,12052],{"class":2980,"line":12045},189,[2978,12047,10447],{"class":3213},[2978,12049,3006],{"class":2995},[2978,12051,10452],{"class":3180},[2978,12053,8474],{"class":2995},[2978,12055,12057],{"class":2980,"line":12056},190,[2978,12058,3288],{"emptyLinePlaceholder":3287},[2978,12060,12062,12064,12067],{"class":2980,"line":12061},191,[2978,12063,6615],{"class":3191},[2978,12065,12066],{"class":3195}," CreatedAtAction",[2978,12068,5658],{"class":2995},[2978,12070,12072,12075,12077,12079],{"class":2980,"line":12071},192,[2978,12073,12074],{"class":3180},"            nameof",[2978,12076,3199],{"class":2995},[2978,12078,10048],{"class":3213},[2978,12080,8388],{"class":2995},[2978,12082,12084,12086,12088,12090,12092,12094,12096,12098],{"class":2980,"line":12083},193,[2978,12085,8773],{"class":3180},[2978,12087,4559],{"class":2995},[2978,12089,5792],{"class":3213},[2978,12091,3188],{"class":2995},[2978,12093,3252],{"class":3213},[2978,12095,3223],{"class":2995},[2978,12097,8780],{"class":3213},[2978,12099,3407],{"class":2995},[2978,12101,12103,12106],{"class":2980,"line":12102},194,[2978,12104,12105],{"class":3213},"            resultDto",[2978,12107,8474],{"class":2995},[2978,12109,12111],{"class":2980,"line":12110},195,[2978,12112,6625],{"class":2995},[2978,12114,12116],{"class":2980,"line":12115},196,[2978,12117,3288],{"emptyLinePlaceholder":3287},[2978,12119,12121,12123,12125,12127],{"class":2980,"line":12120},197,[2978,12122,9872],{"class":3174},[2978,12124,4707],{"class":9875},[2978,12126,9879],{"class":9878},[2978,12128,5734],{"class":9875},[2978,12130,12132],{"class":2980,"line":12131},198,[2978,12133,12134],{"class":3174},"    /// Опублікувати статтю (змінити статус на Published)\n",[2978,12136,12138,12140,12142,12144],{"class":2980,"line":12137},199,[2978,12139,9872],{"class":3174},[2978,12141,9893],{"class":9875},[2978,12143,9879],{"class":9878},[2978,12145,5734],{"class":9875},[2978,12147,12149,12151,12153,12155,12158,12160,12162,12164,12167],{"class":2980,"line":12148},200,[2978,12150,7489],{"class":2995},[2978,12152,11742],{"class":4517},[2978,12154,3199],{"class":2995},[2978,12156,12157],{"class":3024},"\"{id:int}/publish\"",[2978,12159,3456],{"class":2995},[2978,12161,8789],{"class":3213},[2978,12163,3188],{"class":2995},[2978,12165,12166],{"class":3024},"\"PublishArticle\"",[2978,12168,7499],{"class":2995},[2978,12170,12172,12174,12176,12178,12180,12182,12184,12186,12188,12190,12192],{"class":2980,"line":12171},201,[2978,12173,7489],{"class":2995},[2978,12175,9983],{"class":4517},[2978,12177,3199],{"class":2995},[2978,12179,9988],{"class":3180},[2978,12181,3199],{"class":2995},[2978,12183,9993],{"class":4517},[2978,12185,9996],{"class":2995},[2978,12187,9999],{"class":3213},[2978,12189,3223],{"class":2995},[2978,12191,10004],{"class":3213},[2978,12193,7499],{"class":2995},[2978,12195,12197,12199,12201,12203,12205,12207,12209],{"class":2980,"line":12196},202,[2978,12198,7489],{"class":2995},[2978,12200,9983],{"class":4517},[2978,12202,3199],{"class":2995},[2978,12204,9999],{"class":3213},[2978,12206,3223],{"class":2995},[2978,12208,10021],{"class":3213},[2978,12210,7499],{"class":2995},[2978,12212,12214,12216,12218,12220,12222,12224,12227],{"class":2980,"line":12213},203,[2978,12215,7489],{"class":2995},[2978,12217,9983],{"class":4517},[2978,12219,3199],{"class":2995},[2978,12221,9999],{"class":3213},[2978,12223,3223],{"class":2995},[2978,12225,12226],{"class":3213},"Status400BadRequest",[2978,12228,7499],{"class":2995},[2978,12230,12232,12234,12236,12238,12240,12242,12244,12246,12248,12251,12253,12255,12257],{"class":2980,"line":12231},204,[2978,12233,4550],{"class":3180},[2978,12235,10030],{"class":3180},[2978,12237,10033],{"class":4517},[2978,12239,4707],{"class":2995},[2978,12241,10038],{"class":4517},[2978,12243,4707],{"class":2995},[2978,12245,9993],{"class":4517},[2978,12247,10045],{"class":2995},[2978,12249,12250],{"class":3195},"Publish",[2978,12252,3199],{"class":2995},[2978,12254,10704],{"class":3180},[2978,12256,10057],{"class":3213},[2978,12258,5704],{"class":2995},[2978,12260,12262],{"class":2980,"line":12261},205,[2978,12263,5709],{"class":2995},[2978,12265,12267,12269,12271,12273,12275,12277,12279,12281,12283,12286,12288,12290],{"class":2980,"line":12266},206,[2978,12268,5714],{"class":3180},[2978,12270,3185],{"class":3213},[2978,12272,3188],{"class":2995},[2978,12274,3192],{"class":3180},[2978,12276,9709],{"class":3213},[2978,12278,3223],{"class":2995},[2978,12280,4987],{"class":3213},[2978,12282,3223],{"class":2995},[2978,12284,12285],{"class":3195},"FindAsync",[2978,12287,3199],{"class":2995},[2978,12289,5792],{"class":3213},[2978,12291,8474],{"class":2995},[2978,12293,12295],{"class":2980,"line":12294},207,[2978,12296,3288],{"emptyLinePlaceholder":3287},[2978,12298,12300,12302,12304,12306,12308,12310],{"class":2980,"line":12299},208,[2978,12301,6113],{"class":3191},[2978,12303,6116],{"class":2995},[2978,12305,3252],{"class":3213},[2978,12307,10339],{"class":3180},[2978,12309,10342],{"class":3180},[2978,12311,5704],{"class":2995},[2978,12313,12315,12317,12319],{"class":2980,"line":12314},209,[2978,12316,8266],{"class":3191},[2978,12318,10351],{"class":3195},[2978,12320,4733],{"class":2995},[2978,12322,12324],{"class":2980,"line":12323},210,[2978,12325,3288],{"emptyLinePlaceholder":3287},[2978,12327,12329,12331,12333,12335,12337,12339,12341,12343,12345,12347],{"class":2980,"line":12328},211,[2978,12330,6113],{"class":3191},[2978,12332,6116],{"class":2995},[2978,12334,3252],{"class":3213},[2978,12336,3223],{"class":2995},[2978,12338,10433],{"class":3213},[2978,12340,6259],{"class":2995},[2978,12342,4807],{"class":3213},[2978,12344,3223],{"class":2995},[2978,12346,4812],{"class":3213},[2978,12348,5704],{"class":2995},[2978,12350,12352,12354,12357,12359,12361],{"class":2980,"line":12351},212,[2978,12353,8266],{"class":3191},[2978,12355,12356],{"class":3195}," BadRequest",[2978,12358,3199],{"class":2995},[2978,12360,4730],{"class":3180},[2978,12362,12363],{"class":4517}," ProblemDetails\n",[2978,12365,12367],{"class":2980,"line":12366},213,[2978,12368,5758],{"class":2995},[2978,12370,12372,12374,12376,12379],{"class":2980,"line":12371},214,[2978,12373,5827],{"class":3213},[2978,12375,3188],{"class":2995},[2978,12377,12378],{"class":3024},"\"Invalid Operation\"",[2978,12380,3013],{"class":2995},[2978,12382,12384,12387,12389],{"class":2980,"line":12383},215,[2978,12385,12386],{"class":3213},"                Detail",[2978,12388,3188],{"class":2995},[2978,12390,12391],{"class":3024},"\"Only draft articles can be published\"\n",[2978,12393,12395],{"class":2980,"line":12394},216,[2978,12396,12397],{"class":2995},"            });\n",[2978,12399,12401],{"class":2980,"line":12400},217,[2978,12402,3288],{"emptyLinePlaceholder":3287},[2978,12404,12406,12409,12411,12413,12415,12417,12419,12421],{"class":2980,"line":12405},218,[2978,12407,12408],{"class":3213},"        article",[2978,12410,3223],{"class":2995},[2978,12412,10433],{"class":3213},[2978,12414,3188],{"class":2995},[2978,12416,4807],{"class":3213},[2978,12418,3223],{"class":2995},[2978,12420,6498],{"class":3213},[2978,12422,4526],{"class":2995},[2978,12424,12426,12428,12430,12432,12434,12436,12438,12440],{"class":2980,"line":12425},219,[2978,12427,12408],{"class":3213},[2978,12429,3223],{"class":2995},[2978,12431,10841],{"class":3213},[2978,12433,3188],{"class":2995},[2978,12435,4756],{"class":3213},[2978,12437,3223],{"class":2995},[2978,12439,4761],{"class":3213},[2978,12441,4526],{"class":2995},[2978,12443,12445,12447,12449,12451,12453],{"class":2980,"line":12444},220,[2978,12446,11955],{"class":3180},[2978,12448,9709],{"class":3213},[2978,12450,3223],{"class":2995},[2978,12452,11962],{"class":3195},[2978,12454,4733],{"class":2995},[2978,12456,12458],{"class":2980,"line":12457},221,[2978,12459,3288],{"emptyLinePlaceholder":3287},[2978,12461,12463,12465,12467,12469,12471,12473,12475,12477,12479,12481],{"class":2980,"line":12462},222,[2978,12464,5714],{"class":3180},[2978,12466,10369],{"class":3213},[2978,12468,3188],{"class":2995},[2978,12470,10374],{"class":3195},[2978,12472,3199],{"class":2995},[2978,12474,3252],{"class":3213},[2978,12476,3456],{"class":2995},[2978,12478,4730],{"class":3180},[2978,12480,8223],{"class":4517},[2978,12482,3228],{"class":2995},[2978,12484,12486,12488,12490,12492,12494,12496,12498,12500],{"class":2980,"line":12485},223,[2978,12487,10398],{"class":3213},[2978,12489,3223],{"class":2995},[2978,12491,5499],{"class":3213},[2978,12493,3188],{"class":2995},[2978,12495,10407],{"class":3213},[2978,12497,3223],{"class":2995},[2978,12499,5655],{"class":3195},[2978,12501,5658],{"class":2995},[2978,12503,12505,12507,12509,12511],{"class":2980,"line":12504},224,[2978,12506,10418],{"class":3213},[2978,12508,3223],{"class":2995},[2978,12510,8780],{"class":3213},[2978,12512,3013],{"class":2995},[2978,12514,12516,12518,12520,12522],{"class":2980,"line":12515},225,[2978,12517,10418],{"class":3213},[2978,12519,3223],{"class":2995},[2978,12521,10433],{"class":3213},[2978,12523,3013],{"class":2995},[2978,12525,12527,12529],{"class":2980,"line":12526},226,[2978,12528,10440],{"class":3213},[2978,12530,3013],{"class":2995},[2978,12532,12534,12536,12538,12540],{"class":2980,"line":12533},227,[2978,12535,10447],{"class":3213},[2978,12537,3006],{"class":2995},[2978,12539,10452],{"class":3180},[2978,12541,8474],{"class":2995},[2978,12543,12545],{"class":2980,"line":12544},228,[2978,12546,3288],{"emptyLinePlaceholder":3287},[2978,12548,12550,12552,12554,12556,12558],{"class":2980,"line":12549},229,[2978,12551,6615],{"class":3191},[2978,12553,10592],{"class":3195},[2978,12555,3199],{"class":2995},[2978,12557,10489],{"class":3213},[2978,12559,8474],{"class":2995},[2978,12561,12563],{"class":2980,"line":12562},230,[2978,12564,6625],{"class":2995},[2978,12566,12568],{"class":2980,"line":12567},231,[2978,12569,3288],{"emptyLinePlaceholder":3287},[2978,12571,12573,12575,12577,12579],{"class":2980,"line":12572},232,[2978,12574,9872],{"class":3174},[2978,12576,4707],{"class":9875},[2978,12578,9879],{"class":9878},[2978,12580,5734],{"class":9875},[2978,12582,12584],{"class":2980,"line":12583},233,[2978,12585,12586],{"class":3174},"    /// Архівувати статтю\n",[2978,12588,12590,12592,12594,12596],{"class":2980,"line":12589},234,[2978,12591,9872],{"class":3174},[2978,12593,9893],{"class":9875},[2978,12595,9879],{"class":9878},[2978,12597,5734],{"class":9875},[2978,12599,12601,12603,12605,12607,12610,12612,12614,12616,12619],{"class":2980,"line":12600},235,[2978,12602,7489],{"class":2995},[2978,12604,11742],{"class":4517},[2978,12606,3199],{"class":2995},[2978,12608,12609],{"class":3024},"\"{id:int}/archive\"",[2978,12611,3456],{"class":2995},[2978,12613,8789],{"class":3213},[2978,12615,3188],{"class":2995},[2978,12617,12618],{"class":3024},"\"ArchiveArticle\"",[2978,12620,7499],{"class":2995},[2978,12622,12624,12626,12628,12630,12632,12634,12636,12638,12640,12642,12644],{"class":2980,"line":12623},236,[2978,12625,7489],{"class":2995},[2978,12627,9983],{"class":4517},[2978,12629,3199],{"class":2995},[2978,12631,9988],{"class":3180},[2978,12633,3199],{"class":2995},[2978,12635,9993],{"class":4517},[2978,12637,9996],{"class":2995},[2978,12639,9999],{"class":3213},[2978,12641,3223],{"class":2995},[2978,12643,10004],{"class":3213},[2978,12645,7499],{"class":2995},[2978,12647,12649,12651,12653,12655,12657,12659,12661,12663,12665,12668,12670,12672,12674],{"class":2980,"line":12648},237,[2978,12650,4550],{"class":3180},[2978,12652,10030],{"class":3180},[2978,12654,10033],{"class":4517},[2978,12656,4707],{"class":2995},[2978,12658,10038],{"class":4517},[2978,12660,4707],{"class":2995},[2978,12662,9993],{"class":4517},[2978,12664,10045],{"class":2995},[2978,12666,12667],{"class":3195},"Archive",[2978,12669,3199],{"class":2995},[2978,12671,10704],{"class":3180},[2978,12673,10057],{"class":3213},[2978,12675,5704],{"class":2995},[2978,12677,12679],{"class":2980,"line":12678},238,[2978,12680,5709],{"class":2995},[2978,12682,12684,12686,12688,12690,12692,12694,12696,12698,12700,12702,12704,12706],{"class":2980,"line":12683},239,[2978,12685,5714],{"class":3180},[2978,12687,3185],{"class":3213},[2978,12689,3188],{"class":2995},[2978,12691,3192],{"class":3180},[2978,12693,9709],{"class":3213},[2978,12695,3223],{"class":2995},[2978,12697,4987],{"class":3213},[2978,12699,3223],{"class":2995},[2978,12701,12285],{"class":3195},[2978,12703,3199],{"class":2995},[2978,12705,5792],{"class":3213},[2978,12707,8474],{"class":2995},[2978,12709,12711],{"class":2980,"line":12710},240,[2978,12712,3288],{"emptyLinePlaceholder":3287},[2978,12714,12716,12718,12720,12722,12724,12726],{"class":2980,"line":12715},241,[2978,12717,6113],{"class":3191},[2978,12719,6116],{"class":2995},[2978,12721,3252],{"class":3213},[2978,12723,10339],{"class":3180},[2978,12725,10342],{"class":3180},[2978,12727,5704],{"class":2995},[2978,12729,12731,12733,12735],{"class":2980,"line":12730},242,[2978,12732,8266],{"class":3191},[2978,12734,10351],{"class":3195},[2978,12736,4733],{"class":2995},[2978,12738,12740],{"class":2980,"line":12739},243,[2978,12741,3288],{"emptyLinePlaceholder":3287},[2978,12743,12745,12747,12749,12751,12753,12755,12757,12759],{"class":2980,"line":12744},244,[2978,12746,12408],{"class":3213},[2978,12748,3223],{"class":2995},[2978,12750,10433],{"class":3213},[2978,12752,3188],{"class":2995},[2978,12754,4807],{"class":3213},[2978,12756,3223],{"class":2995},[2978,12758,6266],{"class":3213},[2978,12760,4526],{"class":2995},[2978,12762,12764,12766,12768,12770,12772],{"class":2980,"line":12763},245,[2978,12765,11955],{"class":3180},[2978,12767,9709],{"class":3213},[2978,12769,3223],{"class":2995},[2978,12771,11962],{"class":3195},[2978,12773,4733],{"class":2995},[2978,12775,12777],{"class":2980,"line":12776},246,[2978,12778,3288],{"emptyLinePlaceholder":3287},[2978,12780,12782,12784,12786,12788,12790,12792,12794,12796,12798,12800],{"class":2980,"line":12781},247,[2978,12783,5714],{"class":3180},[2978,12785,10369],{"class":3213},[2978,12787,3188],{"class":2995},[2978,12789,10374],{"class":3195},[2978,12791,3199],{"class":2995},[2978,12793,3252],{"class":3213},[2978,12795,3456],{"class":2995},[2978,12797,4730],{"class":3180},[2978,12799,8223],{"class":4517},[2978,12801,3228],{"class":2995},[2978,12803,12805,12807,12809,12811,12813,12815,12817,12819],{"class":2980,"line":12804},248,[2978,12806,10398],{"class":3213},[2978,12808,3223],{"class":2995},[2978,12810,5499],{"class":3213},[2978,12812,3188],{"class":2995},[2978,12814,10407],{"class":3213},[2978,12816,3223],{"class":2995},[2978,12818,5655],{"class":3195},[2978,12820,5658],{"class":2995},[2978,12822,12824,12826,12828,12830],{"class":2980,"line":12823},249,[2978,12825,10418],{"class":3213},[2978,12827,3223],{"class":2995},[2978,12829,8780],{"class":3213},[2978,12831,3013],{"class":2995},[2978,12833,12835,12837,12839,12841],{"class":2980,"line":12834},250,[2978,12836,10418],{"class":3213},[2978,12838,3223],{"class":2995},[2978,12840,10433],{"class":3213},[2978,12842,3013],{"class":2995},[2978,12844,12846,12848],{"class":2980,"line":12845},251,[2978,12847,10440],{"class":3213},[2978,12849,3013],{"class":2995},[2978,12851,12853,12855,12857,12859],{"class":2980,"line":12852},252,[2978,12854,10447],{"class":3213},[2978,12856,3006],{"class":2995},[2978,12858,10452],{"class":3180},[2978,12860,8474],{"class":2995},[2978,12862,12864],{"class":2980,"line":12863},253,[2978,12865,3288],{"emptyLinePlaceholder":3287},[2978,12867,12869,12871,12873,12875,12877],{"class":2980,"line":12868},254,[2978,12870,6615],{"class":3191},[2978,12872,10592],{"class":3195},[2978,12874,3199],{"class":2995},[2978,12876,10489],{"class":3213},[2978,12878,8474],{"class":2995},[2978,12880,12882],{"class":2980,"line":12881},255,[2978,12883,6625],{"class":2995},[2978,12885,12887],{"class":2980,"line":12886},256,[2978,12888,3288],{"emptyLinePlaceholder":3287},[2978,12890,12892,12894,12896,12898],{"class":2980,"line":12891},257,[2978,12893,9872],{"class":3174},[2978,12895,4707],{"class":9875},[2978,12897,9879],{"class":9878},[2978,12899,5734],{"class":9875},[2978,12901,12903],{"class":2980,"line":12902},258,[2978,12904,12905],{"class":3174},"    /// Оновити статтю\n",[2978,12907,12909,12911,12913,12915],{"class":2980,"line":12908},259,[2978,12910,9872],{"class":3174},[2978,12912,9893],{"class":9875},[2978,12914,9879],{"class":9878},[2978,12916,5734],{"class":9875},[2978,12918,12920,12922,12925,12927,12929,12931,12933,12935,12938],{"class":2980,"line":12919},260,[2978,12921,7489],{"class":2995},[2978,12923,12924],{"class":4517},"HttpPut",[2978,12926,3199],{"class":2995},[2978,12928,9965],{"class":3024},[2978,12930,3456],{"class":2995},[2978,12932,8789],{"class":3213},[2978,12934,3188],{"class":2995},[2978,12936,12937],{"class":3024},"\"UpdateArticle\"",[2978,12939,7499],{"class":2995},[2978,12941,12943,12945,12947,12949,12951,12953,12955,12957,12959,12961,12963],{"class":2980,"line":12942},261,[2978,12944,7489],{"class":2995},[2978,12946,9983],{"class":4517},[2978,12948,3199],{"class":2995},[2978,12950,9988],{"class":3180},[2978,12952,3199],{"class":2995},[2978,12954,9993],{"class":4517},[2978,12956,9996],{"class":2995},[2978,12958,9999],{"class":3213},[2978,12960,3223],{"class":2995},[2978,12962,10004],{"class":3213},[2978,12964,7499],{"class":2995},[2978,12966,12968,12970,12972,12974,12976,12978,12980,12982,12984,12987,12989,12991,12993,12996,12998,13000,13003,13005],{"class":2980,"line":12967},262,[2978,12969,4550],{"class":3180},[2978,12971,10030],{"class":3180},[2978,12973,10033],{"class":4517},[2978,12975,4707],{"class":2995},[2978,12977,10038],{"class":4517},[2978,12979,4707],{"class":2995},[2978,12981,9993],{"class":4517},[2978,12983,10045],{"class":2995},[2978,12985,12986],{"class":3195},"Update",[2978,12988,3199],{"class":2995},[2978,12990,10704],{"class":3180},[2978,12992,10057],{"class":3213},[2978,12994,12995],{"class":2995},", [",[2978,12997,11807],{"class":4517},[2978,12999,10070],{"class":2995},[2978,13001,13002],{"class":4517},"UpdateArticleDto",[2978,13004,10369],{"class":3213},[2978,13006,5704],{"class":2995},[2978,13008,13010],{"class":2980,"line":13009},263,[2978,13011,5709],{"class":2995},[2978,13013,13015,13017,13019,13021,13023,13025,13027,13029,13031,13033,13035,13037],{"class":2980,"line":13014},264,[2978,13016,5714],{"class":3180},[2978,13018,3185],{"class":3213},[2978,13020,3188],{"class":2995},[2978,13022,3192],{"class":3180},[2978,13024,9709],{"class":3213},[2978,13026,3223],{"class":2995},[2978,13028,4987],{"class":3213},[2978,13030,3223],{"class":2995},[2978,13032,12285],{"class":3195},[2978,13034,3199],{"class":2995},[2978,13036,5792],{"class":3213},[2978,13038,8474],{"class":2995},[2978,13040,13042],{"class":2980,"line":13041},265,[2978,13043,3288],{"emptyLinePlaceholder":3287},[2978,13045,13047,13049,13051,13053,13055,13057],{"class":2980,"line":13046},266,[2978,13048,6113],{"class":3191},[2978,13050,6116],{"class":2995},[2978,13052,3252],{"class":3213},[2978,13054,10339],{"class":3180},[2978,13056,10342],{"class":3180},[2978,13058,5704],{"class":2995},[2978,13060,13062,13064,13066],{"class":2980,"line":13061},267,[2978,13063,8266],{"class":3191},[2978,13065,10351],{"class":3195},[2978,13067,4733],{"class":2995},[2978,13069,13071],{"class":2980,"line":13070},268,[2978,13072,3288],{"emptyLinePlaceholder":3287},[2978,13074,13076,13078,13080,13082,13084,13086,13088,13090],{"class":2980,"line":13075},269,[2978,13077,12408],{"class":3213},[2978,13079,3223],{"class":2995},[2978,13081,5446],{"class":3213},[2978,13083,3188],{"class":2995},[2978,13085,10489],{"class":3213},[2978,13087,3223],{"class":2995},[2978,13089,5446],{"class":3213},[2978,13091,4526],{"class":2995},[2978,13093,13095,13097,13099,13101,13103,13105,13107,13109],{"class":2980,"line":13094},270,[2978,13096,12408],{"class":3213},[2978,13098,3223],{"class":2995},[2978,13100,11870],{"class":3213},[2978,13102,3188],{"class":2995},[2978,13104,10489],{"class":3213},[2978,13106,3223],{"class":2995},[2978,13108,11870],{"class":3213},[2978,13110,4526],{"class":2995},[2978,13112,13114,13116,13118,13120,13122,13124,13126,13128],{"class":2980,"line":13113},271,[2978,13115,12408],{"class":3213},[2978,13117,3223],{"class":2995},[2978,13119,4774],{"class":3213},[2978,13121,3188],{"class":2995},[2978,13123,4756],{"class":3213},[2978,13125,3223],{"class":2995},[2978,13127,4761],{"class":3213},[2978,13129,4526],{"class":2995},[2978,13131,13133],{"class":2980,"line":13132},272,[2978,13134,3288],{"emptyLinePlaceholder":3287},[2978,13136,13138,13140,13142,13144,13146],{"class":2980,"line":13137},273,[2978,13139,11955],{"class":3180},[2978,13141,9709],{"class":3213},[2978,13143,3223],{"class":2995},[2978,13145,11962],{"class":3195},[2978,13147,4733],{"class":2995},[2978,13149,13151],{"class":2980,"line":13150},274,[2978,13152,3288],{"emptyLinePlaceholder":3287},[2978,13154,13156,13158,13160,13162,13164,13166,13168,13170,13172,13174],{"class":2980,"line":13155},275,[2978,13157,5714],{"class":3180},[2978,13159,11977],{"class":3213},[2978,13161,3188],{"class":2995},[2978,13163,10374],{"class":3195},[2978,13165,3199],{"class":2995},[2978,13167,3252],{"class":3213},[2978,13169,3456],{"class":2995},[2978,13171,4730],{"class":3180},[2978,13173,8223],{"class":4517},[2978,13175,3228],{"class":2995},[2978,13177,13179,13181,13183,13185,13187,13189,13191,13193],{"class":2980,"line":13178},276,[2978,13180,11999],{"class":3213},[2978,13182,3223],{"class":2995},[2978,13184,5499],{"class":3213},[2978,13186,3188],{"class":2995},[2978,13188,10407],{"class":3213},[2978,13190,3223],{"class":2995},[2978,13192,5655],{"class":3195},[2978,13194,5658],{"class":2995},[2978,13196,13198,13200,13202,13204],{"class":2980,"line":13197},277,[2978,13199,10418],{"class":3213},[2978,13201,3223],{"class":2995},[2978,13203,8780],{"class":3213},[2978,13205,3013],{"class":2995},[2978,13207,13209,13211,13213,13215],{"class":2980,"line":13208},278,[2978,13210,10418],{"class":3213},[2978,13212,3223],{"class":2995},[2978,13214,10433],{"class":3213},[2978,13216,3013],{"class":2995},[2978,13218,13220,13222],{"class":2980,"line":13219},279,[2978,13221,10440],{"class":3213},[2978,13223,3013],{"class":2995},[2978,13225,13227,13229,13231,13233],{"class":2980,"line":13226},280,[2978,13228,10447],{"class":3213},[2978,13230,3006],{"class":2995},[2978,13232,10452],{"class":3180},[2978,13234,8474],{"class":2995},[2978,13236,13238],{"class":2980,"line":13237},281,[2978,13239,3288],{"emptyLinePlaceholder":3287},[2978,13241,13243,13245,13247,13249,13252],{"class":2980,"line":13242},282,[2978,13244,6615],{"class":3191},[2978,13246,10592],{"class":3195},[2978,13248,3199],{"class":2995},[2978,13250,13251],{"class":3213},"resultDto",[2978,13253,8474],{"class":2995},[2978,13255,13257],{"class":2980,"line":13256},283,[2978,13258,6625],{"class":2995},[2978,13260,13262],{"class":2980,"line":13261},284,[2978,13263,3288],{"emptyLinePlaceholder":3287},[2978,13265,13267,13269,13271,13273],{"class":2980,"line":13266},285,[2978,13268,9872],{"class":3174},[2978,13270,4707],{"class":9875},[2978,13272,9879],{"class":9878},[2978,13274,5734],{"class":9875},[2978,13276,13278],{"class":2980,"line":13277},286,[2978,13279,13280],{"class":3174},"    /// Видалити статтю\n",[2978,13282,13284,13286,13288,13290],{"class":2980,"line":13283},287,[2978,13285,9872],{"class":3174},[2978,13287,9893],{"class":9875},[2978,13289,9879],{"class":9878},[2978,13291,5734],{"class":9875},[2978,13293,13295,13297,13300,13302,13304,13306,13308,13310,13313],{"class":2980,"line":13294},288,[2978,13296,7489],{"class":2995},[2978,13298,13299],{"class":4517},"HttpDelete",[2978,13301,3199],{"class":2995},[2978,13303,9965],{"class":3024},[2978,13305,3456],{"class":2995},[2978,13307,8789],{"class":3213},[2978,13309,3188],{"class":2995},[2978,13311,13312],{"class":3024},"\"DeleteArticle\"",[2978,13314,7499],{"class":2995},[2978,13316,13318,13320,13322,13324,13326,13328,13331],{"class":2980,"line":13317},289,[2978,13319,7489],{"class":2995},[2978,13321,9983],{"class":4517},[2978,13323,3199],{"class":2995},[2978,13325,9999],{"class":3213},[2978,13327,3223],{"class":2995},[2978,13329,13330],{"class":3213},"Status204NoContent",[2978,13332,7499],{"class":2995},[2978,13334,13336,13338,13340,13342,13344,13346,13348,13351,13353,13355,13357],{"class":2980,"line":13335},290,[2978,13337,4550],{"class":3180},[2978,13339,10030],{"class":3180},[2978,13341,10033],{"class":4517},[2978,13343,4707],{"class":2995},[2978,13345,10686],{"class":4517},[2978,13347,4713],{"class":2995},[2978,13349,13350],{"class":3195},"Delete",[2978,13352,3199],{"class":2995},[2978,13354,10704],{"class":3180},[2978,13356,10057],{"class":3213},[2978,13358,5704],{"class":2995},[2978,13360,13362],{"class":2980,"line":13361},291,[2978,13363,5709],{"class":2995},[2978,13365,13367,13369,13371,13373,13375,13377,13379,13381,13383,13385,13387,13389],{"class":2980,"line":13366},292,[2978,13368,5714],{"class":3180},[2978,13370,3185],{"class":3213},[2978,13372,3188],{"class":2995},[2978,13374,3192],{"class":3180},[2978,13376,9709],{"class":3213},[2978,13378,3223],{"class":2995},[2978,13380,4987],{"class":3213},[2978,13382,3223],{"class":2995},[2978,13384,12285],{"class":3195},[2978,13386,3199],{"class":2995},[2978,13388,5792],{"class":3213},[2978,13390,8474],{"class":2995},[2978,13392,13394],{"class":2980,"line":13393},293,[2978,13395,3288],{"emptyLinePlaceholder":3287},[2978,13397,13399,13401,13403,13405,13407,13409],{"class":2980,"line":13398},294,[2978,13400,6113],{"class":3191},[2978,13402,6116],{"class":2995},[2978,13404,3252],{"class":3213},[2978,13406,10339],{"class":3180},[2978,13408,10342],{"class":3180},[2978,13410,5704],{"class":2995},[2978,13412,13414,13416,13418],{"class":2980,"line":13413},295,[2978,13415,8266],{"class":3191},[2978,13417,10351],{"class":3195},[2978,13419,4733],{"class":2995},[2978,13421,13423],{"class":2980,"line":13422},296,[2978,13424,3288],{"emptyLinePlaceholder":3287},[2978,13426,13428,13430,13432,13434,13436,13439,13441,13443],{"class":2980,"line":13427},297,[2978,13429,9813],{"class":3213},[2978,13431,3223],{"class":2995},[2978,13433,4987],{"class":3213},[2978,13435,3223],{"class":2995},[2978,13437,13438],{"class":3195},"Remove",[2978,13440,3199],{"class":2995},[2978,13442,3252],{"class":3213},[2978,13444,8474],{"class":2995},[2978,13446,13448,13450,13452,13454,13456],{"class":2980,"line":13447},298,[2978,13449,11955],{"class":3180},[2978,13451,9709],{"class":3213},[2978,13453,3223],{"class":2995},[2978,13455,11962],{"class":3195},[2978,13457,4733],{"class":2995},[2978,13459,13461],{"class":2980,"line":13460},299,[2978,13462,3288],{"emptyLinePlaceholder":3287},[2978,13464,13466,13468,13471],{"class":2980,"line":13465},300,[2978,13467,6615],{"class":3191},[2978,13469,13470],{"class":3195}," NoContent",[2978,13472,4733],{"class":2995},[2978,13474,13476],{"class":2980,"line":13475},301,[2978,13477,6625],{"class":2995},[2978,13479,13481],{"class":2980,"line":13480},302,[2978,13482,3288],{"emptyLinePlaceholder":3287},[2978,13484,13486,13488,13491,13494,13496,13498,13500,13502,13504,13506],{"class":2980,"line":13485},303,[2978,13487,9701],{"class":3180},[2978,13489,13490],{"class":4517}," ArticleDto",[2978,13492,13493],{"class":3195}," MapToDto",[2978,13495,3199],{"class":2995},[2978,13497,4982],{"class":4517},[2978,13499,3185],{"class":3213},[2978,13501,3456],{"class":2995},[2978,13503,8461],{"class":4517},[2978,13505,8456],{"class":3213},[2978,13507,5704],{"class":2995},[2978,13509,13511],{"class":2980,"line":13510},304,[2978,13512,5709],{"class":2995},[2978,13514,13516,13518,13520,13522,13524],{"class":2980,"line":13515},305,[2978,13517,5714],{"class":3180},[2978,13519,10369],{"class":3213},[2978,13521,3188],{"class":2995},[2978,13523,4730],{"class":3180},[2978,13525,7321],{"class":4517},[2978,13527,13529],{"class":2980,"line":13528},306,[2978,13530,5739],{"class":2995},[2978,13532,13534,13536,13538,13540,13542,13544],{"class":2980,"line":13533},307,[2978,13535,11426],{"class":3213},[2978,13537,3188],{"class":2995},[2978,13539,3252],{"class":3213},[2978,13541,3223],{"class":2995},[2978,13543,8780],{"class":3213},[2978,13545,3013],{"class":2995},[2978,13547,13549,13551,13553,13555,13557,13559],{"class":2980,"line":13548},308,[2978,13550,11845],{"class":3213},[2978,13552,3188],{"class":2995},[2978,13554,3252],{"class":3213},[2978,13556,3223],{"class":2995},[2978,13558,5446],{"class":3213},[2978,13560,3013],{"class":2995},[2978,13562,13564,13566,13568,13570,13572,13574],{"class":2980,"line":13563},309,[2978,13565,11861],{"class":3213},[2978,13567,3188],{"class":2995},[2978,13569,3252],{"class":3213},[2978,13571,3223],{"class":2995},[2978,13573,11870],{"class":3213},[2978,13575,3013],{"class":2995},[2978,13577,13579,13581,13583,13585,13587,13589],{"class":2980,"line":13578},310,[2978,13580,11878],{"class":3213},[2978,13582,3188],{"class":2995},[2978,13584,3252],{"class":3213},[2978,13586,3223],{"class":2995},[2978,13588,10519],{"class":3213},[2978,13590,3013],{"class":2995},[2978,13592,13594,13596,13598,13600,13602,13604],{"class":2980,"line":13593},311,[2978,13595,11894],{"class":3213},[2978,13597,3188],{"class":2995},[2978,13599,3252],{"class":3213},[2978,13601,3223],{"class":2995},[2978,13603,10575],{"class":3213},[2978,13605,3013],{"class":2995},[2978,13607,13609,13612,13614,13616,13618,13620],{"class":2980,"line":13608},312,[2978,13610,13611],{"class":3213},"            PublishedAt",[2978,13613,3188],{"class":2995},[2978,13615,3252],{"class":3213},[2978,13617,3223],{"class":2995},[2978,13619,10841],{"class":3213},[2978,13621,3013],{"class":2995},[2978,13623,13625,13628,13630,13632,13634,13636],{"class":2980,"line":13624},313,[2978,13626,13627],{"class":3213},"            UpdatedAt",[2978,13629,3188],{"class":2995},[2978,13631,3252],{"class":3213},[2978,13633,3223],{"class":2995},[2978,13635,4774],{"class":3213},[2978,13637,3013],{"class":2995},[2978,13639,13641,13643,13645,13647,13649,13651,13653,13655],{"class":2980,"line":13640},314,[2978,13642,11910],{"class":3213},[2978,13644,3188],{"class":2995},[2978,13646,3252],{"class":3213},[2978,13648,3223],{"class":2995},[2978,13650,10433],{"class":3213},[2978,13652,3223],{"class":2995},[2978,13654,10524],{"class":3195},[2978,13656,13657],{"class":2995},"()\n",[2978,13659,13661],{"class":2980,"line":13660},315,[2978,13662,6099],{"class":2995},[2978,13664,13666],{"class":2980,"line":13665},316,[2978,13667,3288],{"emptyLinePlaceholder":3287},[2978,13669,13671],{"class":2980,"line":13670},317,[2978,13672,13673],{"class":3174},"        // Resource expansion\n",[2978,13675,13677,13679,13681,13683,13685,13687,13690,13692,13694,13696,13698,13700,13702,13704],{"class":2980,"line":13676},318,[2978,13678,6113],{"class":3191},[2978,13680,6116],{"class":2995},[2978,13682,8591],{"class":3213},[2978,13684,3223],{"class":2995},[2978,13686,10163],{"class":3213},[2978,13688,13689],{"class":2995}," || ",[2978,13691,8591],{"class":3213},[2978,13693,3223],{"class":2995},[2978,13695,10212],{"class":3213},[2978,13697,13689],{"class":2995},[2978,13699,8591],{"class":3213},[2978,13701,3223],{"class":2995},[2978,13703,10257],{"class":3213},[2978,13705,5704],{"class":2995},[2978,13707,13709],{"class":2980,"line":13708},319,[2978,13710,5739],{"class":2995},[2978,13712,13714,13716,13718,13720,13722,13724,13726],{"class":2980,"line":13713},320,[2978,13715,10947],{"class":3213},[2978,13717,3223],{"class":2995},[2978,13719,7557],{"class":3213},[2978,13721,3188],{"class":2995},[2978,13723,4730],{"class":3180},[2978,13725,7552],{"class":4517},[2978,13727,4733],{"class":2995},[2978,13729,13731],{"class":2980,"line":13730},321,[2978,13732,3288],{"emptyLinePlaceholder":3287},[2978,13734,13736,13739,13741,13743,13745,13747,13749,13751,13753,13755,13757,13759],{"class":2980,"line":13735},322,[2978,13737,13738],{"class":3191},"            if",[2978,13740,6116],{"class":2995},[2978,13742,8591],{"class":3213},[2978,13744,3223],{"class":2995},[2978,13746,10163],{"class":3213},[2978,13748,6131],{"class":2995},[2978,13750,3252],{"class":3213},[2978,13752,3223],{"class":2995},[2978,13754,4646],{"class":3213},[2978,13756,6259],{"class":2995},[2978,13758,10081],{"class":3180},[2978,13760,5704],{"class":2995},[2978,13762,13764],{"class":2980,"line":13763},323,[2978,13765,5758],{"class":2995},[2978,13767,13769,13772,13774,13776,13778,13780,13782,13784],{"class":2980,"line":13768},324,[2978,13770,13771],{"class":3213},"                dto",[2978,13773,3223],{"class":2995},[2978,13775,7557],{"class":3213},[2978,13777,3223],{"class":2995},[2978,13779,4646],{"class":3213},[2978,13781,3188],{"class":2995},[2978,13783,4730],{"class":3180},[2978,13785,7672],{"class":4517},[2978,13787,13789],{"class":2980,"line":13788},325,[2978,13790,11531],{"class":2995},[2978,13792,13794,13797,13799,13801,13803,13805,13807,13809],{"class":2980,"line":13793},326,[2978,13795,13796],{"class":3213},"                    Id",[2978,13798,3188],{"class":2995},[2978,13800,3252],{"class":3213},[2978,13802,3223],{"class":2995},[2978,13804,4646],{"class":3213},[2978,13806,3223],{"class":2995},[2978,13808,8780],{"class":3213},[2978,13810,3013],{"class":2995},[2978,13812,13814,13817,13819,13821,13823,13825,13827,13829],{"class":2980,"line":13813},327,[2978,13815,13816],{"class":3213},"                    Name",[2978,13818,3188],{"class":2995},[2978,13820,3252],{"class":3213},[2978,13822,3223],{"class":2995},[2978,13824,4646],{"class":3213},[2978,13826,3223],{"class":2995},[2978,13828,8789],{"class":3213},[2978,13830,3013],{"class":2995},[2978,13832,13834,13837,13839,13841,13843,13845,13847,13849],{"class":2980,"line":13833},328,[2978,13835,13836],{"class":3213},"                    Email",[2978,13838,3188],{"class":2995},[2978,13840,3252],{"class":3213},[2978,13842,3223],{"class":2995},[2978,13844,4646],{"class":3213},[2978,13846,3223],{"class":2995},[2978,13848,8798],{"class":3213},[2978,13850,3013],{"class":2995},[2978,13852,13854,13857,13859,13861,13863,13865,13867,13869],{"class":2980,"line":13853},329,[2978,13855,13856],{"class":3213},"                    Bio",[2978,13858,3188],{"class":2995},[2978,13860,3252],{"class":3213},[2978,13862,3223],{"class":2995},[2978,13864,4646],{"class":3213},[2978,13866,3223],{"class":2995},[2978,13868,4960],{"class":3213},[2978,13870,3013],{"class":2995},[2978,13872,13874,13877,13879,13881,13883,13885,13887,13889,13891],{"class":2980,"line":13873},330,[2978,13875,13876],{"class":3213},"                    Links",[2978,13878,3188],{"class":2995},[2978,13880,4730],{"class":3180},[2978,13882,5484],{"class":4517},[2978,13884,4707],{"class":2995},[2978,13886,5489],{"class":3180},[2978,13888,3456],{"class":2995},[2978,13890,5494],{"class":4517},[2978,13892,5734],{"class":2995},[2978,13894,13896],{"class":2980,"line":13895},331,[2978,13897,13898],{"class":2995},"                    {\n",[2978,13900,13902,13905,13907,13909,13911],{"class":2980,"line":13901},332,[2978,13903,13904],{"class":2995},"                        [",[2978,13906,3738],{"class":3024},[2978,13908,5749],{"class":2995},[2978,13910,4730],{"class":3180},[2978,13912,5363],{"class":4517},[2978,13914,13916],{"class":2980,"line":13915},333,[2978,13917,13918],{"class":2995},"                        {\n",[2978,13920,13922,13925,13927,13929,13931,13933,13935,13937,13939,13941,13943,13945,13947,13949,13951,13953,13955,13957,13959,13961],{"class":2980,"line":13921},334,[2978,13923,13924],{"class":3213},"                            Href",[2978,13926,3188],{"class":2995},[2978,13928,11542],{"class":3213},[2978,13930,3223],{"class":2995},[2978,13932,5773],{"class":3195},[2978,13934,3199],{"class":2995},[2978,13936,5778],{"class":3024},[2978,13938,3456],{"class":2995},[2978,13940,5874],{"class":3024},[2978,13942,3456],{"class":2995},[2978,13944,4730],{"class":3180},[2978,13946,4559],{"class":2995},[2978,13948,5792],{"class":3213},[2978,13950,3188],{"class":2995},[2978,13952,3252],{"class":3213},[2978,13954,3223],{"class":2995},[2978,13956,4646],{"class":3213},[2978,13958,3223],{"class":2995},[2978,13960,8780],{"class":3213},[2978,13962,5800],{"class":2995},[2978,13964,13966,13969,13971],{"class":2980,"line":13965},335,[2978,13967,13968],{"class":3213},"                            Rel",[2978,13970,3188],{"class":2995},[2978,13972,6799],{"class":3024},[2978,13974,13976],{"class":2980,"line":13975},336,[2978,13977,13978],{"class":2995},"                        }\n",[2978,13980,13982],{"class":2980,"line":13981},337,[2978,13983,13984],{"class":2995},"                    }\n",[2978,13986,13988],{"class":2980,"line":13987},338,[2978,13989,13990],{"class":2995},"                };\n",[2978,13992,13994],{"class":2980,"line":13993},339,[2978,13995,6094],{"class":2995},[2978,13997,13999],{"class":2980,"line":13998},340,[2978,14000,3288],{"emptyLinePlaceholder":3287},[2978,14002,14004,14006,14008,14010,14012,14014,14016,14018,14020,14022,14024,14026],{"class":2980,"line":14003},341,[2978,14005,13738],{"class":3191},[2978,14007,6116],{"class":2995},[2978,14009,8591],{"class":3213},[2978,14011,3223],{"class":2995},[2978,14013,10212],{"class":3213},[2978,14015,6131],{"class":2995},[2978,14017,3252],{"class":3213},[2978,14019,3223],{"class":2995},[2978,14021,4687],{"class":3213},[2978,14023,6259],{"class":2995},[2978,14025,10081],{"class":3180},[2978,14027,5704],{"class":2995},[2978,14029,14031],{"class":2980,"line":14030},342,[2978,14032,5758],{"class":2995},[2978,14034,14036,14038,14040,14042,14044,14046,14048,14050],{"class":2980,"line":14035},343,[2978,14037,13771],{"class":3213},[2978,14039,3223],{"class":2995},[2978,14041,7557],{"class":3213},[2978,14043,3223],{"class":2995},[2978,14045,4687],{"class":3213},[2978,14047,3188],{"class":2995},[2978,14049,4730],{"class":3180},[2978,14051,7815],{"class":4517},[2978,14053,14055],{"class":2980,"line":14054},344,[2978,14056,11531],{"class":2995},[2978,14058,14060,14062,14064,14066,14068,14070,14072,14074],{"class":2980,"line":14059},345,[2978,14061,13796],{"class":3213},[2978,14063,3188],{"class":2995},[2978,14065,3252],{"class":3213},[2978,14067,3223],{"class":2995},[2978,14069,4687],{"class":3213},[2978,14071,3223],{"class":2995},[2978,14073,8780],{"class":3213},[2978,14075,3013],{"class":2995},[2978,14077,14079,14081,14083,14085,14087,14089,14091,14093],{"class":2980,"line":14078},346,[2978,14080,13816],{"class":3213},[2978,14082,3188],{"class":2995},[2978,14084,3252],{"class":3213},[2978,14086,3223],{"class":2995},[2978,14088,4687],{"class":3213},[2978,14090,3223],{"class":2995},[2978,14092,8789],{"class":3213},[2978,14094,3013],{"class":2995},[2978,14096,14098,14101,14103,14105,14107,14109,14111,14113],{"class":2980,"line":14097},347,[2978,14099,14100],{"class":3213},"                    Description",[2978,14102,3188],{"class":2995},[2978,14104,3252],{"class":3213},[2978,14106,3223],{"class":2995},[2978,14108,4687],{"class":3213},[2978,14110,3223],{"class":2995},[2978,14112,5078],{"class":3213},[2978,14114,3013],{"class":2995},[2978,14116,14118,14120,14122,14124,14126,14128,14130,14132,14134],{"class":2980,"line":14117},348,[2978,14119,13876],{"class":3213},[2978,14121,3188],{"class":2995},[2978,14123,4730],{"class":3180},[2978,14125,5484],{"class":4517},[2978,14127,4707],{"class":2995},[2978,14129,5489],{"class":3180},[2978,14131,3456],{"class":2995},[2978,14133,5494],{"class":4517},[2978,14135,5734],{"class":2995},[2978,14137,14139],{"class":2980,"line":14138},349,[2978,14140,13898],{"class":2995},[2978,14142,14144,14146,14148,14150,14152],{"class":2980,"line":14143},350,[2978,14145,13904],{"class":2995},[2978,14147,3738],{"class":3024},[2978,14149,5749],{"class":2995},[2978,14151,4730],{"class":3180},[2978,14153,5363],{"class":4517},[2978,14155,14157],{"class":2980,"line":14156},351,[2978,14158,13918],{"class":2995},[2978,14160,14162,14164,14166,14168,14170,14172,14174,14176,14178,14180,14182,14184,14186,14188,14190,14192,14194,14196,14198,14200],{"class":2980,"line":14161},352,[2978,14163,13924],{"class":3213},[2978,14165,3188],{"class":2995},[2978,14167,11542],{"class":3213},[2978,14169,3223],{"class":2995},[2978,14171,5773],{"class":3195},[2978,14173,3199],{"class":2995},[2978,14175,5778],{"class":3024},[2978,14177,3456],{"class":2995},[2978,14179,6045],{"class":3024},[2978,14181,3456],{"class":2995},[2978,14183,4730],{"class":3180},[2978,14185,4559],{"class":2995},[2978,14187,5792],{"class":3213},[2978,14189,3188],{"class":2995},[2978,14191,3252],{"class":3213},[2978,14193,3223],{"class":2995},[2978,14195,4687],{"class":3213},[2978,14197,3223],{"class":2995},[2978,14199,8780],{"class":3213},[2978,14201,5800],{"class":2995},[2978,14203,14205,14207,14209],{"class":2980,"line":14204},353,[2978,14206,13968],{"class":3213},[2978,14208,3188],{"class":2995},[2978,14210,6799],{"class":3024},[2978,14212,14214],{"class":2980,"line":14213},354,[2978,14215,13978],{"class":2995},[2978,14217,14219],{"class":2980,"line":14218},355,[2978,14220,13984],{"class":2995},[2978,14222,14224],{"class":2980,"line":14223},356,[2978,14225,13990],{"class":2995},[2978,14227,14229],{"class":2980,"line":14228},357,[2978,14230,6094],{"class":2995},[2978,14232,14234],{"class":2980,"line":14233},358,[2978,14235,3288],{"emptyLinePlaceholder":3287},[2978,14237,14239,14241,14243,14245,14247,14249,14251,14253,14255,14257,14259,14262],{"class":2980,"line":14238},359,[2978,14240,13738],{"class":3191},[2978,14242,6116],{"class":2995},[2978,14244,8591],{"class":3213},[2978,14246,3223],{"class":2995},[2978,14248,10257],{"class":3213},[2978,14250,6131],{"class":2995},[2978,14252,3252],{"class":3213},[2978,14254,3223],{"class":2995},[2978,14256,4716],{"class":3213},[2978,14258,3223],{"class":2995},[2978,14260,14261],{"class":3195},"Any",[2978,14263,8341],{"class":2995},[2978,14265,14267],{"class":2980,"line":14266},360,[2978,14268,5758],{"class":2995},[2978,14270,14272,14274,14276,14278,14280,14282,14284,14286,14288,14290,14292,14294,14296,14298,14300,14302],{"class":2980,"line":14271},361,[2978,14273,13771],{"class":3213},[2978,14275,3223],{"class":2995},[2978,14277,7557],{"class":3213},[2978,14279,3223],{"class":2995},[2978,14281,4716],{"class":3213},[2978,14283,3188],{"class":2995},[2978,14285,3252],{"class":3213},[2978,14287,3223],{"class":2995},[2978,14289,4716],{"class":3213},[2978,14291,3223],{"class":2995},[2978,14293,8318],{"class":3195},[2978,14295,3199],{"class":2995},[2978,14297,11409],{"class":3213},[2978,14299,8325],{"class":2995},[2978,14301,4730],{"class":3180},[2978,14303,7938],{"class":4517},[2978,14305,14307],{"class":2980,"line":14306},362,[2978,14308,11531],{"class":2995},[2978,14310,14312,14314,14316,14318,14320,14322],{"class":2980,"line":14311},363,[2978,14313,13796],{"class":3213},[2978,14315,3188],{"class":2995},[2978,14317,11409],{"class":3213},[2978,14319,3223],{"class":2995},[2978,14321,8780],{"class":3213},[2978,14323,3013],{"class":2995},[2978,14325,14327,14330,14332,14334,14336,14338],{"class":2980,"line":14326},364,[2978,14328,14329],{"class":3213},"                    Text",[2978,14331,3188],{"class":2995},[2978,14333,11409],{"class":3213},[2978,14335,3223],{"class":2995},[2978,14337,7275],{"class":3213},[2978,14339,3013],{"class":2995},[2978,14341,14343,14346,14348,14350,14352,14354],{"class":2980,"line":14342},365,[2978,14344,14345],{"class":3213},"                    AuthorName",[2978,14347,3188],{"class":2995},[2978,14349,11409],{"class":3213},[2978,14351,3223],{"class":2995},[2978,14353,9370],{"class":3213},[2978,14355,3013],{"class":2995},[2978,14357,14359,14362,14364,14366,14368],{"class":2980,"line":14358},366,[2978,14360,14361],{"class":3213},"                    CreatedAt",[2978,14363,3188],{"class":2995},[2978,14365,11409],{"class":3213},[2978,14367,3223],{"class":2995},[2978,14369,14370],{"class":3213},"CreatedAt\n",[2978,14372,14374,14377,14379],{"class":2980,"line":14373},367,[2978,14375,14376],{"class":2995},"                }).",[2978,14378,11016],{"class":3195},[2978,14380,4733],{"class":2995},[2978,14382,14384],{"class":2980,"line":14383},368,[2978,14385,6094],{"class":2995},[2978,14387,14389],{"class":2980,"line":14388},369,[2978,14390,6242],{"class":2995},[2978,14392,14394],{"class":2980,"line":14393},370,[2978,14395,3288],{"emptyLinePlaceholder":3287},[2978,14397,14399,14401,14403],{"class":2980,"line":14398},371,[2978,14400,6615],{"class":3191},[2978,14402,10369],{"class":3213},[2978,14404,4526],{"class":2995},[2978,14406,14408],{"class":2980,"line":14407},372,[2978,14409,6625],{"class":2995},[2978,14411,14413],{"class":2980,"line":14412},373,[2978,14414,3070],{"class":2995},[2978,14416,14418],{"class":2980,"line":14417},374,[2978,14419,3288],{"emptyLinePlaceholder":3287},[2978,14421,14423],{"class":2980,"line":14422},375,[2978,14424,14425],{"class":3174},"// DTOs для створення/оновлення\n",[2978,14427,14429,14431,14434],{"class":2980,"line":14428},376,[2978,14430,4535],{"class":3180},[2978,14432,14433],{"class":3180}," record",[2978,14435,14436],{"class":4517}," CreateArticleDto\n",[2978,14438,14440],{"class":2980,"line":14439},377,[2978,14441,2996],{"class":2995},[2978,14443,14445,14447,14449,14451,14453,14455,14457,14459,14462],{"class":2980,"line":14444},378,[2978,14446,4550],{"class":3180},[2978,14448,4578],{"class":3180},[2978,14450,4581],{"class":3180},[2978,14452,4584],{"class":3213},[2978,14454,4559],{"class":2995},[2978,14456,4562],{"class":3180},[2978,14458,4565],{"class":2995},[2978,14460,14461],{"class":3180},"init",[2978,14463,4571],{"class":2995},[2978,14465,14467,14469,14471,14473,14475,14477,14479,14481,14483],{"class":2980,"line":14466},379,[2978,14468,4550],{"class":3180},[2978,14470,4578],{"class":3180},[2978,14472,4581],{"class":3180},[2978,14474,4605],{"class":3213},[2978,14476,4559],{"class":2995},[2978,14478,4562],{"class":3180},[2978,14480,4565],{"class":2995},[2978,14482,14461],{"class":3180},[2978,14484,4571],{"class":2995},[2978,14486,14488,14490,14492,14494,14496,14498,14500,14502],{"class":2980,"line":14487},380,[2978,14489,4550],{"class":3180},[2978,14491,4553],{"class":3180},[2978,14493,4624],{"class":3213},[2978,14495,4559],{"class":2995},[2978,14497,4562],{"class":3180},[2978,14499,4565],{"class":2995},[2978,14501,14461],{"class":3180},[2978,14503,4571],{"class":2995},[2978,14505,14507,14509,14511,14513,14515,14517,14519,14521],{"class":2980,"line":14506},381,[2978,14508,4550],{"class":3180},[2978,14510,4553],{"class":3180},[2978,14512,4665],{"class":3213},[2978,14514,4559],{"class":2995},[2978,14516,4562],{"class":3180},[2978,14518,4565],{"class":2995},[2978,14520,14461],{"class":3180},[2978,14522,4571],{"class":2995},[2978,14524,14526],{"class":2980,"line":14525},382,[2978,14527,3070],{"class":2995},[2978,14529,14531],{"class":2980,"line":14530},383,[2978,14532,3288],{"emptyLinePlaceholder":3287},[2978,14534,14536,14538,14540],{"class":2980,"line":14535},384,[2978,14537,4535],{"class":3180},[2978,14539,14433],{"class":3180},[2978,14541,14542],{"class":4517}," UpdateArticleDto\n",[2978,14544,14546],{"class":2980,"line":14545},385,[2978,14547,2996],{"class":2995},[2978,14549,14551,14553,14555,14557,14559,14561,14563,14565,14567],{"class":2980,"line":14550},386,[2978,14552,4550],{"class":3180},[2978,14554,4578],{"class":3180},[2978,14556,4581],{"class":3180},[2978,14558,4584],{"class":3213},[2978,14560,4559],{"class":2995},[2978,14562,4562],{"class":3180},[2978,14564,4565],{"class":2995},[2978,14566,14461],{"class":3180},[2978,14568,4571],{"class":2995},[2978,14570,14572,14574,14576,14578,14580,14582,14584,14586,14588],{"class":2980,"line":14571},387,[2978,14573,4550],{"class":3180},[2978,14575,4578],{"class":3180},[2978,14577,4581],{"class":3180},[2978,14579,4605],{"class":3213},[2978,14581,4559],{"class":2995},[2978,14583,4562],{"class":3180},[2978,14585,4565],{"class":2995},[2978,14587,14461],{"class":3180},[2978,14589,4571],{"class":2995},[2978,14591,14593],{"class":2980,"line":14592},388,[2978,14594,3070],{"class":2995},[2964,14596,14597],{},[3074,14598,5285],{},[7206,14600,14601,14615,14621,14628,14633],{},[3092,14602,14603,14608,14609,3343,14612],{},[3074,14604,14605,14607],{},[2975,14606,7214],{}," injection"," — через ",[2975,14610,14611],{},"IUrlHelperFactory",[2975,14613,14614],{},"IActionContextAccessor",[3092,14616,14617,14620],{},[3074,14618,14619],{},"Conditional eager loading"," — завантажуємо пов'язані дані тільки якщо потрібно",[3092,14622,14623,14627],{},[3074,14624,14625],{},[2975,14626,10374],{}," — централізована логіка мапінгу з expansion",[3092,14629,14630,14632],{},[3074,14631,7220],{}," — різні links для draft/published/archived",[3092,14634,14635,3309,14638,3343,14640,14642],{},[3074,14636,14637],{},"HAL формат",[2975,14639,4383],{},[2975,14641,4391],{}," у відповідях",[3882,14644],{},[3329,14646,14648],{"id":14647},"крок-7-programcs-configuration","Крок 7: Program.cs Configuration",[2968,14650,14652],{"className":4505,"code":14651,"language":4507,"meta":2973,"style":2973},"using Microsoft.EntityFrameworkCore;\nusing BlogHateoasApi.Data;\n\nvar builder = WebApplication.CreateBuilder(args);\n\n// DbContext\nbuilder.Services.AddDbContext\u003CBlogDbContext>(options =>\n    options.UseInMemoryDatabase(\"BlogDb\"));\n\n// IUrlHelper dependencies\nbuilder.Services.AddHttpContextAccessor();\nbuilder.Services.AddSingleton\u003CIActionContextAccessor, ActionContextAccessor>();\n\nbuilder.Services.AddControllers();\nbuilder.Services.AddEndpointsApiExplorer();\nbuilder.Services.AddSwaggerGen();\n\nvar app = builder.Build();\n\n// Seed database\nusing (var scope = app.Services.CreateScope())\n{\n    var db = scope.ServiceProvider.GetRequiredService\u003CBlogDbContext>();\n    db.Database.EnsureCreated();\n}\n\nif (app.Environment.IsDevelopment())\n{\n    app.UseSwagger();\n    app.UseSwaggerUI();\n}\n\napp.UseHttpsRedirection();\napp.UseAuthorization();\napp.MapControllers();\n\napp.Run();\n",[2975,14653,14654,14666,14678,14682,14706,14710,14715,14741,14759,14763,14768,14783,14807,14811,14826,14841,14856,14860,14878,14882,14887,14914,14918,14946,14963,14967,14971,14992,14996,15008,15019,15023,15027,15038,15049,15060,15064],{"__ignoreMap":2973},[2978,14655,14656,14658,14660,14662,14664],{"class":2980,"line":2981},[2978,14657,5570],{"class":3191},[2978,14659,5585],{"class":4517},[2978,14661,3223],{"class":2995},[2978,14663,8516],{"class":4517},[2978,14665,4526],{"class":2995},[2978,14667,14668,14670,14672,14674,14676],{"class":2980,"line":2999},[2978,14669,5570],{"class":3191},[2978,14671,4518],{"class":4517},[2978,14673,3223],{"class":2995},[2978,14675,8545],{"class":4517},[2978,14677,4526],{"class":2995},[2978,14679,14680],{"class":2980,"line":3016},[2978,14681,3288],{"emptyLinePlaceholder":3287},[2978,14683,14684,14686,14689,14691,14694,14696,14699,14701,14704],{"class":2980,"line":3030},[2978,14685,8453],{"class":3180},[2978,14687,14688],{"class":3213}," builder",[2978,14690,3188],{"class":2995},[2978,14692,14693],{"class":3213},"WebApplication",[2978,14695,3223],{"class":2995},[2978,14697,14698],{"class":3195},"CreateBuilder",[2978,14700,3199],{"class":2995},[2978,14702,14703],{"class":3213},"args",[2978,14705,8474],{"class":2995},[2978,14707,14708],{"class":2980,"line":3043},[2978,14709,3288],{"emptyLinePlaceholder":3287},[2978,14711,14712],{"class":2980,"line":3056},[2978,14713,14714],{"class":3174},"// DbContext\n",[2978,14716,14717,14720,14722,14725,14727,14730,14732,14734,14737,14739],{"class":2980,"line":3067},[2978,14718,14719],{"class":3213},"builder",[2978,14721,3223],{"class":2995},[2978,14723,14724],{"class":3213},"Services",[2978,14726,3223],{"class":2995},[2978,14728,14729],{"class":3195},"AddDbContext",[2978,14731,4707],{"class":2995},[2978,14733,8586],{"class":4517},[2978,14735,14736],{"class":2995},">(",[2978,14738,8591],{"class":3213},[2978,14740,10915],{"class":2995},[2978,14742,14743,14746,14748,14751,14753,14756],{"class":2980,"line":3442},[2978,14744,14745],{"class":3213},"    options",[2978,14747,3223],{"class":2995},[2978,14749,14750],{"class":3195},"UseInMemoryDatabase",[2978,14752,3199],{"class":2995},[2978,14754,14755],{"class":3024},"\"BlogDb\"",[2978,14757,14758],{"class":2995},"));\n",[2978,14760,14761],{"class":2980,"line":3469},[2978,14762,3288],{"emptyLinePlaceholder":3287},[2978,14764,14765],{"class":2980,"line":3495},[2978,14766,14767],{"class":3174},"// IUrlHelper dependencies\n",[2978,14769,14770,14772,14774,14776,14778,14781],{"class":2980,"line":3501},[2978,14771,14719],{"class":3213},[2978,14773,3223],{"class":2995},[2978,14775,14724],{"class":3213},[2978,14777,3223],{"class":2995},[2978,14779,14780],{"class":3195},"AddHttpContextAccessor",[2978,14782,4733],{"class":2995},[2978,14784,14785,14787,14789,14791,14793,14796,14798,14800,14802,14805],{"class":2980,"line":3642},[2978,14786,14719],{"class":3213},[2978,14788,3223],{"class":2995},[2978,14790,14724],{"class":3213},[2978,14792,3223],{"class":2995},[2978,14794,14795],{"class":3195},"AddSingleton",[2978,14797,4707],{"class":2995},[2978,14799,14614],{"class":4517},[2978,14801,3456],{"class":2995},[2978,14803,14804],{"class":4517},"ActionContextAccessor",[2978,14806,8635],{"class":2995},[2978,14808,14809],{"class":2980,"line":3674},[2978,14810,3288],{"emptyLinePlaceholder":3287},[2978,14812,14813,14815,14817,14819,14821,14824],{"class":2980,"line":3680},[2978,14814,14719],{"class":3213},[2978,14816,3223],{"class":2995},[2978,14818,14724],{"class":3213},[2978,14820,3223],{"class":2995},[2978,14822,14823],{"class":3195},"AddControllers",[2978,14825,4733],{"class":2995},[2978,14827,14828,14830,14832,14834,14836,14839],{"class":2980,"line":3686},[2978,14829,14719],{"class":3213},[2978,14831,3223],{"class":2995},[2978,14833,14724],{"class":3213},[2978,14835,3223],{"class":2995},[2978,14837,14838],{"class":3195},"AddEndpointsApiExplorer",[2978,14840,4733],{"class":2995},[2978,14842,14843,14845,14847,14849,14851,14854],{"class":2980,"line":3699},[2978,14844,14719],{"class":3213},[2978,14846,3223],{"class":2995},[2978,14848,14724],{"class":3213},[2978,14850,3223],{"class":2995},[2978,14852,14853],{"class":3195},"AddSwaggerGen",[2978,14855,4733],{"class":2995},[2978,14857,14858],{"class":2980,"line":4367},[2978,14859,3288],{"emptyLinePlaceholder":3287},[2978,14861,14862,14864,14867,14869,14871,14873,14876],{"class":2980,"line":4825},[2978,14863,8453],{"class":3180},[2978,14865,14866],{"class":3213}," app",[2978,14868,3188],{"class":2995},[2978,14870,14719],{"class":3213},[2978,14872,3223],{"class":2995},[2978,14874,14875],{"class":3195},"Build",[2978,14877,4733],{"class":2995},[2978,14879,14880],{"class":2980,"line":4836},[2978,14881,3288],{"emptyLinePlaceholder":3287},[2978,14883,14884],{"class":2980,"line":4841},[2978,14885,14886],{"class":3174},"// Seed database\n",[2978,14888,14889,14891,14893,14895,14898,14900,14903,14905,14907,14909,14912],{"class":2980,"line":4849},[2978,14890,5570],{"class":3191},[2978,14892,6116],{"class":2995},[2978,14894,8453],{"class":3180},[2978,14896,14897],{"class":3213}," scope",[2978,14899,3188],{"class":2995},[2978,14901,14902],{"class":3213},"app",[2978,14904,3223],{"class":2995},[2978,14906,14724],{"class":3213},[2978,14908,3223],{"class":2995},[2978,14910,14911],{"class":3195},"CreateScope",[2978,14913,8341],{"class":2995},[2978,14915,14916],{"class":2980,"line":4857},[2978,14917,2996],{"class":2995},[2978,14919,14920,14923,14925,14927,14930,14932,14935,14937,14940,14942,14944],{"class":2980,"line":4863},[2978,14921,14922],{"class":3180},"    var",[2978,14924,9766],{"class":3213},[2978,14926,3188],{"class":2995},[2978,14928,14929],{"class":3213},"scope",[2978,14931,3223],{"class":2995},[2978,14933,14934],{"class":3213},"ServiceProvider",[2978,14936,3223],{"class":2995},[2978,14938,14939],{"class":3195},"GetRequiredService",[2978,14941,4707],{"class":2995},[2978,14943,8586],{"class":4517},[2978,14945,8635],{"class":2995},[2978,14947,14948,14951,14953,14956,14958,14961],{"class":2980,"line":4868},[2978,14949,14950],{"class":3213},"    db",[2978,14952,3223],{"class":2995},[2978,14954,14955],{"class":3213},"Database",[2978,14957,3223],{"class":2995},[2978,14959,14960],{"class":3195},"EnsureCreated",[2978,14962,4733],{"class":2995},[2978,14964,14965],{"class":2980,"line":4873},[2978,14966,3070],{"class":2995},[2978,14968,14969],{"class":2980,"line":4883},[2978,14970,3288],{"emptyLinePlaceholder":3287},[2978,14972,14973,14976,14978,14980,14982,14985,14987,14990],{"class":2980,"line":4888},[2978,14974,14975],{"class":3191},"if",[2978,14977,6116],{"class":2995},[2978,14979,14902],{"class":3213},[2978,14981,3223],{"class":2995},[2978,14983,14984],{"class":3213},"Environment",[2978,14986,3223],{"class":2995},[2978,14988,14989],{"class":3195},"IsDevelopment",[2978,14991,8341],{"class":2995},[2978,14993,14994],{"class":2980,"line":4907},[2978,14995,2996],{"class":2995},[2978,14997,14998,15001,15003,15006],{"class":2980,"line":4929},[2978,14999,15000],{"class":3213},"    app",[2978,15002,3223],{"class":2995},[2978,15004,15005],{"class":3195},"UseSwagger",[2978,15007,4733],{"class":2995},[2978,15009,15010,15012,15014,15017],{"class":2980,"line":4951},[2978,15011,15000],{"class":3213},[2978,15013,3223],{"class":2995},[2978,15015,15016],{"class":3195},"UseSwaggerUI",[2978,15018,4733],{"class":2995},[2978,15020,15021],{"class":2980,"line":4973},[2978,15022,3070],{"class":2995},[2978,15024,15025],{"class":2980,"line":5004},[2978,15026,3288],{"emptyLinePlaceholder":3287},[2978,15028,15029,15031,15033,15036],{"class":2980,"line":5009},[2978,15030,14902],{"class":3213},[2978,15032,3223],{"class":2995},[2978,15034,15035],{"class":3195},"UseHttpsRedirection",[2978,15037,4733],{"class":2995},[2978,15039,15040,15042,15044,15047],{"class":2980,"line":5014},[2978,15041,14902],{"class":3213},[2978,15043,3223],{"class":2995},[2978,15045,15046],{"class":3195},"UseAuthorization",[2978,15048,4733],{"class":2995},[2978,15050,15051,15053,15055,15058],{"class":2980,"line":5024},[2978,15052,14902],{"class":3213},[2978,15054,3223],{"class":2995},[2978,15056,15057],{"class":3195},"MapControllers",[2978,15059,4733],{"class":2995},[2978,15061,15062],{"class":2980,"line":5029},[2978,15063,3288],{"emptyLinePlaceholder":3287},[2978,15065,15066,15068,15070,15073],{"class":2980,"line":5048},[2978,15067,14902],{"class":3213},[2978,15069,3223],{"class":2995},[2978,15071,15072],{"class":3195},"Run",[2978,15074,4733],{"class":2995},[2964,15076,15077,15080,15081,15083,15084,3223],{},[3074,15078,15079],{},"Важливо:"," Реєструємо ",[2975,15082,14614],{}," для доступу до ",[2975,15085,7214],{},[3882,15087],{},[3329,15089,15091],{"id":15090},"крок-8-тестування-hateoas","Крок 8: Тестування HATEOAS",[4435,15093,15094,15104,15111,15114,15121,15131,15138,15145,15153,15164,15171,15180,15191,15201,15211,15221,15227,15233,15236,15243,15253,15259,15265,15271,15280,15289,15298,15305,15315,15325,15331,15338,15345,15352,15356,15362,15372,15378,15381,15388,15398,15404,15410,15417,15428,15437,15447,15457,15467,15477,15483,15489,15492,15499,15509,15515,15521,15530,15540,15550,15559,15565,15574,15585,15591],{"title":4437},[4439,15095,15097,4447,15100],{"className":15096},[2980],[2978,15098,4446],{"className":15099},[4445],[3074,15101,15103],{"className":15102},[4451],"dotnet run",[4439,15105,15107,15110],{"className":15106},[2980],[2978,15108,4491],{"className":15109},[4459,4451],": Now listening on: https://localhost:5001",[4439,15112],{"className":15113},[2980],[4439,15115,15117],{"className":15116},[2980],[2978,15118,15120],{"className":15119},[4445],"# Тест 1: Базовий запит (без expansion)",[4439,15122,15124,4447,15127],{"className":15123},[2980],[2978,15125,4446],{"className":15126},[4445],[3074,15128,15130],{"className":15129},[4451],"curl https://localhost:5001/api/articles/1",[4439,15132,15134],{"className":15133},[2980],[2978,15135,15137],{"className":15136},[4459,4451],"HTTP/1.1 200 OK",[4439,15139,15141],{"className":15140},[2980],[2978,15142,15144],{"className":15143},[4490],"{",[4439,15146,15148,15149,15152],{"className":15147},[2980],"  ",[2978,15150,3612],{"className":15151},[4459],": 1,",[4439,15154,15148,15156,3006,15159,15163],{"className":15155},[2980],[2978,15157,3778],{"className":15158},[4459],[2978,15160,3025],{"className":15161},[15162],"text-yellow-400",",",[4439,15165,15148,15167,15152],{"className":15166},[2980],[2978,15168,15170],{"className":15169},[4459],"\"authorId\"",[4439,15172,15148,15174,3006,15177],{"className":15173},[2980],[2978,15175,3788],{"className":15176},[4459],[2978,15178,15144],{"className":15179},[4490],[4439,15181,15183,15184,3006,15187,15163],{"className":15182},[2980],"    ",[2978,15185,3738],{"className":15186},[4459],[2978,15188,15190],{"className":15189},[4490],"{ \"href\": \"/api/articles/1\", \"method\": \"GET\" }",[4439,15192,15183,15194,3006,15197,15163],{"className":15193},[2980],[2978,15195,3632],{"className":15196},[4459],[2978,15198,15200],{"className":15199},[4490],"{ \"href\": \"/api/authors/1\", \"method\": \"GET\" }",[4439,15202,15183,15204,3006,15207,15163],{"className":15203},[2980],[2978,15205,5929],{"className":15206},[4459],[2978,15208,15210],{"className":15209},[4490],"{ \"href\": \"/api/articles/1/comments\" }",[4439,15212,15183,15214,3006,15217],{"className":15213},[2980],[2978,15215,6515],{"className":15216},[4459],[2978,15218,15220],{"className":15219},[4490],"{ \"href\": \"/api/articles/1/archive\", \"method\": \"POST\" }",[4439,15222,15148,15224],{"className":15223},[2980],[2978,15225,3261],{"className":15226},[4490],[4439,15228,15230],{"className":15229},[2980],[2978,15231,3261],{"className":15232},[4490],[4439,15234],{"className":15235},[2980],[4439,15237,15239],{"className":15238},[2980],[2978,15240,15242],{"className":15241},[4445],"# Тест 2: Resource expansion (author + comments)",[4439,15244,15246,4447,15249],{"className":15245},[2980],[2978,15247,4446],{"className":15248},[4445],[3074,15250,15252],{"className":15251},[4451],"curl \"https://localhost:5001/api/articles/1?expand=author,comments\"",[4439,15254,15256],{"className":15255},[2980],[2978,15257,15137],{"className":15258},[4459,4451],[4439,15260,15262],{"className":15261},[2980],[2978,15263,15144],{"className":15264},[4490],[4439,15266,15148,15268,15152],{"className":15267},[2980],[2978,15269,3612],{"className":15270},[4459],[4439,15272,15148,15274,3006,15277,15163],{"className":15273},[2980],[2978,15275,3778],{"className":15276},[4459],[2978,15278,3025],{"className":15279},[15162],[4439,15281,15148,15283,3006,15286],{"className":15282},[2980],[2978,15284,7543],{"className":15285},[4459],[2978,15287,15144],{"className":15288},[4490],[4439,15290,15183,15292,3006,15295],{"className":15291},[2980],[2978,15293,3632],{"className":15294},[4459],[2978,15296,15144],{"className":15297},[4490],[4439,15299,15301,15302,15152],{"className":15300},[2980],"      ",[2978,15303,3612],{"className":15304},[4459],[4439,15306,15301,15308,3006,15312,15163],{"className":15307},[2980],[2978,15309,15311],{"className":15310},[4459],"\"name\"",[2978,15313,3580],{"className":15314},[15162],[4439,15316,15301,15318,3006,15322],{"className":15317},[2980],[2978,15319,15321],{"className":15320},[4459],"\"email\"",[2978,15323,8803],{"className":15324},[15162],[4439,15326,15183,15328,15163],{"className":15327},[2980],[2978,15329,3261],{"className":15330},[4490],[4439,15332,15183,15334,15337],{"className":15333},[2980],[2978,15335,5929],{"className":15336},[4459],": [",[4439,15339,15301,15341,15163],{"className":15340},[2980],[2978,15342,15344],{"className":15343},[4490],"{ \"id\": 1, \"text\": \"Great article!\", \"authorName\": \"Bob\" }",[4439,15346,15301,15348],{"className":15347},[2980],[2978,15349,15351],{"className":15350},[4490],"{ \"id\": 2, \"text\": \"Very helpful!\", \"authorName\": \"Alice\" }",[4439,15353,15355],{"className":15354},[2980],"    ]",[4439,15357,15148,15359,15163],{"className":15358},[2980],[2978,15360,3261],{"className":15361},[4490],[4439,15363,15148,15365,3006,15368],{"className":15364},[2980],[2978,15366,3788],{"className":15367},[4459],[2978,15369,15371],{"className":15370},[4490],"{ ... }",[4439,15373,15375],{"className":15374},[2980],[2978,15376,3261],{"className":15377},[4490],[4439,15379],{"className":15380},[2980],[4439,15382,15384],{"className":15383},[2980],[2978,15385,15387],{"className":15386},[4445],"# Тест 3: Draft article (різні links)",[4439,15389,15391,4447,15394],{"className":15390},[2980],[2978,15392,4446],{"className":15393},[4445],[3074,15395,15397],{"className":15396},[4451],"curl https://localhost:5001/api/articles/2",[4439,15399,15401],{"className":15400},[2980],[2978,15402,15137],{"className":15403},[4459,4451],[4439,15405,15407],{"className":15406},[2980],[2978,15408,15144],{"className":15409},[4490],[4439,15411,15148,15413,15416],{"className":15412},[2980],[2978,15414,3612],{"className":15415},[4459],": 2,",[4439,15418,15148,15420,3006,15424,15163],{"className":15419},[2980],[2978,15421,15423],{"className":15422},[4459],"\"status\"",[2978,15425,15427],{"className":15426},[15162],"\"Draft\"",[4439,15429,15148,15431,3006,15434],{"className":15430},[2980],[2978,15432,3788],{"className":15433},[4459],[2978,15435,15144],{"className":15436},[4490],[4439,15438,15183,15440,3006,15443,15163],{"className":15439},[2980],[2978,15441,3738],{"className":15442},[4459],[2978,15444,15446],{"className":15445},[4490],"{ \"href\": \"/api/articles/2\" }",[4439,15448,15183,15450,3006,15453,15163],{"className":15449},[2980],[2978,15451,6151],{"className":15452},[4459],[2978,15454,15456],{"className":15455},[4490],"{ \"href\": \"/api/articles/2/publish\", \"method\": \"POST\" }",[4439,15458,15183,15460,3006,15463,15163],{"className":15459},[2980],[2978,15461,6287],{"className":15462},[4459],[2978,15464,15466],{"className":15465},[4490],"{ \"href\": \"/api/articles/2\", \"method\": \"PUT\" }",[4439,15468,15183,15470,3006,15473],{"className":15469},[2980],[2978,15471,6386],{"className":15472},[4459],[2978,15474,15476],{"className":15475},[4490],"{ \"href\": \"/api/articles/2\", \"method\": \"DELETE\" }",[4439,15478,15148,15480],{"className":15479},[2980],[2978,15481,3261],{"className":15482},[4490],[4439,15484,15486],{"className":15485},[2980],[2978,15487,3261],{"className":15488},[4490],[4439,15490],{"className":15491},[2980],[4439,15493,15495],{"className":15494},[2980],[2978,15496,15498],{"className":15497},[4445],"# Тест 4: Колекція з пагінацією",[4439,15500,15502,4447,15505],{"className":15501},[2980],[2978,15503,4446],{"className":15504},[4445],[3074,15506,15508],{"className":15507},[4451],"curl \"https://localhost:5001/api/articles?page=1&pageSize=2\"",[4439,15510,15512],{"className":15511},[2980],[2978,15513,15137],{"className":15514},[4459,4451],[4439,15516,15518],{"className":15517},[2980],[2978,15519,15144],{"className":15520},[4490],[4439,15522,15148,15524,3006,15527],{"className":15523},[2980],[2978,15525,3788],{"className":15526},[4459],[2978,15528,15144],{"className":15529},[4490],[4439,15531,15183,15533,3006,15536,15163],{"className":15532},[2980],[2978,15534,3738],{"className":15535},[4459],[2978,15537,15539],{"className":15538},[4490],"{ \"href\": \"/api/articles?page=1\" }",[4439,15541,15183,15543,3006,15546,15163],{"className":15542},[2980],[2978,15544,7029],{"className":15545},[4459],[2978,15547,15549],{"className":15548},[4490],"{ \"href\": \"/api/articles?page=2\" }",[4439,15551,15183,15553,3006,15556],{"className":15552},[2980],[2978,15554,7110],{"className":15555},[4459],[2978,15557,15549],{"className":15558},[4490],[4439,15560,15148,15562,15163],{"className":15561},[2980],[2978,15563,3261],{"className":15564},[4490],[4439,15566,15148,15568,3006,15571],{"className":15567},[2980],[2978,15569,7543],{"className":15570},[4459],[2978,15572,15144],{"className":15573},[4490],[4439,15575,15183,15577,15337,15581,15584],{"className":15576},[2980],[2978,15578,15580],{"className":15579},[4459],"\"articles\"",[2978,15582,3694],{"className":15583},[4445],"]",[4439,15586,15148,15588],{"className":15587},[2980],[2978,15589,3261],{"className":15590},[4490],[4439,15592,15594],{"className":15593},[2980],[2978,15595,3261],{"className":15596},[4490],[3882,15598],{},[2959,15600,15602],{"id":15601},"просунуті-техніки","Просунуті техніки",[3329,15604,15606],{"id":15605},"_1-sparse-fieldsets-вибіркові-поля","1. Sparse Fieldsets — Вибіркові поля",[2964,15608,15609],{},"Дозволяє клієнту вибирати, які поля повертати:",[2968,15611,15613],{"className":2970,"code":15612,"language":2972,"meta":2973,"style":2973},"GET /api/articles/1?fields=id,title,author\n→ Повертає тільки id, title, author (без content, publishedAt)\n",[2975,15614,15615,15620],{"__ignoreMap":2973},[2978,15616,15617],{"class":2980,"line":2981},[2978,15618,15619],{},"GET /api/articles/1?fields=id,title,author\n",[2978,15621,15622],{"class":2980,"line":2999},[2978,15623,15624],{},"→ Повертає тільки id, title, author (без content, publishedAt)\n",[5325,15626,15628],{"id":15627},"implementation","Implementation",[2968,15630,15632],{"className":4505,"code":15631,"language":4507,"meta":2973,"style":2973},"public class FieldSelectionHelper\n{\n    public static object SelectFields\u003CT>(T source, string? fields)\n    {\n        if (string.IsNullOrWhiteSpace(fields))\n            return source!;\n\n        var fieldList = fields.Split(',', StringSplitOptions.RemoveEmptyEntries)\n            .Select(f => f.Trim().ToLower())\n            .ToHashSet();\n\n        var result = new Dictionary\u003Cstring, object?>();\n        var properties = typeof(T).GetProperties();\n\n        foreach (var prop in properties)\n        {\n            if (fieldList.Contains(prop.Name.ToLower()))\n            {\n                result[ToCamelCase(prop.Name)] = prop.GetValue(source);\n            }\n        }\n\n        return result;\n    }\n\n    private static string ToCamelCase(string str)\n    {\n        if (string.IsNullOrEmpty(str) || char.IsLower(str[0]))\n            return str;\n\n        return char.ToLower(str[0]) + str.Substring(1);\n    }\n}\n",[2975,15633,15634,15643,15647,15682,15686,15704,15713,15717,15746,15771,15779,15783,15807,15829,15833,15852,15856,15885,15889,15924,15928,15932,15936,15944,15948,15952,15972,15976,16017,16025,16029,16064,16068],{"__ignoreMap":2973},[2978,15635,15636,15638,15640],{"class":2980,"line":2981},[2978,15637,4535],{"class":3180},[2978,15639,4538],{"class":3180},[2978,15641,15642],{"class":4517}," FieldSelectionHelper\n",[2978,15644,15645],{"class":2980,"line":2999},[2978,15646,2996],{"class":2995},[2978,15648,15649,15651,15653,15656,15659,15661,15664,15666,15668,15671,15673,15675,15677,15680],{"class":2980,"line":3016},[2978,15650,4550],{"class":3180},[2978,15652,5625],{"class":3180},[2978,15654,15655],{"class":3180}," object",[2978,15657,15658],{"class":3195}," SelectFields",[2978,15660,4707],{"class":2995},[2978,15662,15663],{"class":4517},"T",[2978,15665,14736],{"class":2995},[2978,15667,15663],{"class":4517},[2978,15669,15670],{"class":3213}," source",[2978,15672,3456],{"class":2995},[2978,15674,5489],{"class":3180},[2978,15676,3101],{"class":2995},[2978,15678,15679],{"class":3213},"fields",[2978,15681,5704],{"class":2995},[2978,15683,15684],{"class":2980,"line":3030},[2978,15685,5709],{"class":2995},[2978,15687,15688,15690,15692,15694,15696,15698,15700,15702],{"class":2980,"line":3043},[2978,15689,6113],{"class":3191},[2978,15691,6116],{"class":2995},[2978,15693,5489],{"class":3180},[2978,15695,3223],{"class":2995},[2978,15697,8254],{"class":3195},[2978,15699,3199],{"class":2995},[2978,15701,15679],{"class":3213},[2978,15703,8261],{"class":2995},[2978,15705,15706,15708,15710],{"class":2980,"line":3056},[2978,15707,8266],{"class":3191},[2978,15709,15670],{"class":3213},[2978,15711,15712],{"class":2995},"!;\n",[2978,15714,15715],{"class":2980,"line":3067},[2978,15716,3288],{"emptyLinePlaceholder":3287},[2978,15718,15719,15721,15724,15726,15728,15730,15732,15734,15736,15738,15740,15742,15744],{"class":2980,"line":3442},[2978,15720,5714],{"class":3180},[2978,15722,15723],{"class":3213}," fieldList",[2978,15725,3188],{"class":2995},[2978,15727,15679],{"class":3213},[2978,15729,3223],{"class":2995},[2978,15731,8293],{"class":3195},[2978,15733,3199],{"class":2995},[2978,15735,8298],{"class":3024},[2978,15737,3456],{"class":2995},[2978,15739,8303],{"class":3213},[2978,15741,3223],{"class":2995},[2978,15743,8308],{"class":3213},[2978,15745,5704],{"class":2995},[2978,15747,15748,15750,15752,15754,15757,15759,15761,15763,15765,15767,15769],{"class":2980,"line":3469},[2978,15749,8315],{"class":2995},[2978,15751,8318],{"class":3195},[2978,15753,3199],{"class":2995},[2978,15755,15756],{"class":3213},"f",[2978,15758,8325],{"class":2995},[2978,15760,15756],{"class":3213},[2978,15762,3223],{"class":2995},[2978,15764,8332],{"class":3195},[2978,15766,8335],{"class":2995},[2978,15768,8338],{"class":3195},[2978,15770,8341],{"class":2995},[2978,15772,15773,15775,15777],{"class":2980,"line":3495},[2978,15774,8315],{"class":2995},[2978,15776,8348],{"class":3195},[2978,15778,4733],{"class":2995},[2978,15780,15781],{"class":2980,"line":3501},[2978,15782,3288],{"emptyLinePlaceholder":3287},[2978,15784,15785,15787,15790,15792,15794,15796,15798,15800,15802,15804],{"class":2980,"line":3642},[2978,15786,5714],{"class":3180},[2978,15788,15789],{"class":3213}," result",[2978,15791,3188],{"class":2995},[2978,15793,4730],{"class":3180},[2978,15795,5484],{"class":4517},[2978,15797,4707],{"class":2995},[2978,15799,5489],{"class":3180},[2978,15801,3456],{"class":2995},[2978,15803,10663],{"class":3180},[2978,15805,15806],{"class":2995},"?>();\n",[2978,15808,15809,15811,15814,15816,15818,15820,15822,15824,15827],{"class":2980,"line":3674},[2978,15810,5714],{"class":3180},[2978,15812,15813],{"class":3213}," properties",[2978,15815,3188],{"class":2995},[2978,15817,9988],{"class":3180},[2978,15819,3199],{"class":2995},[2978,15821,15663],{"class":4517},[2978,15823,3205],{"class":2995},[2978,15825,15826],{"class":3195},"GetProperties",[2978,15828,4733],{"class":2995},[2978,15830,15831],{"class":2980,"line":3680},[2978,15832,3288],{"emptyLinePlaceholder":3287},[2978,15834,15835,15838,15840,15842,15845,15848,15850],{"class":2980,"line":3686},[2978,15836,15837],{"class":3191},"        foreach",[2978,15839,6116],{"class":2995},[2978,15841,8453],{"class":3180},[2978,15843,15844],{"class":3213}," prop",[2978,15846,15847],{"class":3191}," in",[2978,15849,15813],{"class":3213},[2978,15851,5704],{"class":2995},[2978,15853,15854],{"class":2980,"line":3699},[2978,15855,5739],{"class":2995},[2978,15857,15858,15860,15862,15865,15867,15869,15871,15874,15876,15878,15880,15882],{"class":2980,"line":4367},[2978,15859,13738],{"class":3191},[2978,15861,6116],{"class":2995},[2978,15863,15864],{"class":3213},"fieldList",[2978,15866,3223],{"class":2995},[2978,15868,8381],{"class":3195},[2978,15870,3199],{"class":2995},[2978,15872,15873],{"class":3213},"prop",[2978,15875,3223],{"class":2995},[2978,15877,8789],{"class":3213},[2978,15879,3223],{"class":2995},[2978,15881,8338],{"class":3195},[2978,15883,15884],{"class":2995},"()))\n",[2978,15886,15887],{"class":2980,"line":4825},[2978,15888,5758],{"class":2995},[2978,15890,15891,15894,15896,15899,15901,15903,15905,15907,15910,15912,15914,15917,15919,15922],{"class":2980,"line":4836},[2978,15892,15893],{"class":3213},"                result",[2978,15895,6148],{"class":2995},[2978,15897,15898],{"class":3195},"ToCamelCase",[2978,15900,3199],{"class":2995},[2978,15902,15873],{"class":3213},[2978,15904,3223],{"class":2995},[2978,15906,8789],{"class":3213},[2978,15908,15909],{"class":2995},")] = ",[2978,15911,15873],{"class":3213},[2978,15913,3223],{"class":2995},[2978,15915,15916],{"class":3195},"GetValue",[2978,15918,3199],{"class":2995},[2978,15920,15921],{"class":3213},"source",[2978,15923,8474],{"class":2995},[2978,15925,15926],{"class":2980,"line":4841},[2978,15927,6094],{"class":2995},[2978,15929,15930],{"class":2980,"line":4849},[2978,15931,6242],{"class":2995},[2978,15933,15934],{"class":2980,"line":4857},[2978,15935,3288],{"emptyLinePlaceholder":3287},[2978,15937,15938,15940,15942],{"class":2980,"line":4863},[2978,15939,6615],{"class":3191},[2978,15941,15789],{"class":3213},[2978,15943,4526],{"class":2995},[2978,15945,15946],{"class":2980,"line":4868},[2978,15947,6625],{"class":2995},[2978,15949,15950],{"class":2980,"line":4873},[2978,15951,3288],{"emptyLinePlaceholder":3287},[2978,15953,15954,15956,15958,15960,15963,15965,15967,15970],{"class":2980,"line":4883},[2978,15955,9701],{"class":3180},[2978,15957,5625],{"class":3180},[2978,15959,4581],{"class":3180},[2978,15961,15962],{"class":3195}," ToCamelCase",[2978,15964,3199],{"class":2995},[2978,15966,5489],{"class":3180},[2978,15968,15969],{"class":3213}," str",[2978,15971,5704],{"class":2995},[2978,15973,15974],{"class":2980,"line":4888},[2978,15975,5709],{"class":2995},[2978,15977,15978,15980,15982,15984,15986,15989,15991,15994,15997,16000,16002,16005,16007,16009,16011,16014],{"class":2980,"line":4907},[2978,15979,6113],{"class":3191},[2978,15981,6116],{"class":2995},[2978,15983,5489],{"class":3180},[2978,15985,3223],{"class":2995},[2978,15987,15988],{"class":3195},"IsNullOrEmpty",[2978,15990,3199],{"class":2995},[2978,15992,15993],{"class":3213},"str",[2978,15995,15996],{"class":2995},") || ",[2978,15998,15999],{"class":3180},"char",[2978,16001,3223],{"class":2995},[2978,16003,16004],{"class":3195},"IsLower",[2978,16006,3199],{"class":2995},[2978,16008,15993],{"class":3213},[2978,16010,6148],{"class":2995},[2978,16012,16013],{"class":3009},"0",[2978,16015,16016],{"class":2995},"]))\n",[2978,16018,16019,16021,16023],{"class":2980,"line":4929},[2978,16020,8266],{"class":3191},[2978,16022,15969],{"class":3213},[2978,16024,4526],{"class":2995},[2978,16026,16027],{"class":2980,"line":4951},[2978,16028,3288],{"emptyLinePlaceholder":3287},[2978,16030,16031,16033,16036,16038,16040,16042,16044,16046,16048,16051,16053,16055,16058,16060,16062],{"class":2980,"line":4973},[2978,16032,6615],{"class":3191},[2978,16034,16035],{"class":3180}," char",[2978,16037,3223],{"class":2995},[2978,16039,8338],{"class":3195},[2978,16041,3199],{"class":2995},[2978,16043,15993],{"class":3213},[2978,16045,6148],{"class":2995},[2978,16047,16013],{"class":3009},[2978,16049,16050],{"class":2995},"]) + ",[2978,16052,15993],{"class":3213},[2978,16054,3223],{"class":2995},[2978,16056,16057],{"class":3195},"Substring",[2978,16059,3199],{"class":2995},[2978,16061,3617],{"class":3009},[2978,16063,8474],{"class":2995},[2978,16065,16066],{"class":2980,"line":5004},[2978,16067,6625],{"class":2995},[2978,16069,16070],{"class":2980,"line":5009},[2978,16071,3070],{"class":2995},[5325,16073,16075],{"id":16074},"використання-у-контролері","Використання у контролері",[2968,16077,16079],{"className":4505,"code":16078,"language":4507,"meta":2973,"style":2973},"[HttpGet(\"{id:int}\")]\npublic async Task\u003CIActionResult> GetById(\n    int id,\n    [FromQuery] string? expand = null,\n    [FromQuery] string? fields = null)\n{\n    var article = await _db.Articles.FindAsync(id);\n    if (article is null) return NotFound();\n\n    var dto = MapToDto(article, ExpansionOptions.Parse(expand));\n    dto.Links = LinkGeneratorHelper.GenerateArticleLinks(article.Id, article.Status, _urlHelper, true);\n\n    // Застосовуємо field selection\n    var result = FieldSelectionHelper.SelectFields(dto, fields);\n\n    return Ok(result);\n}\n",[2975,16080,16081,16093,16111,16120,16140,16160,16164,16190,16213,16217,16245,16288,16292,16297,16323,16327,16341],{"__ignoreMap":2973},[2978,16082,16083,16085,16087,16089,16091],{"class":2980,"line":2981},[2978,16084,6148],{"class":2995},[2978,16086,9960],{"class":4517},[2978,16088,3199],{"class":2995},[2978,16090,9965],{"class":3024},[2978,16092,7499],{"class":2995},[2978,16094,16095,16097,16099,16101,16103,16105,16107,16109],{"class":2980,"line":2999},[2978,16096,4535],{"class":3180},[2978,16098,10030],{"class":3180},[2978,16100,10033],{"class":4517},[2978,16102,4707],{"class":2995},[2978,16104,10686],{"class":4517},[2978,16106,4713],{"class":2995},[2978,16108,10048],{"class":3195},[2978,16110,5658],{"class":2995},[2978,16112,16113,16116,16118],{"class":2980,"line":3016},[2978,16114,16115],{"class":3180},"    int",[2978,16117,10057],{"class":3213},[2978,16119,3013],{"class":2995},[2978,16121,16122,16124,16126,16128,16130,16132,16134,16136,16138],{"class":2980,"line":3030},[2978,16123,7489],{"class":2995},[2978,16125,10067],{"class":4517},[2978,16127,10070],{"class":2995},[2978,16129,5489],{"class":3180},[2978,16131,3101],{"class":2995},[2978,16133,8235],{"class":3213},[2978,16135,3188],{"class":2995},[2978,16137,10081],{"class":3180},[2978,16139,3013],{"class":2995},[2978,16141,16142,16144,16146,16148,16150,16152,16154,16156,16158],{"class":2980,"line":3043},[2978,16143,7489],{"class":2995},[2978,16145,10067],{"class":4517},[2978,16147,10070],{"class":2995},[2978,16149,5489],{"class":3180},[2978,16151,3101],{"class":2995},[2978,16153,15679],{"class":3213},[2978,16155,3188],{"class":2995},[2978,16157,10081],{"class":3180},[2978,16159,5704],{"class":2995},[2978,16161,16162],{"class":2980,"line":3056},[2978,16163,2996],{"class":2995},[2978,16165,16166,16168,16170,16172,16174,16176,16178,16180,16182,16184,16186,16188],{"class":2980,"line":3067},[2978,16167,14922],{"class":3180},[2978,16169,3185],{"class":3213},[2978,16171,3188],{"class":2995},[2978,16173,3192],{"class":3180},[2978,16175,9709],{"class":3213},[2978,16177,3223],{"class":2995},[2978,16179,4987],{"class":3213},[2978,16181,3223],{"class":2995},[2978,16183,12285],{"class":3195},[2978,16185,3199],{"class":2995},[2978,16187,5792],{"class":3213},[2978,16189,8474],{"class":2995},[2978,16191,16192,16195,16197,16199,16201,16203,16206,16209,16211],{"class":2980,"line":3442},[2978,16193,16194],{"class":3191},"    if",[2978,16196,6116],{"class":2995},[2978,16198,3252],{"class":3213},[2978,16200,10339],{"class":3180},[2978,16202,10342],{"class":3180},[2978,16204,16205],{"class":2995},") ",[2978,16207,16208],{"class":3191},"return",[2978,16210,10351],{"class":3195},[2978,16212,4733],{"class":2995},[2978,16214,16215],{"class":2980,"line":3469},[2978,16216,3288],{"emptyLinePlaceholder":3287},[2978,16218,16219,16221,16223,16225,16227,16229,16231,16233,16235,16237,16239,16241,16243],{"class":2980,"line":3495},[2978,16220,14922],{"class":3180},[2978,16222,10369],{"class":3213},[2978,16224,3188],{"class":2995},[2978,16226,10374],{"class":3195},[2978,16228,3199],{"class":2995},[2978,16230,3252],{"class":3213},[2978,16232,3456],{"class":2995},[2978,16234,8461],{"class":3213},[2978,16236,3223],{"class":2995},[2978,16238,8466],{"class":3195},[2978,16240,3199],{"class":2995},[2978,16242,8235],{"class":3213},[2978,16244,14758],{"class":2995},[2978,16246,16247,16250,16252,16254,16256,16258,16260,16262,16264,16266,16268,16270,16272,16274,16276,16278,16280,16282,16284,16286],{"class":2980,"line":3501},[2978,16248,16249],{"class":3213},"    dto",[2978,16251,3223],{"class":2995},[2978,16253,5499],{"class":3213},[2978,16255,3188],{"class":2995},[2978,16257,10407],{"class":3213},[2978,16259,3223],{"class":2995},[2978,16261,5655],{"class":3195},[2978,16263,3199],{"class":2995},[2978,16265,3252],{"class":3213},[2978,16267,3223],{"class":2995},[2978,16269,8780],{"class":3213},[2978,16271,3456],{"class":2995},[2978,16273,3252],{"class":3213},[2978,16275,3223],{"class":2995},[2978,16277,10433],{"class":3213},[2978,16279,3456],{"class":2995},[2978,16281,11542],{"class":3213},[2978,16283,3456],{"class":2995},[2978,16285,10452],{"class":3180},[2978,16287,8474],{"class":2995},[2978,16289,16290],{"class":2980,"line":3642},[2978,16291,3288],{"emptyLinePlaceholder":3287},[2978,16293,16294],{"class":2980,"line":3674},[2978,16295,16296],{"class":3174},"    // Застосовуємо field selection\n",[2978,16298,16299,16301,16303,16305,16308,16310,16313,16315,16317,16319,16321],{"class":2980,"line":3680},[2978,16300,14922],{"class":3180},[2978,16302,15789],{"class":3213},[2978,16304,3188],{"class":2995},[2978,16306,16307],{"class":3213},"FieldSelectionHelper",[2978,16309,3223],{"class":2995},[2978,16311,16312],{"class":3195},"SelectFields",[2978,16314,3199],{"class":2995},[2978,16316,10489],{"class":3213},[2978,16318,3456],{"class":2995},[2978,16320,15679],{"class":3213},[2978,16322,8474],{"class":2995},[2978,16324,16325],{"class":2980,"line":3686},[2978,16326,3288],{"emptyLinePlaceholder":3287},[2978,16328,16329,16332,16334,16336,16339],{"class":2980,"line":3699},[2978,16330,16331],{"class":3191},"    return",[2978,16333,10592],{"class":3195},[2978,16335,3199],{"class":2995},[2978,16337,16338],{"class":3213},"result",[2978,16340,8474],{"class":2995},[2978,16342,16343],{"class":2980,"line":4367},[2978,16344,3070],{"class":2995},[2964,16346,16347],{},[3074,16348,16349],{},"Приклад:",[2968,16351,16353],{"className":2970,"code":16352,"language":2972,"meta":2973,"style":2973},"GET /api/articles/1?fields=id,title,_links\n",[2975,16354,16355],{"__ignoreMap":2973},[2978,16356,16357],{"class":2980,"line":2981},[2978,16358,16352],{},[2968,16360,16362],{"className":2986,"code":16361,"language":2988,"meta":2973,"style":2973},"{\n  \"id\": 1,\n  \"title\": \"Introduction to ASP.NET Core\",\n  \"_links\": { ... }\n}\n",[2975,16363,16364,16368,16378,16388,16398],{"__ignoreMap":2973},[2978,16365,16366],{"class":2980,"line":2981},[2978,16367,2996],{"class":2995},[2978,16369,16370,16372,16374,16376],{"class":2980,"line":2999},[2978,16371,3003],{"class":3002},[2978,16373,3006],{"class":2995},[2978,16375,3617],{"class":3009},[2978,16377,3013],{"class":2995},[2978,16379,16380,16382,16384,16386],{"class":2980,"line":3016},[2978,16381,3019],{"class":3002},[2978,16383,3006],{"class":2995},[2978,16385,3025],{"class":3024},[2978,16387,3013],{"class":2995},[2978,16389,16390,16392,16394,16396],{"class":2980,"line":3030},[2978,16391,3385],{"class":3002},[2978,16393,3396],{"class":2995},[2978,16395,3694],{"class":3693},[2978,16397,3492],{"class":2995},[2978,16399,16400],{"class":2980,"line":3043},[2978,16401,3070],{"class":2995},[3882,16403],{},[3329,16405,16407],{"id":16406},"_2-conditional-links-based-on-permissions","2. Conditional Links Based on Permissions",[2964,16409,16410],{},"Генеруйте links залежно від прав користувача:",[2968,16412,16414],{"className":4505,"code":16413,"language":4507,"meta":2973,"style":2973},"public static Dictionary\u003Cstring, Link> GenerateArticleLinks(\n    int articleId,\n    ArticleStatus status,\n    IUrlHelper urlHelper,\n    ClaimsPrincipal user) // Замість bool isOwner\n{\n    var links = new Dictionary\u003Cstring, Link>\n    {\n        [\"self\"] = new Link { Href = urlHelper.Action(\"GetById\", \"Articles\", new { id = articleId })! }\n    };\n\n    // Тільки автор може редагувати\n    if (user.HasClaim(\"ArticleOwner\", articleId.ToString()))\n    {\n        links[\"edit\"] = new Link\n        {\n            Href = urlHelper.Action(\"Update\", \"Articles\", new { id = articleId })!,\n            Method = \"PUT\"\n        };\n    }\n\n    // Тільки адміни можуть видаляти\n    if (user.IsInRole(\"Admin\"))\n    {\n        links[\"delete\"] = new Link\n        {\n            Href = urlHelper.Action(\"Delete\", \"Articles\", new { id = articleId })!,\n            Method = \"DELETE\"\n        };\n    }\n\n    return links;\n}\n",[2975,16415,16416,16438,16446,16455,16464,16477,16481,16503,16507,16555,16560,16564,16569,16598,16602,16617,16621,16656,16666,16670,16674,16678,16683,16703,16707,16721,16725,16759,16768,16772,16776,16780,16788],{"__ignoreMap":2973},[2978,16417,16418,16420,16422,16424,16426,16428,16430,16432,16434,16436],{"class":2980,"line":2981},[2978,16419,4535],{"class":3180},[2978,16421,5625],{"class":3180},[2978,16423,5484],{"class":4517},[2978,16425,4707],{"class":2995},[2978,16427,5489],{"class":3180},[2978,16429,3456],{"class":2995},[2978,16431,5494],{"class":4517},[2978,16433,4713],{"class":2995},[2978,16435,5655],{"class":3195},[2978,16437,5658],{"class":2995},[2978,16439,16440,16442,16444],{"class":2980,"line":2999},[2978,16441,16115],{"class":3180},[2978,16443,5666],{"class":3213},[2978,16445,3013],{"class":2995},[2978,16447,16448,16451,16453],{"class":2980,"line":3016},[2978,16449,16450],{"class":4517},"    ArticleStatus",[2978,16452,5676],{"class":3213},[2978,16454,3013],{"class":2995},[2978,16456,16457,16460,16462],{"class":2980,"line":3030},[2978,16458,16459],{"class":4517},"    IUrlHelper",[2978,16461,5686],{"class":3213},[2978,16463,3013],{"class":2995},[2978,16465,16466,16469,16472,16474],{"class":2980,"line":3043},[2978,16467,16468],{"class":4517},"    ClaimsPrincipal",[2978,16470,16471],{"class":3213}," user",[2978,16473,16205],{"class":2995},[2978,16475,16476],{"class":3174},"// Замість bool isOwner\n",[2978,16478,16479],{"class":2980,"line":3056},[2978,16480,2996],{"class":2995},[2978,16482,16483,16485,16487,16489,16491,16493,16495,16497,16499,16501],{"class":2980,"line":3067},[2978,16484,14922],{"class":3180},[2978,16486,5717],{"class":3213},[2978,16488,3188],{"class":2995},[2978,16490,4730],{"class":3180},[2978,16492,5484],{"class":4517},[2978,16494,4707],{"class":2995},[2978,16496,5489],{"class":3180},[2978,16498,3456],{"class":2995},[2978,16500,5494],{"class":4517},[2978,16502,5734],{"class":2995},[2978,16504,16505],{"class":2980,"line":3442},[2978,16506,5709],{"class":2995},[2978,16508,16509,16511,16513,16515,16517,16520,16522,16524,16526,16528,16530,16532,16534,16536,16538,16540,16542,16544,16546,16548,16550,16552],{"class":2980,"line":3469},[2978,16510,10064],{"class":2995},[2978,16512,3738],{"class":3024},[2978,16514,5749],{"class":2995},[2978,16516,4730],{"class":3180},[2978,16518,16519],{"class":4517}," Link",[2978,16521,4559],{"class":2995},[2978,16523,5530],{"class":3213},[2978,16525,3188],{"class":2995},[2978,16527,5768],{"class":3213},[2978,16529,3223],{"class":2995},[2978,16531,5773],{"class":3195},[2978,16533,3199],{"class":2995},[2978,16535,5778],{"class":3024},[2978,16537,3456],{"class":2995},[2978,16539,5783],{"class":3024},[2978,16541,3456],{"class":2995},[2978,16543,4730],{"class":3180},[2978,16545,4559],{"class":2995},[2978,16547,5792],{"class":3213},[2978,16549,3188],{"class":2995},[2978,16551,5797],{"class":3213},[2978,16553,16554],{"class":2995}," })! }\n",[2978,16556,16557],{"class":2980,"line":3495},[2978,16558,16559],{"class":2995},"    };\n",[2978,16561,16562],{"class":2980,"line":3501},[2978,16563,3288],{"emptyLinePlaceholder":3287},[2978,16565,16566],{"class":2980,"line":3642},[2978,16567,16568],{"class":3174},"    // Тільки автор може редагувати\n",[2978,16570,16571,16573,16575,16578,16580,16583,16585,16588,16590,16592,16594,16596],{"class":2980,"line":3674},[2978,16572,16194],{"class":3191},[2978,16574,6116],{"class":2995},[2978,16576,16577],{"class":3213},"user",[2978,16579,3223],{"class":2995},[2978,16581,16582],{"class":3195},"HasClaim",[2978,16584,3199],{"class":2995},[2978,16586,16587],{"class":3024},"\"ArticleOwner\"",[2978,16589,3456],{"class":2995},[2978,16591,5797],{"class":3213},[2978,16593,3223],{"class":2995},[2978,16595,10524],{"class":3195},[2978,16597,15884],{"class":2995},[2978,16599,16600],{"class":2980,"line":3680},[2978,16601,5709],{"class":2995},[2978,16603,16604,16607,16609,16611,16613,16615],{"class":2980,"line":3686},[2978,16605,16606],{"class":3213},"        links",[2978,16608,6148],{"class":2995},[2978,16610,6287],{"class":3024},[2978,16612,5749],{"class":2995},[2978,16614,4730],{"class":3180},[2978,16616,5363],{"class":4517},[2978,16618,16619],{"class":2980,"line":3699},[2978,16620,5739],{"class":2995},[2978,16622,16623,16626,16628,16630,16632,16634,16636,16638,16640,16642,16644,16646,16648,16650,16652,16654],{"class":2980,"line":4367},[2978,16624,16625],{"class":3213},"            Href",[2978,16627,3188],{"class":2995},[2978,16629,5768],{"class":3213},[2978,16631,3223],{"class":2995},[2978,16633,5773],{"class":3195},[2978,16635,3199],{"class":2995},[2978,16637,6316],{"class":3024},[2978,16639,3456],{"class":2995},[2978,16641,5783],{"class":3024},[2978,16643,3456],{"class":2995},[2978,16645,4730],{"class":3180},[2978,16647,4559],{"class":2995},[2978,16649,5792],{"class":3213},[2978,16651,3188],{"class":2995},[2978,16653,5797],{"class":3213},[2978,16655,5800],{"class":2995},[2978,16657,16658,16661,16663],{"class":2980,"line":4825},[2978,16659,16660],{"class":3213},"            Method",[2978,16662,3188],{"class":2995},[2978,16664,16665],{"class":3024},"\"PUT\"\n",[2978,16667,16668],{"class":2980,"line":4836},[2978,16669,6099],{"class":2995},[2978,16671,16672],{"class":2980,"line":4841},[2978,16673,6625],{"class":2995},[2978,16675,16676],{"class":2980,"line":4849},[2978,16677,3288],{"emptyLinePlaceholder":3287},[2978,16679,16680],{"class":2980,"line":4857},[2978,16681,16682],{"class":3174},"    // Тільки адміни можуть видаляти\n",[2978,16684,16685,16687,16689,16691,16693,16696,16698,16701],{"class":2980,"line":4863},[2978,16686,16194],{"class":3191},[2978,16688,6116],{"class":2995},[2978,16690,16577],{"class":3213},[2978,16692,3223],{"class":2995},[2978,16694,16695],{"class":3195},"IsInRole",[2978,16697,3199],{"class":2995},[2978,16699,16700],{"class":3024},"\"Admin\"",[2978,16702,8261],{"class":2995},[2978,16704,16705],{"class":2980,"line":4868},[2978,16706,5709],{"class":2995},[2978,16708,16709,16711,16713,16715,16717,16719],{"class":2980,"line":4873},[2978,16710,16606],{"class":3213},[2978,16712,6148],{"class":2995},[2978,16714,6386],{"class":3024},[2978,16716,5749],{"class":2995},[2978,16718,4730],{"class":3180},[2978,16720,5363],{"class":4517},[2978,16722,16723],{"class":2980,"line":4883},[2978,16724,5739],{"class":2995},[2978,16726,16727,16729,16731,16733,16735,16737,16739,16741,16743,16745,16747,16749,16751,16753,16755,16757],{"class":2980,"line":4888},[2978,16728,16625],{"class":3213},[2978,16730,3188],{"class":2995},[2978,16732,5768],{"class":3213},[2978,16734,3223],{"class":2995},[2978,16736,5773],{"class":3195},[2978,16738,3199],{"class":2995},[2978,16740,6415],{"class":3024},[2978,16742,3456],{"class":2995},[2978,16744,5783],{"class":3024},[2978,16746,3456],{"class":2995},[2978,16748,4730],{"class":3180},[2978,16750,4559],{"class":2995},[2978,16752,5792],{"class":3213},[2978,16754,3188],{"class":2995},[2978,16756,5797],{"class":3213},[2978,16758,5800],{"class":2995},[2978,16760,16761,16763,16765],{"class":2980,"line":4907},[2978,16762,16660],{"class":3213},[2978,16764,3188],{"class":2995},[2978,16766,16767],{"class":3024},"\"DELETE\"\n",[2978,16769,16770],{"class":2980,"line":4929},[2978,16771,6099],{"class":2995},[2978,16773,16774],{"class":2980,"line":4951},[2978,16775,6625],{"class":2995},[2978,16777,16778],{"class":2980,"line":4973},[2978,16779,3288],{"emptyLinePlaceholder":3287},[2978,16781,16782,16784,16786],{"class":2980,"line":5004},[2978,16783,16331],{"class":3191},[2978,16785,5717],{"class":3213},[2978,16787,4526],{"class":2995},[2978,16789,16790],{"class":2980,"line":5009},[2978,16791,3070],{"class":2995},[2964,16793,16794],{},[3074,16795,16796],{},"Результат для звичайного користувача:",[2968,16798,16800],{"className":2986,"code":16799,"language":2988,"meta":2973,"style":2973},"{\n  \"_links\": {\n    \"self\": { \"href\": \"/api/articles/1\" }\n  }\n}\n",[2975,16801,16802,16806,16812,16827,16831],{"__ignoreMap":2973},[2978,16803,16804],{"class":2980,"line":2981},[2978,16805,2996],{"class":2995},[2978,16807,16808,16810],{"class":2980,"line":2999},[2978,16809,3385],{"class":3002},[2978,16811,3388],{"class":2995},[2978,16813,16814,16816,16818,16820,16822,16825],{"class":2980,"line":3016},[2978,16815,3393],{"class":3002},[2978,16817,3396],{"class":2995},[2978,16819,3399],{"class":3002},[2978,16821,3006],{"class":2995},[2978,16823,16824],{"class":3024},"\"/api/articles/1\"",[2978,16826,3492],{"class":2995},[2978,16828,16829],{"class":2980,"line":3030},[2978,16830,3498],{"class":2995},[2978,16832,16833],{"class":2980,"line":3043},[2978,16834,3070],{"class":2995},[2964,16836,16837],{},[3074,16838,16839],{},"Результат для автора:",[2968,16841,16843],{"className":2986,"code":16842,"language":2988,"meta":2973,"style":2973},"{\n  \"_links\": {\n    \"self\": { \"href\": \"/api/articles/1\" },\n    \"edit\": { \"href\": \"/api/articles/1\", \"method\": \"PUT\" }\n  }\n}\n",[2975,16844,16845,16849,16855,16869,16891,16895],{"__ignoreMap":2973},[2978,16846,16847],{"class":2980,"line":2981},[2978,16848,2996],{"class":2995},[2978,16850,16851,16853],{"class":2980,"line":2999},[2978,16852,3385],{"class":3002},[2978,16854,3388],{"class":2995},[2978,16856,16857,16859,16861,16863,16865,16867],{"class":2980,"line":3016},[2978,16858,3393],{"class":3002},[2978,16860,3396],{"class":2995},[2978,16862,3399],{"class":3002},[2978,16864,3006],{"class":2995},[2978,16866,16824],{"class":3024},[2978,16868,3407],{"class":2995},[2978,16870,16871,16873,16875,16877,16879,16881,16883,16885,16887,16889],{"class":2980,"line":3030},[2978,16872,3445],{"class":3002},[2978,16874,3396],{"class":2995},[2978,16876,3399],{"class":3002},[2978,16878,3006],{"class":2995},[2978,16880,16824],{"class":3024},[2978,16882,3456],{"class":2995},[2978,16884,3459],{"class":3002},[2978,16886,3006],{"class":2995},[2978,16888,3464],{"class":3024},[2978,16890,3492],{"class":2995},[2978,16892,16893],{"class":2980,"line":3043},[2978,16894,3498],{"class":2995},[2978,16896,16897],{"class":2980,"line":3056},[2978,16898,3070],{"class":2995},[3882,16900],{},[3329,16902,16904],{"id":16903},"_3-link-templates-rfc-6570","3. Link Templates (RFC 6570)",[2964,16906,16907],{},"Для параметризованих links використовуйте URI Templates:",[2968,16909,16911],{"className":4505,"code":16910,"language":4507,"meta":2973,"style":2973},"links[\"search\"] = new Link\n{\n    Href = \"/api/articles{?category,author,page}\",\n    Templated = true,\n    Title = \"Search articles\"\n};\n",[2975,16912,16913,16929,16933,16945,16956,16966],{"__ignoreMap":2973},[2978,16914,16915,16918,16920,16923,16925,16927],{"class":2980,"line":2981},[2978,16916,16917],{"class":3213},"links",[2978,16919,6148],{"class":2995},[2978,16921,16922],{"class":3024},"\"search\"",[2978,16924,5749],{"class":2995},[2978,16926,4730],{"class":3180},[2978,16928,5363],{"class":4517},[2978,16930,16931],{"class":2980,"line":2999},[2978,16932,2996],{"class":2995},[2978,16934,16935,16938,16940,16943],{"class":2980,"line":3016},[2978,16936,16937],{"class":3213},"    Href",[2978,16939,3188],{"class":2995},[2978,16941,16942],{"class":3024},"\"/api/articles{?category,author,page}\"",[2978,16944,3013],{"class":2995},[2978,16946,16947,16950,16952,16954],{"class":2980,"line":3030},[2978,16948,16949],{"class":3213},"    Templated",[2978,16951,3188],{"class":2995},[2978,16953,10452],{"class":3180},[2978,16955,3013],{"class":2995},[2978,16957,16958,16961,16963],{"class":2980,"line":3043},[2978,16959,16960],{"class":3213},"    Title",[2978,16962,3188],{"class":2995},[2978,16964,16965],{"class":3024},"\"Search articles\"\n",[2978,16967,16968],{"class":2980,"line":3056},[2978,16969,16970],{"class":2995},"};\n",[2968,16972,16974],{"className":2986,"code":16973,"language":2988,"meta":2973,"style":2973},"{\n  \"_links\": {\n    \"search\": {\n      \"href\": \"/api/articles{?category,author,page}\",\n      \"templated\": true,\n      \"title\": \"Search articles\"\n    }\n  }\n}\n",[2975,16975,16976,16980,16986,16993,17004,17015,17024,17028,17032],{"__ignoreMap":2973},[2978,16977,16978],{"class":2980,"line":2981},[2978,16979,2996],{"class":2995},[2978,16981,16982,16984],{"class":2980,"line":2999},[2978,16983,3385],{"class":3002},[2978,16985,3388],{"class":2995},[2978,16987,16988,16991],{"class":2980,"line":3016},[2978,16989,16990],{"class":3002},"    \"search\"",[2978,16992,3388],{"class":2995},[2978,16994,16995,16998,17000,17002],{"class":2980,"line":3030},[2978,16996,16997],{"class":3002},"      \"href\"",[2978,16999,3006],{"class":2995},[2978,17001,16942],{"class":3024},[2978,17003,3013],{"class":2995},[2978,17005,17006,17009,17011,17013],{"class":2980,"line":3043},[2978,17007,17008],{"class":3002},"      \"templated\"",[2978,17010,3006],{"class":2995},[2978,17012,10452],{"class":3180},[2978,17014,3013],{"class":2995},[2978,17016,17017,17020,17022],{"class":2980,"line":3056},[2978,17018,17019],{"class":3002},"      \"title\"",[2978,17021,3006],{"class":2995},[2978,17023,16965],{"class":3024},[2978,17025,17026],{"class":2980,"line":3067},[2978,17027,6625],{"class":2995},[2978,17029,17030],{"class":2980,"line":3442},[2978,17031,3498],{"class":2995},[2978,17033,17034],{"class":2980,"line":3469},[2978,17035,3070],{"class":2995},[2964,17037,17038],{},"Клієнт може підставити параметри:",[2968,17040,17043],{"className":17041,"code":17042,"language":3122},[3120],"/api/articles?category=tech&author=john&page=2\n",[2975,17044,17042],{"__ignoreMap":2973},[3882,17046],{},[3329,17048,17050],{"id":17049},"_4-curies-compact-uris","4. Curies (Compact URIs)",[2964,17052,17053],{},"Для документації links використовуйте curies:",[2968,17055,17057],{"className":2986,"code":17056,"language":2988,"meta":2973,"style":2973},"{\n  \"_links\": {\n    \"self\": { \"href\": \"/api/articles/1\" },\n    \"curies\": [{\n      \"name\": \"doc\",\n      \"href\": \"https://api.example.com/docs/rels/{rel}\",\n      \"templated\": true\n    }],\n    \"doc:author\": { \"href\": \"/api/authors/1\" },\n    \"doc:comments\": { \"href\": \"/api/articles/1/comments\" }\n  }\n}\n",[2975,17058,17059,17063,17069,17083,17091,17102,17113,17122,17127,17143,17159,17163],{"__ignoreMap":2973},[2978,17060,17061],{"class":2980,"line":2981},[2978,17062,2996],{"class":2995},[2978,17064,17065,17067],{"class":2980,"line":2999},[2978,17066,3385],{"class":3002},[2978,17068,3388],{"class":2995},[2978,17070,17071,17073,17075,17077,17079,17081],{"class":2980,"line":3016},[2978,17072,3393],{"class":3002},[2978,17074,3396],{"class":2995},[2978,17076,3399],{"class":3002},[2978,17078,3006],{"class":2995},[2978,17080,16824],{"class":3024},[2978,17082,3407],{"class":2995},[2978,17084,17085,17088],{"class":2980,"line":3030},[2978,17086,17087],{"class":3002},"    \"curies\"",[2978,17089,17090],{"class":2995},": [{\n",[2978,17092,17093,17095,17097,17100],{"class":2980,"line":3043},[2978,17094,3575],{"class":3002},[2978,17096,3006],{"class":2995},[2978,17098,17099],{"class":3024},"\"doc\"",[2978,17101,3013],{"class":2995},[2978,17103,17104,17106,17108,17111],{"class":2980,"line":3056},[2978,17105,16997],{"class":3002},[2978,17107,3006],{"class":2995},[2978,17109,17110],{"class":3024},"\"https://api.example.com/docs/rels/{rel}\"",[2978,17112,3013],{"class":2995},[2978,17114,17115,17117,17119],{"class":2980,"line":3067},[2978,17116,17008],{"class":3002},[2978,17118,3006],{"class":2995},[2978,17120,17121],{"class":3180},"true\n",[2978,17123,17124],{"class":2980,"line":3442},[2978,17125,17126],{"class":2995},"    }],\n",[2978,17128,17129,17132,17134,17136,17138,17141],{"class":2980,"line":3469},[2978,17130,17131],{"class":3002},"    \"doc:author\"",[2978,17133,3396],{"class":2995},[2978,17135,3399],{"class":3002},[2978,17137,3006],{"class":2995},[2978,17139,17140],{"class":3024},"\"/api/authors/1\"",[2978,17142,3407],{"class":2995},[2978,17144,17145,17148,17150,17152,17154,17157],{"class":2980,"line":3495},[2978,17146,17147],{"class":3002},"    \"doc:comments\"",[2978,17149,3396],{"class":2995},[2978,17151,3399],{"class":3002},[2978,17153,3006],{"class":2995},[2978,17155,17156],{"class":3024},"\"/api/articles/1/comments\"",[2978,17158,3492],{"class":2995},[2978,17160,17161],{"class":2980,"line":3501},[2978,17162,3498],{"class":2995},[2978,17164,17165],{"class":2980,"line":3642},[2978,17166,3070],{"class":2995},[2964,17168,17169],{},"Клієнт може отримати документацію:",[2968,17171,17174],{"className":17172,"code":17173,"language":3122},[3120],"https://api.example.com/docs/rels/author\n→ Документація про rel \"author\"\n",[2975,17175,17173],{"__ignoreMap":2973},[3882,17177],{},[2959,17179,17181],{"id":17180},"практичні-завдання","Практичні завдання",[3329,17183,17185],{"id":17184},"рівень-1-базове-розуміння","Рівень 1: Базове розуміння",[4428,17187,17188,17192,17195,17200,17214,17219,17239,17244,17326,17349,17353,17356,17361,17404,17409,17456],{},[3329,17189,17191],{"id":17190},"завдання-11-richardson-maturity-model","Завдання 1.1: Richardson Maturity Model",[2964,17193,17194],{},"Визначте рівень зрілості для кожного API:",[2964,17196,17197],{},[3074,17198,17199],{},"API A:",[2968,17201,17203],{"className":2970,"code":17202,"language":2972,"meta":2973,"style":2973},"POST /api\n{ \"action\": \"getUser\", \"userId\": 5 }\n",[2975,17204,17205,17209],{"__ignoreMap":2973},[2978,17206,17207],{"class":2980,"line":2981},[2978,17208,3967],{},[2978,17210,17211],{"class":2980,"line":2999},[2978,17212,17213],{},"{ \"action\": \"getUser\", \"userId\": 5 }\n",[2964,17215,17216],{},[3074,17217,17218],{},"API B:",[2968,17220,17222],{"className":2970,"code":17221,"language":2972,"meta":2973,"style":2973},"GET /api/users/5\nPUT /api/users/5\nDELETE /api/users/5\n",[2975,17223,17224,17229,17234],{"__ignoreMap":2973},[2978,17225,17226],{"class":2980,"line":2981},[2978,17227,17228],{},"GET /api/users/5\n",[2978,17230,17231],{"class":2980,"line":2999},[2978,17232,17233],{},"PUT /api/users/5\n",[2978,17235,17236],{"class":2980,"line":3016},[2978,17237,17238],{},"DELETE /api/users/5\n",[2964,17240,17241],{},[3074,17242,17243],{},"API C:",[2968,17245,17247],{"className":2986,"code":17246,"language":2988,"meta":2973,"style":2973},"{\n  \"id\": 5,\n  \"name\": \"John\",\n  \"_links\": {\n    \"self\": { \"href\": \"/api/users/5\" },\n    \"edit\": { \"href\": \"/api/users/5\", \"method\": \"PUT\" }\n  }\n}\n",[2975,17248,17249,17253,17263,17275,17281,17296,17318,17322],{"__ignoreMap":2973},[2978,17250,17251],{"class":2980,"line":2981},[2978,17252,2996],{"class":2995},[2978,17254,17255,17257,17259,17261],{"class":2980,"line":2999},[2978,17256,3003],{"class":3002},[2978,17258,3006],{"class":2995},[2978,17260,3010],{"class":3009},[2978,17262,3013],{"class":2995},[2978,17264,17265,17268,17270,17273],{"class":2980,"line":3016},[2978,17266,17267],{"class":3002},"  \"name\"",[2978,17269,3006],{"class":2995},[2978,17271,17272],{"class":3024},"\"John\"",[2978,17274,3013],{"class":2995},[2978,17276,17277,17279],{"class":2980,"line":3030},[2978,17278,3385],{"class":3002},[2978,17280,3388],{"class":2995},[2978,17282,17283,17285,17287,17289,17291,17294],{"class":2980,"line":3043},[2978,17284,3393],{"class":3002},[2978,17286,3396],{"class":2995},[2978,17288,3399],{"class":3002},[2978,17290,3006],{"class":2995},[2978,17292,17293],{"class":3024},"\"/api/users/5\"",[2978,17295,3407],{"class":2995},[2978,17297,17298,17300,17302,17304,17306,17308,17310,17312,17314,17316],{"class":2980,"line":3056},[2978,17299,3445],{"class":3002},[2978,17301,3396],{"class":2995},[2978,17303,3399],{"class":3002},[2978,17305,3006],{"class":2995},[2978,17307,17293],{"class":3024},[2978,17309,3456],{"class":2995},[2978,17311,3459],{"class":3002},[2978,17313,3006],{"class":2995},[2978,17315,3464],{"class":3024},[2978,17317,3492],{"class":2995},[2978,17319,17320],{"class":2980,"line":3067},[2978,17321,3498],{"class":2995},[2978,17323,17324],{"class":2980,"line":3442},[2978,17325,3070],{"class":2995},[17327,17328,17330],"collapsible",{"title":17329},"Показати відповіді",[3089,17331,17332,17337,17342],{},[3092,17333,17334,17336],{},[3074,17335,17199],{}," Level 0 (The Swamp of POX) — один endpoint, POST для всього",[3092,17338,17339,17341],{},[3074,17340,17218],{}," Level 2 (HTTP Verbs) — використовує GET/PUT/DELETE та ресурси",[3092,17343,17344,17346,17347],{},[3074,17345,17243],{}," Level 3 (Hypermedia Controls) — HATEOAS з ",[2975,17348,4383],{},[3329,17350,17352],{"id":17351},"завдання-12-hal-формат","Завдання 1.2: HAL формат",[2964,17354,17355],{},"Який з цих JSON є валідним HAL форматом?",[2964,17357,17358],{},[3074,17359,17360],{},"Варіант A:",[2968,17362,17364],{"className":2986,"code":17363,"language":2988,"meta":2973,"style":2973},"{\n  \"id\": 1,\n  \"links\": {\n    \"self\": \"/api/articles/1\"\n  }\n}\n",[2975,17365,17366,17370,17380,17387,17396,17400],{"__ignoreMap":2973},[2978,17367,17368],{"class":2980,"line":2981},[2978,17369,2996],{"class":2995},[2978,17371,17372,17374,17376,17378],{"class":2980,"line":2999},[2978,17373,3003],{"class":3002},[2978,17375,3006],{"class":2995},[2978,17377,3617],{"class":3009},[2978,17379,3013],{"class":2995},[2978,17381,17382,17385],{"class":2980,"line":3016},[2978,17383,17384],{"class":3002},"  \"links\"",[2978,17386,3388],{"class":2995},[2978,17388,17389,17391,17393],{"class":2980,"line":3030},[2978,17390,3393],{"class":3002},[2978,17392,3006],{"class":2995},[2978,17394,17395],{"class":3024},"\"/api/articles/1\"\n",[2978,17397,17398],{"class":2980,"line":3043},[2978,17399,3498],{"class":2995},[2978,17401,17402],{"class":2980,"line":3056},[2978,17403,3070],{"class":2995},[2964,17405,17406],{},[3074,17407,17408],{},"Варіант B:",[2968,17410,17412],{"className":2986,"code":17411,"language":2988,"meta":2973,"style":2973},"{\n  \"id\": 1,\n  \"_links\": {\n    \"self\": { \"href\": \"/api/articles/1\" }\n  }\n}\n",[2975,17413,17414,17418,17428,17434,17448,17452],{"__ignoreMap":2973},[2978,17415,17416],{"class":2980,"line":2981},[2978,17417,2996],{"class":2995},[2978,17419,17420,17422,17424,17426],{"class":2980,"line":2999},[2978,17421,3003],{"class":3002},[2978,17423,3006],{"class":2995},[2978,17425,3617],{"class":3009},[2978,17427,3013],{"class":2995},[2978,17429,17430,17432],{"class":2980,"line":3016},[2978,17431,3385],{"class":3002},[2978,17433,3388],{"class":2995},[2978,17435,17436,17438,17440,17442,17444,17446],{"class":2980,"line":3030},[2978,17437,3393],{"class":3002},[2978,17439,3396],{"class":2995},[2978,17441,3399],{"class":3002},[2978,17443,3006],{"class":2995},[2978,17445,16824],{"class":3024},[2978,17447,3492],{"class":2995},[2978,17449,17450],{"class":2980,"line":3043},[2978,17451,3498],{"class":2995},[2978,17453,17454],{"class":2980,"line":3056},[2978,17455,3070],{"class":2995},[17327,17457,17459,17464,17467],{"title":17458},"Показати відповідь",[2964,17460,17461],{},[3074,17462,17463],{},"Правильна відповідь: Варіант B",[2964,17465,17466],{},"HAL формат вимагає:",[3089,17468,17469,17474,17480],{},[3092,17470,17471,17473],{},[2975,17472,4383],{}," (з підкресленням)",[3092,17475,17476,17477,17479],{},"Кожен link має бути об'єктом з ",[2975,17478,4407],{}," властивістю",[3092,17481,17482,17484],{},[2975,17483,4399],{}," link є обов'язковим",[3882,17486],{},[3329,17488,17490],{"id":17489},"рівень-2-логіка-та-розширення","Рівень 2: Логіка та розширення",[4428,17492,17493,17497,17503,18473,18477,18480,19140,19144,19147],{},[3329,17494,17496],{"id":17495},"завдання-21-nested-resource-expansion","Завдання 2.1: Nested Resource Expansion",[2964,17498,17499,17500,3087],{},"Реалізуйте вкладений expansion: ",[2975,17501,17502],{},"?expand=author.articles",[17327,17504,17506,17511,17837,17842,18250,18255,18332,18337,18346],{"title":17505},"Показати рішення",[2964,17507,17508],{},[3074,17509,17510],{},"1. Розширений ExpansionOptions:",[2968,17512,17514],{"className":4505,"code":17513,"language":4507,"meta":2973,"style":2973},"public class ExpansionOptions\n{\n    public bool IncludeAuthor { get; set; }\n    public bool IncludeAuthorArticles { get; set; }\n    public bool IncludeCategory { get; set; }\n    public bool IncludeComments { get; set; }\n\n    public static ExpansionOptions Parse(string? expand)\n    {\n        if (string.IsNullOrWhiteSpace(expand))\n            return new ExpansionOptions();\n\n        var parts = expand.Split(',', StringSplitOptions.RemoveEmptyEntries)\n            .Select(p => p.Trim().ToLower())\n            .ToList();\n\n        return new ExpansionOptions\n        {\n            IncludeAuthor = parts.Any(p => p.StartsWith(\"author\")),\n            IncludeAuthorArticles = parts.Contains(\"author.articles\"),\n            IncludeCategory = parts.Contains(\"category\"),\n            IncludeComments = parts.Contains(\"comments\")\n        };\n    }\n}\n",[2975,17515,17516,17524,17528,17546,17565,17583,17601,17605,17625,17629,17647,17657,17661,17689,17713,17721,17725,17733,17737,17769,17789,17807,17825,17829,17833],{"__ignoreMap":2973},[2978,17517,17518,17520,17522],{"class":2980,"line":2981},[2978,17519,4535],{"class":3180},[2978,17521,4538],{"class":3180},[2978,17523,8148],{"class":4517},[2978,17525,17526],{"class":2980,"line":2999},[2978,17527,2996],{"class":2995},[2978,17529,17530,17532,17534,17536,17538,17540,17542,17544],{"class":2980,"line":3016},[2978,17531,4550],{"class":3180},[2978,17533,8159],{"class":3180},[2978,17535,8162],{"class":3213},[2978,17537,4559],{"class":2995},[2978,17539,4562],{"class":3180},[2978,17541,4565],{"class":2995},[2978,17543,4568],{"class":3180},[2978,17545,4571],{"class":2995},[2978,17547,17548,17550,17552,17555,17557,17559,17561,17563],{"class":2980,"line":3030},[2978,17549,4550],{"class":3180},[2978,17551,8159],{"class":3180},[2978,17553,17554],{"class":3213}," IncludeAuthorArticles",[2978,17556,4559],{"class":2995},[2978,17558,4562],{"class":3180},[2978,17560,4565],{"class":2995},[2978,17562,4568],{"class":3180},[2978,17564,4571],{"class":2995},[2978,17566,17567,17569,17571,17573,17575,17577,17579,17581],{"class":2980,"line":3043},[2978,17568,4550],{"class":3180},[2978,17570,8159],{"class":3180},[2978,17572,8181],{"class":3213},[2978,17574,4559],{"class":2995},[2978,17576,4562],{"class":3180},[2978,17578,4565],{"class":2995},[2978,17580,4568],{"class":3180},[2978,17582,4571],{"class":2995},[2978,17584,17585,17587,17589,17591,17593,17595,17597,17599],{"class":2980,"line":3056},[2978,17586,4550],{"class":3180},[2978,17588,8159],{"class":3180},[2978,17590,8200],{"class":3213},[2978,17592,4559],{"class":2995},[2978,17594,4562],{"class":3180},[2978,17596,4565],{"class":2995},[2978,17598,4568],{"class":3180},[2978,17600,4571],{"class":2995},[2978,17602,17603],{"class":2980,"line":3067},[2978,17604,3288],{"emptyLinePlaceholder":3287},[2978,17606,17607,17609,17611,17613,17615,17617,17619,17621,17623],{"class":2980,"line":3442},[2978,17608,4550],{"class":3180},[2978,17610,5625],{"class":3180},[2978,17612,8223],{"class":4517},[2978,17614,8226],{"class":3195},[2978,17616,3199],{"class":2995},[2978,17618,5489],{"class":3180},[2978,17620,3101],{"class":2995},[2978,17622,8235],{"class":3213},[2978,17624,5704],{"class":2995},[2978,17626,17627],{"class":2980,"line":3469},[2978,17628,5709],{"class":2995},[2978,17630,17631,17633,17635,17637,17639,17641,17643,17645],{"class":2980,"line":3495},[2978,17632,6113],{"class":3191},[2978,17634,6116],{"class":2995},[2978,17636,5489],{"class":3180},[2978,17638,3223],{"class":2995},[2978,17640,8254],{"class":3195},[2978,17642,3199],{"class":2995},[2978,17644,8235],{"class":3213},[2978,17646,8261],{"class":2995},[2978,17648,17649,17651,17653,17655],{"class":2980,"line":3501},[2978,17650,8266],{"class":3191},[2978,17652,8269],{"class":3180},[2978,17654,8223],{"class":4517},[2978,17656,4733],{"class":2995},[2978,17658,17659],{"class":2980,"line":3642},[2978,17660,3288],{"emptyLinePlaceholder":3287},[2978,17662,17663,17665,17667,17669,17671,17673,17675,17677,17679,17681,17683,17685,17687],{"class":2980,"line":3674},[2978,17664,5714],{"class":3180},[2978,17666,8284],{"class":3213},[2978,17668,3188],{"class":2995},[2978,17670,8235],{"class":3213},[2978,17672,3223],{"class":2995},[2978,17674,8293],{"class":3195},[2978,17676,3199],{"class":2995},[2978,17678,8298],{"class":3024},[2978,17680,3456],{"class":2995},[2978,17682,8303],{"class":3213},[2978,17684,3223],{"class":2995},[2978,17686,8308],{"class":3213},[2978,17688,5704],{"class":2995},[2978,17690,17691,17693,17695,17697,17699,17701,17703,17705,17707,17709,17711],{"class":2980,"line":3680},[2978,17692,8315],{"class":2995},[2978,17694,8318],{"class":3195},[2978,17696,3199],{"class":2995},[2978,17698,2964],{"class":3213},[2978,17700,8325],{"class":2995},[2978,17702,2964],{"class":3213},[2978,17704,3223],{"class":2995},[2978,17706,8332],{"class":3195},[2978,17708,8335],{"class":2995},[2978,17710,8338],{"class":3195},[2978,17712,8341],{"class":2995},[2978,17714,17715,17717,17719],{"class":2980,"line":3686},[2978,17716,8315],{"class":2995},[2978,17718,11016],{"class":3195},[2978,17720,4733],{"class":2995},[2978,17722,17723],{"class":2980,"line":3699},[2978,17724,3288],{"emptyLinePlaceholder":3287},[2978,17726,17727,17729,17731],{"class":2980,"line":4367},[2978,17728,6615],{"class":3191},[2978,17730,8269],{"class":3180},[2978,17732,8148],{"class":4517},[2978,17734,17735],{"class":2980,"line":4825},[2978,17736,5739],{"class":2995},[2978,17738,17739,17741,17743,17745,17747,17749,17751,17753,17755,17757,17759,17762,17764,17766],{"class":2980,"line":4836},[2978,17740,8371],{"class":3213},[2978,17742,3188],{"class":2995},[2978,17744,8376],{"class":3213},[2978,17746,3223],{"class":2995},[2978,17748,14261],{"class":3195},[2978,17750,3199],{"class":2995},[2978,17752,2964],{"class":3213},[2978,17754,8325],{"class":2995},[2978,17756,2964],{"class":3213},[2978,17758,3223],{"class":2995},[2978,17760,17761],{"class":3195},"StartsWith",[2978,17763,3199],{"class":2995},[2978,17765,3632],{"class":3024},[2978,17767,17768],{"class":2995},")),\n",[2978,17770,17771,17774,17776,17778,17780,17782,17784,17787],{"class":2980,"line":4841},[2978,17772,17773],{"class":3213},"            IncludeAuthorArticles",[2978,17775,3188],{"class":2995},[2978,17777,8376],{"class":3213},[2978,17779,3223],{"class":2995},[2978,17781,8381],{"class":3195},[2978,17783,3199],{"class":2995},[2978,17785,17786],{"class":3024},"\"author.articles\"",[2978,17788,8388],{"class":2995},[2978,17790,17791,17793,17795,17797,17799,17801,17803,17805],{"class":2980,"line":4849},[2978,17792,8393],{"class":3213},[2978,17794,3188],{"class":2995},[2978,17796,8376],{"class":3213},[2978,17798,3223],{"class":2995},[2978,17800,8381],{"class":3195},[2978,17802,3199],{"class":2995},[2978,17804,6014],{"class":3024},[2978,17806,8388],{"class":2995},[2978,17808,17809,17811,17813,17815,17817,17819,17821,17823],{"class":2980,"line":4857},[2978,17810,8412],{"class":3213},[2978,17812,3188],{"class":2995},[2978,17814,8376],{"class":3213},[2978,17816,3223],{"class":2995},[2978,17818,8381],{"class":3195},[2978,17820,3199],{"class":2995},[2978,17822,5929],{"class":3024},[2978,17824,5704],{"class":2995},[2978,17826,17827],{"class":2980,"line":4863},[2978,17828,6099],{"class":2995},[2978,17830,17831],{"class":2980,"line":4868},[2978,17832,6625],{"class":2995},[2978,17834,17835],{"class":2980,"line":4873},[2978,17836,3070],{"class":2995},[2964,17838,17839],{},[3074,17840,17841],{},"2. Оновлений MapToDto:",[2968,17843,17845],{"className":4505,"code":17844,"language":4507,"meta":2973,"style":2973},"private ArticleDto MapToDto(Article article, ExpansionOptions options)\n{\n    var dto = new ArticleDto { /* ... */ };\n\n    if (options.IncludeAuthor && article.Author != null)\n    {\n        dto.Embedded ??= new EmbeddedResources();\n        dto.Embedded.Author = new AuthorDto\n        {\n            Id = article.Author.Id,\n            Name = article.Author.Name,\n            Email = article.Author.Email,\n            Bio = article.Author.Bio\n        };\n\n        // Nested expansion\n        if (options.IncludeAuthorArticles)\n        {\n            dto.Embedded.Author.Articles = article.Author.Articles\n                .Where(a => a.Id != article.Id) // Виключаємо поточну статтю\n                .Take(5) // Обмежуємо кількість\n                .Select(a => new ArticleSummaryDto\n                {\n                    Id = a.Id,\n                    Title = a.Title,\n                    PublishedAt = a.PublishedAt\n                })\n                .ToList();\n        }\n    }\n\n    return dto;\n}\n",[2975,17846,17847,17870,17874,17894,17898,17924,17928,17945,17963,17967,17985,18004,18023,18041,18045,18049,18054,18069,18073,18101,18134,18149,18166,18170,18184,18199,18213,18218,18226,18230,18234,18238,18246],{"__ignoreMap":2973},[2978,17848,17849,17852,17854,17856,17858,17860,17862,17864,17866,17868],{"class":2980,"line":2981},[2978,17850,17851],{"class":3180},"private",[2978,17853,13490],{"class":4517},[2978,17855,13493],{"class":3195},[2978,17857,3199],{"class":2995},[2978,17859,4982],{"class":4517},[2978,17861,3185],{"class":3213},[2978,17863,3456],{"class":2995},[2978,17865,8461],{"class":4517},[2978,17867,8456],{"class":3213},[2978,17869,5704],{"class":2995},[2978,17871,17872],{"class":2980,"line":2999},[2978,17873,2996],{"class":2995},[2978,17875,17876,17878,17880,17882,17884,17886,17888,17891],{"class":2980,"line":3016},[2978,17877,14922],{"class":3180},[2978,17879,10369],{"class":3213},[2978,17881,3188],{"class":2995},[2978,17883,4730],{"class":3180},[2978,17885,13490],{"class":4517},[2978,17887,4559],{"class":2995},[2978,17889,17890],{"class":3174},"/* ... */",[2978,17892,17893],{"class":2995}," };\n",[2978,17895,17896],{"class":2980,"line":3030},[2978,17897,3288],{"emptyLinePlaceholder":3287},[2978,17899,17900,17902,17904,17906,17908,17910,17912,17914,17916,17918,17920,17922],{"class":2980,"line":3043},[2978,17901,16194],{"class":3191},[2978,17903,6116],{"class":2995},[2978,17905,8591],{"class":3213},[2978,17907,3223],{"class":2995},[2978,17909,10163],{"class":3213},[2978,17911,6131],{"class":2995},[2978,17913,3252],{"class":3213},[2978,17915,3223],{"class":2995},[2978,17917,4646],{"class":3213},[2978,17919,6259],{"class":2995},[2978,17921,10081],{"class":3180},[2978,17923,5704],{"class":2995},[2978,17925,17926],{"class":2980,"line":3056},[2978,17927,5709],{"class":2995},[2978,17929,17930,17932,17934,17936,17939,17941,17943],{"class":2980,"line":3067},[2978,17931,10398],{"class":3213},[2978,17933,3223],{"class":2995},[2978,17935,7557],{"class":3213},[2978,17937,17938],{"class":2995}," ??= ",[2978,17940,4730],{"class":3180},[2978,17942,7552],{"class":4517},[2978,17944,4733],{"class":2995},[2978,17946,17947,17949,17951,17953,17955,17957,17959,17961],{"class":2980,"line":3442},[2978,17948,10398],{"class":3213},[2978,17950,3223],{"class":2995},[2978,17952,7557],{"class":3213},[2978,17954,3223],{"class":2995},[2978,17956,4646],{"class":3213},[2978,17958,3188],{"class":2995},[2978,17960,4730],{"class":3180},[2978,17962,7672],{"class":4517},[2978,17964,17965],{"class":2980,"line":3469},[2978,17966,5739],{"class":2995},[2978,17968,17969,17971,17973,17975,17977,17979,17981,17983],{"class":2980,"line":3495},[2978,17970,11426],{"class":3213},[2978,17972,3188],{"class":2995},[2978,17974,3252],{"class":3213},[2978,17976,3223],{"class":2995},[2978,17978,4646],{"class":3213},[2978,17980,3223],{"class":2995},[2978,17982,8780],{"class":3213},[2978,17984,3013],{"class":2995},[2978,17986,17987,17990,17992,17994,17996,17998,18000,18002],{"class":2980,"line":3501},[2978,17988,17989],{"class":3213},"            Name",[2978,17991,3188],{"class":2995},[2978,17993,3252],{"class":3213},[2978,17995,3223],{"class":2995},[2978,17997,4646],{"class":3213},[2978,17999,3223],{"class":2995},[2978,18001,8789],{"class":3213},[2978,18003,3013],{"class":2995},[2978,18005,18006,18009,18011,18013,18015,18017,18019,18021],{"class":2980,"line":3642},[2978,18007,18008],{"class":3213},"            Email",[2978,18010,3188],{"class":2995},[2978,18012,3252],{"class":3213},[2978,18014,3223],{"class":2995},[2978,18016,4646],{"class":3213},[2978,18018,3223],{"class":2995},[2978,18020,8798],{"class":3213},[2978,18022,3013],{"class":2995},[2978,18024,18025,18028,18030,18032,18034,18036,18038],{"class":2980,"line":3674},[2978,18026,18027],{"class":3213},"            Bio",[2978,18029,3188],{"class":2995},[2978,18031,3252],{"class":3213},[2978,18033,3223],{"class":2995},[2978,18035,4646],{"class":3213},[2978,18037,3223],{"class":2995},[2978,18039,18040],{"class":3213},"Bio\n",[2978,18042,18043],{"class":2980,"line":3680},[2978,18044,6099],{"class":2995},[2978,18046,18047],{"class":2980,"line":3686},[2978,18048,3288],{"emptyLinePlaceholder":3287},[2978,18050,18051],{"class":2980,"line":3699},[2978,18052,18053],{"class":3174},"        // Nested expansion\n",[2978,18055,18056,18058,18060,18062,18064,18067],{"class":2980,"line":4367},[2978,18057,6113],{"class":3191},[2978,18059,6116],{"class":2995},[2978,18061,8591],{"class":3213},[2978,18063,3223],{"class":2995},[2978,18065,18066],{"class":3213},"IncludeAuthorArticles",[2978,18068,5704],{"class":2995},[2978,18070,18071],{"class":2980,"line":4825},[2978,18072,5739],{"class":2995},[2978,18074,18075,18077,18079,18081,18083,18085,18087,18089,18091,18093,18095,18097,18099],{"class":2980,"line":4836},[2978,18076,10947],{"class":3213},[2978,18078,3223],{"class":2995},[2978,18080,7557],{"class":3213},[2978,18082,3223],{"class":2995},[2978,18084,4646],{"class":3213},[2978,18086,3223],{"class":2995},[2978,18088,4987],{"class":3213},[2978,18090,3188],{"class":2995},[2978,18092,3252],{"class":3213},[2978,18094,3223],{"class":2995},[2978,18096,4646],{"class":3213},[2978,18098,3223],{"class":2995},[2978,18100,10821],{"class":3213},[2978,18102,18103,18106,18109,18111,18113,18115,18117,18119,18121,18123,18125,18127,18129,18131],{"class":2980,"line":4841},[2978,18104,18105],{"class":2995},"                .",[2978,18107,18108],{"class":3195},"Where",[2978,18110,3199],{"class":2995},[2978,18112,10185],{"class":3213},[2978,18114,8325],{"class":2995},[2978,18116,10185],{"class":3213},[2978,18118,3223],{"class":2995},[2978,18120,8780],{"class":3213},[2978,18122,6259],{"class":2995},[2978,18124,3252],{"class":3213},[2978,18126,3223],{"class":2995},[2978,18128,8780],{"class":3213},[2978,18130,16205],{"class":2995},[2978,18132,18133],{"class":3174},"// Виключаємо поточну статтю\n",[2978,18135,18136,18138,18140,18142,18144,18146],{"class":2980,"line":4849},[2978,18137,18105],{"class":2995},[2978,18139,10873],{"class":3195},[2978,18141,3199],{"class":2995},[2978,18143,3010],{"class":3009},[2978,18145,16205],{"class":2995},[2978,18147,18148],{"class":3174},"// Обмежуємо кількість\n",[2978,18150,18151,18153,18155,18157,18159,18161,18163],{"class":2980,"line":4857},[2978,18152,18105],{"class":2995},[2978,18154,8318],{"class":3195},[2978,18156,3199],{"class":2995},[2978,18158,10185],{"class":3213},[2978,18160,8325],{"class":2995},[2978,18162,4730],{"class":3180},[2978,18164,18165],{"class":4517}," ArticleSummaryDto\n",[2978,18167,18168],{"class":2980,"line":4863},[2978,18169,11531],{"class":2995},[2978,18171,18172,18174,18176,18178,18180,18182],{"class":2980,"line":4868},[2978,18173,13796],{"class":3213},[2978,18175,3188],{"class":2995},[2978,18177,10185],{"class":3213},[2978,18179,3223],{"class":2995},[2978,18181,8780],{"class":3213},[2978,18183,3013],{"class":2995},[2978,18185,18186,18189,18191,18193,18195,18197],{"class":2980,"line":4873},[2978,18187,18188],{"class":3213},"                    Title",[2978,18190,3188],{"class":2995},[2978,18192,10185],{"class":3213},[2978,18194,3223],{"class":2995},[2978,18196,5446],{"class":3213},[2978,18198,3013],{"class":2995},[2978,18200,18201,18204,18206,18208,18210],{"class":2980,"line":4883},[2978,18202,18203],{"class":3213},"                    PublishedAt",[2978,18205,3188],{"class":2995},[2978,18207,10185],{"class":3213},[2978,18209,3223],{"class":2995},[2978,18211,18212],{"class":3213},"PublishedAt\n",[2978,18214,18215],{"class":2980,"line":4888},[2978,18216,18217],{"class":2995},"                })\n",[2978,18219,18220,18222,18224],{"class":2980,"line":4907},[2978,18221,18105],{"class":2995},[2978,18223,11016],{"class":3195},[2978,18225,4733],{"class":2995},[2978,18227,18228],{"class":2980,"line":4929},[2978,18229,6242],{"class":2995},[2978,18231,18232],{"class":2980,"line":4951},[2978,18233,6625],{"class":2995},[2978,18235,18236],{"class":2980,"line":4973},[2978,18237,3288],{"emptyLinePlaceholder":3287},[2978,18239,18240,18242,18244],{"class":2980,"line":5004},[2978,18241,16331],{"class":3191},[2978,18243,10369],{"class":3213},[2978,18245,4526],{"class":2995},[2978,18247,18248],{"class":2980,"line":5009},[2978,18249,3070],{"class":2995},[2964,18251,18252],{},[3074,18253,18254],{},"3. Eager loading у контролері:",[2968,18256,18258],{"className":4505,"code":18257,"language":4507,"meta":2973,"style":2973},"if (expansionOptions.IncludeAuthorArticles)\n{\n    query = query.Include(a => a.Author)\n                 .ThenInclude(author => author.Articles);\n}\n",[2975,18259,18260,18274,18278,18305,18328],{"__ignoreMap":2973},[2978,18261,18262,18264,18266,18268,18270,18272],{"class":2980,"line":2981},[2978,18263,14975],{"class":3191},[2978,18265,6116],{"class":2995},[2978,18267,10158],{"class":3213},[2978,18269,3223],{"class":2995},[2978,18271,18066],{"class":3213},[2978,18273,5704],{"class":2995},[2978,18275,18276],{"class":2980,"line":2999},[2978,18277,2996],{"class":2995},[2978,18279,18280,18283,18285,18287,18289,18291,18293,18295,18297,18299,18301,18303],{"class":2980,"line":3016},[2978,18281,18282],{"class":3213},"    query",[2978,18284,3188],{"class":2995},[2978,18286,10175],{"class":3213},[2978,18288,3223],{"class":2995},[2978,18290,10180],{"class":3195},[2978,18292,3199],{"class":2995},[2978,18294,10185],{"class":3213},[2978,18296,8325],{"class":2995},[2978,18298,10185],{"class":3213},[2978,18300,3223],{"class":2995},[2978,18302,4646],{"class":3213},[2978,18304,5704],{"class":2995},[2978,18306,18307,18310,18313,18315,18318,18320,18322,18324,18326],{"class":2980,"line":3030},[2978,18308,18309],{"class":2995},"                 .",[2978,18311,18312],{"class":3195},"ThenInclude",[2978,18314,3199],{"class":2995},[2978,18316,18317],{"class":3213},"author",[2978,18319,8325],{"class":2995},[2978,18321,18317],{"class":3213},[2978,18323,3223],{"class":2995},[2978,18325,4987],{"class":3213},[2978,18327,8474],{"class":2995},[2978,18329,18330],{"class":2980,"line":3043},[2978,18331,3070],{"class":2995},[2964,18333,18334],{},[3074,18335,18336],{},"Результат:",[2968,18338,18340],{"className":2970,"code":18339,"language":2972,"meta":2973,"style":2973},"GET /api/articles/1?expand=author.articles\n",[2975,18341,18342],{"__ignoreMap":2973},[2978,18343,18344],{"class":2980,"line":2981},[2978,18345,18339],{},[2968,18347,18349],{"className":2986,"code":18348,"language":2988,"meta":2973,"style":2973},"{\n  \"id\": 1,\n  \"title\": \"Introduction to ASP.NET Core\",\n  \"_embedded\": {\n    \"author\": {\n      \"id\": 1,\n      \"name\": \"John Doe\",\n      \"articles\": [\n        { \"id\": 3, \"title\": \"REST API Best Practices\" },\n        { \"id\": 5, \"title\": \"Microservices Architecture\" }\n      ]\n    }\n  }\n}\n",[2975,18350,18351,18355,18365,18375,18381,18387,18397,18407,18414,18435,18456,18461,18465,18469],{"__ignoreMap":2973},[2978,18352,18353],{"class":2980,"line":2981},[2978,18354,2996],{"class":2995},[2978,18356,18357,18359,18361,18363],{"class":2980,"line":2999},[2978,18358,3003],{"class":3002},[2978,18360,3006],{"class":2995},[2978,18362,3617],{"class":3009},[2978,18364,3013],{"class":2995},[2978,18366,18367,18369,18371,18373],{"class":2980,"line":3016},[2978,18368,3019],{"class":3002},[2978,18370,3006],{"class":2995},[2978,18372,3025],{"class":3024},[2978,18374,3013],{"class":2995},[2978,18376,18377,18379],{"class":2980,"line":3030},[2978,18378,3551],{"class":3002},[2978,18380,3388],{"class":2995},[2978,18382,18383,18385],{"class":2980,"line":3043},[2978,18384,3412],{"class":3002},[2978,18386,3388],{"class":2995},[2978,18388,18389,18391,18393,18395],{"class":2980,"line":3056},[2978,18390,3564],{"class":3002},[2978,18392,3006],{"class":2995},[2978,18394,3617],{"class":3009},[2978,18396,3013],{"class":2995},[2978,18398,18399,18401,18403,18405],{"class":2980,"line":3067},[2978,18400,3575],{"class":3002},[2978,18402,3006],{"class":2995},[2978,18404,3580],{"class":3024},[2978,18406,3013],{"class":2995},[2978,18408,18409,18412],{"class":2980,"line":3442},[2978,18410,18411],{"class":3002},"      \"articles\"",[2978,18413,3604],{"class":2995},[2978,18415,18416,18419,18421,18423,18425,18427,18429,18431,18433],{"class":2980,"line":3469},[2978,18417,18418],{"class":2995},"        { ",[2978,18420,3612],{"class":3002},[2978,18422,3006],{"class":2995},[2978,18424,3051],{"class":3009},[2978,18426,3456],{"class":2995},[2978,18428,3778],{"class":3002},[2978,18430,3006],{"class":2995},[2978,18432,9229],{"class":3024},[2978,18434,3407],{"class":2995},[2978,18436,18437,18439,18441,18443,18445,18447,18449,18451,18454],{"class":2980,"line":3495},[2978,18438,18418],{"class":2995},[2978,18440,3612],{"class":3002},[2978,18442,3006],{"class":2995},[2978,18444,3010],{"class":3009},[2978,18446,3456],{"class":2995},[2978,18448,3778],{"class":3002},[2978,18450,3006],{"class":2995},[2978,18452,18453],{"class":3024},"\"Microservices Architecture\"",[2978,18455,3492],{"class":2995},[2978,18457,18458],{"class":2980,"line":3501},[2978,18459,18460],{"class":2995},"      ]\n",[2978,18462,18463],{"class":2980,"line":3642},[2978,18464,6625],{"class":2995},[2978,18466,18467],{"class":2980,"line":3674},[2978,18468,3498],{"class":2995},[2978,18470,18471],{"class":2980,"line":3680},[2978,18472,3070],{"class":2995},[3329,18474,18476],{"id":18475},"завдання-22-expansion-depth-limit","Завдання 2.2: Expansion Depth Limit",[2964,18478,18479],{},"Додайте обмеження глибини expansion для захисту від зловживань:",[17327,18481,18482,19001,19006,19120,19125],{"title":17505},[2968,18483,18485],{"className":4505,"code":18484,"language":4507,"meta":2973,"style":2973},"public class ExpansionOptions\n{\n    private const int MaxDepth = 2;\n    public int CurrentDepth { get; private set; }\n\n    public bool IncludeAuthor { get; set; }\n    public bool IncludeAuthorArticles { get; set; }\n\n    public static ExpansionOptions Parse(string? expand, int depth = 0)\n    {\n        if (depth > MaxDepth)\n        {\n            throw new ArgumentException($\"Expansion depth cannot exceed {MaxDepth}\");\n        }\n\n        if (string.IsNullOrWhiteSpace(expand))\n            return new ExpansionOptions { CurrentDepth = depth };\n\n        var parts = expand.Split(',', StringSplitOptions.RemoveEmptyEntries)\n            .Select(p => p.Trim().ToLower())\n            .ToList();\n\n        // Підраховуємо максимальну глибину\n        var maxRequestedDepth = parts\n            .Select(p => p.Count(c => c == '.') + 1)\n            .DefaultIfEmpty(0)\n            .Max();\n\n        if (maxRequestedDepth > MaxDepth)\n        {\n            throw new ArgumentException($\"Expansion depth {maxRequestedDepth} exceeds maximum {MaxDepth}\");\n        }\n\n        return new ExpansionOptions\n        {\n            CurrentDepth = depth,\n            IncludeAuthor = parts.Any(p => p.StartsWith(\"author\")),\n            IncludeAuthorArticles = parts.Contains(\"author.articles\")\n        };\n    }\n}\n",[2975,18486,18487,18495,18499,18517,18539,18543,18561,18579,18583,18614,18618,18634,18638,18664,18668,18672,18690,18709,18713,18741,18765,18773,18777,18782,18794,18833,18846,18855,18859,18874,18878,18910,18914,18918,18926,18930,18941,18971,18989,18993,18997],{"__ignoreMap":2973},[2978,18488,18489,18491,18493],{"class":2980,"line":2981},[2978,18490,4535],{"class":3180},[2978,18492,4538],{"class":3180},[2978,18494,8148],{"class":4517},[2978,18496,18497],{"class":2980,"line":2999},[2978,18498,2996],{"class":2995},[2978,18500,18501,18503,18506,18508,18511,18513,18515],{"class":2980,"line":3016},[2978,18502,9701],{"class":3180},[2978,18504,18505],{"class":3180}," const",[2978,18507,4553],{"class":3180},[2978,18509,18510],{"class":3213}," MaxDepth",[2978,18512,3188],{"class":2995},[2978,18514,3651],{"class":3009},[2978,18516,4526],{"class":2995},[2978,18518,18519,18521,18523,18526,18528,18530,18532,18534,18537],{"class":2980,"line":3030},[2978,18520,4550],{"class":3180},[2978,18522,4553],{"class":3180},[2978,18524,18525],{"class":3213}," CurrentDepth",[2978,18527,4559],{"class":2995},[2978,18529,4562],{"class":3180},[2978,18531,4565],{"class":2995},[2978,18533,17851],{"class":3180},[2978,18535,18536],{"class":3180}," set",[2978,18538,4571],{"class":2995},[2978,18540,18541],{"class":2980,"line":3043},[2978,18542,3288],{"emptyLinePlaceholder":3287},[2978,18544,18545,18547,18549,18551,18553,18555,18557,18559],{"class":2980,"line":3056},[2978,18546,4550],{"class":3180},[2978,18548,8159],{"class":3180},[2978,18550,8162],{"class":3213},[2978,18552,4559],{"class":2995},[2978,18554,4562],{"class":3180},[2978,18556,4565],{"class":2995},[2978,18558,4568],{"class":3180},[2978,18560,4571],{"class":2995},[2978,18562,18563,18565,18567,18569,18571,18573,18575,18577],{"class":2980,"line":3067},[2978,18564,4550],{"class":3180},[2978,18566,8159],{"class":3180},[2978,18568,17554],{"class":3213},[2978,18570,4559],{"class":2995},[2978,18572,4562],{"class":3180},[2978,18574,4565],{"class":2995},[2978,18576,4568],{"class":3180},[2978,18578,4571],{"class":2995},[2978,18580,18581],{"class":2980,"line":3442},[2978,18582,3288],{"emptyLinePlaceholder":3287},[2978,18584,18585,18587,18589,18591,18593,18595,18597,18599,18601,18603,18605,18608,18610,18612],{"class":2980,"line":3469},[2978,18586,4550],{"class":3180},[2978,18588,5625],{"class":3180},[2978,18590,8223],{"class":4517},[2978,18592,8226],{"class":3195},[2978,18594,3199],{"class":2995},[2978,18596,5489],{"class":3180},[2978,18598,3101],{"class":2995},[2978,18600,8235],{"class":3213},[2978,18602,3456],{"class":2995},[2978,18604,10704],{"class":3180},[2978,18606,18607],{"class":3213}," depth",[2978,18609,3188],{"class":2995},[2978,18611,16013],{"class":3009},[2978,18613,5704],{"class":2995},[2978,18615,18616],{"class":2980,"line":3495},[2978,18617,5709],{"class":2995},[2978,18619,18620,18622,18624,18627,18629,18632],{"class":2980,"line":3501},[2978,18621,6113],{"class":3191},[2978,18623,6116],{"class":2995},[2978,18625,18626],{"class":3213},"depth",[2978,18628,6826],{"class":2995},[2978,18630,18631],{"class":3213},"MaxDepth",[2978,18633,5704],{"class":2995},[2978,18635,18636],{"class":2980,"line":3642},[2978,18637,5739],{"class":2995},[2978,18639,18640,18643,18645,18648,18650,18653,18655,18657,18659,18662],{"class":2980,"line":3674},[2978,18641,18642],{"class":3191},"            throw",[2978,18644,8269],{"class":3180},[2978,18646,18647],{"class":4517}," ArgumentException",[2978,18649,3199],{"class":2995},[2978,18651,18652],{"class":3024},"$\"Expansion depth cannot exceed ",[2978,18654,15144],{"class":3255},[2978,18656,18631],{"class":3213},[2978,18658,3261],{"class":3255},[2978,18660,18661],{"class":3024},"\"",[2978,18663,8474],{"class":2995},[2978,18665,18666],{"class":2980,"line":3680},[2978,18667,6242],{"class":2995},[2978,18669,18670],{"class":2980,"line":3686},[2978,18671,3288],{"emptyLinePlaceholder":3287},[2978,18673,18674,18676,18678,18680,18682,18684,18686,18688],{"class":2980,"line":3699},[2978,18675,6113],{"class":3191},[2978,18677,6116],{"class":2995},[2978,18679,5489],{"class":3180},[2978,18681,3223],{"class":2995},[2978,18683,8254],{"class":3195},[2978,18685,3199],{"class":2995},[2978,18687,8235],{"class":3213},[2978,18689,8261],{"class":2995},[2978,18691,18692,18694,18696,18698,18700,18703,18705,18707],{"class":2980,"line":4367},[2978,18693,8266],{"class":3191},[2978,18695,8269],{"class":3180},[2978,18697,8223],{"class":4517},[2978,18699,4559],{"class":2995},[2978,18701,18702],{"class":3213},"CurrentDepth",[2978,18704,3188],{"class":2995},[2978,18706,18626],{"class":3213},[2978,18708,17893],{"class":2995},[2978,18710,18711],{"class":2980,"line":4825},[2978,18712,3288],{"emptyLinePlaceholder":3287},[2978,18714,18715,18717,18719,18721,18723,18725,18727,18729,18731,18733,18735,18737,18739],{"class":2980,"line":4836},[2978,18716,5714],{"class":3180},[2978,18718,8284],{"class":3213},[2978,18720,3188],{"class":2995},[2978,18722,8235],{"class":3213},[2978,18724,3223],{"class":2995},[2978,18726,8293],{"class":3195},[2978,18728,3199],{"class":2995},[2978,18730,8298],{"class":3024},[2978,18732,3456],{"class":2995},[2978,18734,8303],{"class":3213},[2978,18736,3223],{"class":2995},[2978,18738,8308],{"class":3213},[2978,18740,5704],{"class":2995},[2978,18742,18743,18745,18747,18749,18751,18753,18755,18757,18759,18761,18763],{"class":2980,"line":4841},[2978,18744,8315],{"class":2995},[2978,18746,8318],{"class":3195},[2978,18748,3199],{"class":2995},[2978,18750,2964],{"class":3213},[2978,18752,8325],{"class":2995},[2978,18754,2964],{"class":3213},[2978,18756,3223],{"class":2995},[2978,18758,8332],{"class":3195},[2978,18760,8335],{"class":2995},[2978,18762,8338],{"class":3195},[2978,18764,8341],{"class":2995},[2978,18766,18767,18769,18771],{"class":2980,"line":4849},[2978,18768,8315],{"class":2995},[2978,18770,11016],{"class":3195},[2978,18772,4733],{"class":2995},[2978,18774,18775],{"class":2980,"line":4857},[2978,18776,3288],{"emptyLinePlaceholder":3287},[2978,18778,18779],{"class":2980,"line":4863},[2978,18780,18781],{"class":3174},"        // Підраховуємо максимальну глибину\n",[2978,18783,18784,18786,18789,18791],{"class":2980,"line":4868},[2978,18785,5714],{"class":3180},[2978,18787,18788],{"class":3213}," maxRequestedDepth",[2978,18790,3188],{"class":2995},[2978,18792,18793],{"class":3213},"parts\n",[2978,18795,18796,18798,18800,18802,18804,18806,18808,18810,18813,18815,18817,18819,18821,18823,18826,18829,18831],{"class":2980,"line":4873},[2978,18797,8315],{"class":2995},[2978,18799,8318],{"class":3195},[2978,18801,3199],{"class":2995},[2978,18803,2964],{"class":3213},[2978,18805,8325],{"class":2995},[2978,18807,2964],{"class":3213},[2978,18809,3223],{"class":2995},[2978,18811,18812],{"class":3195},"Count",[2978,18814,3199],{"class":2995},[2978,18816,11409],{"class":3213},[2978,18818,8325],{"class":2995},[2978,18820,11409],{"class":3213},[2978,18822,6122],{"class":2995},[2978,18824,18825],{"class":3024},"'.'",[2978,18827,18828],{"class":2995},") + ",[2978,18830,3617],{"class":3009},[2978,18832,5704],{"class":2995},[2978,18834,18835,18837,18840,18842,18844],{"class":2980,"line":4883},[2978,18836,8315],{"class":2995},[2978,18838,18839],{"class":3195},"DefaultIfEmpty",[2978,18841,3199],{"class":2995},[2978,18843,16013],{"class":3009},[2978,18845,5704],{"class":2995},[2978,18847,18848,18850,18853],{"class":2980,"line":4888},[2978,18849,8315],{"class":2995},[2978,18851,18852],{"class":3195},"Max",[2978,18854,4733],{"class":2995},[2978,18856,18857],{"class":2980,"line":4907},[2978,18858,3288],{"emptyLinePlaceholder":3287},[2978,18860,18861,18863,18865,18868,18870,18872],{"class":2980,"line":4929},[2978,18862,6113],{"class":3191},[2978,18864,6116],{"class":2995},[2978,18866,18867],{"class":3213},"maxRequestedDepth",[2978,18869,6826],{"class":2995},[2978,18871,18631],{"class":3213},[2978,18873,5704],{"class":2995},[2978,18875,18876],{"class":2980,"line":4951},[2978,18877,5739],{"class":2995},[2978,18879,18880,18882,18884,18886,18888,18891,18893,18895,18897,18900,18902,18904,18906,18908],{"class":2980,"line":4973},[2978,18881,18642],{"class":3191},[2978,18883,8269],{"class":3180},[2978,18885,18647],{"class":4517},[2978,18887,3199],{"class":2995},[2978,18889,18890],{"class":3024},"$\"Expansion depth ",[2978,18892,15144],{"class":3255},[2978,18894,18867],{"class":3213},[2978,18896,3261],{"class":3255},[2978,18898,18899],{"class":3024}," exceeds maximum ",[2978,18901,15144],{"class":3255},[2978,18903,18631],{"class":3213},[2978,18905,3261],{"class":3255},[2978,18907,18661],{"class":3024},[2978,18909,8474],{"class":2995},[2978,18911,18912],{"class":2980,"line":5004},[2978,18913,6242],{"class":2995},[2978,18915,18916],{"class":2980,"line":5009},[2978,18917,3288],{"emptyLinePlaceholder":3287},[2978,18919,18920,18922,18924],{"class":2980,"line":5014},[2978,18921,6615],{"class":3191},[2978,18923,8269],{"class":3180},[2978,18925,8148],{"class":4517},[2978,18927,18928],{"class":2980,"line":5024},[2978,18929,5739],{"class":2995},[2978,18931,18932,18935,18937,18939],{"class":2980,"line":5029},[2978,18933,18934],{"class":3213},"            CurrentDepth",[2978,18936,3188],{"class":2995},[2978,18938,18626],{"class":3213},[2978,18940,3013],{"class":2995},[2978,18942,18943,18945,18947,18949,18951,18953,18955,18957,18959,18961,18963,18965,18967,18969],{"class":2980,"line":5048},[2978,18944,8371],{"class":3213},[2978,18946,3188],{"class":2995},[2978,18948,8376],{"class":3213},[2978,18950,3223],{"class":2995},[2978,18952,14261],{"class":3195},[2978,18954,3199],{"class":2995},[2978,18956,2964],{"class":3213},[2978,18958,8325],{"class":2995},[2978,18960,2964],{"class":3213},[2978,18962,3223],{"class":2995},[2978,18964,17761],{"class":3195},[2978,18966,3199],{"class":2995},[2978,18968,3632],{"class":3024},[2978,18970,17768],{"class":2995},[2978,18972,18973,18975,18977,18979,18981,18983,18985,18987],{"class":2980,"line":5069},[2978,18974,17773],{"class":3213},[2978,18976,3188],{"class":2995},[2978,18978,8376],{"class":3213},[2978,18980,3223],{"class":2995},[2978,18982,8381],{"class":3195},[2978,18984,3199],{"class":2995},[2978,18986,17786],{"class":3024},[2978,18988,5704],{"class":2995},[2978,18990,18991],{"class":2980,"line":5091},[2978,18992,6099],{"class":2995},[2978,18994,18995],{"class":2980,"line":5120},[2978,18996,6625],{"class":2995},[2978,18998,18999],{"class":2980,"line":5125},[2978,19000,3070],{"class":2995},[2964,19002,19003],{},[3074,19004,19005],{},"Обробка помилки у контролері:",[2968,19007,19009],{"className":4505,"code":19008,"language":4507,"meta":2973,"style":2973},"try\n{\n    var expansionOptions = ExpansionOptions.Parse(expand);\n    // ...\n}\ncatch (ArgumentException ex)\n{\n    return BadRequest(new ProblemDetails\n    {\n        Title = \"Invalid Expansion\",\n        Detail = ex.Message\n    });\n}\n",[2975,19010,19011,19016,19020,19040,19045,19049,19064,19068,19080,19084,19096,19111,19116],{"__ignoreMap":2973},[2978,19012,19013],{"class":2980,"line":2981},[2978,19014,19015],{"class":3191},"try\n",[2978,19017,19018],{"class":2980,"line":2999},[2978,19019,2996],{"class":2995},[2978,19021,19022,19024,19026,19028,19030,19032,19034,19036,19038],{"class":2980,"line":3016},[2978,19023,14922],{"class":3180},[2978,19025,10094],{"class":3213},[2978,19027,3188],{"class":2995},[2978,19029,8461],{"class":3213},[2978,19031,3223],{"class":2995},[2978,19033,8466],{"class":3195},[2978,19035,3199],{"class":2995},[2978,19037,8235],{"class":3213},[2978,19039,8474],{"class":2995},[2978,19041,19042],{"class":2980,"line":3030},[2978,19043,19044],{"class":3174},"    // ...\n",[2978,19046,19047],{"class":2980,"line":3043},[2978,19048,3070],{"class":2995},[2978,19050,19051,19054,19056,19059,19062],{"class":2980,"line":3056},[2978,19052,19053],{"class":3191},"catch",[2978,19055,6116],{"class":2995},[2978,19057,19058],{"class":4517},"ArgumentException",[2978,19060,19061],{"class":3213}," ex",[2978,19063,5704],{"class":2995},[2978,19065,19066],{"class":2980,"line":3067},[2978,19067,2996],{"class":2995},[2978,19069,19070,19072,19074,19076,19078],{"class":2980,"line":3442},[2978,19071,16331],{"class":3191},[2978,19073,12356],{"class":3195},[2978,19075,3199],{"class":2995},[2978,19077,4730],{"class":3180},[2978,19079,12363],{"class":4517},[2978,19081,19082],{"class":2980,"line":3469},[2978,19083,5709],{"class":2995},[2978,19085,19086,19089,19091,19094],{"class":2980,"line":3495},[2978,19087,19088],{"class":3213},"        Title",[2978,19090,3188],{"class":2995},[2978,19092,19093],{"class":3024},"\"Invalid Expansion\"",[2978,19095,3013],{"class":2995},[2978,19097,19098,19101,19103,19106,19108],{"class":2980,"line":3501},[2978,19099,19100],{"class":3213},"        Detail",[2978,19102,3188],{"class":2995},[2978,19104,19105],{"class":3213},"ex",[2978,19107,3223],{"class":2995},[2978,19109,19110],{"class":3213},"Message\n",[2978,19112,19113],{"class":2980,"line":3642},[2978,19114,19115],{"class":2995},"    });\n",[2978,19117,19118],{"class":2980,"line":3674},[2978,19119,3070],{"class":2995},[2964,19121,19122],{},[3074,19123,19124],{},"Тестування:",[2968,19126,19128],{"className":2970,"code":19127,"language":2972,"meta":2973,"style":2973},"GET /api/articles/1?expand=author.articles.author.articles\n→ 400 Bad Request: \"Expansion depth 3 exceeds maximum 2\"\n",[2975,19129,19130,19135],{"__ignoreMap":2973},[2978,19131,19132],{"class":2980,"line":2981},[2978,19133,19134],{},"GET /api/articles/1?expand=author.articles.author.articles\n",[2978,19136,19137],{"class":2980,"line":2999},[2978,19138,19139],{},"→ 400 Bad Request: \"Expansion depth 3 exceeds maximum 2\"\n",[3329,19141,19143],{"id":19142},"завдання-23-conditional-expansion","Завдання 2.3: Conditional Expansion",[2964,19145,19146],{},"Дозволяйте expansion тільки для певних ролей:",[17327,19148,19149,19617,19622],{"title":17505},[2968,19150,19152],{"className":4505,"code":19151,"language":4507,"meta":2973,"style":2973},"public class ExpansionValidator\n{\n    private static readonly Dictionary\u003Cstring, string[]> ExpansionPermissions = new()\n    {\n        [\"author\"] = new[] { \"User\", \"Admin\" },\n        [\"author.articles\"] = new[] { \"Admin\" },\n        [\"comments\"] = new[] { \"User\", \"Admin\" },\n        [\"category\"] = new[] { \"User\", \"Admin\" }\n    };\n\n    public static (bool IsValid, string? Error) Validate(\n        string? expand,\n        ClaimsPrincipal user)\n    {\n        if (string.IsNullOrWhiteSpace(expand))\n            return (true, null);\n\n        var parts = expand.Split(',', StringSplitOptions.RemoveEmptyEntries)\n            .Select(p => p.Trim().ToLower());\n\n        foreach (var part in parts)\n        {\n            if (!ExpansionPermissions.TryGetValue(part, out var allowedRoles))\n            {\n                return (false, $\"Expansion '{part}' is not supported\");\n            }\n\n            if (!allowedRoles.Any(role => user.IsInRole(role)))\n            {\n                return (false, $\"Insufficient permissions for expansion '{part}'\");\n            }\n        }\n\n        return (true, null);\n    }\n}\n",[2975,19153,19154,19163,19167,19197,19201,19223,19239,19259,19279,19283,19287,19317,19327,19336,19340,19358,19372,19376,19404,19428,19432,19449,19453,19485,19489,19514,19518,19522,19555,19559,19583,19587,19591,19595,19609,19613],{"__ignoreMap":2973},[2978,19155,19156,19158,19160],{"class":2980,"line":2981},[2978,19157,4535],{"class":3180},[2978,19159,4538],{"class":3180},[2978,19161,19162],{"class":4517}," ExpansionValidator\n",[2978,19164,19165],{"class":2980,"line":2999},[2978,19166,2996],{"class":2995},[2978,19168,19169,19171,19173,19175,19177,19179,19181,19183,19185,19188,19191,19193,19195],{"class":2980,"line":3016},[2978,19170,9701],{"class":3180},[2978,19172,5625],{"class":3180},[2978,19174,9704],{"class":3180},[2978,19176,5484],{"class":4517},[2978,19178,4707],{"class":2995},[2978,19180,5489],{"class":3180},[2978,19182,3456],{"class":2995},[2978,19184,5489],{"class":3180},[2978,19186,19187],{"class":2995},"[]> ",[2978,19189,19190],{"class":3213},"ExpansionPermissions",[2978,19192,3188],{"class":2995},[2978,19194,4730],{"class":3180},[2978,19196,13657],{"class":2995},[2978,19198,19199],{"class":2980,"line":3030},[2978,19200,5709],{"class":2995},[2978,19202,19203,19205,19207,19209,19211,19214,19217,19219,19221],{"class":2980,"line":3043},[2978,19204,10064],{"class":2995},[2978,19206,3632],{"class":3024},[2978,19208,5749],{"class":2995},[2978,19210,4730],{"class":3180},[2978,19212,19213],{"class":2995},"[] { ",[2978,19215,19216],{"class":3024},"\"User\"",[2978,19218,3456],{"class":2995},[2978,19220,16700],{"class":3024},[2978,19222,3407],{"class":2995},[2978,19224,19225,19227,19229,19231,19233,19235,19237],{"class":2980,"line":3056},[2978,19226,10064],{"class":2995},[2978,19228,17786],{"class":3024},[2978,19230,5749],{"class":2995},[2978,19232,4730],{"class":3180},[2978,19234,19213],{"class":2995},[2978,19236,16700],{"class":3024},[2978,19238,3407],{"class":2995},[2978,19240,19241,19243,19245,19247,19249,19251,19253,19255,19257],{"class":2980,"line":3067},[2978,19242,10064],{"class":2995},[2978,19244,5929],{"class":3024},[2978,19246,5749],{"class":2995},[2978,19248,4730],{"class":3180},[2978,19250,19213],{"class":2995},[2978,19252,19216],{"class":3024},[2978,19254,3456],{"class":2995},[2978,19256,16700],{"class":3024},[2978,19258,3407],{"class":2995},[2978,19260,19261,19263,19265,19267,19269,19271,19273,19275,19277],{"class":2980,"line":3442},[2978,19262,10064],{"class":2995},[2978,19264,6014],{"class":3024},[2978,19266,5749],{"class":2995},[2978,19268,4730],{"class":3180},[2978,19270,19213],{"class":2995},[2978,19272,19216],{"class":3024},[2978,19274,3456],{"class":2995},[2978,19276,16700],{"class":3024},[2978,19278,3492],{"class":2995},[2978,19280,19281],{"class":2980,"line":3469},[2978,19282,16559],{"class":2995},[2978,19284,19285],{"class":2980,"line":3495},[2978,19286,3288],{"emptyLinePlaceholder":3287},[2978,19288,19289,19291,19293,19295,19298,19301,19303,19305,19307,19310,19312,19315],{"class":2980,"line":3501},[2978,19290,4550],{"class":3180},[2978,19292,5625],{"class":3180},[2978,19294,6116],{"class":2995},[2978,19296,19297],{"class":3180},"bool",[2978,19299,19300],{"class":3213}," IsValid",[2978,19302,3456],{"class":2995},[2978,19304,5489],{"class":3180},[2978,19306,3101],{"class":2995},[2978,19308,19309],{"class":3213},"Error",[2978,19311,16205],{"class":2995},[2978,19313,19314],{"class":3195},"Validate",[2978,19316,5658],{"class":2995},[2978,19318,19319,19321,19323,19325],{"class":2980,"line":3642},[2978,19320,6669],{"class":3180},[2978,19322,3101],{"class":2995},[2978,19324,8235],{"class":3213},[2978,19326,3013],{"class":2995},[2978,19328,19329,19332,19334],{"class":2980,"line":3674},[2978,19330,19331],{"class":4517},"        ClaimsPrincipal",[2978,19333,16471],{"class":3213},[2978,19335,5704],{"class":2995},[2978,19337,19338],{"class":2980,"line":3680},[2978,19339,5709],{"class":2995},[2978,19341,19342,19344,19346,19348,19350,19352,19354,19356],{"class":2980,"line":3686},[2978,19343,6113],{"class":3191},[2978,19345,6116],{"class":2995},[2978,19347,5489],{"class":3180},[2978,19349,3223],{"class":2995},[2978,19351,8254],{"class":3195},[2978,19353,3199],{"class":2995},[2978,19355,8235],{"class":3213},[2978,19357,8261],{"class":2995},[2978,19359,19360,19362,19364,19366,19368,19370],{"class":2980,"line":3699},[2978,19361,8266],{"class":3191},[2978,19363,6116],{"class":2995},[2978,19365,10452],{"class":3180},[2978,19367,3456],{"class":2995},[2978,19369,10081],{"class":3180},[2978,19371,8474],{"class":2995},[2978,19373,19374],{"class":2980,"line":4367},[2978,19375,3288],{"emptyLinePlaceholder":3287},[2978,19377,19378,19380,19382,19384,19386,19388,19390,19392,19394,19396,19398,19400,19402],{"class":2980,"line":4825},[2978,19379,5714],{"class":3180},[2978,19381,8284],{"class":3213},[2978,19383,3188],{"class":2995},[2978,19385,8235],{"class":3213},[2978,19387,3223],{"class":2995},[2978,19389,8293],{"class":3195},[2978,19391,3199],{"class":2995},[2978,19393,8298],{"class":3024},[2978,19395,3456],{"class":2995},[2978,19397,8303],{"class":3213},[2978,19399,3223],{"class":2995},[2978,19401,8308],{"class":3213},[2978,19403,5704],{"class":2995},[2978,19405,19406,19408,19410,19412,19414,19416,19418,19420,19422,19424,19426],{"class":2980,"line":4836},[2978,19407,8315],{"class":2995},[2978,19409,8318],{"class":3195},[2978,19411,3199],{"class":2995},[2978,19413,2964],{"class":3213},[2978,19415,8325],{"class":2995},[2978,19417,2964],{"class":3213},[2978,19419,3223],{"class":2995},[2978,19421,8332],{"class":3195},[2978,19423,8335],{"class":2995},[2978,19425,8338],{"class":3195},[2978,19427,3228],{"class":2995},[2978,19429,19430],{"class":2980,"line":4841},[2978,19431,3288],{"emptyLinePlaceholder":3287},[2978,19433,19434,19436,19438,19440,19443,19445,19447],{"class":2980,"line":4849},[2978,19435,15837],{"class":3191},[2978,19437,6116],{"class":2995},[2978,19439,8453],{"class":3180},[2978,19441,19442],{"class":3213}," part",[2978,19444,15847],{"class":3191},[2978,19446,8284],{"class":3213},[2978,19448,5704],{"class":2995},[2978,19450,19451],{"class":2980,"line":4857},[2978,19452,5739],{"class":2995},[2978,19454,19455,19457,19460,19462,19464,19467,19469,19472,19474,19477,19480,19483],{"class":2980,"line":4863},[2978,19456,13738],{"class":3191},[2978,19458,19459],{"class":2995}," (!",[2978,19461,19190],{"class":3213},[2978,19463,3223],{"class":2995},[2978,19465,19466],{"class":3195},"TryGetValue",[2978,19468,3199],{"class":2995},[2978,19470,19471],{"class":3213},"part",[2978,19473,3456],{"class":2995},[2978,19475,19476],{"class":3180},"out",[2978,19478,19479],{"class":3180}," var",[2978,19481,19482],{"class":3213}," allowedRoles",[2978,19484,8261],{"class":2995},[2978,19486,19487],{"class":2980,"line":4868},[2978,19488,5758],{"class":2995},[2978,19490,19491,19494,19496,19498,19500,19503,19505,19507,19509,19512],{"class":2980,"line":4873},[2978,19492,19493],{"class":3191},"                return",[2978,19495,6116],{"class":2995},[2978,19497,5701],{"class":3180},[2978,19499,3456],{"class":2995},[2978,19501,19502],{"class":3024},"$\"Expansion '",[2978,19504,15144],{"class":3255},[2978,19506,19471],{"class":3213},[2978,19508,3261],{"class":3255},[2978,19510,19511],{"class":3024},"' is not supported\"",[2978,19513,8474],{"class":2995},[2978,19515,19516],{"class":2980,"line":4883},[2978,19517,6094],{"class":2995},[2978,19519,19520],{"class":2980,"line":4888},[2978,19521,3288],{"emptyLinePlaceholder":3287},[2978,19523,19524,19526,19528,19531,19533,19535,19537,19540,19542,19544,19546,19548,19550,19552],{"class":2980,"line":4907},[2978,19525,13738],{"class":3191},[2978,19527,19459],{"class":2995},[2978,19529,19530],{"class":3213},"allowedRoles",[2978,19532,3223],{"class":2995},[2978,19534,14261],{"class":3195},[2978,19536,3199],{"class":2995},[2978,19538,19539],{"class":3213},"role",[2978,19541,8325],{"class":2995},[2978,19543,16577],{"class":3213},[2978,19545,3223],{"class":2995},[2978,19547,16695],{"class":3195},[2978,19549,3199],{"class":2995},[2978,19551,19539],{"class":3213},[2978,19553,19554],{"class":2995},")))\n",[2978,19556,19557],{"class":2980,"line":4929},[2978,19558,5758],{"class":2995},[2978,19560,19561,19563,19565,19567,19569,19572,19574,19576,19578,19581],{"class":2980,"line":4951},[2978,19562,19493],{"class":3191},[2978,19564,6116],{"class":2995},[2978,19566,5701],{"class":3180},[2978,19568,3456],{"class":2995},[2978,19570,19571],{"class":3024},"$\"Insufficient permissions for expansion '",[2978,19573,15144],{"class":3255},[2978,19575,19471],{"class":3213},[2978,19577,3261],{"class":3255},[2978,19579,19580],{"class":3024},"'\"",[2978,19582,8474],{"class":2995},[2978,19584,19585],{"class":2980,"line":4973},[2978,19586,6094],{"class":2995},[2978,19588,19589],{"class":2980,"line":5004},[2978,19590,6242],{"class":2995},[2978,19592,19593],{"class":2980,"line":5009},[2978,19594,3288],{"emptyLinePlaceholder":3287},[2978,19596,19597,19599,19601,19603,19605,19607],{"class":2980,"line":5014},[2978,19598,6615],{"class":3191},[2978,19600,6116],{"class":2995},[2978,19602,10452],{"class":3180},[2978,19604,3456],{"class":2995},[2978,19606,10081],{"class":3180},[2978,19608,8474],{"class":2995},[2978,19610,19611],{"class":2980,"line":5024},[2978,19612,6625],{"class":2995},[2978,19614,19615],{"class":2980,"line":5029},[2978,19616,3070],{"class":2995},[2964,19618,19619],{},[3074,19620,19621],{},"Використання у контролері:",[2968,19623,19625],{"className":4505,"code":19624,"language":4507,"meta":2973,"style":2973},"[HttpGet(\"{id:int}\")]\npublic async Task\u003CIActionResult> GetById(int id, [FromQuery] string? expand = null)\n{\n    var (isValid, error) = ExpansionValidator.Validate(expand, User);\n    \n    if (!isValid)\n    {\n        return Forbidden(new ProblemDetails\n        {\n            Title = \"Expansion Not Allowed\",\n            Detail = error\n        });\n    }\n\n    // Продовжуємо обробку...\n}\n",[2975,19626,19627,19639,19679,19683,19718,19722,19732,19736,19749,19753,19764,19774,19779,19783,19787,19792],{"__ignoreMap":2973},[2978,19628,19629,19631,19633,19635,19637],{"class":2980,"line":2981},[2978,19630,6148],{"class":2995},[2978,19632,9960],{"class":4517},[2978,19634,3199],{"class":2995},[2978,19636,9965],{"class":3024},[2978,19638,7499],{"class":2995},[2978,19640,19641,19643,19645,19647,19649,19651,19653,19655,19657,19659,19661,19663,19665,19667,19669,19671,19673,19675,19677],{"class":2980,"line":2999},[2978,19642,4535],{"class":3180},[2978,19644,10030],{"class":3180},[2978,19646,10033],{"class":4517},[2978,19648,4707],{"class":2995},[2978,19650,10686],{"class":4517},[2978,19652,4713],{"class":2995},[2978,19654,10048],{"class":3195},[2978,19656,3199],{"class":2995},[2978,19658,10704],{"class":3180},[2978,19660,10057],{"class":3213},[2978,19662,12995],{"class":2995},[2978,19664,10067],{"class":4517},[2978,19666,10070],{"class":2995},[2978,19668,5489],{"class":3180},[2978,19670,3101],{"class":2995},[2978,19672,8235],{"class":3213},[2978,19674,3188],{"class":2995},[2978,19676,10081],{"class":3180},[2978,19678,5704],{"class":2995},[2978,19680,19681],{"class":2980,"line":3016},[2978,19682,2996],{"class":2995},[2978,19684,19685,19687,19689,19692,19694,19697,19700,19703,19705,19707,19709,19711,19713,19716],{"class":2980,"line":3030},[2978,19686,14922],{"class":3180},[2978,19688,6116],{"class":2995},[2978,19690,19691],{"class":3213},"isValid",[2978,19693,3456],{"class":2995},[2978,19695,19696],{"class":3213},"error",[2978,19698,19699],{"class":2995},") = ",[2978,19701,19702],{"class":3213},"ExpansionValidator",[2978,19704,3223],{"class":2995},[2978,19706,19314],{"class":3195},[2978,19708,3199],{"class":2995},[2978,19710,8235],{"class":3213},[2978,19712,3456],{"class":2995},[2978,19714,19715],{"class":3213},"User",[2978,19717,8474],{"class":2995},[2978,19719,19720],{"class":2980,"line":3043},[2978,19721,3932],{"class":2995},[2978,19723,19724,19726,19728,19730],{"class":2980,"line":3056},[2978,19725,16194],{"class":3191},[2978,19727,19459],{"class":2995},[2978,19729,19691],{"class":3213},[2978,19731,5704],{"class":2995},[2978,19733,19734],{"class":2980,"line":3067},[2978,19735,5709],{"class":2995},[2978,19737,19738,19740,19743,19745,19747],{"class":2980,"line":3442},[2978,19739,6615],{"class":3191},[2978,19741,19742],{"class":3195}," Forbidden",[2978,19744,3199],{"class":2995},[2978,19746,4730],{"class":3180},[2978,19748,12363],{"class":4517},[2978,19750,19751],{"class":2980,"line":3469},[2978,19752,5739],{"class":2995},[2978,19754,19755,19757,19759,19762],{"class":2980,"line":3495},[2978,19756,11845],{"class":3213},[2978,19758,3188],{"class":2995},[2978,19760,19761],{"class":3024},"\"Expansion Not Allowed\"",[2978,19763,3013],{"class":2995},[2978,19765,19766,19769,19771],{"class":2980,"line":3501},[2978,19767,19768],{"class":3213},"            Detail",[2978,19770,3188],{"class":2995},[2978,19772,19773],{"class":3213},"error\n",[2978,19775,19776],{"class":2980,"line":3642},[2978,19777,19778],{"class":2995},"        });\n",[2978,19780,19781],{"class":2980,"line":3674},[2978,19782,6625],{"class":2995},[2978,19784,19785],{"class":2980,"line":3680},[2978,19786,3288],{"emptyLinePlaceholder":3287},[2978,19788,19789],{"class":2980,"line":3686},[2978,19790,19791],{"class":3174},"    // Продовжуємо обробку...\n",[2978,19793,19794],{"class":2980,"line":3699},[2978,19795,3070],{"class":2995},[3882,19797],{},[3329,19799,19801],{"id":19800},"рівень-3-архітектура-та-створення","Рівень 3: Архітектура та створення",[4428,19803,19804,19808,19811,20776,20780,20783,21888,21892,21895],{},[3329,19805,19807],{"id":19806},"завдання-31-generic-hateoas-service","Завдання 3.1: Generic HATEOAS Service",[2964,19809,19810],{},"Створіть generic сервіс для додавання HATEOAS links до будь-яких ресурсів:",[17327,19812,19813,19818,19974,19979,20371,20376,20406,20411,20763,20767],{"title":17505},[2964,19814,19815],{},[3074,19816,19817],{},"1. Interface:",[2968,19819,19821],{"className":4505,"code":19820,"language":4507,"meta":2973,"style":2973},"public interface IHateoasService\n{\n    T AddLinks\u003CT>(T resource, params (string rel, string action, string? controller, object? routeValues, string? method)[] links)\n        where T : IHateoasResource;\n}\n\npublic interface IHateoasResource\n{\n    Dictionary\u003Cstring, Link>? Links { get; set; }\n}\n",[2975,19822,19823,19833,19837,19907,19922,19926,19930,19939,19943,19970],{"__ignoreMap":2973},[2978,19824,19825,19827,19830],{"class":2980,"line":2981},[2978,19826,4535],{"class":3180},[2978,19828,19829],{"class":3180}," interface",[2978,19831,19832],{"class":4517}," IHateoasService\n",[2978,19834,19835],{"class":2980,"line":2999},[2978,19836,2996],{"class":2995},[2978,19838,19839,19842,19845,19847,19849,19851,19853,19856,19858,19861,19863,19865,19868,19870,19872,19874,19876,19878,19880,19882,19884,19886,19888,19891,19893,19895,19897,19900,19903,19905],{"class":2980,"line":3016},[2978,19840,19841],{"class":4517},"    T",[2978,19843,19844],{"class":3195}," AddLinks",[2978,19846,4707],{"class":2995},[2978,19848,15663],{"class":4517},[2978,19850,14736],{"class":2995},[2978,19852,15663],{"class":4517},[2978,19854,19855],{"class":3213}," resource",[2978,19857,3456],{"class":2995},[2978,19859,19860],{"class":3180},"params",[2978,19862,6116],{"class":2995},[2978,19864,5489],{"class":3180},[2978,19866,19867],{"class":3213}," rel",[2978,19869,3456],{"class":2995},[2978,19871,5489],{"class":3180},[2978,19873,6672],{"class":3213},[2978,19875,3456],{"class":2995},[2978,19877,5489],{"class":3180},[2978,19879,3101],{"class":2995},[2978,19881,6778],{"class":3213},[2978,19883,3456],{"class":2995},[2978,19885,10663],{"class":3180},[2978,19887,3101],{"class":2995},[2978,19889,19890],{"class":3213},"routeValues",[2978,19892,3456],{"class":2995},[2978,19894,5489],{"class":3180},[2978,19896,3101],{"class":2995},[2978,19898,19899],{"class":3213},"method",[2978,19901,19902],{"class":2995},")[] ",[2978,19904,16917],{"class":3213},[2978,19906,5704],{"class":2995},[2978,19908,19909,19912,19915,19917,19920],{"class":2980,"line":3030},[2978,19910,19911],{"class":3180},"        where",[2978,19913,19914],{"class":4517}," T",[2978,19916,8563],{"class":2995},[2978,19918,19919],{"class":4517},"IHateoasResource",[2978,19921,4526],{"class":2995},[2978,19923,19924],{"class":2980,"line":3043},[2978,19925,3070],{"class":2995},[2978,19927,19928],{"class":2980,"line":3056},[2978,19929,3288],{"emptyLinePlaceholder":3287},[2978,19931,19932,19934,19936],{"class":2980,"line":3067},[2978,19933,4535],{"class":3180},[2978,19935,19829],{"class":3180},[2978,19937,19938],{"class":4517}," IHateoasResource\n",[2978,19940,19941],{"class":2980,"line":3442},[2978,19942,2996],{"class":2995},[2978,19944,19945,19948,19950,19952,19954,19956,19958,19960,19962,19964,19966,19968],{"class":2980,"line":3469},[2978,19946,19947],{"class":4517},"    Dictionary",[2978,19949,4707],{"class":2995},[2978,19951,5489],{"class":3180},[2978,19953,3456],{"class":2995},[2978,19955,5494],{"class":4517},[2978,19957,7516],{"class":2995},[2978,19959,5499],{"class":3213},[2978,19961,4559],{"class":2995},[2978,19963,4562],{"class":3180},[2978,19965,4565],{"class":2995},[2978,19967,4568],{"class":3180},[2978,19969,4571],{"class":2995},[2978,19971,19972],{"class":2980,"line":3495},[2978,19973,3070],{"class":2995},[2964,19975,19976],{},[3074,19977,19978],{},"2. Implementation:",[2968,19980,19982],{"className":4505,"code":19981,"language":4507,"meta":2973,"style":2973},"public class HateoasService : IHateoasService\n{\n    private readonly IUrlHelper _urlHelper;\n\n    public HateoasService(IUrlHelperFactory urlHelperFactory, IActionContextAccessor actionContextAccessor)\n    {\n        _urlHelper = urlHelperFactory.GetUrlHelper(actionContextAccessor.ActionContext!);\n    }\n\n    public T AddLinks\u003CT>(\n        T resource,\n        params (string rel, string action, string? controller, object? routeValues, string? method)[] links)\n        where T : IHateoasResource\n    {\n        resource.Links = new Dictionary\u003Cstring, Link>();\n\n        foreach (var (rel, action, controller, routeValues, method) in links)\n        {\n            var href = _urlHelper.Action(action, controller, routeValues);\n            \n            if (href != null)\n            {\n                resource.Links[rel] = new Link\n                {\n                    Href = href,\n                    Rel = rel,\n                    Method = method ?? \"GET\"\n                };\n            }\n        }\n\n        return resource;\n    }\n}\n",[2975,19983,19984,19998,20002,20014,20018,20038,20042,20064,20068,20072,20087,20096,20143,20154,20158,20183,20187,20225,20229,20258,20263,20277,20281,20300,20304,20314,20324,20339,20343,20347,20351,20355,20363,20367],{"__ignoreMap":2973},[2978,19985,19986,19988,19990,19993,19995],{"class":2980,"line":2981},[2978,19987,4535],{"class":3180},[2978,19989,4538],{"class":3180},[2978,19991,19992],{"class":4517}," HateoasService",[2978,19994,8563],{"class":2995},[2978,19996,19997],{"class":4517},"IHateoasService\n",[2978,19999,20000],{"class":2980,"line":2999},[2978,20001,2996],{"class":2995},[2978,20003,20004,20006,20008,20010,20012],{"class":2980,"line":3016},[2978,20005,9701],{"class":3180},[2978,20007,9704],{"class":3180},[2978,20009,9741],{"class":4517},[2978,20011,9744],{"class":3213},[2978,20013,4526],{"class":2995},[2978,20015,20016],{"class":2980,"line":3030},[2978,20017,3288],{"emptyLinePlaceholder":3287},[2978,20019,20020,20022,20024,20026,20028,20030,20032,20034,20036],{"class":2980,"line":3043},[2978,20021,4550],{"class":3180},[2978,20023,19992],{"class":3195},[2978,20025,3199],{"class":2995},[2978,20027,14611],{"class":4517},[2978,20029,9792],{"class":3213},[2978,20031,3456],{"class":2995},[2978,20033,14614],{"class":4517},[2978,20035,9802],{"class":3213},[2978,20037,5704],{"class":2995},[2978,20039,20040],{"class":2980,"line":3056},[2978,20041,5709],{"class":2995},[2978,20043,20044,20046,20048,20050,20052,20054,20056,20058,20060,20062],{"class":2980,"line":3067},[2978,20045,9836],{"class":3213},[2978,20047,3188],{"class":2995},[2978,20049,9841],{"class":3213},[2978,20051,3223],{"class":2995},[2978,20053,9846],{"class":3195},[2978,20055,3199],{"class":2995},[2978,20057,9851],{"class":3213},[2978,20059,3223],{"class":2995},[2978,20061,9856],{"class":3213},[2978,20063,9859],{"class":2995},[2978,20065,20066],{"class":2980,"line":3442},[2978,20067,6625],{"class":2995},[2978,20069,20070],{"class":2980,"line":3469},[2978,20071,3288],{"emptyLinePlaceholder":3287},[2978,20073,20074,20076,20078,20080,20082,20084],{"class":2980,"line":3495},[2978,20075,4550],{"class":3180},[2978,20077,19914],{"class":4517},[2978,20079,19844],{"class":3195},[2978,20081,4707],{"class":2995},[2978,20083,15663],{"class":4517},[2978,20085,20086],{"class":2995},">(\n",[2978,20088,20089,20092,20094],{"class":2980,"line":3501},[2978,20090,20091],{"class":4517},"        T",[2978,20093,19855],{"class":3213},[2978,20095,3013],{"class":2995},[2978,20097,20098,20101,20103,20105,20107,20109,20111,20113,20115,20117,20119,20121,20123,20125,20127,20129,20131,20133,20135,20137,20139,20141],{"class":2980,"line":3642},[2978,20099,20100],{"class":3180},"        params",[2978,20102,6116],{"class":2995},[2978,20104,5489],{"class":3180},[2978,20106,19867],{"class":3213},[2978,20108,3456],{"class":2995},[2978,20110,5489],{"class":3180},[2978,20112,6672],{"class":3213},[2978,20114,3456],{"class":2995},[2978,20116,5489],{"class":3180},[2978,20118,3101],{"class":2995},[2978,20120,6778],{"class":3213},[2978,20122,3456],{"class":2995},[2978,20124,10663],{"class":3180},[2978,20126,3101],{"class":2995},[2978,20128,19890],{"class":3213},[2978,20130,3456],{"class":2995},[2978,20132,5489],{"class":3180},[2978,20134,3101],{"class":2995},[2978,20136,19899],{"class":3213},[2978,20138,19902],{"class":2995},[2978,20140,16917],{"class":3213},[2978,20142,5704],{"class":2995},[2978,20144,20145,20147,20149,20151],{"class":2980,"line":3674},[2978,20146,19911],{"class":3180},[2978,20148,19914],{"class":4517},[2978,20150,8563],{"class":2995},[2978,20152,20153],{"class":4517},"IHateoasResource\n",[2978,20155,20156],{"class":2980,"line":3680},[2978,20157,5709],{"class":2995},[2978,20159,20160,20163,20165,20167,20169,20171,20173,20175,20177,20179,20181],{"class":2980,"line":3686},[2978,20161,20162],{"class":3213},"        resource",[2978,20164,3223],{"class":2995},[2978,20166,5499],{"class":3213},[2978,20168,3188],{"class":2995},[2978,20170,4730],{"class":3180},[2978,20172,5484],{"class":4517},[2978,20174,4707],{"class":2995},[2978,20176,5489],{"class":3180},[2978,20178,3456],{"class":2995},[2978,20180,5494],{"class":4517},[2978,20182,8635],{"class":2995},[2978,20184,20185],{"class":2980,"line":3699},[2978,20186,3288],{"emptyLinePlaceholder":3287},[2978,20188,20189,20191,20193,20195,20197,20200,20202,20204,20206,20208,20210,20212,20214,20216,20218,20221,20223],{"class":2980,"line":4367},[2978,20190,15837],{"class":3191},[2978,20192,6116],{"class":2995},[2978,20194,8453],{"class":3180},[2978,20196,6116],{"class":2995},[2978,20198,20199],{"class":3213},"rel",[2978,20201,3456],{"class":2995},[2978,20203,6773],{"class":3213},[2978,20205,3456],{"class":2995},[2978,20207,6778],{"class":3213},[2978,20209,3456],{"class":2995},[2978,20211,19890],{"class":3213},[2978,20213,3456],{"class":2995},[2978,20215,19899],{"class":3213},[2978,20217,16205],{"class":2995},[2978,20219,20220],{"class":3191},"in",[2978,20222,5717],{"class":3213},[2978,20224,5704],{"class":2995},[2978,20226,20227],{"class":2980,"line":4825},[2978,20228,5739],{"class":2995},[2978,20230,20231,20233,20236,20238,20240,20242,20244,20246,20248,20250,20252,20254,20256],{"class":2980,"line":4836},[2978,20232,10924],{"class":3180},[2978,20234,20235],{"class":3213}," href",[2978,20237,3188],{"class":2995},[2978,20239,11542],{"class":3213},[2978,20241,3223],{"class":2995},[2978,20243,5773],{"class":3195},[2978,20245,3199],{"class":2995},[2978,20247,6773],{"class":3213},[2978,20249,3456],{"class":2995},[2978,20251,6778],{"class":3213},[2978,20253,3456],{"class":2995},[2978,20255,19890],{"class":3213},[2978,20257,8474],{"class":2995},[2978,20259,20260],{"class":2980,"line":4841},[2978,20261,20262],{"class":2995},"            \n",[2978,20264,20265,20267,20269,20271,20273,20275],{"class":2980,"line":4849},[2978,20266,13738],{"class":3191},[2978,20268,6116],{"class":2995},[2978,20270,4407],{"class":3213},[2978,20272,6259],{"class":2995},[2978,20274,10081],{"class":3180},[2978,20276,5704],{"class":2995},[2978,20278,20279],{"class":2980,"line":4857},[2978,20280,5758],{"class":2995},[2978,20282,20283,20286,20288,20290,20292,20294,20296,20298],{"class":2980,"line":4863},[2978,20284,20285],{"class":3213},"                resource",[2978,20287,3223],{"class":2995},[2978,20289,5499],{"class":3213},[2978,20291,6148],{"class":2995},[2978,20293,20199],{"class":3213},[2978,20295,5749],{"class":2995},[2978,20297,4730],{"class":3180},[2978,20299,5363],{"class":4517},[2978,20301,20302],{"class":2980,"line":4868},[2978,20303,11531],{"class":2995},[2978,20305,20306,20308,20310,20312],{"class":2980,"line":4873},[2978,20307,11537],{"class":3213},[2978,20309,3188],{"class":2995},[2978,20311,4407],{"class":3213},[2978,20313,3013],{"class":2995},[2978,20315,20316,20318,20320,20322],{"class":2980,"line":4883},[2978,20317,11580],{"class":3213},[2978,20319,3188],{"class":2995},[2978,20321,20199],{"class":3213},[2978,20323,3013],{"class":2995},[2978,20325,20326,20329,20331,20333,20336],{"class":2980,"line":4888},[2978,20327,20328],{"class":3213},"                    Method",[2978,20330,3188],{"class":2995},[2978,20332,19899],{"class":3213},[2978,20334,20335],{"class":2995}," ?? ",[2978,20337,20338],{"class":3024},"\"GET\"\n",[2978,20340,20341],{"class":2980,"line":4907},[2978,20342,13990],{"class":2995},[2978,20344,20345],{"class":2980,"line":4929},[2978,20346,6094],{"class":2995},[2978,20348,20349],{"class":2980,"line":4951},[2978,20350,6242],{"class":2995},[2978,20352,20353],{"class":2980,"line":4973},[2978,20354,3288],{"emptyLinePlaceholder":3287},[2978,20356,20357,20359,20361],{"class":2980,"line":5004},[2978,20358,6615],{"class":3191},[2978,20360,19855],{"class":3213},[2978,20362,4526],{"class":2995},[2978,20364,20365],{"class":2980,"line":5009},[2978,20366,6625],{"class":2995},[2978,20368,20369],{"class":2980,"line":5014},[2978,20370,3070],{"class":2995},[2964,20372,20373],{},[3074,20374,20375],{},"3. Реєстрація:",[2968,20377,20379],{"className":4505,"code":20378,"language":4507,"meta":2973,"style":2973},"builder.Services.AddScoped\u003CIHateoasService, HateoasService>();\n",[2975,20380,20381],{"__ignoreMap":2973},[2978,20382,20383,20385,20387,20389,20391,20394,20396,20399,20401,20404],{"class":2980,"line":2981},[2978,20384,14719],{"class":3213},[2978,20386,3223],{"class":2995},[2978,20388,14724],{"class":3213},[2978,20390,3223],{"class":2995},[2978,20392,20393],{"class":3195},"AddScoped",[2978,20395,4707],{"class":2995},[2978,20397,20398],{"class":4517},"IHateoasService",[2978,20400,3456],{"class":2995},[2978,20402,20403],{"class":4517},"HateoasService",[2978,20405,8635],{"class":2995},[2964,20407,20408],{},[3074,20409,20410],{},"4. Використання у контролері:",[2968,20412,20414],{"className":4505,"code":20413,"language":4507,"meta":2973,"style":2973},"public class ArticlesController : ControllerBase\n{\n    private readonly IHateoasService _hateoasService;\n\n    [HttpGet(\"{id:int}\")]\n    public async Task\u003CActionResult\u003CArticleDto>> GetById(int id)\n    {\n        var article = await _db.Articles.FindAsync(id);\n        if (article is null) return NotFound();\n\n        var dto = MapToDto(article);\n\n        // Додаємо links через сервіс\n        _hateoasService.AddLinks(dto,\n            (\"self\", \"GetById\", \"Articles\", new { id }, \"GET\"),\n            (\"author\", \"GetById\", \"Authors\", new { id = article.AuthorId }, \"GET\"),\n            (\"comments\", \"GetComments\", \"Articles\", new { id }, \"GET\"),\n            (\"edit\", \"Update\", \"Articles\", new { id }, \"PUT\"),\n            (\"delete\", \"Delete\", \"Articles\", new { id }, \"DELETE\")\n        );\n\n        return Ok(dto);\n    }\n}\n",[2975,20415,20416,20428,20432,20446,20450,20462,20490,20494,20520,20540,20544,20560,20564,20569,20585,20615,20651,20679,20707,20735,20739,20743,20755,20759],{"__ignoreMap":2973},[2978,20417,20418,20420,20422,20424,20426],{"class":2980,"line":2981},[2978,20419,4535],{"class":3180},[2978,20421,4538],{"class":3180},[2978,20423,9687],{"class":4517},[2978,20425,8563],{"class":2995},[2978,20427,9692],{"class":4517},[2978,20429,20430],{"class":2980,"line":2999},[2978,20431,2996],{"class":2995},[2978,20433,20434,20436,20438,20441,20444],{"class":2980,"line":3016},[2978,20435,9701],{"class":3180},[2978,20437,9704],{"class":3180},[2978,20439,20440],{"class":4517}," IHateoasService",[2978,20442,20443],{"class":3213}," _hateoasService",[2978,20445,4526],{"class":2995},[2978,20447,20448],{"class":2980,"line":3030},[2978,20449,3288],{"emptyLinePlaceholder":3287},[2978,20451,20452,20454,20456,20458,20460],{"class":2980,"line":3043},[2978,20453,7489],{"class":2995},[2978,20455,9960],{"class":4517},[2978,20457,3199],{"class":2995},[2978,20459,9965],{"class":3024},[2978,20461,7499],{"class":2995},[2978,20463,20464,20466,20468,20470,20472,20474,20476,20478,20480,20482,20484,20486,20488],{"class":2980,"line":3056},[2978,20465,4550],{"class":3180},[2978,20467,10030],{"class":3180},[2978,20469,10033],{"class":4517},[2978,20471,4707],{"class":2995},[2978,20473,10038],{"class":4517},[2978,20475,4707],{"class":2995},[2978,20477,9993],{"class":4517},[2978,20479,10045],{"class":2995},[2978,20481,10048],{"class":3195},[2978,20483,3199],{"class":2995},[2978,20485,10704],{"class":3180},[2978,20487,10057],{"class":3213},[2978,20489,5704],{"class":2995},[2978,20491,20492],{"class":2980,"line":3067},[2978,20493,5709],{"class":2995},[2978,20495,20496,20498,20500,20502,20504,20506,20508,20510,20512,20514,20516,20518],{"class":2980,"line":3442},[2978,20497,5714],{"class":3180},[2978,20499,3185],{"class":3213},[2978,20501,3188],{"class":2995},[2978,20503,3192],{"class":3180},[2978,20505,9709],{"class":3213},[2978,20507,3223],{"class":2995},[2978,20509,4987],{"class":3213},[2978,20511,3223],{"class":2995},[2978,20513,12285],{"class":3195},[2978,20515,3199],{"class":2995},[2978,20517,5792],{"class":3213},[2978,20519,8474],{"class":2995},[2978,20521,20522,20524,20526,20528,20530,20532,20534,20536,20538],{"class":2980,"line":3469},[2978,20523,6113],{"class":3191},[2978,20525,6116],{"class":2995},[2978,20527,3252],{"class":3213},[2978,20529,10339],{"class":3180},[2978,20531,10342],{"class":3180},[2978,20533,16205],{"class":2995},[2978,20535,16208],{"class":3191},[2978,20537,10351],{"class":3195},[2978,20539,4733],{"class":2995},[2978,20541,20542],{"class":2980,"line":3495},[2978,20543,3288],{"emptyLinePlaceholder":3287},[2978,20545,20546,20548,20550,20552,20554,20556,20558],{"class":2980,"line":3501},[2978,20547,5714],{"class":3180},[2978,20549,10369],{"class":3213},[2978,20551,3188],{"class":2995},[2978,20553,10374],{"class":3195},[2978,20555,3199],{"class":2995},[2978,20557,3252],{"class":3213},[2978,20559,8474],{"class":2995},[2978,20561,20562],{"class":2980,"line":3642},[2978,20563,3288],{"emptyLinePlaceholder":3287},[2978,20565,20566],{"class":2980,"line":3674},[2978,20567,20568],{"class":3174},"        // Додаємо links через сервіс\n",[2978,20570,20571,20574,20576,20579,20581,20583],{"class":2980,"line":3680},[2978,20572,20573],{"class":3213},"        _hateoasService",[2978,20575,3223],{"class":2995},[2978,20577,20578],{"class":3195},"AddLinks",[2978,20580,3199],{"class":2995},[2978,20582,10489],{"class":3213},[2978,20584,3013],{"class":2995},[2978,20586,20587,20590,20592,20594,20596,20598,20600,20602,20604,20606,20608,20611,20613],{"class":2980,"line":3686},[2978,20588,20589],{"class":2995},"            (",[2978,20591,3738],{"class":3024},[2978,20593,3456],{"class":2995},[2978,20595,5778],{"class":3024},[2978,20597,3456],{"class":2995},[2978,20599,5783],{"class":3024},[2978,20601,3456],{"class":2995},[2978,20603,4730],{"class":3180},[2978,20605,4559],{"class":2995},[2978,20607,5792],{"class":3213},[2978,20609,20610],{"class":2995}," }, ",[2978,20612,5433],{"class":3024},[2978,20614,8388],{"class":2995},[2978,20616,20617,20619,20621,20623,20625,20627,20629,20631,20633,20635,20637,20639,20641,20643,20645,20647,20649],{"class":2980,"line":3699},[2978,20618,20589],{"class":2995},[2978,20620,3632],{"class":3024},[2978,20622,3456],{"class":2995},[2978,20624,5778],{"class":3024},[2978,20626,3456],{"class":2995},[2978,20628,5874],{"class":3024},[2978,20630,3456],{"class":2995},[2978,20632,4730],{"class":3180},[2978,20634,4559],{"class":2995},[2978,20636,5792],{"class":3213},[2978,20638,3188],{"class":2995},[2978,20640,3252],{"class":3213},[2978,20642,3223],{"class":2995},[2978,20644,10519],{"class":3213},[2978,20646,20610],{"class":2995},[2978,20648,5433],{"class":3024},[2978,20650,8388],{"class":2995},[2978,20652,20653,20655,20657,20659,20661,20663,20665,20667,20669,20671,20673,20675,20677],{"class":2980,"line":4367},[2978,20654,20589],{"class":2995},[2978,20656,5929],{"class":3024},[2978,20658,3456],{"class":2995},[2978,20660,5956],{"class":3024},[2978,20662,3456],{"class":2995},[2978,20664,5783],{"class":3024},[2978,20666,3456],{"class":2995},[2978,20668,4730],{"class":3180},[2978,20670,4559],{"class":2995},[2978,20672,5792],{"class":3213},[2978,20674,20610],{"class":2995},[2978,20676,5433],{"class":3024},[2978,20678,8388],{"class":2995},[2978,20680,20681,20683,20685,20687,20689,20691,20693,20695,20697,20699,20701,20703,20705],{"class":2980,"line":4825},[2978,20682,20589],{"class":2995},[2978,20684,6287],{"class":3024},[2978,20686,3456],{"class":2995},[2978,20688,6316],{"class":3024},[2978,20690,3456],{"class":2995},[2978,20692,5783],{"class":3024},[2978,20694,3456],{"class":2995},[2978,20696,4730],{"class":3180},[2978,20698,4559],{"class":2995},[2978,20700,5792],{"class":3213},[2978,20702,20610],{"class":2995},[2978,20704,3464],{"class":3024},[2978,20706,8388],{"class":2995},[2978,20708,20709,20711,20713,20715,20717,20719,20721,20723,20725,20727,20729,20731,20733],{"class":2980,"line":4836},[2978,20710,20589],{"class":2995},[2978,20712,6386],{"class":3024},[2978,20714,3456],{"class":2995},[2978,20716,6415],{"class":3024},[2978,20718,3456],{"class":2995},[2978,20720,5783],{"class":3024},[2978,20722,3456],{"class":2995},[2978,20724,4730],{"class":3180},[2978,20726,4559],{"class":2995},[2978,20728,5792],{"class":3213},[2978,20730,20610],{"class":2995},[2978,20732,3489],{"class":3024},[2978,20734,5704],{"class":2995},[2978,20736,20737],{"class":2980,"line":4841},[2978,20738,8862],{"class":2995},[2978,20740,20741],{"class":2980,"line":4849},[2978,20742,3288],{"emptyLinePlaceholder":3287},[2978,20744,20745,20747,20749,20751,20753],{"class":2980,"line":4857},[2978,20746,6615],{"class":3191},[2978,20748,10592],{"class":3195},[2978,20750,3199],{"class":2995},[2978,20752,10489],{"class":3213},[2978,20754,8474],{"class":2995},[2978,20756,20757],{"class":2980,"line":4863},[2978,20758,6625],{"class":2995},[2978,20760,20761],{"class":2980,"line":4868},[2978,20762,3070],{"class":2995},[2964,20764,20765],{},[3074,20766,4143],{},[2964,20768,20769,20770,20772,20773,20775],{},"✅ Reusable для всіх ресурсів",[4152,20771],{},"\n✅ Централізована логіка генерації links",[4152,20774],{},"\n✅ Легко тестувати",[3329,20777,20779],{"id":20778},"завдання-32-hateoas-action-filter","Завдання 3.2: HATEOAS Action Filter",[2964,20781,20782],{},"Створіть Action Filter для автоматичного додавання HATEOAS links:",[17327,20784,20785,20790,20895,20900,21670,21674,21726,21731,21875,21879],{"title":17505},[2964,20786,20787],{},[3074,20788,20789],{},"1. Attribute для конфігурації:",[2968,20791,20793],{"className":4505,"code":20792,"language":4507,"meta":2973,"style":2973},"[AttributeUsage(AttributeTargets.Method)]\npublic class HateoasAttribute : Attribute\n{\n    public string[] Relations { get; }\n\n    public HateoasAttribute(params string[] relations)\n    {\n        Relations = relations;\n    }\n}\n",[2975,20794,20795,20813,20827,20831,20849,20853,20872,20876,20887,20891],{"__ignoreMap":2973},[2978,20796,20797,20799,20802,20804,20807,20809,20811],{"class":2980,"line":2981},[2978,20798,6148],{"class":2995},[2978,20800,20801],{"class":4517},"AttributeUsage",[2978,20803,3199],{"class":2995},[2978,20805,20806],{"class":3213},"AttributeTargets",[2978,20808,3223],{"class":2995},[2978,20810,5420],{"class":3213},[2978,20812,7499],{"class":2995},[2978,20814,20815,20817,20819,20822,20824],{"class":2980,"line":2999},[2978,20816,4535],{"class":3180},[2978,20818,4538],{"class":3180},[2978,20820,20821],{"class":4517}," HateoasAttribute",[2978,20823,8563],{"class":2995},[2978,20825,20826],{"class":4517},"Attribute\n",[2978,20828,20829],{"class":2980,"line":3016},[2978,20830,2996],{"class":2995},[2978,20832,20833,20835,20837,20840,20843,20845,20847],{"class":2980,"line":3030},[2978,20834,4550],{"class":3180},[2978,20836,4581],{"class":3180},[2978,20838,20839],{"class":2995},"[] ",[2978,20841,20842],{"class":3213},"Relations",[2978,20844,4559],{"class":2995},[2978,20846,4562],{"class":3180},[2978,20848,4571],{"class":2995},[2978,20850,20851],{"class":2980,"line":3043},[2978,20852,3288],{"emptyLinePlaceholder":3287},[2978,20854,20855,20857,20859,20861,20863,20865,20867,20870],{"class":2980,"line":3056},[2978,20856,4550],{"class":3180},[2978,20858,20821],{"class":3195},[2978,20860,3199],{"class":2995},[2978,20862,19860],{"class":3180},[2978,20864,4581],{"class":3180},[2978,20866,20839],{"class":2995},[2978,20868,20869],{"class":3213},"relations",[2978,20871,5704],{"class":2995},[2978,20873,20874],{"class":2980,"line":3067},[2978,20875,5709],{"class":2995},[2978,20877,20878,20881,20883,20885],{"class":2980,"line":3442},[2978,20879,20880],{"class":3213},"        Relations",[2978,20882,3188],{"class":2995},[2978,20884,20869],{"class":3213},[2978,20886,4526],{"class":2995},[2978,20888,20889],{"class":2980,"line":3469},[2978,20890,6625],{"class":2995},[2978,20892,20893],{"class":2980,"line":3495},[2978,20894,3070],{"class":2995},[2964,20896,20897],{},[3074,20898,20899],{},"2. Filter:",[2968,20901,20903],{"className":4505,"code":20902,"language":4507,"meta":2973,"style":2973},"public class HateoasFilter : IAsyncResultFilter\n{\n    private readonly IUrlHelper _urlHelper;\n\n    public HateoasFilter(IUrlHelperFactory urlHelperFactory, IActionContextAccessor actionContextAccessor)\n    {\n        _urlHelper = urlHelperFactory.GetUrlHelper(actionContextAccessor.ActionContext!);\n    }\n\n    public async Task OnResultExecutionAsync(\n        ResultExecutingContext context,\n        ResultExecutionDelegate next)\n    {\n        // Перевіряємо наявність атрибута\n        var hateoasAttribute = context.ActionDescriptor.EndpointMetadata\n            .OfType\u003CHateoasAttribute>()\n            .FirstOrDefault();\n\n        if (hateoasAttribute != null && context.Result is ObjectResult objectResult)\n        {\n            if (objectResult.Value is IHateoasResource resource)\n            {\n                resource.Links = GenerateLinks(context, hateoasAttribute.Relations);\n            }\n        }\n\n        await next();\n    }\n\n    private Dictionary\u003Cstring, Link> GenerateLinks(\n        ResultExecutingContext context,\n        string[] relations)\n    {\n        var links = new Dictionary\u003Cstring, Link>();\n        var routeData = context.RouteData;\n        var controller = routeData.Values[\"controller\"]?.ToString();\n        var id = routeData.Values[\"id\"];\n\n        foreach (var rel in relations)\n        {\n            var link = rel.ToLower() switch\n            {\n                \"self\" => new Link\n                {\n                    Href = _urlHelper.Action(context.ActionDescriptor.RouteValues[\"action\"], controller, new { id })!,\n                    Rel = \"self\"\n                },\n                \"edit\" => new Link\n                {\n                    Href = _urlHelper.Action(\"Update\", controller, new { id })!,\n                    Rel = \"edit\",\n                    Method = \"PUT\"\n                },\n                \"delete\" => new Link\n                {\n                    Href = _urlHelper.Action(\"Delete\", controller, new { id })!,\n                    Rel = \"delete\",\n                    Method = \"DELETE\"\n                },\n                _ => null\n            };\n\n            if (link != null)\n            {\n                links[rel] = link;\n            }\n        }\n\n        return links;\n    }\n}\n",[2975,20904,20905,20919,20923,20935,20939,20959,20963,20985,20989,20993,21006,21016,21026,21030,21035,21057,21072,21081,21085,21117,21121,21144,21148,21175,21179,21183,21187,21195,21199,21203,21223,21231,21241,21245,21267,21285,21313,21334,21338,21355,21359,21380,21384,21395,21399,21444,21452,21456,21467,21471,21501,21511,21519,21523,21534,21538,21568,21578,21586,21590,21600,21604,21608,21623,21627,21642,21646,21650,21654,21662,21666],{"__ignoreMap":2973},[2978,20906,20907,20909,20911,20914,20916],{"class":2980,"line":2981},[2978,20908,4535],{"class":3180},[2978,20910,4538],{"class":3180},[2978,20912,20913],{"class":4517}," HateoasFilter",[2978,20915,8563],{"class":2995},[2978,20917,20918],{"class":4517},"IAsyncResultFilter\n",[2978,20920,20921],{"class":2980,"line":2999},[2978,20922,2996],{"class":2995},[2978,20924,20925,20927,20929,20931,20933],{"class":2980,"line":3016},[2978,20926,9701],{"class":3180},[2978,20928,9704],{"class":3180},[2978,20930,9741],{"class":4517},[2978,20932,9744],{"class":3213},[2978,20934,4526],{"class":2995},[2978,20936,20937],{"class":2980,"line":3030},[2978,20938,3288],{"emptyLinePlaceholder":3287},[2978,20940,20941,20943,20945,20947,20949,20951,20953,20955,20957],{"class":2980,"line":3043},[2978,20942,4550],{"class":3180},[2978,20944,20913],{"class":3195},[2978,20946,3199],{"class":2995},[2978,20948,14611],{"class":4517},[2978,20950,9792],{"class":3213},[2978,20952,3456],{"class":2995},[2978,20954,14614],{"class":4517},[2978,20956,9802],{"class":3213},[2978,20958,5704],{"class":2995},[2978,20960,20961],{"class":2980,"line":3056},[2978,20962,5709],{"class":2995},[2978,20964,20965,20967,20969,20971,20973,20975,20977,20979,20981,20983],{"class":2980,"line":3067},[2978,20966,9836],{"class":3213},[2978,20968,3188],{"class":2995},[2978,20970,9841],{"class":3213},[2978,20972,3223],{"class":2995},[2978,20974,9846],{"class":3195},[2978,20976,3199],{"class":2995},[2978,20978,9851],{"class":3213},[2978,20980,3223],{"class":2995},[2978,20982,9856],{"class":3213},[2978,20984,9859],{"class":2995},[2978,20986,20987],{"class":2980,"line":3442},[2978,20988,6625],{"class":2995},[2978,20990,20991],{"class":2980,"line":3469},[2978,20992,3288],{"emptyLinePlaceholder":3287},[2978,20994,20995,20997,20999,21001,21004],{"class":2980,"line":3495},[2978,20996,4550],{"class":3180},[2978,20998,10030],{"class":3180},[2978,21000,10033],{"class":4517},[2978,21002,21003],{"class":3195}," OnResultExecutionAsync",[2978,21005,5658],{"class":2995},[2978,21007,21008,21011,21014],{"class":2980,"line":3501},[2978,21009,21010],{"class":4517},"        ResultExecutingContext",[2978,21012,21013],{"class":3213}," context",[2978,21015,3013],{"class":2995},[2978,21017,21018,21021,21024],{"class":2980,"line":3642},[2978,21019,21020],{"class":4517},"        ResultExecutionDelegate",[2978,21022,21023],{"class":3213}," next",[2978,21025,5704],{"class":2995},[2978,21027,21028],{"class":2980,"line":3674},[2978,21029,5709],{"class":2995},[2978,21031,21032],{"class":2980,"line":3680},[2978,21033,21034],{"class":3174},"        // Перевіряємо наявність атрибута\n",[2978,21036,21037,21039,21042,21044,21047,21049,21052,21054],{"class":2980,"line":3686},[2978,21038,5714],{"class":3180},[2978,21040,21041],{"class":3213}," hateoasAttribute",[2978,21043,3188],{"class":2995},[2978,21045,21046],{"class":3213},"context",[2978,21048,3223],{"class":2995},[2978,21050,21051],{"class":3213},"ActionDescriptor",[2978,21053,3223],{"class":2995},[2978,21055,21056],{"class":3213},"EndpointMetadata\n",[2978,21058,21059,21061,21064,21066,21069],{"class":2980,"line":3699},[2978,21060,8315],{"class":2995},[2978,21062,21063],{"class":3195},"OfType",[2978,21065,4707],{"class":2995},[2978,21067,21068],{"class":4517},"HateoasAttribute",[2978,21070,21071],{"class":2995},">()\n",[2978,21073,21074,21076,21079],{"class":2980,"line":4367},[2978,21075,8315],{"class":2995},[2978,21077,21078],{"class":3195},"FirstOrDefault",[2978,21080,4733],{"class":2995},[2978,21082,21083],{"class":2980,"line":4825},[2978,21084,3288],{"emptyLinePlaceholder":3287},[2978,21086,21087,21089,21091,21094,21096,21098,21100,21102,21104,21107,21109,21112,21115],{"class":2980,"line":4836},[2978,21088,6113],{"class":3191},[2978,21090,6116],{"class":2995},[2978,21092,21093],{"class":3213},"hateoasAttribute",[2978,21095,6259],{"class":2995},[2978,21097,10081],{"class":3180},[2978,21099,6131],{"class":2995},[2978,21101,21046],{"class":3213},[2978,21103,3223],{"class":2995},[2978,21105,21106],{"class":3213},"Result",[2978,21108,10339],{"class":3180},[2978,21110,21111],{"class":4517}," ObjectResult",[2978,21113,21114],{"class":3213}," objectResult",[2978,21116,5704],{"class":2995},[2978,21118,21119],{"class":2980,"line":4841},[2978,21120,5739],{"class":2995},[2978,21122,21123,21125,21127,21130,21132,21135,21137,21140,21142],{"class":2980,"line":4849},[2978,21124,13738],{"class":3191},[2978,21126,6116],{"class":2995},[2978,21128,21129],{"class":3213},"objectResult",[2978,21131,3223],{"class":2995},[2978,21133,21134],{"class":3213},"Value",[2978,21136,10339],{"class":3180},[2978,21138,21139],{"class":4517}," IHateoasResource",[2978,21141,19855],{"class":3213},[2978,21143,5704],{"class":2995},[2978,21145,21146],{"class":2980,"line":4857},[2978,21147,5758],{"class":2995},[2978,21149,21150,21152,21154,21156,21158,21161,21163,21165,21167,21169,21171,21173],{"class":2980,"line":4863},[2978,21151,20285],{"class":3213},[2978,21153,3223],{"class":2995},[2978,21155,5499],{"class":3213},[2978,21157,3188],{"class":2995},[2978,21159,21160],{"class":3195},"GenerateLinks",[2978,21162,3199],{"class":2995},[2978,21164,21046],{"class":3213},[2978,21166,3456],{"class":2995},[2978,21168,21093],{"class":3213},[2978,21170,3223],{"class":2995},[2978,21172,20842],{"class":3213},[2978,21174,8474],{"class":2995},[2978,21176,21177],{"class":2980,"line":4868},[2978,21178,6094],{"class":2995},[2978,21180,21181],{"class":2980,"line":4873},[2978,21182,6242],{"class":2995},[2978,21184,21185],{"class":2980,"line":4883},[2978,21186,3288],{"emptyLinePlaceholder":3287},[2978,21188,21189,21191,21193],{"class":2980,"line":4888},[2978,21190,11955],{"class":3180},[2978,21192,21023],{"class":3195},[2978,21194,4733],{"class":2995},[2978,21196,21197],{"class":2980,"line":4907},[2978,21198,6625],{"class":2995},[2978,21200,21201],{"class":2980,"line":4929},[2978,21202,3288],{"emptyLinePlaceholder":3287},[2978,21204,21205,21207,21209,21211,21213,21215,21217,21219,21221],{"class":2980,"line":4951},[2978,21206,9701],{"class":3180},[2978,21208,5484],{"class":4517},[2978,21210,4707],{"class":2995},[2978,21212,5489],{"class":3180},[2978,21214,3456],{"class":2995},[2978,21216,5494],{"class":4517},[2978,21218,4713],{"class":2995},[2978,21220,21160],{"class":3195},[2978,21222,5658],{"class":2995},[2978,21224,21225,21227,21229],{"class":2980,"line":4973},[2978,21226,21010],{"class":4517},[2978,21228,21013],{"class":3213},[2978,21230,3013],{"class":2995},[2978,21232,21233,21235,21237,21239],{"class":2980,"line":5004},[2978,21234,6669],{"class":3180},[2978,21236,20839],{"class":2995},[2978,21238,20869],{"class":3213},[2978,21240,5704],{"class":2995},[2978,21242,21243],{"class":2980,"line":5009},[2978,21244,5709],{"class":2995},[2978,21246,21247,21249,21251,21253,21255,21257,21259,21261,21263,21265],{"class":2980,"line":5014},[2978,21248,5714],{"class":3180},[2978,21250,5717],{"class":3213},[2978,21252,3188],{"class":2995},[2978,21254,4730],{"class":3180},[2978,21256,5484],{"class":4517},[2978,21258,4707],{"class":2995},[2978,21260,5489],{"class":3180},[2978,21262,3456],{"class":2995},[2978,21264,5494],{"class":4517},[2978,21266,8635],{"class":2995},[2978,21268,21269,21271,21274,21276,21278,21280,21283],{"class":2980,"line":5024},[2978,21270,5714],{"class":3180},[2978,21272,21273],{"class":3213}," routeData",[2978,21275,3188],{"class":2995},[2978,21277,21046],{"class":3213},[2978,21279,3223],{"class":2995},[2978,21281,21282],{"class":3213},"RouteData",[2978,21284,4526],{"class":2995},[2978,21286,21287,21289,21291,21293,21296,21298,21301,21303,21306,21309,21311],{"class":2980,"line":5029},[2978,21288,5714],{"class":3180},[2978,21290,6682],{"class":3213},[2978,21292,3188],{"class":2995},[2978,21294,21295],{"class":3213},"routeData",[2978,21297,3223],{"class":2995},[2978,21299,21300],{"class":3213},"Values",[2978,21302,6148],{"class":2995},[2978,21304,21305],{"class":3024},"\"controller\"",[2978,21307,21308],{"class":2995},"]?.",[2978,21310,10524],{"class":3195},[2978,21312,4733],{"class":2995},[2978,21314,21315,21317,21319,21321,21323,21325,21327,21329,21331],{"class":2980,"line":5048},[2978,21316,5714],{"class":3180},[2978,21318,10057],{"class":3213},[2978,21320,3188],{"class":2995},[2978,21322,21295],{"class":3213},[2978,21324,3223],{"class":2995},[2978,21326,21300],{"class":3213},[2978,21328,6148],{"class":2995},[2978,21330,3612],{"class":3024},[2978,21332,21333],{"class":2995},"];\n",[2978,21335,21336],{"class":2980,"line":5069},[2978,21337,3288],{"emptyLinePlaceholder":3287},[2978,21339,21340,21342,21344,21346,21348,21350,21353],{"class":2980,"line":5091},[2978,21341,15837],{"class":3191},[2978,21343,6116],{"class":2995},[2978,21345,8453],{"class":3180},[2978,21347,19867],{"class":3213},[2978,21349,15847],{"class":3191},[2978,21351,21352],{"class":3213}," relations",[2978,21354,5704],{"class":2995},[2978,21356,21357],{"class":2980,"line":5120},[2978,21358,5739],{"class":2995},[2978,21360,21361,21363,21366,21368,21370,21372,21374,21377],{"class":2980,"line":5125},[2978,21362,10924],{"class":3180},[2978,21364,21365],{"class":3213}," link",[2978,21367,3188],{"class":2995},[2978,21369,20199],{"class":3213},[2978,21371,3223],{"class":2995},[2978,21373,8338],{"class":3195},[2978,21375,21376],{"class":2995},"() ",[2978,21378,21379],{"class":3191},"switch\n",[2978,21381,21382],{"class":2980,"line":5130},[2978,21383,5758],{"class":2995},[2978,21385,21386,21389,21391,21393],{"class":2980,"line":5140},[2978,21387,21388],{"class":3024},"                \"self\"",[2978,21390,8325],{"class":2995},[2978,21392,4730],{"class":3180},[2978,21394,5363],{"class":4517},[2978,21396,21397],{"class":2980,"line":5145},[2978,21398,11531],{"class":2995},[2978,21400,21401,21403,21405,21407,21409,21411,21413,21415,21417,21419,21421,21424,21426,21429,21432,21434,21436,21438,21440,21442],{"class":2980,"line":5164},[2978,21402,11537],{"class":3213},[2978,21404,3188],{"class":2995},[2978,21406,11542],{"class":3213},[2978,21408,3223],{"class":2995},[2978,21410,5773],{"class":3195},[2978,21412,3199],{"class":2995},[2978,21414,21046],{"class":3213},[2978,21416,3223],{"class":2995},[2978,21418,21051],{"class":3213},[2978,21420,3223],{"class":2995},[2978,21422,21423],{"class":3213},"RouteValues",[2978,21425,6148],{"class":2995},[2978,21427,21428],{"class":3024},"\"action\"",[2978,21430,21431],{"class":2995},"], ",[2978,21433,6778],{"class":3213},[2978,21435,3456],{"class":2995},[2978,21437,4730],{"class":3180},[2978,21439,4559],{"class":2995},[2978,21441,5792],{"class":3213},[2978,21443,5800],{"class":2995},[2978,21445,21446,21448,21450],{"class":2980,"line":5186},[2978,21447,11580],{"class":3213},[2978,21449,3188],{"class":2995},[2978,21451,6799],{"class":3024},[2978,21453,21454],{"class":2980,"line":5208},[2978,21455,11590],{"class":2995},[2978,21457,21458,21461,21463,21465],{"class":2980,"line":5228},[2978,21459,21460],{"class":3024},"                \"edit\"",[2978,21462,8325],{"class":2995},[2978,21464,4730],{"class":3180},[2978,21466,5363],{"class":4517},[2978,21468,21469],{"class":2980,"line":5250},[2978,21470,11531],{"class":2995},[2978,21472,21473,21475,21477,21479,21481,21483,21485,21487,21489,21491,21493,21495,21497,21499],{"class":2980,"line":5278},[2978,21474,11537],{"class":3213},[2978,21476,3188],{"class":2995},[2978,21478,11542],{"class":3213},[2978,21480,3223],{"class":2995},[2978,21482,5773],{"class":3195},[2978,21484,3199],{"class":2995},[2978,21486,6316],{"class":3024},[2978,21488,3456],{"class":2995},[2978,21490,6778],{"class":3213},[2978,21492,3456],{"class":2995},[2978,21494,4730],{"class":3180},[2978,21496,4559],{"class":2995},[2978,21498,5792],{"class":3213},[2978,21500,5800],{"class":2995},[2978,21502,21503,21505,21507,21509],{"class":2980,"line":6164},[2978,21504,11580],{"class":3213},[2978,21506,3188],{"class":2995},[2978,21508,6287],{"class":3024},[2978,21510,3013],{"class":2995},[2978,21512,21513,21515,21517],{"class":2980,"line":6200},[2978,21514,20328],{"class":3213},[2978,21516,3188],{"class":2995},[2978,21518,16665],{"class":3024},[2978,21520,21521],{"class":2980,"line":6211},[2978,21522,11590],{"class":2995},[2978,21524,21525,21528,21530,21532],{"class":2980,"line":6223},[2978,21526,21527],{"class":3024},"                \"delete\"",[2978,21529,8325],{"class":2995},[2978,21531,4730],{"class":3180},[2978,21533,5363],{"class":4517},[2978,21535,21536],{"class":2980,"line":6233},[2978,21537,11531],{"class":2995},[2978,21539,21540,21542,21544,21546,21548,21550,21552,21554,21556,21558,21560,21562,21564,21566],{"class":2980,"line":6239},[2978,21541,11537],{"class":3213},[2978,21543,3188],{"class":2995},[2978,21545,11542],{"class":3213},[2978,21547,3223],{"class":2995},[2978,21549,5773],{"class":3195},[2978,21551,3199],{"class":2995},[2978,21553,6415],{"class":3024},[2978,21555,3456],{"class":2995},[2978,21557,6778],{"class":3213},[2978,21559,3456],{"class":2995},[2978,21561,4730],{"class":3180},[2978,21563,4559],{"class":2995},[2978,21565,5792],{"class":3213},[2978,21567,5800],{"class":2995},[2978,21569,21570,21572,21574,21576],{"class":2980,"line":6245},[2978,21571,11580],{"class":3213},[2978,21573,3188],{"class":2995},[2978,21575,6386],{"class":3024},[2978,21577,3013],{"class":2995},[2978,21579,21580,21582,21584],{"class":2980,"line":6250},[2978,21581,20328],{"class":3213},[2978,21583,3188],{"class":2995},[2978,21585,16767],{"class":3024},[2978,21587,21588],{"class":2980,"line":6275},[2978,21589,11590],{"class":2995},[2978,21591,21592,21595,21597],{"class":2980,"line":6280},[2978,21593,21594],{"class":3180},"                _",[2978,21596,8325],{"class":2995},[2978,21598,21599],{"class":3180},"null\n",[2978,21601,21602],{"class":2980,"line":6296},[2978,21603,6236],{"class":2995},[2978,21605,21606],{"class":2980,"line":6301},[2978,21607,3288],{"emptyLinePlaceholder":3287},[2978,21609,21610,21612,21614,21617,21619,21621],{"class":2980,"line":6337},[2978,21611,13738],{"class":3191},[2978,21613,6116],{"class":2995},[2978,21615,21616],{"class":3213},"link",[2978,21618,6259],{"class":2995},[2978,21620,10081],{"class":3180},[2978,21622,5704],{"class":2995},[2978,21624,21625],{"class":2980,"line":6348},[2978,21626,5758],{"class":2995},[2978,21628,21629,21632,21634,21636,21638,21640],{"class":2980,"line":6359},[2978,21630,21631],{"class":3213},"                links",[2978,21633,6148],{"class":2995},[2978,21635,20199],{"class":3213},[2978,21637,5749],{"class":2995},[2978,21639,21616],{"class":3213},[2978,21641,4526],{"class":2995},[2978,21643,21644],{"class":2980,"line":6369},[2978,21645,6094],{"class":2995},[2978,21647,21648],{"class":2980,"line":6374},[2978,21649,6242],{"class":2995},[2978,21651,21652],{"class":2980,"line":6379},[2978,21653,3288],{"emptyLinePlaceholder":3287},[2978,21655,21656,21658,21660],{"class":2980,"line":6395},[2978,21657,6615],{"class":3191},[2978,21659,5717],{"class":3213},[2978,21661,4526],{"class":2995},[2978,21663,21664],{"class":2980,"line":6400},[2978,21665,6625],{"class":2995},[2978,21667,21668],{"class":2980,"line":6436},[2978,21669,3070],{"class":2995},[2964,21671,21672],{},[3074,21673,20375],{},[2968,21675,21677],{"className":4505,"code":21676,"language":4507,"meta":2973,"style":2973},"builder.Services.AddControllers(options =>\n{\n    options.Filters.Add\u003CHateoasFilter>();\n});\n",[2975,21678,21679,21697,21701,21721],{"__ignoreMap":2973},[2978,21680,21681,21683,21685,21687,21689,21691,21693,21695],{"class":2980,"line":2981},[2978,21682,14719],{"class":3213},[2978,21684,3223],{"class":2995},[2978,21686,14724],{"class":3213},[2978,21688,3223],{"class":2995},[2978,21690,14823],{"class":3195},[2978,21692,3199],{"class":2995},[2978,21694,8591],{"class":3213},[2978,21696,10915],{"class":2995},[2978,21698,21699],{"class":2980,"line":2999},[2978,21700,2996],{"class":2995},[2978,21702,21703,21705,21707,21710,21712,21714,21716,21719],{"class":2980,"line":3016},[2978,21704,14745],{"class":3213},[2978,21706,3223],{"class":2995},[2978,21708,21709],{"class":3213},"Filters",[2978,21711,3223],{"class":2995},[2978,21713,11943],{"class":3195},[2978,21715,4707],{"class":2995},[2978,21717,21718],{"class":4517},"HateoasFilter",[2978,21720,8635],{"class":2995},[2978,21722,21723],{"class":2980,"line":3030},[2978,21724,21725],{"class":2995},"});\n",[2964,21727,21728],{},[3074,21729,21730],{},"4. Використання:",[2968,21732,21734],{"className":4505,"code":21733,"language":4507,"meta":2973,"style":2973},"[HttpGet(\"{id:int}\")]\n[Hateoas(\"self\", \"edit\", \"delete\")] // Автоматично додасть links!\npublic async Task\u003CActionResult\u003CArticleDto>> GetById(int id)\n{\n    var article = await _db.Articles.FindAsync(id);\n    if (article is null) return NotFound();\n\n    return Ok(MapToDto(article));\n}\n",[2975,21735,21736,21748,21773,21801,21805,21831,21851,21855,21871],{"__ignoreMap":2973},[2978,21737,21738,21740,21742,21744,21746],{"class":2980,"line":2981},[2978,21739,6148],{"class":2995},[2978,21741,9960],{"class":4517},[2978,21743,3199],{"class":2995},[2978,21745,9965],{"class":3024},[2978,21747,7499],{"class":2995},[2978,21749,21750,21752,21755,21757,21759,21761,21763,21765,21767,21770],{"class":2980,"line":2999},[2978,21751,6148],{"class":2995},[2978,21753,21754],{"class":4517},"Hateoas",[2978,21756,3199],{"class":2995},[2978,21758,3738],{"class":3024},[2978,21760,3456],{"class":2995},[2978,21762,6287],{"class":3024},[2978,21764,3456],{"class":2995},[2978,21766,6386],{"class":3024},[2978,21768,21769],{"class":2995},")] ",[2978,21771,21772],{"class":3174},"// Автоматично додасть links!\n",[2978,21774,21775,21777,21779,21781,21783,21785,21787,21789,21791,21793,21795,21797,21799],{"class":2980,"line":3016},[2978,21776,4535],{"class":3180},[2978,21778,10030],{"class":3180},[2978,21780,10033],{"class":4517},[2978,21782,4707],{"class":2995},[2978,21784,10038],{"class":4517},[2978,21786,4707],{"class":2995},[2978,21788,9993],{"class":4517},[2978,21790,10045],{"class":2995},[2978,21792,10048],{"class":3195},[2978,21794,3199],{"class":2995},[2978,21796,10704],{"class":3180},[2978,21798,10057],{"class":3213},[2978,21800,5704],{"class":2995},[2978,21802,21803],{"class":2980,"line":3030},[2978,21804,2996],{"class":2995},[2978,21806,21807,21809,21811,21813,21815,21817,21819,21821,21823,21825,21827,21829],{"class":2980,"line":3043},[2978,21808,14922],{"class":3180},[2978,21810,3185],{"class":3213},[2978,21812,3188],{"class":2995},[2978,21814,3192],{"class":3180},[2978,21816,9709],{"class":3213},[2978,21818,3223],{"class":2995},[2978,21820,4987],{"class":3213},[2978,21822,3223],{"class":2995},[2978,21824,12285],{"class":3195},[2978,21826,3199],{"class":2995},[2978,21828,5792],{"class":3213},[2978,21830,8474],{"class":2995},[2978,21832,21833,21835,21837,21839,21841,21843,21845,21847,21849],{"class":2980,"line":3056},[2978,21834,16194],{"class":3191},[2978,21836,6116],{"class":2995},[2978,21838,3252],{"class":3213},[2978,21840,10339],{"class":3180},[2978,21842,10342],{"class":3180},[2978,21844,16205],{"class":2995},[2978,21846,16208],{"class":3191},[2978,21848,10351],{"class":3195},[2978,21850,4733],{"class":2995},[2978,21852,21853],{"class":2980,"line":3067},[2978,21854,3288],{"emptyLinePlaceholder":3287},[2978,21856,21857,21859,21861,21863,21865,21867,21869],{"class":2980,"line":3442},[2978,21858,16331],{"class":3191},[2978,21860,10592],{"class":3195},[2978,21862,3199],{"class":2995},[2978,21864,10374],{"class":3195},[2978,21866,3199],{"class":2995},[2978,21868,3252],{"class":3213},[2978,21870,14758],{"class":2995},[2978,21872,21873],{"class":2980,"line":3469},[2978,21874,3070],{"class":2995},[2964,21876,21877],{},[3074,21878,4143],{},[2964,21880,21881,21882,21884,21885,21887],{},"✅ Декларативний підхід",[4152,21883],{},"\n✅ Чистий код контролерів",[4152,21886],{},"\n✅ Консистентність links",[3329,21889,21891],{"id":21890},"завдання-33-hal-browser-integration","Завдання 3.3: HAL Browser Integration",[2964,21893,21894],{},"Створіть endpoint для HAL Browser (інтерактивна документація):",[17327,21896,21897,21902,22376,22381,22387,22588,22593,22649,22653],{"title":17505},[2964,21898,21899],{},[3074,21900,21901],{},"1. Root Endpoint (API Entry Point):",[2968,21903,21905],{"className":4505,"code":21904,"language":4507,"meta":2973,"style":2973},"[ApiController]\n[Route(\"api\")]\npublic class RootController : ControllerBase\n{\n    private readonly IUrlHelper _urlHelper;\n\n    public RootController(IUrlHelperFactory urlHelperFactory, IActionContextAccessor actionContextAccessor)\n    {\n        _urlHelper = urlHelperFactory.GetUrlHelper(actionContextAccessor.ActionContext!);\n    }\n\n    [HttpGet(Name = \"GetRoot\")]\n    public IActionResult GetRoot()\n    {\n        var root = new\n        {\n            _links = new Dictionary\u003Cstring, object>\n            {\n                [\"self\"] = new { href = _urlHelper.Action(\"GetRoot\", \"Root\")! },\n                [\"articles\"] = new\n                {\n                    href = _urlHelper.Action(\"GetAll\", \"Articles\")!,\n                    title = \"Browse articles\"\n                },\n                [\"authors\"] = new\n                {\n                    href = _urlHelper.Action(\"GetAll\", \"Authors\")!,\n                    title = \"Browse authors\"\n                },\n                [\"categories\"] = new\n                {\n                    href = _urlHelper.Action(\"GetAll\", \"Categories\")!,\n                    title = \"Browse categories\"\n                },\n                [\"search\"] = new\n                {\n                    href = \"/api/articles{?category,author,page}\",\n                    templated = true,\n                    title = \"Search articles\"\n                }\n            },\n            version = \"1.0\",\n            description = \"Blog API with HATEOAS support\"\n        };\n\n        return Ok(root);\n    }\n}\n",[2975,21906,21907,21915,21928,21941,21945,21957,21961,21981,21985,22007,22011,22015,22032,22044,22048,22059,22063,22083,22087,22121,22131,22135,22160,22170,22174,22185,22189,22211,22220,22224,22235,22239,22261,22270,22274,22284,22288,22298,22309,22317,22321,22325,22337,22347,22351,22355,22368,22372],{"__ignoreMap":2973},[2978,21908,21909,21911,21913],{"class":2980,"line":2981},[2978,21910,6148],{"class":2995},[2978,21912,9661],{"class":4517},[2978,21914,9664],{"class":2995},[2978,21916,21917,21919,21921,21923,21926],{"class":2980,"line":2999},[2978,21918,6148],{"class":2995},[2978,21920,9671],{"class":4517},[2978,21922,3199],{"class":2995},[2978,21924,21925],{"class":3024},"\"api\"",[2978,21927,7499],{"class":2995},[2978,21929,21930,21932,21934,21937,21939],{"class":2980,"line":3016},[2978,21931,4535],{"class":3180},[2978,21933,4538],{"class":3180},[2978,21935,21936],{"class":4517}," RootController",[2978,21938,8563],{"class":2995},[2978,21940,9692],{"class":4517},[2978,21942,21943],{"class":2980,"line":3030},[2978,21944,2996],{"class":2995},[2978,21946,21947,21949,21951,21953,21955],{"class":2980,"line":3043},[2978,21948,9701],{"class":3180},[2978,21950,9704],{"class":3180},[2978,21952,9741],{"class":4517},[2978,21954,9744],{"class":3213},[2978,21956,4526],{"class":2995},[2978,21958,21959],{"class":2980,"line":3056},[2978,21960,3288],{"emptyLinePlaceholder":3287},[2978,21962,21963,21965,21967,21969,21971,21973,21975,21977,21979],{"class":2980,"line":3067},[2978,21964,4550],{"class":3180},[2978,21966,21936],{"class":3195},[2978,21968,3199],{"class":2995},[2978,21970,14611],{"class":4517},[2978,21972,9792],{"class":3213},[2978,21974,3456],{"class":2995},[2978,21976,14614],{"class":4517},[2978,21978,9802],{"class":3213},[2978,21980,5704],{"class":2995},[2978,21982,21983],{"class":2980,"line":3442},[2978,21984,5709],{"class":2995},[2978,21986,21987,21989,21991,21993,21995,21997,21999,22001,22003,22005],{"class":2980,"line":3469},[2978,21988,9836],{"class":3213},[2978,21990,3188],{"class":2995},[2978,21992,9841],{"class":3213},[2978,21994,3223],{"class":2995},[2978,21996,9846],{"class":3195},[2978,21998,3199],{"class":2995},[2978,22000,9851],{"class":3213},[2978,22002,3223],{"class":2995},[2978,22004,9856],{"class":3213},[2978,22006,9859],{"class":2995},[2978,22008,22009],{"class":2980,"line":3495},[2978,22010,6625],{"class":2995},[2978,22012,22013],{"class":2980,"line":3501},[2978,22014,3288],{"emptyLinePlaceholder":3287},[2978,22016,22017,22019,22021,22023,22025,22027,22030],{"class":2980,"line":3642},[2978,22018,7489],{"class":2995},[2978,22020,9960],{"class":4517},[2978,22022,3199],{"class":2995},[2978,22024,8789],{"class":3213},[2978,22026,3188],{"class":2995},[2978,22028,22029],{"class":3024},"\"GetRoot\"",[2978,22031,7499],{"class":2995},[2978,22033,22034,22036,22039,22042],{"class":2980,"line":3674},[2978,22035,4550],{"class":3180},[2978,22037,22038],{"class":4517}," IActionResult",[2978,22040,22041],{"class":3195}," GetRoot",[2978,22043,13657],{"class":2995},[2978,22045,22046],{"class":2980,"line":3680},[2978,22047,5709],{"class":2995},[2978,22049,22050,22052,22055,22057],{"class":2980,"line":3686},[2978,22051,5714],{"class":3180},[2978,22053,22054],{"class":3213}," root",[2978,22056,3188],{"class":2995},[2978,22058,11089],{"class":3180},[2978,22060,22061],{"class":2980,"line":3699},[2978,22062,5739],{"class":2995},[2978,22064,22065,22067,22069,22071,22073,22075,22077,22079,22081],{"class":2980,"line":4367},[2978,22066,11098],{"class":3213},[2978,22068,3188],{"class":2995},[2978,22070,4730],{"class":3180},[2978,22072,5484],{"class":4517},[2978,22074,4707],{"class":2995},[2978,22076,5489],{"class":3180},[2978,22078,3456],{"class":2995},[2978,22080,10663],{"class":3180},[2978,22082,5734],{"class":2995},[2978,22084,22085],{"class":2980,"line":4825},[2978,22086,5758],{"class":2995},[2978,22088,22089,22091,22093,22095,22097,22099,22101,22103,22105,22107,22109,22111,22113,22115,22118],{"class":2980,"line":4836},[2978,22090,11517],{"class":2995},[2978,22092,3738],{"class":3024},[2978,22094,5749],{"class":2995},[2978,22096,4730],{"class":3180},[2978,22098,4559],{"class":2995},[2978,22100,4407],{"class":3213},[2978,22102,3188],{"class":2995},[2978,22104,11542],{"class":3213},[2978,22106,3223],{"class":2995},[2978,22108,5773],{"class":3195},[2978,22110,3199],{"class":2995},[2978,22112,22029],{"class":3024},[2978,22114,3456],{"class":2995},[2978,22116,22117],{"class":3024},"\"Root\"",[2978,22119,22120],{"class":2995},")! },\n",[2978,22122,22123,22125,22127,22129],{"class":2980,"line":4841},[2978,22124,11517],{"class":2995},[2978,22126,15580],{"class":3024},[2978,22128,5749],{"class":2995},[2978,22130,11089],{"class":3180},[2978,22132,22133],{"class":2980,"line":4849},[2978,22134,11531],{"class":2995},[2978,22136,22137,22140,22142,22144,22146,22148,22150,22153,22155,22157],{"class":2980,"line":4857},[2978,22138,22139],{"class":3213},"                    href",[2978,22141,3188],{"class":2995},[2978,22143,11542],{"class":3213},[2978,22145,3223],{"class":2995},[2978,22147,5773],{"class":3195},[2978,22149,3199],{"class":2995},[2978,22151,22152],{"class":3024},"\"GetAll\"",[2978,22154,3456],{"class":2995},[2978,22156,5783],{"class":3024},[2978,22158,22159],{"class":2995},")!,\n",[2978,22161,22162,22165,22167],{"class":2980,"line":4863},[2978,22163,22164],{"class":3213},"                    title",[2978,22166,3188],{"class":2995},[2978,22168,22169],{"class":3024},"\"Browse articles\"\n",[2978,22171,22172],{"class":2980,"line":4868},[2978,22173,11590],{"class":2995},[2978,22175,22176,22178,22181,22183],{"class":2980,"line":4873},[2978,22177,11517],{"class":2995},[2978,22179,22180],{"class":3024},"\"authors\"",[2978,22182,5749],{"class":2995},[2978,22184,11089],{"class":3180},[2978,22186,22187],{"class":2980,"line":4883},[2978,22188,11531],{"class":2995},[2978,22190,22191,22193,22195,22197,22199,22201,22203,22205,22207,22209],{"class":2980,"line":4888},[2978,22192,22139],{"class":3213},[2978,22194,3188],{"class":2995},[2978,22196,11542],{"class":3213},[2978,22198,3223],{"class":2995},[2978,22200,5773],{"class":3195},[2978,22202,3199],{"class":2995},[2978,22204,22152],{"class":3024},[2978,22206,3456],{"class":2995},[2978,22208,5874],{"class":3024},[2978,22210,22159],{"class":2995},[2978,22212,22213,22215,22217],{"class":2980,"line":4907},[2978,22214,22164],{"class":3213},[2978,22216,3188],{"class":2995},[2978,22218,22219],{"class":3024},"\"Browse authors\"\n",[2978,22221,22222],{"class":2980,"line":4929},[2978,22223,11590],{"class":2995},[2978,22225,22226,22228,22231,22233],{"class":2980,"line":4951},[2978,22227,11517],{"class":2995},[2978,22229,22230],{"class":3024},"\"categories\"",[2978,22232,5749],{"class":2995},[2978,22234,11089],{"class":3180},[2978,22236,22237],{"class":2980,"line":4973},[2978,22238,11531],{"class":2995},[2978,22240,22241,22243,22245,22247,22249,22251,22253,22255,22257,22259],{"class":2980,"line":5004},[2978,22242,22139],{"class":3213},[2978,22244,3188],{"class":2995},[2978,22246,11542],{"class":3213},[2978,22248,3223],{"class":2995},[2978,22250,5773],{"class":3195},[2978,22252,3199],{"class":2995},[2978,22254,22152],{"class":3024},[2978,22256,3456],{"class":2995},[2978,22258,6045],{"class":3024},[2978,22260,22159],{"class":2995},[2978,22262,22263,22265,22267],{"class":2980,"line":5009},[2978,22264,22164],{"class":3213},[2978,22266,3188],{"class":2995},[2978,22268,22269],{"class":3024},"\"Browse categories\"\n",[2978,22271,22272],{"class":2980,"line":5014},[2978,22273,11590],{"class":2995},[2978,22275,22276,22278,22280,22282],{"class":2980,"line":5024},[2978,22277,11517],{"class":2995},[2978,22279,16922],{"class":3024},[2978,22281,5749],{"class":2995},[2978,22283,11089],{"class":3180},[2978,22285,22286],{"class":2980,"line":5029},[2978,22287,11531],{"class":2995},[2978,22289,22290,22292,22294,22296],{"class":2980,"line":5048},[2978,22291,22139],{"class":3213},[2978,22293,3188],{"class":2995},[2978,22295,16942],{"class":3024},[2978,22297,3013],{"class":2995},[2978,22299,22300,22303,22305,22307],{"class":2980,"line":5069},[2978,22301,22302],{"class":3213},"                    templated",[2978,22304,3188],{"class":2995},[2978,22306,10452],{"class":3180},[2978,22308,3013],{"class":2995},[2978,22310,22311,22313,22315],{"class":2980,"line":5091},[2978,22312,22164],{"class":3213},[2978,22314,3188],{"class":2995},[2978,22316,16965],{"class":3024},[2978,22318,22319],{"class":2980,"line":5120},[2978,22320,11664],{"class":2995},[2978,22322,22323],{"class":2980,"line":5125},[2978,22324,5837],{"class":2995},[2978,22326,22327,22330,22332,22335],{"class":2980,"line":5130},[2978,22328,22329],{"class":3213},"            version",[2978,22331,3188],{"class":2995},[2978,22333,22334],{"class":3024},"\"1.0\"",[2978,22336,3013],{"class":2995},[2978,22338,22339,22342,22344],{"class":2980,"line":5140},[2978,22340,22341],{"class":3213},"            description",[2978,22343,3188],{"class":2995},[2978,22345,22346],{"class":3024},"\"Blog API with HATEOAS support\"\n",[2978,22348,22349],{"class":2980,"line":5145},[2978,22350,6099],{"class":2995},[2978,22352,22353],{"class":2980,"line":5164},[2978,22354,3288],{"emptyLinePlaceholder":3287},[2978,22356,22357,22359,22361,22363,22366],{"class":2980,"line":5186},[2978,22358,6615],{"class":3191},[2978,22360,10592],{"class":3195},[2978,22362,3199],{"class":2995},[2978,22364,22365],{"class":3213},"root",[2978,22367,8474],{"class":2995},[2978,22369,22370],{"class":2980,"line":5208},[2978,22371,6625],{"class":2995},[2978,22373,22374],{"class":2980,"line":5228},[2978,22375,3070],{"class":2995},[2964,22377,22378],{},[3074,22379,22380],{},"2. HAL Browser HTML:",[2964,22382,22383,22384,3087],{},"Створіть ",[2975,22385,22386],{},"wwwroot/hal-browser.html",[2968,22388,22392],{"className":22389,"code":22390,"language":22391,"meta":2973,"style":2973},"language-html shiki shiki-themes light-plus dark-plus dark-plus","\u003C!DOCTYPE html>\n\u003Chtml>\n\u003Chead>\n    \u003Ctitle>HAL Browser\u003C/title>\n    \u003Clink rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/hal-browser@latest/hal-browser.css\">\n\u003C/head>\n\u003Cbody>\n    \u003Cdiv id=\"browser\">\u003C/div>\n    \u003Cscript src=\"https://cdn.jsdelivr.net/npm/hal-browser@latest/hal-browser.js\">\u003C/script>\n    \u003Cscript>\n        HALBrowser.browser('/api', document.getElementById('browser'));\n    \u003C/script>\n\u003C/body>\n\u003C/html>\n","html",[2975,22393,22394,22407,22415,22424,22442,22465,22473,22482,22502,22523,22531,22563,22572,22580],{"__ignoreMap":2973},[2978,22395,22396,22399,22402,22405],{"class":2980,"line":2981},[2978,22397,22398],{"class":9875},"\u003C!",[2978,22400,22401],{"class":9878},"DOCTYPE",[2978,22403,22404],{"class":9909}," html",[2978,22406,5734],{"class":9875},[2978,22408,22409,22411,22413],{"class":2980,"line":2999},[2978,22410,4707],{"class":9875},[2978,22412,22391],{"class":9878},[2978,22414,5734],{"class":9875},[2978,22416,22417,22419,22422],{"class":2980,"line":3016},[2978,22418,4707],{"class":9875},[2978,22420,22421],{"class":9878},"head",[2978,22423,5734],{"class":9875},[2978,22425,22426,22429,22431,22433,22436,22438,22440],{"class":2980,"line":3030},[2978,22427,22428],{"class":9875},"    \u003C",[2978,22430,4415],{"class":9878},[2978,22432,9918],{"class":9875},[2978,22434,22435],{"class":2995},"HAL Browser",[2978,22437,9893],{"class":9875},[2978,22439,4415],{"class":9878},[2978,22441,5734],{"class":9875},[2978,22443,22444,22446,22448,22450,22452,22456,22458,22460,22463],{"class":2980,"line":3043},[2978,22445,22428],{"class":9875},[2978,22447,21616],{"class":9878},[2978,22449,19867],{"class":9909},[2978,22451,9913],{"class":2995},[2978,22453,22455],{"class":22454},"su9tN","\"stylesheet\"",[2978,22457,20235],{"class":9909},[2978,22459,9913],{"class":2995},[2978,22461,22462],{"class":22454},"\"https://cdn.jsdelivr.net/npm/hal-browser@latest/hal-browser.css\"",[2978,22464,5734],{"class":9875},[2978,22466,22467,22469,22471],{"class":2980,"line":3056},[2978,22468,9893],{"class":9875},[2978,22470,22421],{"class":9878},[2978,22472,5734],{"class":9875},[2978,22474,22475,22477,22480],{"class":2980,"line":3067},[2978,22476,4707],{"class":9875},[2978,22478,22479],{"class":9878},"body",[2978,22481,5734],{"class":9875},[2978,22483,22484,22486,22488,22490,22492,22495,22498,22500],{"class":2980,"line":3442},[2978,22485,22428],{"class":9875},[2978,22487,4439],{"class":9878},[2978,22489,10057],{"class":9909},[2978,22491,9913],{"class":2995},[2978,22493,22494],{"class":22454},"\"browser\"",[2978,22496,22497],{"class":9875},">\u003C/",[2978,22499,4439],{"class":9878},[2978,22501,5734],{"class":9875},[2978,22503,22504,22506,22509,22512,22514,22517,22519,22521],{"class":2980,"line":3469},[2978,22505,22428],{"class":9875},[2978,22507,22508],{"class":9878},"script",[2978,22510,22511],{"class":9909}," src",[2978,22513,9913],{"class":3255},[2978,22515,22516],{"class":22454},"\"https://cdn.jsdelivr.net/npm/hal-browser@latest/hal-browser.js\"",[2978,22518,22497],{"class":9875},[2978,22520,22508],{"class":9878},[2978,22522,5734],{"class":9875},[2978,22524,22525,22527,22529],{"class":2980,"line":3495},[2978,22526,22428],{"class":9875},[2978,22528,22508],{"class":9878},[2978,22530,5734],{"class":9875},[2978,22532,22533,22536,22538,22541,22543,22546,22548,22551,22553,22556,22558,22561],{"class":2980,"line":3501},[2978,22534,22535],{"class":3213},"        HALBrowser",[2978,22537,3223],{"class":3255},[2978,22539,22540],{"class":3195},"browser",[2978,22542,3199],{"class":3255},[2978,22544,22545],{"class":3024},"'/api'",[2978,22547,3456],{"class":3255},[2978,22549,22550],{"class":3213},"document",[2978,22552,3223],{"class":3255},[2978,22554,22555],{"class":3195},"getElementById",[2978,22557,3199],{"class":3255},[2978,22559,22560],{"class":3024},"'browser'",[2978,22562,14758],{"class":3255},[2978,22564,22565,22568,22570],{"class":2980,"line":3642},[2978,22566,22567],{"class":9875},"    \u003C/",[2978,22569,22508],{"class":9878},[2978,22571,5734],{"class":9875},[2978,22573,22574,22576,22578],{"class":2980,"line":3674},[2978,22575,9893],{"class":9875},[2978,22577,22479],{"class":9878},[2978,22579,5734],{"class":9875},[2978,22581,22582,22584,22586],{"class":2980,"line":3680},[2978,22583,9893],{"class":9875},[2978,22585,22391],{"class":9878},[2978,22587,5734],{"class":9875},[2964,22589,22590],{},[3074,22591,22592],{},"3. Налаштування Program.cs:",[2968,22594,22596],{"className":4505,"code":22595,"language":4507,"meta":2973,"style":2973},"app.UseStaticFiles(); // Для wwwroot\n\napp.MapGet(\"/\", () => Results.Redirect(\"/hal-browser.html\"));\n",[2975,22597,22598,22613,22617],{"__ignoreMap":2973},[2978,22599,22600,22602,22604,22607,22610],{"class":2980,"line":2981},[2978,22601,14902],{"class":3213},[2978,22603,3223],{"class":2995},[2978,22605,22606],{"class":3195},"UseStaticFiles",[2978,22608,22609],{"class":2995},"(); ",[2978,22611,22612],{"class":3174},"// Для wwwroot\n",[2978,22614,22615],{"class":2980,"line":2999},[2978,22616,3288],{"emptyLinePlaceholder":3287},[2978,22618,22619,22621,22623,22626,22628,22631,22634,22637,22639,22642,22644,22647],{"class":2980,"line":3016},[2978,22620,14902],{"class":3213},[2978,22622,3223],{"class":2995},[2978,22624,22625],{"class":3195},"MapGet",[2978,22627,3199],{"class":2995},[2978,22629,22630],{"class":3024},"\"/\"",[2978,22632,22633],{"class":2995},", () => ",[2978,22635,22636],{"class":3213},"Results",[2978,22638,3223],{"class":2995},[2978,22640,22641],{"class":3195},"Redirect",[2978,22643,3199],{"class":2995},[2978,22645,22646],{"class":3024},"\"/hal-browser.html\"",[2978,22648,14758],{"class":2995},[2964,22650,22651],{},[3074,22652,18336],{},[2964,22654,22655,22656,22659],{},"Відкрийте ",[2975,22657,22658],{},"https://localhost:5001/"," → інтерактивний браузер API з можливістю переходу по links.",[3882,22661],{},[2959,22663,22665],{"id":22664},"резюме","Резюме",[2964,22667,22668,22669,3343,22671,22673],{},"У цій статті ви навчилися реалізовувати ",[3074,22670,3342],{},[3074,22672,3346],{}," для Web API:",[3329,22675,22677],{"id":22676},"ключові-концепції","Ключові концепції",[2964,22679,22680],{},[3074,22681,22682],{},"1. Richardson Maturity Model:",[3089,22684,22685,22691,22697,22703],{},[3092,22686,22687,22690],{},[3074,22688,22689],{},"Level 0"," — один endpoint, POST для всього",[3092,22692,22693,22696],{},[3074,22694,22695],{},"Level 1"," — множина ресурсів",[3092,22698,22699,22702],{},[3074,22700,22701],{},"Level 2"," — HTTP verbs (GET, POST, PUT, DELETE)",[3092,22704,22705,22708],{},[3074,22706,22707],{},"Level 3"," — Hypermedia Controls (HATEOAS)",[2964,22710,22711],{},[3074,22712,22713],{},"2. HATEOAS переваги:",[3089,22715,22716,22719,22722,22725],{},[3092,22717,22718],{},"✅ Decoupling — клієнт не хардкодить URL-и",[3092,22720,22721],{},"✅ Evolvability — можна змінювати структуру без ламання клієнтів",[3092,22723,22724],{},"✅ Discoverability — API самодокументується",[3092,22726,22727],{},"✅ Dynamic behavior — сервер контролює доступні дії",[2964,22729,22730],{},[3074,22731,22732],{},"3. HAL (Hypertext Application Language):",[3089,22734,22735,22739,22744],{},[3092,22736,22737,4384],{},[2975,22738,4383],{},[3092,22740,22741,22743],{},[2975,22742,4391],{}," — вбудовані ресурси",[3092,22745,22746,22748],{},[2975,22747,4399],{}," — обов'язкове посилання на ресурс",[2964,22750,22751],{},[3074,22752,22753],{},"4. Resource Expansion:",[3089,22755,22756,22759,22765],{},[3092,22757,22758],{},"Зменшує кількість HTTP-запитів",[3092,22760,22761,22764],{},[2975,22762,22763],{},"?expand=author,comments"," — вбудовує пов'язані ресурси",[3092,22766,22767],{},"Потребує eager loading для продуктивності",[2964,22769,22770],{},[3074,22771,22772],{},"5. Sparse Fieldsets:",[3089,22774,22775,22781,22784],{},[3092,22776,22777,22780],{},[2975,22778,22779],{},"?fields=id,title,author"," — повертає тільки вказані поля",[3092,22782,22783],{},"Зменшує розмір payload",[3092,22785,22786],{},"Оптимізує мобільні додатки",[3329,22788,22790],{"id":22789},"коли-використовувати-hateoas","Коли використовувати HATEOAS",[22792,22793,22794,22807],"table",{},[22795,22796,22797],"thead",{},[22798,22799,22800,22804],"tr",{},[22801,22802,22803],"th",{},"Сценарій",[22801,22805,22806],{},"Рекомендація",[22808,22809,22810,22819,22826,22833,22841,22849],"tbody",{},[22798,22811,22812,22816],{},[22813,22814,22815],"td",{},"Публічний API для сторонніх розробників",[22813,22817,22818],{},"✅ Так",[22798,22820,22821,22824],{},[22813,22822,22823],{},"Складний workflow з багатьма станами",[22813,22825,22818],{},[22798,22827,22828,22831],{},[22813,22829,22830],{},"API що часто змінюється",[22813,22832,22818],{},[22798,22834,22835,22838],{},[22813,22836,22837],{},"Простий CRUD API",[22813,22839,22840],{},"❌ Overkill",[22798,22842,22843,22846],{},[22813,22844,22845],{},"Internal API з одним клієнтом",[22813,22847,22848],{},"❌ Не обов'язково",[22798,22850,22851,22854],{},[22813,22852,22853],{},"Mobile-first API (розмір payload критичний)",[22813,22855,22856],{},"⚠️ З обережністю",[3329,22858,22860],{"id":22859},"best-practices","Best Practices",[2964,22862,4146,22863,22868,4154,22870,22873,22874,4154,22876,22879,22880,4154,22882,22885,22886,4154,22888,22891,4154,22893,22898,22899,4154,22901,22904],{},[3074,22864,22865,22866,21365],{},"Завжди включайте ",[2975,22867,4399],{},[4152,22869],{},[3074,22871,22872],{},"Використовуйте conditional links"," (залежно від прав та стану)",[4152,22875],{},[3074,22877,22878],{},"Документуйте rel types"," (через curies або окрему документацію)",[4152,22881],{},[3074,22883,22884],{},"Обмежуйте глибину expansion"," (max 2-3 рівні)",[4152,22887],{},[3074,22889,22890],{},"Кешуйте згенеровані links",[4152,22892],{},[3074,22894,22895,22896],{},"Використовуйте ",[2975,22897,7214],{}," замість хардкоду URL-ів",[4152,22900],{},[3074,22902,22903],{},"Тестуйте links"," (перевіряйте, що всі URL-и валідні)",[4125,22906,22907,22912],{},[2964,22908,22909],{},[3074,22910,22911],{},"Production Checklist:",[3089,22913,22914,22917,22920,22923,22926,22929],{},[3092,22915,22916],{},"✅ Conditional links based on permissions",[3092,22918,22919],{},"✅ Expansion depth limit (max 2-3)",[3092,22921,22922],{},"✅ Sparse fieldsets для оптимізації",[3092,22924,22925],{},"✅ Кешування згенерованих links",[3092,22927,22928],{},"✅ Документація rel types",[3092,22930,22931],{},"✅ HAL Browser для розробників",[3882,22933],{},[2959,22935,22937],{"id":22936},"додаткові-ресурси","Додаткові ресурси",[22939,22940,22941,22952,22960,22969],"card-group",{},[22942,22943,22946],"card",{"icon":22944,"title":22945},"i-heroicons-book-open","HAL Specification",[10185,22947,22951],{"href":22948,"rel":22949},"https://stateless.group/hal_specification.html",[22950],"nofollow","HAL - Hypertext Application Language",[22942,22953,22955],{"icon":22954,"title":3891},"i-heroicons-chart-bar",[10185,22956,22959],{"href":22957,"rel":22958},"https://martinfowler.com/articles/richardsonMaturityModel.html",[22950],"Martin Fowler - Richardson Maturity Model",[22942,22961,22964],{"icon":22962,"title":22963},"i-heroicons-document-text","RFC 6570",[10185,22965,22968],{"href":22966,"rel":22967},"https://datatracker.ietf.org/doc/html/rfc6570",[22950],"URI Template Specification",[22942,22970,22973],{"icon":22971,"title":22972},"i-heroicons-light-bulb","REST API Best Practices",[10185,22974,22977],{"href":22975,"rel":22976},"https://github.com/microsoft/api-guidelines/blob/vNext/Guidelines.md",[22950],"Microsoft REST API Guidelines",[3882,22979],{},[3322,22981,22983,4447,22986,22989],{"icon":22982},"i-heroicons-arrow-right",[3074,22984,22985],{},"Наступна стаття:",[10185,22987,22988],{"href":1328},"Гібридна архітектура: Minimal API + Controllers"," — як комбінувати Minimal API та Controllers у одному проєкті, vertical slice architecture, feature folders та Carter library.",[22991,22992,22993],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sHH4Y, html code.shiki .sHH4Y{--shiki-light:#000000;--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .sLwNe, html code.shiki .sLwNe{--shiki-light:#0451A5;--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}html pre.shiki code .sJj4R, html code.shiki .sJj4R{--shiki-light:#098658;--shiki-default:#B5CEA8;--shiki-dark:#B5CEA8}html pre.shiki code .sbdoH, html code.shiki .sbdoH{--shiki-light:#A31515;--shiki-default:#CE9178;--shiki-dark:#CE9178}html pre.shiki code .spJ8K, html code.shiki .spJ8K{--shiki-light:#008000;--shiki-default:#6A9955;--shiki-dark:#6A9955}html pre.shiki code .su1O8, html code.shiki .su1O8{--shiki-light:#0000FF;--shiki-default:#569CD6;--shiki-dark:#569CD6}html pre.shiki code .s-QsJ, html code.shiki .s-QsJ{--shiki-light:#0070C1;--shiki-default:#4FC1FF;--shiki-dark:#4FC1FF}html pre.shiki code .sCDza, html code.shiki .sCDza{--shiki-light:#AF00DB;--shiki-default:#CE92A4;--shiki-dark:#CE92A4}html pre.shiki code .s8Opu, html code.shiki .s8Opu{--shiki-light:#795E26;--shiki-default:#DCDCAA;--shiki-dark:#DCDCAA}html pre.shiki code .siwwj, html code.shiki .siwwj{--shiki-light:#001080;--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}html pre.shiki code .sD7JJ, html code.shiki .sD7JJ{--shiki-light:#000000FF;--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .se1LK, html code.shiki .se1LK{--shiki-light:#CD3131;--shiki-default:#F44747;--shiki-dark:#F44747}html pre.shiki code .sN1BT, html code.shiki .sN1BT{--shiki-light:#267F99;--shiki-default:#4EC9B0;--shiki-dark:#4EC9B0}html pre.shiki code .s0P7L, html code.shiki .s0P7L{--shiki-light:#800000;--shiki-default:#808080;--shiki-dark:#808080}html pre.shiki code .sKtos, html code.shiki .sKtos{--shiki-light:#800000;--shiki-default:#569CD6;--shiki-dark:#569CD6}html pre.shiki code .sa4r_, html code.shiki .sa4r_{--shiki-light:#E50000;--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}html pre.shiki code .su9tN, html code.shiki .su9tN{--shiki-light:#0000FF;--shiki-default:#CE9178;--shiki-dark:#CE9178}",{"title":2973,"searchDepth":2999,"depth":2999,"links":22995},[22996,22999,23004,23016,23022,23035,23040],{"id":2961,"depth":2999,"text":2962,"children":22997},[22998],{"id":3331,"depth":3016,"text":3332},{"id":3886,"depth":2999,"text":3887,"children":23000},[23001,23002,23003],{"id":3890,"depth":3016,"text":3891},{"id":4137,"depth":3016,"text":4138},{"id":4210,"depth":3016,"text":4211},{"id":4421,"depth":2999,"text":4422,"children":23005},[23006,23007,23008,23009,23010,23011,23012,23013,23014,23015],{"id":4425,"depth":3016,"text":4426},{"id":4432,"depth":3016,"text":4433},{"id":4495,"depth":3016,"text":4496},{"id":5322,"depth":3016,"text":5323},{"id":7248,"depth":3016,"text":7249},{"id":8108,"depth":3016,"text":8109},{"id":8494,"depth":3016,"text":8495},{"id":9542,"depth":3016,"text":9543},{"id":14647,"depth":3016,"text":14648},{"id":15090,"depth":3016,"text":15091},{"id":15601,"depth":2999,"text":15602,"children":23017},[23018,23019,23020,23021],{"id":15605,"depth":3016,"text":15606},{"id":16406,"depth":3016,"text":16407},{"id":16903,"depth":3016,"text":16904},{"id":17049,"depth":3016,"text":17050},{"id":17180,"depth":2999,"text":17181,"children":23023},[23024,23025,23026,23027,23028,23029,23030,23031,23032,23033,23034],{"id":17184,"depth":3016,"text":17185},{"id":17190,"depth":3016,"text":17191},{"id":17351,"depth":3016,"text":17352},{"id":17489,"depth":3016,"text":17490},{"id":17495,"depth":3016,"text":17496},{"id":18475,"depth":3016,"text":18476},{"id":19142,"depth":3016,"text":19143},{"id":19800,"depth":3016,"text":19801},{"id":19806,"depth":3016,"text":19807},{"id":20778,"depth":3016,"text":20779},{"id":21890,"depth":3016,"text":21891},{"id":22664,"depth":2999,"text":22665,"children":23036},[23037,23038,23039],{"id":22676,"depth":3016,"text":22677},{"id":22789,"depth":3016,"text":22790},{"id":22859,"depth":3016,"text":22860},{"id":22936,"depth":2999,"text":22937},"Hypermedia as the Engine of Application State, Richardson Maturity Model, HAL формат, LinkGenerator в ASP.NET Core, resource expansion через ?expand=author,comments, sparse fieldsets та self-discoverable API.","md",null,{},{"title":1323,"description":23041},"64nAL6ND9JIwAP3y805f15WCJzYvKCbXNo38-YxkAN0",[23048,23050],{"title":1319,"path":1320,"stem":1321,"description":23049,"children":-1},"Практична реалізація PagedList\u003CT>, query-based фільтрація через DTO, dynamic сортування, X-Pagination headers, HATEOAS links та cursor-based пагінація для великих датасетів.",{"title":1327,"path":1328,"stem":1329,"description":23051,"children":-1},"Комбінування Minimal API та Controllers у одному проєкті, vertical slice architecture, feature folders замість шарів, Carter library для організації endpoints, стратегії розподілу відповідальності.",1777912429660]