[{"data":1,"prerenderedAt":23024},["ShallowReactive",2],{"navigation_docs":3,"-aws-lambda":3338,"-aws-lambda-surround":23019},[4,1707,1904,2358,2539,2608,2815,2937,2987,3044,3078,3204,3281,3334],{"title":5,"icon":6,"path":7,"stem":8,"children":9},"C#","i-devicon-csharp","\u002Fcsharp","01.csharp",[10,13,60,90,120,202,219,253,379,404,457,650,1364,1654,1703],{"title":11,"path":7,"stem":12},"C# та .NET","01.csharp\u002Findex",{"title":14,"icon":15,"path":16,"stem":17,"children":18,"page":59},"Fundamentals","i-lucide-book-open","\u002Fcsharp\u002Ffundamentals","01.csharp\u002F01.fundamentals",[19,23,27,31,35,39,43,47,51,55],{"title":20,"path":21,"stem":22},"Вступ до екосистеми .NET","\u002Fcsharp\u002Ffundamentals\u002Fintroduction-to-ecosystem","01.csharp\u002F01.fundamentals\u002F01.introduction-to-ecosystem",{"title":24,"path":25,"stem":26},"Структура програми на C#","\u002Fcsharp\u002Ffundamentals\u002Fprogram-structure","01.csharp\u002F01.fundamentals\u002F02.program-structure",{"title":28,"path":29,"stem":30},"Змінні та Типи Даних","\u002Fcsharp\u002Ffundamentals\u002Fvariables-data-types","01.csharp\u002F01.fundamentals\u002F03.variables-data-types",{"title":32,"path":33,"stem":34},"Масиви","\u002Fcsharp\u002Ffundamentals\u002Farrays","01.csharp\u002F01.fundamentals\u002F04.arrays",{"title":36,"path":37,"stem":38},"Strings & Text Handling","\u002Fcsharp\u002Ffundamentals\u002Fstrings-text-handling","01.csharp\u002F01.fundamentals\u002F05.strings-text-handling",{"title":40,"path":41,"stem":42},"Дати і Час","\u002Fcsharp\u002Ffundamentals\u002Fdates-time-handling","01.csharp\u002F01.fundamentals\u002F06.dates-time-handling",{"title":44,"path":45,"stem":46},"Потік Керування","\u002Fcsharp\u002Ffundamentals\u002Fcontrol-flow","01.csharp\u002F01.fundamentals\u002F07.control-flow",{"title":48,"path":49,"stem":50},"Методи","\u002Fcsharp\u002Ffundamentals\u002Fmethods","01.csharp\u002F01.fundamentals\u002F08.methods",{"title":52,"path":53,"stem":54},"Основи Відлагодження","\u002Fcsharp\u002Ffundamentals\u002Fdebugging-basics","01.csharp\u002F01.fundamentals\u002F09.debugging-basics",{"title":56,"path":57,"stem":58},"Інтерактивна Консоль (Classic)","\u002Fcsharp\u002Ffundamentals\u002Finteractive-console","01.csharp\u002F01.fundamentals\u002F10.interactive-console",false,{"title":61,"icon":62,"path":63,"stem":64,"children":65,"page":59},"OOP","i-lucide-box","\u002Fcsharp\u002Foop","01.csharp\u002F02.oop",[66,70,74,78,82,86],{"title":67,"path":68,"stem":69},"Package Management (Управління Пакетами)","\u002Fcsharp\u002Foop\u002Fpackage-management","01.csharp\u002F02.oop\u002F01.package-management",{"title":71,"path":72,"stem":73},"Класи та Об'єкти","\u002Fcsharp\u002Foop\u002Fclasses-objects","01.csharp\u002F02.oop\u002F02.classes-objects",{"title":75,"path":76,"stem":77},"Властивості та Поля","\u002Fcsharp\u002Foop\u002Fproperties-fields","01.csharp\u002F02.oop\u002F03.properties-fields",{"title":79,"path":80,"stem":81},"Стовпи ООП","\u002Fcsharp\u002Foop\u002Foop-pillars","01.csharp\u002F02.oop\u002F04.oop-pillars",{"title":83,"path":84,"stem":85},"Advanced Types","\u002Fcsharp\u002Foop\u002Fadvanced-types","01.csharp\u002F02.oop\u002F05.advanced-types",{"title":87,"path":88,"stem":89},"Namespaces (Простори Імен)","\u002Fcsharp\u002Foop\u002Fnamespaces","01.csharp\u002F02.oop\u002F06.namespaces",{"title":91,"icon":92,"path":93,"stem":94,"children":95,"page":59},"Advanced Core","i-lucide-zap","\u002Fcsharp\u002Fadvanced-core","01.csharp\u002F03.advanced-core",[96,100,104,108,112,116],{"title":97,"path":98,"stem":99},"Generics (Узагальнення)","\u002Fcsharp\u002Fadvanced-core\u002Fgenerics","01.csharp\u002F03.advanced-core\u002F01.generics",{"title":101,"path":102,"stem":103},"Делегати, Події та Лямбда-вирази","\u002Fcsharp\u002Fadvanced-core\u002Fdelegates-events-lambdas","01.csharp\u002F03.advanced-core\u002F02.delegates-events-lambdas",{"title":105,"path":106,"stem":107},"Interfaces Deep Dive (Інтерфейси: Поглиблений Розгляд)","\u002Fcsharp\u002Fadvanced-core\u002Finterfaces-deep-dive","01.csharp\u002F03.advanced-core\u002F03.interfaces-deep-dive",{"title":109,"path":110,"stem":111},"Обробка Винятків","\u002Fcsharp\u002Fadvanced-core\u002Fexception-handling","01.csharp\u002F03.advanced-core\u002F04.exception-handling",{"title":113,"path":114,"stem":115},"Pattern Matching","\u002Fcsharp\u002Fadvanced-core\u002Fpattern-matching","01.csharp\u002F03.advanced-core\u002F05.pattern-matching",{"title":117,"path":118,"stem":119},"Додаткові Можливості C#","\u002Fcsharp\u002Fadvanced-core\u002Fadditional-features","01.csharp\u002F03.advanced-core\u002F06.additional-features",{"title":121,"icon":122,"path":123,"stem":124,"children":125,"page":59},"Architecture Best Practices","i-lucide-building-2","\u002Fcsharp\u002Farchitecture-best-practices","01.csharp\u002F04.architecture-best-practices",[126,130,149,153,157,161,165,169],{"title":127,"path":128,"stem":129},"Software Design Principles (Частина 1)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fsoftware-design-principles","01.csharp\u002F04.architecture-best-practices\u002F01.software-design-principles",{"title":131,"icon":132,"path":133,"stem":134,"children":135,"page":59},"Design Patterns","i-lucide-folder","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns",[136],{"title":137,"icon":132,"path":138,"stem":139,"children":140,"page":59},"Creational","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational",[141,145],{"title":142,"path":143,"stem":144},"Singleton (Одинак)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational\u002Fsingleton","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational\u002F01.singleton",{"title":146,"path":147,"stem":148},"Builder (Будівельник)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational\u002Fbuilder","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational\u002F02.builder",{"title":150,"path":151,"stem":152},"Building Professional CLIs","\u002Fcsharp\u002Farchitecture-best-practices\u002Fbuilding-professional-clis","01.csharp\u002F04.architecture-best-practices\u002F03.building-professional-clis",{"title":154,"path":155,"stem":156},"Validation & Flow Control","\u002Fcsharp\u002Farchitecture-best-practices\u002Fvalidation-flow-control","01.csharp\u002F04.architecture-best-practices\u002F04.validation-flow-control",{"title":158,"path":159,"stem":160},"The Modern .NET Host (Microsoft.Extensions)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fmodern-dotnet-host","01.csharp\u002F04.architecture-best-practices\u002F05.modern-dotnet-host",{"title":162,"path":163,"stem":164},"Data Mapper: Repository та DAO патерни (Частина 1)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdata-mapper-part1","01.csharp\u002F04.architecture-best-practices\u002F06.data-mapper-part1",{"title":166,"path":167,"stem":168},"Data Mapper: Repository та DAO патерни (Частина 2)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdata-mapper-part2","01.csharp\u002F04.architecture-best-practices\u002F07.data-mapper-part2",{"title":170,"icon":132,"path":171,"stem":172,"children":173,"page":59},"Di Ioc","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc",[174,178,182,186,190,194,198],{"title":175,"path":176,"stem":177},"Проблема залежностей та Інверсія Контролю","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fthe-dependency-problem","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F01.the-dependency-problem",{"title":179,"path":180,"stem":181},"Будуємо власний Service Container","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fbuild-your-own-container","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F02.build-your-own-container",{"title":183,"path":184,"stem":185},"Service Locator: Паттерн та Анти-паттерн","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fservice-locator-pattern","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F03.service-locator-pattern",{"title":187,"path":188,"stem":189},"Паттерни Dependency Injection","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fdependency-injection-patterns","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F04.dependency-injection-patterns",{"title":191,"path":192,"stem":193},"Microsoft DI: IServiceCollection та IServiceProvider","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fmicrosoft-di-deep-dive","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F05.microsoft-di-deep-dive",{"title":195,"path":196,"stem":197},"Service Lifetimes та Scopes","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fservice-lifetimes-and-scopes","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F06.service-lifetimes-and-scopes",{"title":199,"path":200,"stem":201},"DI Анти-паттерни та Найкращі Практики","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fdi-anti-patterns-and-best-practices","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F07.di-anti-patterns-and-best-practices",{"title":203,"icon":132,"path":204,"stem":205,"children":206,"page":59},"Standard Library","\u002Fcsharp\u002Fstandard-library","01.csharp\u002F05.standard-library",[207,211,215],{"title":208,"path":209,"stem":210},"Collections (Колекції)","\u002Fcsharp\u002Fstandard-library\u002Fcollections","01.csharp\u002F05.standard-library\u002F01.collections",{"title":212,"path":213,"stem":214},"High Performance Types (Високопродуктивні Типи)","\u002Fcsharp\u002Fstandard-library\u002Fhigh-performance-types","01.csharp\u002F05.standard-library\u002F02.high-performance-types",{"title":216,"path":217,"stem":218},"LINQ (Language Integrated Query)","\u002Fcsharp\u002Fstandard-library\u002Flinq","01.csharp\u002F05.standard-library\u002F03.linq",{"title":220,"icon":221,"path":222,"stem":223,"children":224,"page":59},"System Internals Concurrency","i-lucide-server","\u002Fcsharp\u002Fsystem-internals-concurrency","01.csharp\u002F06.system-internals-concurrency",[225,229,233,237,241,245,249],{"title":226,"path":227,"stem":228},"Memory Management","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fmemory-management","01.csharp\u002F06.system-internals-concurrency\u002F01.memory-management",{"title":230,"path":231,"stem":232},"Reflection API: System.Type та Метадані","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Freflection-fundamentals","01.csharp\u002F06.system-internals-concurrency\u002F02.reflection-fundamentals",{"title":234,"path":235,"stem":236},"Attributes та Dynamic Language Runtime","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fattributes-dynamic","01.csharp\u002F06.system-internals-concurrency\u002F03.attributes-dynamic",{"title":238,"path":239,"stem":240},"Expression Trees: Швидка Альтернатива Рефлексії","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fexpression-trees-compiled","01.csharp\u002F06.system-internals-concurrency\u002F04.expression-trees-compiled",{"title":242,"path":243,"stem":244},"Source Generators: Compile-Time Code Generation","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fsource-generators","01.csharp\u002F06.system-internals-concurrency\u002F05.source-generators",{"title":246,"path":247,"stem":248},"Multithreading Fundamentals","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fmultithreading-fundamentals","01.csharp\u002F06.system-internals-concurrency\u002F06.multithreading-fundamentals",{"title":250,"path":251,"stem":252},"Synchronization Primitives","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fsynchronization-primitives","01.csharp\u002F06.system-internals-concurrency\u002F07.synchronization-primitives",{"title":254,"icon":255,"path":256,"stem":257,"children":258,"page":59},"System Programming Windows","i-lucide-cpu","\u002Fcsharp\u002Fsystem-programming-windows","01.csharp\u002F07.system-programming-windows",[259,263,267,271,275,279,283,287,291,295,299,303,307,311,315,319,323,327,331,335,339,343,347,351,355,359,363,367,371,375],{"title":260,"path":261,"stem":262},"Як Працює Операційна Система","\u002Fcsharp\u002Fsystem-programming-windows\u002Fhow-os-works","01.csharp\u002F07.system-programming-windows\u002F01.how-os-works",{"title":264,"path":265,"stem":266},"Процеси в .NET — API та Запуск","\u002Fcsharp\u002Fsystem-programming-windows\u002Fprocesses-in-dotnet","01.csharp\u002F07.system-programming-windows\u002F02.processes-in-dotnet",{"title":268,"path":269,"stem":270},"Процеси в .NET — IPC та Міжпроцесна Комунікація","\u002Fcsharp\u002Fsystem-programming-windows\u002F02a.processes-ipc","01.csharp\u002F07.system-programming-windows\u002F02a.processes-ipc",{"title":272,"path":273,"stem":274},"Application Domains та Збірки — AppDomain і AssemblyLoadContext","\u002Fcsharp\u002Fsystem-programming-windows\u002Fappdomains-assemblies","01.csharp\u002F07.system-programming-windows\u002F03.appdomains-assemblies",{"title":276,"path":277,"stem":278},"Application Domains та Збірки — Plug-in Система з Hot-Reload","\u002Fcsharp\u002Fsystem-programming-windows\u002F03a.appdomains-plugin-system","01.csharp\u002F07.system-programming-windows\u002F03a.appdomains-plugin-system",{"title":280,"path":281,"stem":282},"Потоки — Основи та API Thread","\u002Fcsharp\u002Fsystem-programming-windows\u002Fthread-fundamentals","01.csharp\u002F07.system-programming-windows\u002F04.thread-fundamentals",{"title":284,"path":285,"stem":286},"Потоки — Lifecycle, Пріоритети та Безпечне Завершення","\u002Fcsharp\u002Fsystem-programming-windows\u002F04a.thread-lifecycle-priorities","01.csharp\u002F07.system-programming-windows\u002F04a.thread-lifecycle-priorities",{"title":288,"path":289,"stem":290},"Проблеми Спільного Стану — Race Condition та Data Race","\u002Fcsharp\u002Fsystem-programming-windows\u002Fshared-state-problems","01.csharp\u002F07.system-programming-windows\u002F05.shared-state-problems",{"title":292,"path":293,"stem":294},"Проблеми Спільного Стану — Memory Model та volatile","\u002Fcsharp\u002Fsystem-programming-windows\u002F05a.shared-state-memory-model","01.csharp\u002F07.system-programming-windows\u002F05a.shared-state-memory-model",{"title":296,"path":297,"stem":298},"Синхронізація — Monitor, lock та еволюція примітивів","\u002Fcsharp\u002Fsystem-programming-windows\u002Fsynchronization-fundamentals","01.csharp\u002F07.system-programming-windows\u002F06.synchronization-fundamentals",{"title":300,"path":301,"stem":302},"Синхронізація — Наскрізний Приклад та Deadlock Detection","\u002Fcsharp\u002Fsystem-programming-windows\u002F06a.synchronization-walkthrough","01.csharp\u002F07.system-programming-windows\u002F06a.synchronization-walkthrough",{"title":304,"path":305,"stem":306},"Синхронізація — Mutex, Semaphore та Event-Based Primitives","\u002Fcsharp\u002Fsystem-programming-windows\u002Fsynchronization-advanced","01.csharp\u002F07.system-programming-windows\u002F07.synchronization-advanced",{"title":308,"path":309,"stem":310},"Синхронізація — Interlocked, Volatile та Lock-Free Структури","\u002Fcsharp\u002Fsystem-programming-windows\u002F07a.synchronization-advanced-walkthrough","01.csharp\u002F07.system-programming-windows\u002F07a.synchronization-advanced-walkthrough",{"title":312,"path":313,"stem":314},"Interlocked, CAS та Lock-Free Структури","\u002Fcsharp\u002Fsystem-programming-windows\u002Finterlocked-cas-lockfree","01.csharp\u002F07.system-programming-windows\u002F08.interlocked-cas-lockfree",{"title":316,"path":317,"stem":318},"Volatile, Memory Model та Spinning","\u002Fcsharp\u002Fsystem-programming-windows\u002F08a.volatile-memory-model","01.csharp\u002F07.system-programming-windows\u002F08a.volatile-memory-model",{"title":320,"path":321,"stem":322},"ThreadPool — Пул Потоків для Ефективного Виконання","\u002Fcsharp\u002Fsystem-programming-windows\u002Fthread-pool","01.csharp\u002F07.system-programming-windows\u002F09.thread-pool",{"title":324,"path":325,"stem":326},"ThreadPool — Просунуті Сценарії та Внутрішня Будова","\u002Fcsharp\u002Fsystem-programming-windows\u002F09a.thread-pool-advanced","01.csharp\u002F07.system-programming-windows\u002F09a.thread-pool-advanced",{"title":328,"path":329,"stem":330},"Concurrent та Immutable Collections","\u002Fcsharp\u002Fsystem-programming-windows\u002Fconcurrent-collections","01.csharp\u002F07.system-programming-windows\u002F10.concurrent-collections",{"title":332,"path":333,"stem":334},"TPL, Task та Композиція — Від Thread до Task","\u002Fcsharp\u002Fsystem-programming-windows\u002Ftpl-parallel-plinq","01.csharp\u002F07.system-programming-windows\u002F11.tpl-parallel-plinq",{"title":336,"path":337,"stem":338},"Parallel Class та PLINQ — Data Parallelism","\u002Fcsharp\u002Fsystem-programming-windows\u002F11a.tpl-parallel-plinq-advanced","01.csharp\u002F07.system-programming-windows\u002F11a.tpl-parallel-plinq-advanced",{"title":340,"path":341,"stem":342},"Async\u002FAwait — Фундамент Асинхронного Програмування","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-fundamentals","01.csharp\u002F07.system-programming-windows\u002F12.async-fundamentals",{"title":344,"path":345,"stem":346},"SynchronizationContext та ConfigureAwait — Контекст Виконання","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-context-configureawait","01.csharp\u002F07.system-programming-windows\u002F13.async-context-configureawait",{"title":348,"path":349,"stem":350},"Async — Просунуті Паттерни","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-advanced","01.csharp\u002F07.system-programming-windows\u002F14.async-advanced",{"title":352,"path":353,"stem":354},"System.Threading.Channels — Async Producer-Consumer","\u002Fcsharp\u002Fsystem-programming-windows\u002Fchannels","01.csharp\u002F07.system-programming-windows\u002F15.channels",{"title":356,"path":357,"stem":358},"Асинхронна Синхронізація","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-synchronization","01.csharp\u002F07.system-programming-windows\u002F16.async-synchronization",{"title":360,"path":361,"stem":362},"Unsafe Code та Вказівники","\u002Fcsharp\u002Fsystem-programming-windows\u002Funsafe-code","01.csharp\u002F07.system-programming-windows\u002F17.unsafe-code",{"title":364,"path":365,"stem":366},"P\u002FInvoke та Windows API — Міст між .NET та Native Code","\u002Fcsharp\u002Fsystem-programming-windows\u002Fpinvoke-winapi","01.csharp\u002F07.system-programming-windows\u002F18.pinvoke-winapi",{"title":368,"path":369,"stem":370},"Реєстр Windows — Центральна База Конфігурації Системи","\u002Fcsharp\u002Fsystem-programming-windows\u002Fwindows-registry","01.csharp\u002F07.system-programming-windows\u002F19.windows-registry",{"title":372,"path":373,"stem":374},"Windows Hooks, Hotkeys та Services — Глибока Інтеграція з ОС","\u002Fcsharp\u002Fsystem-programming-windows\u002Fwindows-hooks-services","01.csharp\u002F07.system-programming-windows\u002F20.windows-hooks-services",{"title":376,"path":377,"stem":378},"Системне Програмування C# (Windows) — 07.system-programming-windows","\u002Fcsharp\u002Fsystem-programming-windows\u002Fimplementation_plan","01.csharp\u002F07.system-programming-windows\u002Fimplementation_plan",{"title":380,"icon":132,"path":381,"stem":382,"children":383,"page":59},"Io","\u002Fcsharp\u002Fio","01.csharp\u002F08.io",[384,388,392,396,400],{"title":385,"path":386,"stem":387},"8.1.1. Основи роботи з файловою системою","\u002Fcsharp\u002Fio\u002Ffile-system-basics","01.csharp\u002F08.io\u002F01.file-system-basics",{"title":389,"path":390,"stem":391},"8.1.2. Потоки (Streams) та Серіалізація Даних","\u002Fcsharp\u002Fio\u002Fstreams-serialization","01.csharp\u002F08.io\u002F02.streams-serialization",{"title":393,"path":394,"stem":395},"8.2.1. JSON Serialization з System.Text.Json","\u002Fcsharp\u002Fio\u002Fjson-serialization","01.csharp\u002F08.io\u002F03.json-serialization",{"title":397,"path":398,"stem":399},"8.2.2. XML Serialization та LINQ to XML","\u002Fcsharp\u002Fio\u002Fxml-serialization","01.csharp\u002F08.io\u002F04.xml-serialization",{"title":401,"path":402,"stem":403},"8.2.3. Binary Serialization: MessagePack та Protocol Buffers","\u002Fcsharp\u002Fio\u002Fbinary-serialization","01.csharp\u002F08.io\u002F05.binary-serialization",{"title":405,"icon":132,"path":406,"stem":407,"children":408,"page":59},"Ado Net","\u002Fcsharp\u002Fado-net","01.csharp\u002F09.ado-net",[409,413,417,421,425,429,433,437,441,445,449,453],{"title":410,"path":411,"stem":412},"9.1. Введення в ADO.NET","\u002Fcsharp\u002Fado-net\u002Fintroduction-to-adonet","01.csharp\u002F09.ado-net\u002F01.introduction-to-adonet",{"title":414,"path":415,"stem":416},"9.2. Клас DbConnection — з'єднання з базою даних","\u002Fcsharp\u002Fado-net\u002Fconnection","01.csharp\u002F09.ado-net\u002F02.connection",{"title":418,"path":419,"stem":420},"9.3. Клас DbCommand — виконання SQL-запитів","\u002Fcsharp\u002Fado-net\u002Fcommand-and-queries","01.csharp\u002F09.ado-net\u002F03.command-and-queries",{"title":422,"path":423,"stem":424},"9.4. Клас DbDataReader — ефективне читання даних","\u002Fcsharp\u002Fado-net\u002Fdatareader","01.csharp\u002F09.ado-net\u002F04.datareader",{"title":426,"path":427,"stem":428},"9.5. Параметризовані запити та захист від SQL Injection","\u002Fcsharp\u002Fado-net\u002Fparameters-and-sql-injection","01.csharp\u002F09.ado-net\u002F05.parameters-and-sql-injection",{"title":430,"path":431,"stem":432},"9.6. Транзакції в ADO.NET","\u002Fcsharp\u002Fado-net\u002Ftransactions","01.csharp\u002F09.ado-net\u002F06.transactions",{"title":434,"path":435,"stem":436},"9.7. DbProviderFactory — провайдер-незалежний код","\u002Fcsharp\u002Fado-net\u002Fprovider-factory","01.csharp\u002F09.ado-net\u002F07.provider-factory",{"title":438,"path":439,"stem":440},"9.8. Асинхронний доступ до даних","\u002Fcsharp\u002Fado-net\u002Fasync-data-access","01.csharp\u002F09.ado-net\u002F08.async-data-access",{"title":442,"path":443,"stem":444},"9.9. Від'єднаний режим: DataSet, DataTable, DataRow","\u002Fcsharp\u002Fado-net\u002Fdisconnected-mode-dataset","01.csharp\u002F09.ado-net\u002F09.disconnected-mode-dataset",{"title":446,"path":447,"stem":448},"9.10. DataAdapter — міст між DataSet та базою даних","\u002Fcsharp\u002Fado-net\u002Fdata-adapter","01.csharp\u002F09.ado-net\u002F10.data-adapter",{"title":450,"path":451,"stem":452},"9.11. Data Mapper та Repository: Архітектура доступу до даних","\u002Fcsharp\u002Fado-net\u002Fdata-mapper-repository","01.csharp\u002F09.ado-net\u002F11.data-mapper-repository",{"title":454,"path":455,"stem":456},"9.12. Identity Map, Unit of Work та Specification Pattern","\u002Fcsharp\u002Fado-net\u002Fadvanced-patterns","01.csharp\u002F09.ado-net\u002F12.advanced-patterns",{"title":458,"icon":255,"path":459,"stem":460,"children":461,"page":59},"Ef Core","\u002Fcsharp\u002Fef-core","01.csharp\u002F10.ef-core",[462,466,470,474,478,482,486,490,494,498,502,506,510,514,518,522,526,532,538,542,546,550,554,558,562,566,570,574,578,582,586,590,594,598,602,606,610,614,618,622,626,630,634,638,642,646],{"title":463,"path":464,"stem":465},"Що таке ORM? Від SQL до об'єктів","\u002Fcsharp\u002Fef-core\u002Fwhat-is-orm","01.csharp\u002F10.ef-core\u002F01.what-is-orm",{"title":467,"path":468,"stem":469},"Перший проєкт — від нуля до CRUD","\u002Fcsharp\u002Fef-core\u002Ffirst-project","01.csharp\u002F10.ef-core\u002F02.first-project",{"title":471,"path":472,"stem":473},"DbContext — Серце EF Core","\u002Fcsharp\u002Fef-core\u002Fdbcontext-deep-dive","01.csharp\u002F10.ef-core\u002F03.dbcontext-deep-dive",{"title":475,"path":476,"stem":477},"Провайдери баз даних — Архітектура та Вибір СУБД","\u002Fcsharp\u002Fef-core\u002Fdatabase-providers","01.csharp\u002F10.ef-core\u002F04.database-providers",{"title":479,"path":480,"stem":481},"Конвенції EF Core — Магія без конфігурації","\u002Fcsharp\u002Fef-core\u002Fconventions","01.csharp\u002F10.ef-core\u002F05.conventions",{"title":483,"path":484,"stem":485},"Fluent API та Data Annotations — Явна конфігурація моделі","\u002Fcsharp\u002Fef-core\u002Ffluent-api-vs-annotations","01.csharp\u002F10.ef-core\u002F06.fluent-api-vs-annotations",{"title":487,"path":488,"stem":489},"Зв'язки — One-to-One та One-to-Many","\u002Fcsharp\u002Fef-core\u002Frelationships-basics","01.csharp\u002F10.ef-core\u002F07.relationships-basics",{"title":491,"path":492,"stem":493},"Зв'язки Advanced — Many-to-Many та Складні Сценарії","\u002Fcsharp\u002Fef-core\u002Frelationships-advanced","01.csharp\u002F10.ef-core\u002F08.relationships-advanced",{"title":495,"path":496,"stem":497},"Властивості — Типи, Конвертери, Компаратори (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fproperty-configuration-part1","01.csharp\u002F10.ef-core\u002F09.property-configuration-part1",{"title":499,"path":500,"stem":501},"Властивості — Value Comparers, Generators, Shadow Properties (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fproperty-configuration-part2","01.csharp\u002F10.ef-core\u002F09.property-configuration-part2",{"title":503,"path":504,"stem":505},"Складні типи — Owned Types та Complex Types (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fcomplex-types-owned-part1","01.csharp\u002F10.ef-core\u002F10.complex-types-owned-part1",{"title":507,"path":508,"stem":509},"Складні типи — Complex Types, Keyless Entities, Порівняння (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fcomplex-types-owned-part2","01.csharp\u002F10.ef-core\u002F10.complex-types-owned-part2",{"title":511,"path":512,"stem":513},"JSON Columns — Складні дані у JSON (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fjson-columns-part1","01.csharp\u002F10.ef-core\u002F11.json-columns-part1",{"title":515,"path":516,"stem":517},"JSON Columns — Value Comparers, Індекси, Провайдери (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fjson-columns-part2","01.csharp\u002F10.ef-core\u002F11.json-columns-part2",{"title":519,"path":520,"stem":521},"Успадкування — Абстрактні класи та TPH (Частина 1)","\u002Fcsharp\u002Fef-core\u002Finheritance-part1","01.csharp\u002F10.ef-core\u002F12.inheritance-part1",{"title":523,"path":524,"stem":525},"Успадкування — TPT, TPC та Порівняння Стратегій (Частина 2)","\u002Fcsharp\u002Fef-core\u002Finheritance-part2","01.csharp\u002F10.ef-core\u002F12.inheritance-part2",{"title":527,"path":528,"stem":529,"children":530},"Індекси, Обмеження та Схема (Частина 1)","\u002Fcsharp\u002Fef-core\u002Findexes-constraints-part1","01.csharp\u002F10.ef-core\u002F13.indexes-constraints-part1",[531],{"title":527,"path":528,"stem":529},{"title":533,"path":534,"stem":535,"children":536},"Індекси, Обмеження та Схема (Частина 2)","\u002Fcsharp\u002Fef-core\u002Findexes-constraints-part2","01.csharp\u002F10.ef-core\u002F13.indexes-constraints-part2",[537],{"title":533,"path":534,"stem":535},{"title":539,"path":540,"stem":541},"Seed Data — Початкові Дані (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fseeding-part1","01.csharp\u002F10.ef-core\u002F14.seeding-part1",{"title":543,"path":544,"stem":545},"Seed Data — SQL-скрипти, Bogus та Стратегії (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fseeding-part2","01.csharp\u002F10.ef-core\u002F14.seeding-part2",{"title":547,"path":548,"stem":549},"Global Query Filters — Глобальні Фільтри (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fglobal-query-filters-part1","01.csharp\u002F10.ef-core\u002F15.global-query-filters-part1",{"title":551,"path":552,"stem":553},"Global Query Filters — Підводні камені та Інтеграція (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fglobal-query-filters-part2","01.csharp\u002F10.ef-core\u002F15.global-query-filters-part2",{"title":555,"path":556,"stem":557},"LINQ-запити в EF Core (Частина 1)","\u002Fcsharp\u002Fef-core\u002Flinq-queries-part1","01.csharp\u002F10.ef-core\u002F16.linq-queries-part1",{"title":559,"path":560,"stem":561},"LINQ-запити в EF Core (Частина 2)","\u002Fcsharp\u002Fef-core\u002Flinq-queries-part2","01.csharp\u002F10.ef-core\u002F16.linq-queries-part2",{"title":563,"path":564,"stem":565},"Завантаження Пов'язаних Даних (Частина 1)","\u002Fcsharp\u002Fef-core\u002Floading-related-data-part1","01.csharp\u002F10.ef-core\u002F17.loading-related-data-part1",{"title":567,"path":568,"stem":569},"Завантаження Пов'язаних Даних (Частина 2)","\u002Fcsharp\u002Fef-core\u002Floading-related-data-part2","01.csharp\u002F10.ef-core\u002F17.loading-related-data-part2",{"title":571,"path":572,"stem":573},"Raw SQL, Views та Stored Procedures (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fraw-sql-part1","01.csharp\u002F10.ef-core\u002F18.raw-sql-part1",{"title":575,"path":576,"stem":577},"Raw SQL — Stored Procedures, DbFunction та Bulk Operations (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fraw-sql-part2","01.csharp\u002F10.ef-core\u002F18.raw-sql-part2",{"title":579,"path":580,"stem":581},"Продвинуті Запити — Compiled Queries, Bulk та Оптимізація (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fadvanced-queries-part1","01.csharp\u002F10.ef-core\u002F19.advanced-queries-part1",{"title":583,"path":584,"stem":585},"Продвинуті Запити — Query Tags, Bulk та Interceptors (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fadvanced-queries-part2","01.csharp\u002F10.ef-core\u002F19.advanced-queries-part2",{"title":587,"path":588,"stem":589},"Change Tracker — Відстеження Змін (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fchange-tracking-part1","01.csharp\u002F10.ef-core\u002F20.change-tracking-part1",{"title":591,"path":592,"stem":593},"Change Tracker — Графи Об'єктів та Disconnected (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fchange-tracking-part2","01.csharp\u002F10.ef-core\u002F20.change-tracking-part2",{"title":595,"path":596,"stem":597},"Збереження Даних та Транзакції (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fsaving-data-part1","01.csharp\u002F10.ef-core\u002F21.saving-data-part1",{"title":599,"path":600,"stem":601},"Збереження Даних — Concurrency та Outbox (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fsaving-data-part2","01.csharp\u002F10.ef-core\u002F21.saving-data-part2",{"title":603,"path":604,"stem":605},"Конкурентність та Блокування (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fconcurrency-part1","01.csharp\u002F10.ef-core\u002F22.concurrency-part1",{"title":607,"path":608,"stem":609},"Конкурентність — Дедлоки та Queue Processing (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fconcurrency-part2","01.csharp\u002F10.ef-core\u002F22.concurrency-part2",{"title":611,"path":612,"stem":613},"Міграції в EF Core — Основи (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fmigrations-basics-part1","01.csharp\u002F10.ef-core\u002F23.migrations-basics-part1",{"title":615,"path":616,"stem":617},"Міграції в EF Core — Основи (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fmigrations-basics-part2","01.csharp\u002F10.ef-core\u002F23.migrations-basics-part2",{"title":619,"path":620,"stem":621},"Міграції — Просунуті Сценарії (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fmigrations-advanced-part1","01.csharp\u002F10.ef-core\u002F24.migrations-advanced-part1",{"title":623,"path":624,"stem":625},"Міграції — Просунуті Сценарії (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fmigrations-advanced-part2","01.csharp\u002F10.ef-core\u002F24.migrations-advanced-part2",{"title":627,"path":628,"stem":629},"Управління Схемою та Database-First (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fschema-management-part1","01.csharp\u002F10.ef-core\u002F25.schema-management-part1",{"title":631,"path":632,"stem":633},"Управління Схемою та Database-First (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fschema-management-part2","01.csharp\u002F10.ef-core\u002F25.schema-management-part2",{"title":635,"path":636,"stem":637},"Продуктивність EF Core — Основи (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fperformance-fundamentals-part1","01.csharp\u002F10.ef-core\u002F26.performance-fundamentals-part1",{"title":639,"path":640,"stem":641},"Interceptors в EF Core (Частина 1)","\u002Fcsharp\u002Fef-core\u002Finterceptors-part1","01.csharp\u002F10.ef-core\u002F29.interceptors-part1",{"title":643,"path":644,"stem":645},"Interceptors в EF Core — Connection, Transaction та Materialization (Частина 2)","\u002Fcsharp\u002Fef-core\u002Finterceptors-part2","01.csharp\u002F10.ef-core\u002F29.interceptors-part2",{"title":647,"path":648,"stem":649},"План вивчення Entity Framework Core — Повний курс","\u002Fcsharp\u002Fef-core\u002Fimplementation_plan","01.csharp\u002F10.ef-core\u002Fimplementation_plan",{"title":651,"icon":652,"path":653,"stem":654,"children":655,"page":59},"ASP.NET","i-devicon-dotnetcore","\u002Fcsharp\u002Faspnet","01.csharp\u002F11.aspnet",[656,730,791,869,927,941,967,1057,1111,1182,1212,1289,1346],{"title":657,"icon":658,"path":659,"stem":660,"children":661,"page":59},"Minimal API","i-lucide-network","\u002Fcsharp\u002Faspnet\u002Fminimal-api","01.csharp\u002F11.aspnet\u002F01.minimal-api",[662,666,670,674,678,682,686,690,694,698,702,706,710,714,718,722,726],{"title":663,"path":664,"stem":665},"Вступ до ASP.NET та еволюція фреймворку","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fintroduction","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F01.introduction",{"title":667,"path":668,"stem":669},"Перший додаток на ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Ffirst-application","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F02.first-application",{"title":671,"path":672,"stem":673},"WebApplication, Builder та Dependency Injection","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fwebapplication-builder","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F03.webapplication-builder",{"title":675,"path":676,"stem":677},"Конвеєр запитів та Middleware","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frequest-pipeline-middleware","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F04.request-pipeline-middleware",{"title":679,"path":680,"stem":681},"Маршрутизація в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frouting-basics","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F05.routing-basics",{"title":683,"path":684,"stem":685},"Маршрутизація в ASP.NET Core: Розширені можливості","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frouting-advanced","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F06.routing-advanced",{"title":687,"path":688,"stem":689},"Статичні файли в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstatic-files","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F07.static-files",{"title":691,"path":692,"stem":693},"Статичні Активи: MapStaticAssets (ASP.NET Core 9.0)","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstatic-assets","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F08.static-assets",{"title":695,"path":696,"stem":697},"Конфігурація в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fconfiguration-fundamentals","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F09.configuration-fundamentals",{"title":699,"path":700,"stem":701},"Конфігурація: Паттерн Options","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fconfiguration-options","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F10.configuration-options",{"title":703,"path":704,"stem":705},"Логування в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Flogging-basics","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F11.logging-basics",{"title":707,"path":708,"stem":709},"Логування: Serilog та Middleware","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Flogging-advanced","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F12.logging-advanced",{"title":711,"path":712,"stem":713},"Управління станом: HttpContext.Items та Cookies","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstate-management","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F13.state-management",{"title":715,"path":716,"stem":717},"Стан сесії: Sessions","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fsession-state","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F14.session-state",{"title":719,"path":720,"stem":721},"Структура проєкту: від хаосу до архітектури","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fproject-structure","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F15.project-structure",{"title":723,"path":724,"stem":725},"Scalar у Minimal API: повний проєкт і Fluent OpenAPI","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fscalar-openapi-fluent","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F16.scalar-openapi-fluent",{"title":727,"path":728,"stem":729},"Swagger \u002F Swashbuckle у Minimal API: окремий класичний шлях","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fswagger-swashbuckle","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F17.swagger-swashbuckle",{"title":731,"icon":658,"path":732,"stem":733,"children":734,"page":59},"API","\u002Fcsharp\u002Faspnet\u002Fapi","01.csharp\u002F11.aspnet\u002F02.api",[735,739,743,747,751,755,759,763,767,771,775,779,783,787],{"title":736,"path":737,"stem":738},"Що таке API. Клієнт-серверна архітектура","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fwhat-is-api","01.csharp\u002F11.aspnet\u002F02.api\u002F01.what-is-api",{"title":740,"path":741,"stem":742},"Формати даних: JSON, XML, TOML та бінарні формати","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fdata-formats","01.csharp\u002F11.aspnet\u002F02.api\u002F02.data-formats",{"title":744,"path":745,"stem":746},"Парадигми API та концепція REST","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-paradigms-rest","01.csharp\u002F11.aspnet\u002F02.api\u002F03.api-paradigms-rest",{"title":748,"path":749,"stem":750},"HTTP-методи, статус-коди та заголовки","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fhttp-methods-status-codes","01.csharp\u002F11.aspnet\u002F02.api\u002F04.http-methods-status-codes",{"title":752,"path":753,"stem":754},"Організація HTTP API за принципами REST","\u002Fcsharp\u002Faspnet\u002Fapi\u002Frest-organizing","01.csharp\u002F11.aspnet\u002F02.api\u002F05.rest-organizing",{"title":756,"path":757,"stem":758},"Номенклатура URL та CRUD-операції","\u002Fcsharp\u002Faspnet\u002Fapi\u002Furl-nomenclature-crud","01.csharp\u002F11.aspnet\u002F02.api\u002F06.url-nomenclature-crud",{"title":760,"path":761,"stem":762},"Правила дизайну: іменування та стандарти","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-naming","01.csharp\u002F11.aspnet\u002F02.api\u002F07.api-design-naming",{"title":764,"path":765,"stem":766},"Валідація, ліміти та обробка помилок","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-validation","01.csharp\u002F11.aspnet\u002F02.api\u002F08.api-design-validation",{"title":768,"path":769,"stem":770},"Обробка помилок у Minimal API","\u002Fcsharp\u002Faspnet\u002Fapi\u002Ferror-handling-http","01.csharp\u002F11.aspnet\u002F02.api\u002F09.error-handling-http",{"title":772,"path":773,"stem":774},"Ідемпотентність та синхронізація стану","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fidempotency-sync","01.csharp\u002F11.aspnet\u002F02.api\u002F10.idempotency-sync",{"title":776,"path":777,"stem":778},"Пагінація та організація списків","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fpagination-lists","01.csharp\u002F11.aspnet\u002F02.api\u002F11.pagination-lists",{"title":780,"path":781,"stem":782},"Безпека API, кешування та інтернаціоналізація","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fsecurity-auth","01.csharp\u002F11.aspnet\u002F02.api\u002F12.security-auth",{"title":784,"path":785,"stem":786},"Процес проєктування API та документування","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-process","01.csharp\u002F11.aspnet\u002F02.api\u002F13.api-design-process",{"title":788,"path":789,"stem":790},"OpenAPI: контракт, специфікація та документація API","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fopenapi","01.csharp\u002F11.aspnet\u002F02.api\u002F14.openapi",{"title":792,"icon":793,"path":794,"stem":795,"children":796,"page":59},"Auth","i-lucide-shield-check","\u002Fcsharp\u002Faspnet\u002Fauth","01.csharp\u002F11.aspnet\u002F03.auth",[797,801,805,809,813,817,821,825,829,833,837,841,845,849,853,857,861,865],{"title":798,"path":799,"stem":800},"Основи аутентифікації та авторизації","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fauth-fundamentals","01.csharp\u002F11.aspnet\u002F03.auth\u002F01.auth-fundamentals",{"title":802,"path":803,"stem":804},"JWT-аутентифікація","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fjwt-authentication","01.csharp\u002F11.aspnet\u002F03.auth\u002F02.jwt-authentication",{"title":806,"path":807,"stem":808},"Авторизація: ролі, політики та resource-based доступ","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fauthorization-policies","01.csharp\u002F11.aspnet\u002F03.auth\u002F03.authorization-policies",{"title":810,"path":811,"stem":812},"Cookie-аутентифікація та ASP.NET Core Identity","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fcookie-auth-identity","01.csharp\u002F11.aspnet\u002F03.auth\u002F04.cookie-auth-identity",{"title":814,"path":815,"stem":816},"JWT + Refresh Tokens (HttpOnly Cookie)","\u002Fcsharp\u002Faspnet\u002Fauth\u002F04b.identity-auth-jwt","01.csharp\u002F11.aspnet\u002F03.auth\u002F04b.identity-auth-jwt",{"title":818,"path":819,"stem":820},"Identity: Підтвердження Email та Скидання Пароля","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-email-confirmation","01.csharp\u002F11.aspnet\u002F03.auth\u002F05.identity-email-confirmation",{"title":822,"path":823,"stem":824},"Identity: Двофакторна Аутентифікація (2FA)","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-two-factor","01.csharp\u002F11.aspnet\u002F03.auth\u002F06.identity-two-factor",{"title":826,"path":827,"stem":828},"Identity: Внутрішня Архітектура та Кастомізація","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-internals","01.csharp\u002F11.aspnet\u002F03.auth\u002F07.identity-internals",{"title":830,"path":831,"stem":832},"OAuth 2.0 та зовнішні провайдери","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foauth-external-providers","01.csharp\u002F11.aspnet\u002F03.auth\u002F08.oauth-external-providers",{"title":834,"path":835,"stem":836},"Безпека на практиці: CORS, HTTPS та захист від атак","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fsecurity-hardening","01.csharp\u002F11.aspnet\u002F03.auth\u002F09.security-hardening",{"title":838,"path":839,"stem":840},"Теорія OAuth 2.0: Поняття, Аналогії та Флоу","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foauth-theory","01.csharp\u002F11.aspnet\u002F03.auth\u002F10.oauth-theory",{"title":842,"path":843,"stem":844},"OIDC, OAuth 2.0 та Keycloak в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foidc-keycloak","01.csharp\u002F11.aspnet\u002F03.auth\u002F10.oidc-keycloak",{"title":846,"path":847,"stem":848},"API Keys аутентифікація в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fapi-keys","01.csharp\u002F11.aspnet\u002F03.auth\u002F11.api-keys",{"title":850,"path":851,"stem":852},"Rate Limiting та Throttling в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frate-limiting","01.csharp\u002F11.aspnet\u002F03.auth\u002F12.rate-limiting",{"title":854,"path":855,"stem":856},"Refresh Token Rotation в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frefresh-token-rotation","01.csharp\u002F11.aspnet\u002F03.auth\u002F13.refresh-token-rotation",{"title":858,"path":859,"stem":860},"Certificate Authentication та mTLS в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fcertificate-auth","01.csharp\u002F11.aspnet\u002F03.auth\u002F14.certificate-auth",{"title":862,"path":863,"stem":864},"RBAC, ABAC та ReBAC в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frbac-abac-rebac","01.csharp\u002F11.aspnet\u002F03.auth\u002F15.rbac-abac-rebac",{"title":866,"path":867,"stem":868},"Multi-tenancy та ізоляція даних в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fmulti-tenancy","01.csharp\u002F11.aspnet\u002F03.auth\u002F16.multi-tenancy",{"title":870,"icon":871,"path":872,"stem":873,"children":874,"page":59},"Нотифікації","i-lucide-bell","\u002Fcsharp\u002Faspnet\u002Fnotifications","01.csharp\u002F11.aspnet\u002F04.notifications",[875,879,883,887,891,895,899,903,907,911,915,919,923],{"title":876,"path":877,"stem":878},"In-App нотифікації через базу даних","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fin-app-database-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F01.in-app-database-notifications",{"title":880,"path":881,"stem":882},"Polling: Регулярний запит оновлень","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fpolling","01.csharp\u002F11.aspnet\u002F04.notifications\u002F02.polling",{"title":884,"path":885,"stem":886},"Server-Sent Events: Однострімовий push від сервера","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fserver-sent-events","01.csharp\u002F11.aspnet\u002F04.notifications\u002F03.server-sent-events",{"title":888,"path":889,"stem":890},"WebSockets: Двостороннє з'єднання в реальному часі","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fwebsockets","01.csharp\u002F11.aspnet\u002F04.notifications\u002F04.websockets",{"title":892,"path":893,"stem":894},"SignalR: Абстракція над транспортами реального часу","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fsignalr","01.csharp\u002F11.aspnet\u002F04.notifications\u002F05.signalr",{"title":896,"path":897,"stem":898},"Background Services: Фонові задачі в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fbackground-services","01.csharp\u002F11.aspnet\u002F04.notifications\u002F06.background-services",{"title":900,"path":901,"stem":902},"Web Push нотифікації","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fweb-push","01.csharp\u002F11.aspnet\u002F04.notifications\u002F07.web-push",{"title":904,"path":905,"stem":906},"Email нотифікації","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Femail-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F08.email-notifications",{"title":908,"path":909,"stem":910},"Порівняння підходів: Як вибрати правильну технологію нотифікацій","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fchoosing-the-right-approach","01.csharp\u002F11.aspnet\u002F04.notifications\u002F09.choosing-the-right-approach",{"title":912,"path":913,"stem":914},"Hangfire: Надійне планування фонових задач","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire","01.csharp\u002F11.aspnet\u002F04.notifications\u002F10.hangfire",{"title":916,"path":917,"stem":918},"Практика: Конвертація зображень у WebP через Hangfire","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire-image-webp","01.csharp\u002F11.aspnet\u002F04.notifications\u002F11.hangfire-image-webp",{"title":920,"path":921,"stem":922},"Практика: Підготовка відео до HLS-стрімінгу через Hangfire","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire-video-hls","01.csharp\u002F11.aspnet\u002F04.notifications\u002F12.hangfire-video-hls",{"title":924,"path":925,"stem":926},"Telegram-нотифікації: від одного повідомлення до масових розсилок і мульти-канального підходу","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Ftelegram-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F13.telegram-notifications",{"title":928,"icon":929,"path":930,"stem":931,"children":932,"page":59},"Інтернаціоналізація","i-lucide-languages","\u002Fcsharp\u002Faspnet\u002Fi18n","01.csharp\u002F11.aspnet\u002F05.i18n",[933,937],{"title":934,"path":935,"stem":936},"Інтернаціоналізація (i18n) у Minimal API: від A до Я","\u002Fcsharp\u002Faspnet\u002Fi18n\u002Finternationalization","01.csharp\u002F11.aspnet\u002F05.i18n\u002F01.internationalization",{"title":938,"path":939,"stem":940},"Humanizer: людиномовні рядки у .NET","\u002Fcsharp\u002Faspnet\u002Fi18n\u002Fhumanizer","01.csharp\u002F11.aspnet\u002F05.i18n\u002F02.humanizer",{"title":942,"icon":943,"path":944,"stem":945,"children":946,"page":59},"Кешування","i-lucide-layers","\u002Fcsharp\u002Faspnet\u002Fcaching","01.csharp\u002F11.aspnet\u002F06.caching",[947,951,955,959,963],{"title":948,"path":949,"stem":950},"Огляд кешування: чотири рівні і коли що обирати","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fcaching","01.csharp\u002F11.aspnet\u002F06.caching\u002F01.caching",{"title":952,"path":953,"stem":954},"IMemoryCache: кеш в оперативній пам'яті","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fmemory-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F02.memory-cache",{"title":956,"path":957,"stem":958},"IDistributedCache і Redis: розподілений кеш","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fdistributed-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F03.distributed-cache",{"title":960,"path":961,"stem":962},"Response Cache: HTTP-кешування через Cache-Control","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fresponse-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F04.response-cache",{"title":964,"path":965,"stem":966},"Output Cache: серверний кеш HTTP-відповідей (.NET 7+)","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Foutput-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F05.output-cache",{"title":968,"icon":969,"path":970,"stem":971,"children":972,"page":59},"Тестування","i-lucide-test-tube","\u002Fcsharp\u002Faspnet\u002Ftesting","01.csharp\u002F11.aspnet\u002F07.testing",[973,977,981,985,989,993,997,1001,1005,1009,1013,1017,1021,1025,1029,1033,1037,1041,1045,1049,1053],{"title":974,"path":975,"stem":976},"Що таке тестування? Від інтуїції до науки","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwhat-is-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F01.what-is-testing",{"title":978,"path":979,"stem":980},"Піраміда тестування — Стратегія, а не Догма","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-pyramid","01.csharp\u002F11.aspnet\u002F07.testing\u002F02.testing-pyramid",{"title":982,"path":983,"stem":984},"Дві Школи Тестування — Лондон проти Детройту","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-schools","01.csharp\u002F11.aspnet\u002F07.testing\u002F03.testing-schools",{"title":986,"path":987,"stem":988},"TDD та BDD — Тести як Дизайн-інструмент","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftdd-and-bdd","01.csharp\u002F11.aspnet\u002F07.testing\u002F04.tdd-and-bdd",{"title":990,"path":991,"stem":992},"Що саме тестувати — Техніки аналізу та Циклomatична складність","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwhat-to-test","01.csharp\u002F11.aspnet\u002F07.testing\u002F05.what-to-test",{"title":994,"path":995,"stem":996},"Тестові Фреймворки — Навіщо вони і що всередині","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftest-frameworks","01.csharp\u002F11.aspnet\u002F07.testing\u002F06.test-frameworks",{"title":998,"path":999,"stem":1000},"xUnit — Факти, Теорії та Lifecycle тестів","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fxunit-basics","01.csharp\u002F11.aspnet\u002F07.testing\u002F07.xunit-basics",{"title":1002,"path":1003,"stem":1004},"xUnit Advanced — Fixtures, Кастомізація та Розширення","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fxunit-advanced","01.csharp\u002F11.aspnet\u002F07.testing\u002F08.xunit-advanced",{"title":1006,"path":1007,"stem":1008},"Moq — Глибоке занурення в мокування","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fmocking-with-moq","01.csharp\u002F11.aspnet\u002F07.testing\u002F09.mocking-with-moq",{"title":1010,"path":1011,"stem":1012},"Тестування Баз Даних — EF Core, SQLite та Testcontainers","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fdatabase-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F10.database-testing",{"title":1014,"path":1015,"stem":1016},"Integration Testing — Частина 1 [Теорія та WebApplicationFactory]","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fintegration-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F11.integration-testing",{"title":1018,"path":1019,"stem":1020},"Інтеграційне тестування — Практика","\u002Fcsharp\u002Faspnet\u002Ftesting\u002F11a.integration-testing-practice","01.csharp\u002F11.aspnet\u002F07.testing\u002F11a.integration-testing-practice",{"title":1022,"path":1023,"stem":1024},"Integration Testing — Частина 2 [Просунуті Сценарії та Testcontainers]","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fintegration-testing-advanced","01.csharp\u002F11.aspnet\u002F07.testing\u002F12.integration-testing-advanced",{"title":1026,"path":1027,"stem":1028},"Професійний Postman: Колекції, Змінні та GitHub Інтеграція","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fpostman-professional","01.csharp\u002F11.aspnet\u002F07.testing\u002F13.postman-professional",{"title":1030,"path":1031,"stem":1032},"HttpClient у Тестах Частина 1: Архітектура та MockHttpMessageHandler","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fhttpclient-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F14.httpclient-testing",{"title":1034,"path":1035,"stem":1036},"HttpClient у Тестах Частина 2: WireMock.Net та Resilience","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwiremock-net","01.csharp\u002F11.aspnet\u002F07.testing\u002F15.wiremock-net",{"title":1038,"path":1039,"stem":1040},"Патерни та Анти-патерни Тестування: Test Smells","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-patterns","01.csharp\u002F11.aspnet\u002F07.testing\u002F16.testing-patterns",{"title":1042,"path":1043,"stem":1044},"Просунуті інструменти: Time, Snapshots та Властивості","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fadvanced-testing-tools","01.csharp\u002F11.aspnet\u002F07.testing\u002F17.advanced-testing-tools",{"title":1046,"path":1047,"stem":1048},"Тестування Архітектури з NetArchTest","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Farchitecture-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F18.architecture-testing",{"title":1050,"path":1051,"stem":1052},"Тестування Продуктивності: BenchmarkDotNet, NBomber та k6","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fperformance-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F19.performance-testing",{"title":1054,"path":1055,"stem":1056},"Залишок плану для курсу \"Тестування ASP.NET Minimal API\"","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fremaining_plan","01.csharp\u002F11.aspnet\u002F07.testing\u002Fremaining_plan",{"title":1058,"icon":1059,"path":1060,"stem":1061,"children":1062,"page":59},"Платежі","i-lucide-credit-card","\u002Fcsharp\u002Faspnet\u002Fpayments","01.csharp\u002F11.aspnet\u002F08.payments",[1063,1067,1071,1075,1079,1083,1087,1091,1095,1099,1103,1107],{"title":1064,"path":1065,"stem":1066},"Основи платіжної інфраструктури","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-fundamentals","01.csharp\u002F11.aspnet\u002F08.payments\u002F01.payment-fundamentals",{"title":1068,"path":1069,"stem":1070},"Методи оплати в Україні","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-methods-ukraine","01.csharp\u002F11.aspnet\u002F08.payments\u002F02.payment-methods-ukraine",{"title":1072,"path":1073,"stem":1074},"PCI DSS та безпека платежів","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpci-dss-security","01.csharp\u002F11.aspnet\u002F08.payments\u002F03.pci-dss-security",{"title":1076,"path":1077,"stem":1078},"Архітектура платіжної підсистеми","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-architecture","01.csharp\u002F11.aspnet\u002F08.payments\u002F04.payment-architecture",{"title":1080,"path":1081,"stem":1082},"Інтеграція LiqPay (ПриватБанк)","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fliqpay-integration","01.csharp\u002F11.aspnet\u002F08.payments\u002F05.liqpay-integration",{"title":1084,"path":1085,"stem":1086},"Інтеграція Monobank Acquiring API","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fmonobank-acquiring","01.csharp\u002F11.aspnet\u002F08.payments\u002F06.monobank-acquiring",{"title":1088,"path":1089,"stem":1090},"Інтеграція Stripe","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fstripe-integration","01.csharp\u002F11.aspnet\u002F08.payments\u002F07.stripe-integration",{"title":1092,"path":1093,"stem":1094},"Webhooks — глибоке занурення","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fwebhooks-deep-dive","01.csharp\u002F11.aspnet\u002F08.payments\u002F08.webhooks-deep-dive",{"title":1096,"path":1097,"stem":1098},"Підписки та рекурентні платежі","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fsubscriptions-recurring","01.csharp\u002F11.aspnet\u002F08.payments\u002F09.subscriptions-recurring",{"title":1100,"path":1101,"stem":1102},"Повернення коштів та диспути","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Frefunds-disputes","01.csharp\u002F11.aspnet\u002F08.payments\u002F10.refunds-disputes",{"title":1104,"path":1105,"stem":1106},"Тестування платіжних інтеграцій","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Ftesting-payments","01.csharp\u002F11.aspnet\u002F08.payments\u002F11.testing-payments",{"title":1108,"path":1109,"stem":1110},"Чекліст виходу в Production","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fproduction-checklist","01.csharp\u002F11.aspnet\u002F08.payments\u002F12.production-checklist",{"title":1112,"icon":1113,"items":1114,"path":1127,"stem":1128,"children":1129,"page":59},"Популярні бібліотеки","lucide:box",[1115,1116,1117,1118,1119,1120,1121,1122,1123,1124,1125,1126],"01.fluent-validation","02.mapster","03.erroror-result-pattern","04.serilog","05.mediatr","06.polly","07.health-checks","08.feature-management","09.fluent-email","10.quest-pdf","11.bogus","12.humanizer-guard","\u002Fcsharp\u002Faspnet\u002Flibraries","01.csharp\u002F11.aspnet\u002F09.libraries",[1130,1134,1138,1142,1146,1150,1154,1158,1162,1166,1170,1174,1178],{"title":1131,"path":1132,"stem":1133},"Валідація з FluentValidation в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffluent-validation","01.csharp\u002F11.aspnet\u002F09.libraries\u002F01.fluent-validation",{"title":1135,"path":1136,"stem":1137},"Маппінг об","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fmapster","01.csharp\u002F11.aspnet\u002F09.libraries\u002F02.mapster",{"title":1139,"path":1140,"stem":1141},"Обробка помилок з ErrorOr та Result Pattern в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ferroror-result-pattern","01.csharp\u002F11.aspnet\u002F09.libraries\u002F03.erroror-result-pattern",{"title":1143,"path":1144,"stem":1145},"Структуроване логування з Serilog в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fserilog","01.csharp\u002F11.aspnet\u002F09.libraries\u002F04.serilog",{"title":1147,"path":1148,"stem":1149},"CQRS та Mediator з MediatR в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fmediatr","01.csharp\u002F11.aspnet\u002F09.libraries\u002F05.mediatr",{"title":1151,"path":1152,"stem":1153},"Відмовостійкість з Polly в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fpolly","01.csharp\u002F11.aspnet\u002F09.libraries\u002F06.polly",{"title":1155,"path":1156,"stem":1157},"Health Checks в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fhealth-checks","01.csharp\u002F11.aspnet\u002F09.libraries\u002F07.health-checks",{"title":1159,"path":1160,"stem":1161},"Feature Management та Feature Flags в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffeature-management","01.csharp\u002F11.aspnet\u002F09.libraries\u002F08.feature-management",{"title":1163,"path":1164,"stem":1165},"Відправка Email з FluentEmail в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffluent-email","01.csharp\u002F11.aspnet\u002F09.libraries\u002F09.fluent-email",{"title":1167,"path":1168,"stem":1169},"Генерація PDF з QuestPDF в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fquest-pdf","01.csharp\u002F11.aspnet\u002F09.libraries\u002F10.quest-pdf",{"title":1171,"path":1172,"stem":1173},"Генерація тестових даних з Bogus в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fbogus","01.csharp\u002F11.aspnet\u002F09.libraries\u002F11.bogus",{"title":1175,"path":1176,"stem":1177},"Humanizer та Guard Clauses в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fhumanizer-guard","01.csharp\u002F11.aspnet\u002F09.libraries\u002F12.humanizer-guard",{"title":1179,"path":1180,"stem":1181},"План модуля 10.libraries — Популярні бібліотеки ASP.NET","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fplan","01.csharp\u002F11.aspnet\u002F09.libraries\u002Fplan",{"title":1183,"icon":1184,"path":1185,"stem":1186,"children":1187,"page":59},"Razor Pages","i-lucide-layout-template","\u002Fcsharp\u002Faspnet\u002Frazor-pages","01.csharp\u002F11.aspnet\u002F10.razor-pages",[1188,1192,1196,1200,1204,1208],{"title":1189,"path":1190,"stem":1191},"Від Minimal API до Razor Pages: концептуальний перехід","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Ffrom-minimal-api","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F01.from-minimal-api",{"title":1193,"path":1194,"stem":1195},"PageModel: логіка сторінки Razor Pages","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fpage-model","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F02.page-model",{"title":1197,"path":1198,"stem":1199},"Razor синтаксис: шаблонізатор у .cshtml","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Frazor-syntax","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F03.razor-syntax",{"title":1201,"path":1202,"stem":1203},"Tag Helpers: типізований HTML","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Ftag-helpers","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F04.tag-helpers",{"title":1205,"path":1206,"stem":1207},"Форми і валідація: повний цикл обробки даних","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fforms-validation","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F05.forms-validation",{"title":1209,"path":1210,"stem":1211},"Практичний проєкт: TaskManager на Razor Pages","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fproject-task-manager","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F06.project-task-manager",{"title":1213,"path":1214,"stem":1215,"children":1216,"page":59},"ASP.NET Core MVC","\u002Fcsharp\u002Faspnet\u002Fmvc","01.csharp\u002F11.aspnet\u002F11.mvc",[1217,1221,1225,1229,1233,1237,1241,1245,1249,1253,1257,1261,1265,1269,1273,1277,1281,1285],{"title":1218,"path":1219,"stem":1220},"Патерн MVC: архітектура, що змінила веб","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmvc-pattern","01.csharp\u002F11.aspnet\u002F11.mvc\u002F01.mvc-pattern",{"title":1222,"path":1223,"stem":1224},"Від Razor Pages до MVC: концептуальний перехід","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffrom-razor-pages","01.csharp\u002F11.aspnet\u002F11.mvc\u002F02.from-razor-pages",{"title":1226,"path":1227,"stem":1228},"Controllers та Actions: серце MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fcontrollers-actions","01.csharp\u002F11.aspnet\u002F11.mvc\u002F03.controllers-actions",{"title":1230,"path":1231,"stem":1232},"Маршрутизація в MVC: Convention vs Attribute Routing","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Frouting-mvc","01.csharp\u002F11.aspnet\u002F11.mvc\u002F04.routing-mvc",{"title":1234,"path":1235,"stem":1236},"Model Binding: від HTTP до C#","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmodel-binding","01.csharp\u002F11.aspnet\u002F11.mvc\u002F05.model-binding",{"title":1238,"path":1239,"stem":1240},"Views, ViewData, ViewBag, TempData і ViewModel","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fviews-viewdata-tempdata","01.csharp\u002F11.aspnet\u002F11.mvc\u002F06.views-viewdata-tempdata",{"title":1242,"path":1243,"stem":1244},"Filters: аспектно-орієнтоване програмування в MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffilters","01.csharp\u002F11.aspnet\u002F11.mvc\u002F07.filters",{"title":1246,"path":1247,"stem":1248},"Areas: структурування великих застосунків","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fareas","01.csharp\u002F11.aspnet\u002F11.mvc\u002F08.areas",{"title":1250,"path":1251,"stem":1252},"View Components: повторювані незалежні блоки UI","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fview-components","01.csharp\u002F11.aspnet\u002F11.mvc\u002F09.view-components",{"title":1254,"path":1255,"stem":1256},"Display та Editor Templates","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fdisplay-editor-templates","01.csharp\u002F11.aspnet\u002F11.mvc\u002F10.display-editor-templates",{"title":1258,"path":1259,"stem":1260},"Валідація: IValidatableObject та FluentValidation","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fvalidation-advanced","01.csharp\u002F11.aspnet\u002F11.mvc\u002F11.validation-advanced",{"title":1262,"path":1263,"stem":1264},"HTMX: інтерактивність через HTML-атрибути","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fhtmx","01.csharp\u002F11.aspnet\u002F11.mvc\u002F12.htmx",{"title":1266,"path":1267,"stem":1268},"HTMX у ASP.NET Core MVC: серверна інтеграція","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fajax-htmx-mvc","01.csharp\u002F11.aspnet\u002F11.mvc\u002F13.ajax-htmx-mvc",{"title":1270,"path":1271,"stem":1272},"Практичний проєкт: Каталог товарів з HTMX","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fhtmx-project","01.csharp\u002F11.aspnet\u002F11.mvc\u002F14.htmx-project",{"title":1274,"path":1275,"stem":1276},"Завантаження та обробка файлів","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffile-upload","01.csharp\u002F11.aspnet\u002F11.mvc\u002F15.file-upload",{"title":1278,"path":1279,"stem":1280},"Глобалізація та Локалізація MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fglobalization-localization","01.csharp\u002F11.aspnet\u002F11.mvc\u002F16.globalization-localization",{"title":1282,"path":1283,"stem":1284},"Підсумковий проєкт: Блог-платформа","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmvc-project","01.csharp\u002F11.aspnet\u002F11.mvc\u002F17.mvc-project",{"title":1286,"path":1287,"stem":1288},"План курсу: ASP.NET Core MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fplan","01.csharp\u002F11.aspnet\u002F11.mvc\u002Fplan",{"title":1290,"path":1291,"stem":1292,"children":1293,"page":59},"Web Api","\u002Fcsharp\u002Faspnet\u002Fweb-api","01.csharp\u002F11.aspnet\u002F12.web-api",[1294,1298,1302,1306,1310,1314,1318,1322,1326,1330,1334,1338,1342],{"title":1295,"path":1296,"stem":1297},"Від Minimal API до Controller-based API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Ffrom-minimal-api-to-controllers","01.csharp\u002F11.aspnet\u002F12.web-api\u002F01.from-minimal-api-to-controllers",{"title":1299,"path":1300,"stem":1301},"ControllerBase, ActionResult\u003CT> та Response Types","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fcontroller-base-actionresult","01.csharp\u002F11.aspnet\u002F12.web-api\u002F02.controller-base-actionresult",{"title":1303,"path":1304,"stem":1305},"Content Negotiation - JSON, XML та власні форматери","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fcontent-negotiation","01.csharp\u002F11.aspnet\u002F12.web-api\u002F03.content-negotiation",{"title":1307,"path":1308,"stem":1309},"Версіонування API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fapi-versioning","01.csharp\u002F11.aspnet\u002F12.web-api\u002F04.api-versioning",{"title":1311,"path":1312,"stem":1313},"ProblemDetails та структурована обробка помилок","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fproblemdetails-error-handling","01.csharp\u002F11.aspnet\u002F12.web-api\u002F05.problemdetails-error-handling",{"title":1315,"path":1316,"stem":1317},"Фільтри у Web API контексті","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Ffilters-for-api","01.csharp\u002F11.aspnet\u002F12.web-api\u002F06.filters-for-api",{"title":1319,"path":1320,"stem":1321},"Пагінація, фільтрація та сортування","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fpagination-filtering-sorting","01.csharp\u002F11.aspnet\u002F12.web-api\u002F07.pagination-filtering-sorting",{"title":1323,"path":1324,"stem":1325},"HATEOAS та Resource Expansion","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fhateoas-resource-expansion","01.csharp\u002F11.aspnet\u002F12.web-api\u002F08.hateoas-resource-expansion",{"title":1327,"path":1328,"stem":1329},"Гібридна архітектура - Minimal API + Controllers","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fminimal-api-vs-controllers-hybrid","01.csharp\u002F11.aspnet\u002F12.web-api\u002F09.minimal-api-vs-controllers-hybrid",{"title":1331,"path":1332,"stem":1333},"Документація API - Swashbuckle, NSwag та генерація клієнтів","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fapi-documentation-generation","01.csharp\u002F11.aspnet\u002F12.web-api\u002F10.api-documentation-generation",{"title":1335,"path":1336,"stem":1337},"Health Checks та моніторинг API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fhealth-checks-monitoring","01.csharp\u002F11.aspnet\u002F12.web-api\u002F11.health-checks-monitoring",{"title":1339,"path":1340,"stem":1341},"Підсумковий проєкт - Production-Ready REST API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fweb-api-project","01.csharp\u002F11.aspnet\u002F12.web-api\u002F12.web-api-project",{"title":1343,"path":1344,"stem":1345},"План курсу: ASP.NET Core Web API (Controllers)","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fplan","01.csharp\u002F11.aspnet\u002F12.web-api\u002Fplan",{"title":1347,"icon":1348,"path":1349,"stem":1350,"children":1351,"page":59},"Моніторинг","i-lucide-activity","\u002Fcsharp\u002Faspnet\u002Fmonitoring","01.csharp\u002F11.aspnet\u002F13.monitoring",[1352,1356,1360],{"title":1353,"path":1354,"stem":1355},"Спостережуваність: від console.log до production-систем","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fobservability-intro","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F01.observability-intro",{"title":1357,"path":1358,"stem":1359},"Health Checks: перший рівень observability","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fhealth-checks","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F02.health-checks",{"title":1361,"path":1362,"stem":1363},"Вбудовані метрики .NET 10 та System.Diagnostics.Metrics","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fdotnet-metrics","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F03.dotnet-metrics",{"title":1365,"icon":1366,"path":1367,"stem":1368,"children":1369,"page":59},"Desktop UI","i-lucide-app-window","\u002Fcsharp\u002Fdesktop-ui","01.csharp\u002F12.desktop-ui",[1370,1374,1378,1382,1386,1390,1394,1398,1402,1406,1410,1414,1418,1422,1426,1430,1434,1438,1442,1446,1450,1454,1458,1462,1466,1470,1474,1478,1482,1486,1490,1494,1498,1502,1506,1510,1514,1518,1522,1526,1530,1534,1538,1542,1546,1550,1554,1558,1562,1566,1570,1574,1578,1582,1586,1590,1594,1598,1602,1606,1610,1614,1618,1622,1626,1630,1634,1638,1642,1646,1650],{"title":1371,"path":1372,"stem":1373},"Що таке десктопна розробка?","\u002Fcsharp\u002Fdesktop-ui\u002Fwhat-is-desktop-dev","01.csharp\u002F12.desktop-ui\u002F01.what-is-desktop-dev",{"title":1375,"path":1376,"stem":1377},"Архітектура WPF — як влаштований графічний інтерфейс","\u002Fcsharp\u002Fdesktop-ui\u002Fwpf-architecture","01.csharp\u002F12.desktop-ui\u002F02.wpf-architecture",{"title":1379,"path":1380,"stem":1381},"Перший WPF-проєкт — від нуля до вікна","\u002Fcsharp\u002Fdesktop-ui\u002Ffirst-wpf-app","01.csharp\u002F12.desktop-ui\u002F03.first-wpf-app",{"title":1383,"path":1384,"stem":1385},"Перший Avalonia-проєкт: WPF для всіх платформ","\u002Fcsharp\u002Fdesktop-ui\u002F03a.first-avalonia-app","01.csharp\u002F12.desktop-ui\u002F03a.first-avalonia-app",{"title":1387,"path":1388,"stem":1389},"XAML: декларативний інтерфейс","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-basics","01.csharp\u002F12.desktop-ui\u002F04.xaml-basics",{"title":1391,"path":1392,"stem":1393},"Fluent UI у WPF — сучасний дизайн Windows 11","\u002Fcsharp\u002Fdesktop-ui\u002F04a.wpf-fluent-ui","01.csharp\u002F12.desktop-ui\u002F04a.wpf-fluent-ui",{"title":1395,"path":1396,"stem":1397},"WPF UI — сучасна бібліотека Fluent контролів","\u002Fcsharp\u002Fdesktop-ui\u002F04b.wpf-ui-library","01.csharp\u002F12.desktop-ui\u002F04b.wpf-ui-library",{"title":1399,"path":1400,"stem":1401},"HandyControl — велика бібліотека UI контролів для WPF","\u002Fcsharp\u002Fdesktop-ui\u002F04c.handycontrol-library","01.csharp\u002F12.desktop-ui\u002F04c.handycontrol-library",{"title":1403,"path":1404,"stem":1405},"Простори імен та ресурси XAML","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-namespaces-resources","01.csharp\u002F12.desktop-ui\u002F05.xaml-namespaces-resources",{"title":1407,"path":1408,"stem":1409},"XAML в Avalonia: ключові відмінності від WPF","\u002Fcsharp\u002Fdesktop-ui\u002F05a.avalonia-xaml-differences","01.csharp\u002F12.desktop-ui\u002F05a.avalonia-xaml-differences",{"title":1411,"path":1412,"stem":1413},"Розширення розмітки XAML (Markup Extensions)","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-markup-extensions","01.csharp\u002F12.desktop-ui\u002F06.xaml-markup-extensions",{"title":1415,"path":1416,"stem":1417},"Панелі Layout: StackPanel, WrapPanel, DockPanel","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-panels-part1","01.csharp\u002F12.desktop-ui\u002F07.layout-panels-part1",{"title":1419,"path":1420,"stem":1421},"Grid, Canvas, UniformGrid","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-panels-part2","01.csharp\u002F12.desktop-ui\u002F07.layout-panels-part2",{"title":1423,"path":1424,"stem":1425},"Просунуті техніки Layout","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-advanced","01.csharp\u002F12.desktop-ui\u002F08.layout-advanced",{"title":1427,"path":1428,"stem":1429},"Адаптивний Layout та найкращі практики","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-responsive","01.csharp\u002F12.desktop-ui\u002F09.layout-responsive",{"title":1431,"path":1432,"stem":1433},"Layout в Avalonia: відмінності та нові можливості","\u002Fcsharp\u002Fdesktop-ui\u002F09a.layout-avalonia","01.csharp\u002F12.desktop-ui\u002F09a.layout-avalonia",{"title":1435,"path":1436,"stem":1437},"Button, Image, ProgressBar та інші базові контроли","\u002Fcsharp\u002Fdesktop-ui\u002Fbasic-controls","01.csharp\u002F12.desktop-ui\u002F10.basic-controls",{"title":1439,"path":1440,"stem":1441},"Контроли в Avalonia: відмінності від WPF","\u002Fcsharp\u002Fdesktop-ui\u002F10a.controls-avalonia","01.csharp\u002F12.desktop-ui\u002F10a.controls-avalonia",{"title":1443,"path":1444,"stem":1445},"Текстові контроли — TextBlock, TextBox, RichTextBox","\u002Fcsharp\u002Fdesktop-ui\u002Ftext-controls","01.csharp\u002F12.desktop-ui\u002F11.text-controls",{"title":1447,"path":1448,"stem":1449},"Контроли вибору — CheckBox, RadioButton, ComboBox, ListBox, DatePicker","\u002Fcsharp\u002Fdesktop-ui\u002Fselection-controls","01.csharp\u002F12.desktop-ui\u002F12.selection-controls",{"title":1451,"path":1452,"stem":1453},"Content Model — GroupBox, Expander, TabControl, StatusBar","\u002Fcsharp\u002Fdesktop-ui\u002Fcontent-controls","01.csharp\u002F12.desktop-ui\u002F13.content-controls",{"title":1455,"path":1456,"stem":1457},"UI\u002FUX принципи десктопних застосунків","\u002Fcsharp\u002Fdesktop-ui\u002F13a.ui-ux-principles","01.csharp\u002F12.desktop-ui\u002F13a.ui-ux-principles",{"title":1459,"path":1460,"stem":1461},"Dependency Properties — Концепція та Value Resolution","\u002Fcsharp\u002Fdesktop-ui\u002Fdependency-properties-part1","01.csharp\u002F12.desktop-ui\u002F14.dependency-properties-part1",{"title":1463,"path":1464,"stem":1465},"Avalonia Property System — StyledProperty та DirectProperty","\u002Fcsharp\u002Fdesktop-ui\u002F14a.avalonia-property-system","01.csharp\u002F12.desktop-ui\u002F14a.avalonia-property-system",{"title":1467,"path":1468,"stem":1469},"Attached Properties — Властивості без меж","\u002Fcsharp\u002Fdesktop-ui\u002Fattached-properties","01.csharp\u002F12.desktop-ui\u002F15.attached-properties",{"title":1471,"path":1472,"stem":1473},"Routed Events — Маршрутизація подій у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Frouted-events","01.csharp\u002F12.desktop-ui\u002F16.routed-events",{"title":1475,"path":1476,"stem":1477},"Data Binding — Від Code-Behind до Декларативності","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-basics-part1","01.csharp\u002F12.desktop-ui\u002F17.data-binding-basics-part1",{"title":1479,"path":1480,"stem":1481},"INotifyPropertyChanged — Живе оновлення UI","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-basics-part2","01.csharp\u002F12.desktop-ui\u002F17.data-binding-basics-part2",{"title":1483,"path":1484,"stem":1485},"Compiled Bindings в Avalonia — Безпека на етапі компіляції","\u002Fcsharp\u002Fdesktop-ui\u002F17a.avalonia-compiled-bindings","01.csharp\u002F12.desktop-ui\u002F17a.avalonia-compiled-bindings",{"title":1487,"path":1488,"stem":1489},"Просунутий Data Binding — ElementName, RelativeSource, MultiBinding","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-advanced","01.csharp\u002F12.desktop-ui\u002F18.data-binding-advanced",{"title":1491,"path":1492,"stem":1493},"Value Converters — Перетворення типів даних у Data Binding","\u002Fcsharp\u002Fdesktop-ui\u002Fvalue-converters","01.csharp\u002F12.desktop-ui\u002F19.value-converters",{"title":1495,"path":1496,"stem":1497},"Data Templates — Візуалізація об'єктів у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-templates","01.csharp\u002F12.desktop-ui\u002F20.data-templates",{"title":1499,"path":1500,"stem":1501},"Collections Binding Part 1 — ObservableCollection та ItemsControl","\u002Fcsharp\u002Fdesktop-ui\u002Fcollections-binding-part1","01.csharp\u002F12.desktop-ui\u002F21.collections-binding-part1",{"title":1503,"path":1504,"stem":1505},"Collections Binding Part 2 — ICollectionView, Filtering, Sorting та Virtualization","\u002Fcsharp\u002Fdesktop-ui\u002Fcollections-binding-part2","01.csharp\u002F12.desktop-ui\u002F21.collections-binding-part2",{"title":1507,"path":1508,"stem":1509},"MVVM Pattern — Від Spaghetti Code до архітектури","\u002Fcsharp\u002Fdesktop-ui\u002Fmvvm-pattern","01.csharp\u002F12.desktop-ui\u002F22.mvvm-pattern",{"title":1511,"path":1512,"stem":1513},"ViewModel Implementation — Від BaseViewModel до валідації","\u002Fcsharp\u002Fdesktop-ui\u002Fviewmodel-implementation","01.csharp\u002F12.desktop-ui\u002F23.viewmodel-implementation",{"title":1515,"path":1516,"stem":1517},"Commands — Від event handlers до декларативних команд","\u002Fcsharp\u002Fdesktop-ui\u002Fcommands","01.csharp\u002F12.desktop-ui\u002F24.commands",{"title":1519,"path":1520,"stem":1521},"MVVM Toolkit — MVVM без boilerplate через Source Generators","\u002Fcsharp\u002Fdesktop-ui\u002Fmvvm-toolkit","01.csharp\u002F12.desktop-ui\u002F25.mvvm-toolkit",{"title":1523,"path":1524,"stem":1525},"Messenger Pattern — Комунікація між ViewModel без прямих посилань","\u002Fcsharp\u002Fdesktop-ui\u002Fmessenger-pattern","01.csharp\u002F12.desktop-ui\u002F26.messenger-pattern",{"title":1527,"path":1528,"stem":1529},"Стилі WPF — CSS для десктопу","\u002Fcsharp\u002Fdesktop-ui\u002Fstyles-basics","01.csharp\u002F12.desktop-ui\u002F27.styles-basics",{"title":1531,"path":1532,"stem":1533},"CSS-like стилі Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002F27a.avalonia-css-styling","01.csharp\u002F12.desktop-ui\u002F27a.avalonia-css-styling",{"title":1535,"path":1536,"stem":1537},"Control Templates — Частина 1. Концепція та TemplateBinding","\u002Fcsharp\u002Fdesktop-ui\u002Fcontrol-templates-part1","01.csharp\u002F12.desktop-ui\u002F28.control-templates-part1",{"title":1539,"path":1540,"stem":1541},"Control Templates — Частина 2. Named Parts та ContentPresenter","\u002Fcsharp\u002Fdesktop-ui\u002Fcontrol-templates-part2","01.csharp\u002F12.desktop-ui\u002F28.control-templates-part2",{"title":1543,"path":1544,"stem":1545},"Control Themes в Avalonia — нова ера стилізації","\u002Fcsharp\u002Fdesktop-ui\u002F28a.avalonia-control-themes","01.csharp\u002F12.desktop-ui\u002F28a.avalonia-control-themes",{"title":1547,"path":1548,"stem":1549},"Triggers та Visual State Manager у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Ftriggers-visual-states","01.csharp\u002F12.desktop-ui\u002F29.triggers-visual-states",{"title":1551,"path":1552,"stem":1553},"Pseudo-classes в Avalonia — замість WPF Triggers","\u002Fcsharp\u002Fdesktop-ui\u002F29a.avalonia-pseudo-classes","01.csharp\u002F12.desktop-ui\u002F29a.avalonia-pseudo-classes",{"title":1555,"path":1556,"stem":1557},"Теми та ресурсні словники у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fresources-themes","01.csharp\u002F12.desktop-ui\u002F30.resources-themes",{"title":1559,"path":1560,"stem":1561},"Avalonia Themes — Fluent Design та система тематизації","\u002Fcsharp\u002Fdesktop-ui\u002F30a.avalonia-themes-fluent","01.csharp\u002F12.desktop-ui\u002F30a.avalonia-themes-fluent",{"title":1563,"path":1564,"stem":1565},"Контроли колекцій — глибоке занурення","\u002Fcsharp\u002Fdesktop-ui\u002Fcollection-controls","01.csharp\u002F12.desktop-ui\u002F31.collection-controls",{"title":1567,"path":1568,"stem":1569},"DataGrid — колонки та базове відображення","\u002Fcsharp\u002Fdesktop-ui\u002Fdatagrid-part1","01.csharp\u002F12.desktop-ui\u002F32.datagrid-part1",{"title":1571,"path":1572,"stem":1573},"DataGrid — сортування, фільтрація, редагування","\u002Fcsharp\u002Fdesktop-ui\u002Fdatagrid-part2","01.csharp\u002F12.desktop-ui\u002F32.datagrid-part2",{"title":1575,"path":1576,"stem":1577},"TreeView та GridView","\u002Fcsharp\u002Fdesktop-ui\u002Ftreeview-listview","01.csharp\u002F12.desktop-ui\u002F33.treeview-listview",{"title":1579,"path":1580,"stem":1581},"Меню, Toolbar, ContextMenu, StatusBar","\u002Fcsharp\u002Fdesktop-ui\u002Fmenus-toolbars","01.csharp\u002F12.desktop-ui\u002F34.menus-toolbars",{"title":1583,"path":1584,"stem":1585},"Навігація та керування вікнами. Частина 1: вікна та сторінки","\u002Fcsharp\u002Fdesktop-ui\u002Fnavigation-windows-part1","01.csharp\u002F12.desktop-ui\u002F35.navigation-windows-part1",{"title":1587,"path":1588,"stem":1589},"Навігація та керування вікнами. Частина 2: MVVM-навігація","\u002Fcsharp\u002Fdesktop-ui\u002Fnavigation-windows-part2","01.csharp\u002F12.desktop-ui\u002F35.navigation-windows-part2",{"title":1591,"path":1592,"stem":1593},"Avalonia — Навігація та діалоги","\u002Fcsharp\u002Fdesktop-ui\u002F35a.avalonia-navigation-dialogs","01.csharp\u002F12.desktop-ui\u002F35a.avalonia-navigation-dialogs",{"title":1595,"path":1596,"stem":1597},"Діалоги та File Pickers у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fdialogs-file-pickers","01.csharp\u002F12.desktop-ui\u002F36.dialogs-file-pickers",{"title":1599,"path":1600,"stem":1601},"UserControl: компонентний підхід у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fuser-controls","01.csharp\u002F12.desktop-ui\u002F37.user-controls",{"title":1603,"path":1604,"stem":1605},"Custom Controls: Lookless Controls у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fcustom-controls","01.csharp\u002F12.desktop-ui\u002F38.custom-controls",{"title":1607,"path":1608,"stem":1609},"Avalonia TemplatedControl — Lookless Controls","\u002Fcsharp\u002Fdesktop-ui\u002F38a.avalonia-templated-controls","01.csharp\u002F12.desktop-ui\u002F38a.avalonia-templated-controls",{"title":1611,"path":1612,"stem":1613},"Анімації у WPF: Storyboard та Easing Functions","\u002Fcsharp\u002Fdesktop-ui\u002Fanimations-transitions","01.csharp\u002F12.desktop-ui\u002F39.animations-transitions",{"title":1615,"path":1616,"stem":1617},"Анімації в Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002F39a.avalonia-animations","01.csharp\u002F12.desktop-ui\u002F39a.avalonia-animations",{"title":1619,"path":1620,"stem":1621},"2D Графіка та Мультимедіа у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fmedia-graphics","01.csharp\u002F12.desktop-ui\u002F40.media-graphics",{"title":1623,"path":1624,"stem":1625},"Dependency Injection у WPF та Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002Fdi-integration","01.csharp\u002F12.desktop-ui\u002F41.di-integration",{"title":1627,"path":1628,"stem":1629},"SQLite та EF Core у десктопних додатках","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-persistence-part1","01.csharp\u002F12.desktop-ui\u002F42.data-persistence-part1",{"title":1631,"path":1632,"stem":1633},"Repository Pattern та Unit of Work","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-persistence-part2","01.csharp\u002F12.desktop-ui\u002F43.data-persistence-part2",{"title":1635,"path":1636,"stem":1637},"Тестування ViewModels","\u002Fcsharp\u002Fdesktop-ui\u002Fviewmodel-testing","01.csharp\u002F12.desktop-ui\u002F44.viewmodel-testing",{"title":1639,"path":1640,"stem":1641},"Avalonia Headless Testing — тестування UI без вікон","\u002Fcsharp\u002Fdesktop-ui\u002F44a.avalonia-headless-testing","01.csharp\u002F12.desktop-ui\u002F44a.avalonia-headless-testing",{"title":1643,"path":1644,"stem":1645},"Кросплатформна розробка з Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002Favalonia-cross-platform","01.csharp\u002F12.desktop-ui\u002F45.avalonia-cross-platform",{"title":1647,"path":1648,"stem":1649},"Пакування та розгортання Avalonia додатків","\u002Fcsharp\u002Fdesktop-ui\u002Favalonia-packaging-deployment","01.csharp\u002F12.desktop-ui\u002F46.avalonia-packaging-deployment",{"title":1651,"path":1652,"stem":1653},"Розгортання WPF застосунків","\u002Fcsharp\u002Fdesktop-ui\u002Fwpf-packaging-deployment","01.csharp\u002F12.desktop-ui\u002F47.wpf-packaging-deployment",{"title":1655,"icon":658,"path":1656,"stem":1657,"children":1658,"page":59},"Network Programming","\u002Fcsharp\u002Fnetwork-programming","01.csharp\u002F13.network-programming",[1659,1663,1667,1671,1675,1679,1683,1687,1691,1695,1699],{"title":1660,"path":1661,"stem":1662},"Основи комп'ютерних мереж","\u002Fcsharp\u002Fnetwork-programming\u002Ffoundations","01.csharp\u002F13.network-programming\u002F01.foundations",{"title":1664,"path":1665,"stem":1666},"Модель OSI та стек TCP\u002FIP","\u002Fcsharp\u002Fnetwork-programming\u002Fosi-model","01.csharp\u002F13.network-programming\u002F02.osi-model",{"title":1668,"path":1669,"stem":1670},"IP-протокол та адресація","\u002Fcsharp\u002Fnetwork-programming\u002Fip-addressing","01.csharp\u002F13.network-programming\u002F03.ip-addressing",{"title":1672,"path":1673,"stem":1674},"UDP — протокол без з'єднання","\u002Fcsharp\u002Fnetwork-programming\u002Fudp","01.csharp\u002F13.network-programming\u002F05.udp",{"title":1676,"path":1677,"stem":1678},"UDP Broadcast та Multicast","\u002Fcsharp\u002Fnetwork-programming\u002Fudp-broadcast-multicast","01.csharp\u002F13.network-programming\u002F06.udp-broadcast-multicast",{"title":1680,"path":1681,"stem":1682},"HTTP — протокол вебу","\u002Fcsharp\u002Fnetwork-programming\u002Fhttp-fundamentals","01.csharp\u002F13.network-programming\u002F07.http-fundamentals",{"title":1684,"path":1685,"stem":1686},"HttpListener — вбудований HTTP-сервер .NET","\u002Fcsharp\u002Fnetwork-programming\u002F07a.http-listener","01.csharp\u002F13.network-programming\u002F07a.http-listener",{"title":1688,"path":1689,"stem":1690},"HTTP Advanced — cookies, аутентифікація та HTTPS","\u002Fcsharp\u002Fnetwork-programming\u002Fhttp-advanced","01.csharp\u002F13.network-programming\u002F08.http-advanced",{"title":1692,"path":1693,"stem":1694},"SMTP та протоколи електронної пошти","\u002Fcsharp\u002Fnetwork-programming\u002Fsmtp","01.csharp\u002F13.network-programming\u002F09.smtp",{"title":1696,"path":1697,"stem":1698},"WebSocket — повнодуплексний протокол реального часу","\u002Fcsharp\u002Fnetwork-programming\u002Fwebsockets","01.csharp\u002F13.network-programming\u002F10.websockets",{"title":1700,"path":1701,"stem":1702},"TLS\u002FSSL — криптографічний захист мережевих з'єднань","\u002Fcsharp\u002Fnetwork-programming\u002Ftls-ssl","01.csharp\u002F13.network-programming\u002F11.tls-ssl",{"title":1704,"path":1705,"stem":1706},"C# & .NET: The Ultimate Roadmap","\u002Fcsharp\u002Froadmap","01.csharp\u002Froadmap",{"title":1708,"icon":1709,"path":1710,"stem":1711,"children":1712,"page":59},"C++","i-devicon-cplusplus","\u002Fcpp","02.cpp",[1713,1717,1721,1725,1729,1733,1737,1741,1745,1748,1752,1756,1760,1764,1768,1772,1776,1780,1784,1788,1792,1796,1800,1804,1808,1812,1816,1820,1824,1828,1832,1836,1840,1844,1848,1852,1856,1860,1864,1868,1872,1876,1880,1884,1888,1892,1896,1900],{"title":1714,"path":1715,"stem":1716},"Вступ у програмування та алгоритми","\u002Fcpp\u002Fintro-algorithms","02.cpp\u002F01.intro-algorithms",{"title":1718,"path":1719,"stem":1720},"Code Style: угоди про оформлення коду","\u002Fcpp\u002Fcode-style","02.cpp\u002F02.code-style",{"title":1722,"path":1723,"stem":1724},"Середовище розробки та перший проєкт","\u002Fcpp\u002Fide-setup","02.cpp\u002F03.ide-setup",{"title":1726,"path":1727,"stem":1728},"Вивід даних на екран","\u002Fcpp\u002Fdata-output","02.cpp\u002F04.data-output",{"title":1730,"path":1731,"stem":1732},"Типи даних, змінні та константи","\u002Fcpp\u002Fdata-types-variables","02.cpp\u002F05.data-types-variables",{"title":1734,"path":1735,"stem":1736},"Ввід даних з клавіатури","\u002Fcpp\u002Fdata-input","02.cpp\u002F06.data-input",{"title":1738,"path":1739,"stem":1740},"Оператори, перетворення типів та логічні операції","\u002Fcpp\u002Foperators-type-conversion","02.cpp\u002F07.operators-type-conversion",{"title":1742,"path":1743,"stem":1744},"Цикли","\u002Fcpp\u002Floops","02.cpp\u002F08.loops",{"title":32,"path":1746,"stem":1747},"\u002Fcpp\u002Farrays","02.cpp\u002F09.arrays",{"title":1749,"path":1750,"stem":1751},"Алгоритми сортування та аналіз складності","\u002Fcpp\u002Fsorting","02.cpp\u002F10.sorting",{"title":1753,"path":1754,"stem":1755},"Алгоритми пошуку","\u002Fcpp\u002Fsearching","02.cpp\u002F11.searching",{"title":1757,"path":1758,"stem":1759},"Функції: основи","\u002Fcpp\u002Ffunctions-basics","02.cpp\u002F12.functions-basics",{"title":1761,"path":1762,"stem":1763},"Функції: прототипи, область видимості та додаткові можливості","\u002Fcpp\u002Ffunctions-scope","02.cpp\u002F13.functions-scope",{"title":1765,"path":1766,"stem":1767},"Функції: перевантаження та шаблони","\u002Fcpp\u002Ffunctions-overloading-templates","02.cpp\u002F14.functions-overloading-templates",{"title":1769,"path":1770,"stem":1771},"Вказівники: основи","\u002Fcpp\u002Fpointers-basics","02.cpp\u002F15.pointers-basics",{"title":1773,"path":1774,"stem":1775},"Посилання (References)","\u002Fcpp\u002Freferences","02.cpp\u002F16.references",{"title":1777,"path":1778,"stem":1779},"Вказівники, const і масиви","\u002Fcpp\u002Fpointers-const-arrays","02.cpp\u002F17.pointers-const-arrays",{"title":1781,"path":1782,"stem":1783},"Адресна арифметика","\u002Fcpp\u002Fpointer-arithmetic","02.cpp\u002F18.pointer-arithmetic",{"title":1785,"path":1786,"stem":1787},"Динамічна пам'ять","\u002Fcpp\u002Fdynamic-memory","02.cpp\u002F19.dynamic-memory",{"title":1789,"path":1790,"stem":1791},"Вказівники типу void","\u002Fcpp\u002Fvoid-pointers","02.cpp\u002F20.void-pointers",{"title":1793,"path":1794,"stem":1795},"Вказівники на вказівники","\u002Fcpp\u002Fpointers-to-pointers","02.cpp\u002F21.pointers-to-pointers",{"title":1797,"path":1798,"stem":1799},"Оператор доступу до членів через вказівник (->)","\u002Fcpp\u002Fmember-access-operator","02.cpp\u002F22.member-access-operator",{"title":1801,"path":1802,"stem":1803},"Цикл for-each (Range-based for)","\u002Fcpp\u002Fforeach-loop","02.cpp\u002F23.foreach-loop",{"title":1805,"path":1806,"stem":1807},"Вказівники на функції","\u002Fcpp\u002Ffunction-pointers","02.cpp\u002F24.function-pointers",{"title":1809,"path":1810,"stem":1811},"Лямбда-вирази","\u002Fcpp\u002Flambdas","02.cpp\u002F25.lambdas",{"title":1813,"path":1814,"stem":1815},"Лямбда-захоплення","\u002Fcpp\u002Flambda-captures","02.cpp\u002F26.lambda-captures",{"title":1817,"path":1818,"stem":1819},"Еліпсис","\u002Fcpp\u002Fellipsis","02.cpp\u002F27.ellipsis",{"title":1821,"path":1822,"stem":1823},"Безпечні альтернативи еліпсису","\u002Fcpp\u002F27a.ellipsis","02.cpp\u002F27a.ellipsis",{"title":1825,"path":1826,"stem":1827},"Аргументи командного рядка","\u002Fcpp\u002Fcommand-line-arguments","02.cpp\u002F28.command-line-arguments",{"title":1829,"path":1830,"stem":1831},"Перерахування (enum)","\u002Fcpp\u002Fenum","02.cpp\u002F29.enum",{"title":1833,"path":1834,"stem":1835},"Класи-перерахування (enum class)","\u002Fcpp\u002Fenum-class","02.cpp\u002F30.enum-class",{"title":1837,"path":1838,"stem":1839},"Псевдоніми типів (typedef і using)","\u002Fcpp\u002Ftype-aliases","02.cpp\u002F31.type-aliases",{"title":1841,"path":1842,"stem":1843},"Системи числення та двійкова арифметика","\u002Fcpp\u002Fnumber-systems","02.cpp\u002F32.number-systems",{"title":1845,"path":1846,"stem":1847},"Структури (struct): агрегування даних","\u002Fcpp\u002Fstruct","02.cpp\u002F33.struct",{"title":1849,"path":1850,"stem":1851},"Структури у функціях","\u002Fcpp\u002Fstruct-functions","02.cpp\u002F34.struct-functions",{"title":1853,"path":1854,"stem":1855},"Масиви структур і вкладені структури","\u002Fcpp\u002Fstruct-arrays","02.cpp\u002F35.struct-arrays",{"title":1857,"path":1858,"stem":1859},"Патерни struct та межі застосування","\u002Fcpp\u002Fstruct-patterns","02.cpp\u002F36.struct-patterns",{"title":1861,"path":1862,"stem":1863},"Символи та таблиця ASCII","\u002Fcpp\u002Fascii-characters","02.cpp\u002F37.ascii-characters",{"title":1865,"path":1866,"stem":1867},"Unicode та кодування UTF","\u002Fcpp\u002Funicode-utf","02.cpp\u002F38.unicode-utf",{"title":1869,"path":1870,"stem":1871},"C-style рядки","\u002Fcpp\u002Fc-strings","02.cpp\u002F39.c-strings",{"title":1873,"path":1874,"stem":1875},"Вступ до std::string","\u002Fcpp\u002Fstd-string-intro","02.cpp\u002F40.std-string-intro",{"title":1877,"path":1878,"stem":1879},"Довжина, ємність та доступ до символів std::string","\u002Fcpp\u002Fstd-string-capacity-access","02.cpp\u002F41.std-string-capacity-access",{"title":1881,"path":1882,"stem":1883},"Модифікація std::string: присвоювання, додавання, вставка, видалення та заміна","\u002Fcpp\u002Fstd-string-modification","02.cpp\u002F42.std-string-modification",{"title":1885,"path":1886,"stem":1887},"Пошук у std::string: find, npos та практичні патерни","\u002Fcpp\u002Fstd-string-search","02.cpp\u002F43.std-string-search",{"title":1889,"path":1890,"stem":1891},"std::string_view: невласницький погляд на рядок без копіювання","\u002Fcpp\u002Fstd-string-view","02.cpp\u002F44.std-string-view",{"title":1893,"path":1894,"stem":1895},"Об'єднання (union): один блок пам'яті, кілька інтерпретацій","\u002Fcpp\u002Funion","02.cpp\u002F45.union",{"title":1897,"path":1898,"stem":1899},"Організація коду: файли, препроцесор, простори імен","\u002Fcpp\u002Fmultifile-programs","02.cpp\u002F46.multifile-programs",{"title":1901,"path":1902,"stem":1903},"План навчання: Курс C++ — Продовження (Статті 29–60+)","\u002Fcpp\u002Fcurriculum-plan","02.cpp\u002Fcurriculum-plan",{"title":1905,"icon":1906,"path":1907,"stem":1908,"children":1909,"page":59},"JavaScript","i-devicon-javascript","\u002Fjavascript","03.javascript",[1910,1936,1990,2012,2316,2354],{"title":1911,"icon":1912,"path":1913,"stem":1914,"children":1915,"page":59},"Events","i-lucide-mouse-pointer-click","\u002Fjavascript\u002Fevents","03.javascript\u002F01.events",[1916,1920,1924,1928,1932],{"title":1917,"path":1918,"stem":1919},"Вступ до подій браузера","\u002Fjavascript\u002Fevents\u002Fintro","03.javascript\u002F01.events\u002F01.intro",{"title":1921,"path":1922,"stem":1923},"Бульбашковий механізм (Bubbling) та занурення (Capturing)","\u002Fjavascript\u002Fevents\u002Fbubbling-capturing","03.javascript\u002F01.events\u002F02.bubbling-capturing",{"title":1925,"path":1926,"stem":1927},"Делегування подій (Event Delegation)","\u002Fjavascript\u002Fevents\u002Fdelegate-events","03.javascript\u002F01.events\u002F03.delegate-events",{"title":1929,"path":1930,"stem":1931},"Типові дії браузера та preventDefault()","\u002Fjavascript\u002Fevents\u002Fprevent-default","03.javascript\u002F01.events\u002F04.prevent-default",{"title":1933,"path":1934,"stem":1935},"Запуск користувацьких подій (Custom Events)","\u002Fjavascript\u002Fevents\u002Fcustom-events","03.javascript\u002F01.events\u002F05.custom-events",{"title":1937,"icon":1938,"path":1939,"stem":1940,"children":1941,"page":59},"Network","i-lucide-globe","\u002Fjavascript\u002Fnetwork","03.javascript\u002F02.network",[1942,1946,1950,1954,1958,1962,1966,1970,1974,1978,1982,1986],{"title":1943,"path":1944,"stem":1945},"Fetch API - Сучасний підхід до HTTP-запитів","\u002Fjavascript\u002Fnetwork\u002F01-fetch-api","03.javascript\u002F02.network\u002F01-fetch-api",{"title":1947,"path":1948,"stem":1949},"FormData - Робота з формами та файлами","\u002Fjavascript\u002Fnetwork\u002F02-formdata","03.javascript\u002F02.network\u002F02-formdata",{"title":1951,"path":1952,"stem":1953},"Відстеження прогресу завантаження","\u002Fjavascript\u002Fnetwork\u002F03-download-progress","03.javascript\u002F02.network\u002F03-download-progress",{"title":1955,"path":1956,"stem":1957},"Переривання fetch-запитів","\u002Fjavascript\u002Fnetwork\u002F04-abort-requests","03.javascript\u002F02.network\u002F04-abort-requests",{"title":1959,"path":1960,"stem":1961},"CORS - Запити між різними джерелами","\u002Fjavascript\u002Fnetwork\u002F05-cors","03.javascript\u002F02.network\u002F05-cors",{"title":1963,"path":1964,"stem":1965},"Fetch API - Повний довідник опцій","\u002Fjavascript\u002Fnetwork\u002F06-fetch-options","03.javascript\u002F02.network\u002F06-fetch-options",{"title":1967,"path":1968,"stem":1969},"URL Objects - Робота з посиланнями","\u002Fjavascript\u002Fnetwork\u002F07-url-objects","03.javascript\u002F02.network\u002F07-url-objects",{"title":1971,"path":1972,"stem":1973},"XMLHttpRequest - AJAX та низькорівневі запити","\u002Fjavascript\u002Fnetwork\u002F08-xmlhttprequest","03.javascript\u002F02.network\u002F08-xmlhttprequest",{"title":1975,"path":1976,"stem":1977},"Відновлюване завантаження файлів","\u002Fjavascript\u002Fnetwork\u002F09-resumable-upload","03.javascript\u002F02.network\u002F09-resumable-upload",{"title":1979,"path":1980,"stem":1981},"Cookies, document.cookie та світ після \"Cookiepocalypse\"","\u002Fjavascript\u002Fnetwork\u002F10-cookies","03.javascript\u002F02.network\u002F10-cookies",{"title":1983,"path":1984,"stem":1985},"js-cookie: Керування Cookies без Болю","\u002Fjavascript\u002Fnetwork\u002F11-js-cookie","03.javascript\u002F02.network\u002F11-js-cookie",{"title":1987,"path":1988,"stem":1989},"Axios: Потужний HTTP-клієнт для JavaScript","\u002Fjavascript\u002Fnetwork\u002F12-axios","03.javascript\u002F02.network\u002F12-axios",{"title":1991,"icon":1992,"path":1993,"stem":1994,"children":1995,"page":59},"Bom","i-lucide-monitor","\u002Fjavascript\u002Fbom","03.javascript\u002F03.bom",[1996,2000,2004,2008],{"title":1997,"path":1998,"stem":1999},"LocalStorage, SessionStorage та patterns збереження даних","\u002Fjavascript\u002Fbom\u002F01-localstorage","03.javascript\u002F03.bom\u002F01-localstorage",{"title":2001,"path":2002,"stem":2003},"Location Object - Керування адресою сторінки","\u002Fjavascript\u002Fbom\u002F02-location-object","03.javascript\u002F03.bom\u002F02-location-object",{"title":2005,"path":2006,"stem":2007},"History API - Керування історією браузера","\u002Fjavascript\u002Fbom\u002F03-history-api","03.javascript\u002F03.bom\u002F03-history-api",{"title":2009,"path":2010,"stem":2011},"Navigator Object - Ідентифікація та Можливості Пристрою","\u002Fjavascript\u002Fbom\u002F04-navigator-object","03.javascript\u002F03.bom\u002F04-navigator-object",{"title":2013,"icon":2014,"path":2015,"stem":2016,"children":2017},"React","i-devicon-react","\u002Fjavascript\u002Freact","03.javascript\u002F04.react\u002Findex",[2018,2019,2023,2027,2031,2035,2098,2133,2285],{"title":2013,"path":2015,"stem":2016},{"title":2020,"path":2021,"stem":2022},"Робота з Формами в React","\u002Fjavascript\u002Freact\u002Freact-forms","03.javascript\u002F04.react\u002F01.react-forms",{"title":2024,"path":2025,"stem":2026},"React Hook Form: Професійна Робота з Формами","\u002Fjavascript\u002Freact\u002Freact-hook-form","03.javascript\u002F04.react\u002F02.react-hook-form",{"title":2028,"path":2029,"stem":2030},"React Hook Form: Глибоке Розуміння Архітектури та Оптимізації","\u002Fjavascript\u002Freact\u002Freact-hook-form-new","03.javascript\u002F04.react\u002F02.react-hook-form-new",{"title":2032,"path":2033,"stem":2034},"Axios та React: Професійна Архітектура Запитів","\u002Fjavascript\u002Freact\u002Fdata-fetching-axios","03.javascript\u002F04.react\u002F03.data-fetching-axios",{"title":2036,"icon":132,"path":2037,"stem":2038,"children":2039},"Tanstack Query","\u002Fjavascript\u002Freact\u002Ftanstack-query","03.javascript\u002F04.react\u002F04.tanstack-query\u002Findex",[2040,2042,2046,2050,2054,2058,2062,2066,2070,2074,2078,2082,2086,2090,2094],{"title":2041,"path":2037,"stem":2038},"TanStack Query: Майстерність Керування Станом Сервера",{"title":2043,"path":2044,"stem":2045},"Парадигма Server State: Чому useEffect недостатньо","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fserver-state-paradigm","03.javascript\u002F04.react\u002F04.tanstack-query\u002F01.server-state-paradigm",{"title":2047,"path":2048,"stem":2049},"Встановлення та Налаштування: Фундамент","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Finstallation-and-devtools","03.javascript\u002F04.react\u002F04.tanstack-query\u002F02.installation-and-devtools",{"title":2051,"path":2052,"stem":2053},"Основи Запитів та Магія Ключів","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fquery-basics-and-keys","03.javascript\u002F04.react\u002F04.tanstack-query\u002F03.query-basics-and-keys",{"title":2055,"path":2056,"stem":2057},"Синхронізація Даних: Життєвий Цикл Запиту","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fdata-synchronization","03.javascript\u002F04.react\u002F04.tanstack-query\u002F04.data-synchronization",{"title":2059,"path":2060,"stem":2061},"Мутації та Інвалідація: Зміна Даних","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fmutations-and-invalidation","03.javascript\u002F04.react\u002F04.tanstack-query\u002F05.mutations-and-invalidation",{"title":2063,"path":2064,"stem":2065},"Оптимістичні Оновлення: Швидше за Світло","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Foptimistic-updates","03.javascript\u002F04.react\u002F04.tanstack-query\u002F06.optimistic-updates",{"title":2067,"path":2068,"stem":2069},"Пагінація та Infinite Scroll","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fpagination-and-load-more","03.javascript\u002F04.react\u002F04.tanstack-query\u002F07.pagination-and-load-more",{"title":2071,"path":2072,"stem":2073},"Просунуті Патерни та Оптимізація","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fadvanced-patterns","03.javascript\u002F04.react\u002F04.tanstack-query\u002F08.advanced-patterns",{"title":2075,"path":2076,"stem":2077},"Архітектура та Best Practices","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Farchitecture-and-best-practices","03.javascript\u002F04.react\u002F04.tanstack-query\u002F09.architecture-and-best-practices",{"title":2079,"path":2080,"stem":2081},"Server-Side Rendering (SSR) та Гідратація","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fserver-side-rendering","03.javascript\u002F04.react\u002F04.tanstack-query\u002F10.server-side-rendering",{"title":2083,"path":2084,"stem":2085},"Стратегії Тестування","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Ftesting-strategies","03.javascript\u002F04.react\u002F04.tanstack-query\u002F11.testing-strategies",{"title":2087,"path":2088,"stem":2089},"Аутентифікація та Обробка Помилок","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fauthentication-and-errors","03.javascript\u002F04.react\u002F04.tanstack-query\u002F12.authentication-and-errors",{"title":2091,"path":2092,"stem":2093},"React Suspense та Майбутнє","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Freact-suspense","03.javascript\u002F04.react\u002F04.tanstack-query\u002F13.react-suspense",{"title":2095,"path":2096,"stem":2097},"Глибоке Занурення в Продуктивність","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fperformance-deep-dive","03.javascript\u002F04.react\u002F04.tanstack-query\u002F14.performance-deep-dive",{"title":2099,"icon":2014,"path":2100,"stem":2101,"children":2102},"React Router","\u002Fjavascript\u002Freact\u002Freact-router","03.javascript\u002F04.react\u002F05.react-router\u002Findex",[2103,2105,2109,2113,2117,2121,2125,2129],{"title":2104,"path":2100,"stem":2101},"React Router: Навігаційна система сучасного вебу",{"title":2106,"path":2107,"stem":2108},"Налаштування та Базовий Роутинг","\u002Fjavascript\u002Freact\u002Freact-router\u002Fsetup-and-basic-routing","03.javascript\u002F04.react\u002F05.react-router\u002F01.setup-and-basic-routing",{"title":2110,"path":2111,"stem":2112},"Динамічна Навігація","\u002Fjavascript\u002Freact\u002Freact-router\u002Fnavigation-and-links","03.javascript\u002F04.react\u002F05.react-router\u002F02.navigation-and-links",{"title":2114,"path":2115,"stem":2116},"Вкладені Маршрути та Макети","\u002Fjavascript\u002Freact\u002Freact-router\u002Fnested-routes-and-layouts","03.javascript\u002F04.react\u002F05.react-router\u002F03.nested-routes-and-layouts",{"title":2118,"path":2119,"stem":2120},"Динамічні Маршрути та Параметри","\u002Fjavascript\u002Freact\u002Freact-router\u002Fdynamic-routing","03.javascript\u002F04.react\u002F05.react-router\u002F04.dynamic-routing",{"title":2122,"path":2123,"stem":2124},"Data APIs: Loaders та Actions","\u002Fjavascript\u002Freact\u002Freact-router\u002Fdata-loading","03.javascript\u002F04.react\u002F05.react-router\u002F05.data-loading",{"title":2126,"path":2127,"stem":2128},"Просунуті Патерни","\u002Fjavascript\u002Freact\u002Freact-router\u002Fadvanced-patterns","03.javascript\u002F04.react\u002F05.react-router\u002F06.advanced-patterns",{"title":2130,"path":2131,"stem":2132},"Legacy Routing: Компонентний підхід","\u002Fjavascript\u002Freact\u002Freact-router\u002Flegacy-routing","03.javascript\u002F04.react\u002F05.react-router\u002F07.legacy-routing",{"title":2134,"icon":132,"path":2135,"stem":2136,"children":2137},"Redux","\u002Fjavascript\u002Freact\u002Fredux","03.javascript\u002F04.react\u002F06.redux\u002Findex",[2138,2140,2156,2185,2194,2215,2231,2260],{"title":2139,"path":2135,"stem":2136},"Redux: Еволюція управління станом",{"title":14,"icon":15,"path":2141,"stem":2142,"children":2143,"page":59},"\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals",[2144,2148,2152],{"title":2145,"path":2146,"stem":2147},"Вступ до State Management","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fintro-state-management","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F01.intro-state-management",{"title":2149,"path":2150,"stem":2151},"Філософія Redux та Три Принципи","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fredux-philosophy","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F02.redux-philosophy",{"title":2153,"path":2154,"stem":2155},"Чисті функції та Іммутабельність","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fpure-functions-immutability","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F03.pure-functions-immutability",{"title":2157,"icon":132,"path":2158,"stem":2159,"children":2160,"page":59},"Classic Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux",[2161,2165,2169,2173,2177,2181],{"title":2162,"path":2163,"stem":2164},"Створення Store (Classic Redux)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fstore-setup","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F01.store-setup",{"title":2166,"path":2167,"stem":2168},"Actions, Constants та Action Creators","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Factions-constants","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F02.actions-constants",{"title":2170,"path":2171,"stem":2172},"Логіка Reducers","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Freducers","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F03.reducers",{"title":2174,"path":2175,"stem":2176},"Комбінування Reducers (Root Reducer)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fdata-flow","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F04.data-flow",{"title":2178,"path":2179,"stem":2180},"Підключення до React (React-Redux)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Freact-redux-connection","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F05.react-redux-connection",{"title":2182,"path":2183,"stem":2184},"Middleware та Асинхронність (Redux Thunk)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fmiddleware-thunk","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F06.middleware-thunk",{"title":2186,"icon":132,"path":2187,"stem":2188,"children":2189,"page":59},"Transition To Rtk","\u002Fjavascript\u002Freact\u002Fredux\u002Ftransition-to-rtk","03.javascript\u002F04.react\u002F06.redux\u002F03.transition-to-rtk",[2190],{"title":2191,"path":2192,"stem":2193},"Проблеми класичного Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Ftransition-to-rtk\u002Fproblems-with-classic","03.javascript\u002F04.react\u002F06.redux\u002F03.transition-to-rtk\u002F01.problems-with-classic",{"title":2195,"icon":132,"path":2196,"stem":2197,"children":2198,"page":59},"Redux Toolkit","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit",[2199,2203,2207,2211],{"title":2200,"path":2201,"stem":2202},"Налаштування Store з configureStore","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fconfigure-store","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F01.configure-store",{"title":2204,"path":2205,"stem":2206},"createSlice: Революція в Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fcreate-slice","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F02.create-slice",{"title":2208,"path":2209,"stem":2210},"Асинхронність з createAsyncThunk","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fasync-thunks","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F03.async-thunks",{"title":2212,"path":2213,"stem":2214},"04. Entity Adapter: Керування нормалізованим станом","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fentity-adapter","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F04.entity-adapter",{"title":2216,"icon":92,"path":2217,"stem":2218,"children":2219,"page":59},"Advanced","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced",[2220,2224,2228],{"title":2221,"path":2222,"stem":2223},"Мемоізація та Селектори: Повний Гайд по Reselect","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Fselectors-reselect","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F01.selectors-reselect",{"title":2225,"path":2226,"stem":2227},"RTK Query: Архітектура Серверного Кешу","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Frtk-query-intro","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F02.rtk-query-intro",{"title":2075,"path":2229,"stem":2230},"\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Farchitecture-best-practices","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F03.architecture-best-practices",{"title":2232,"icon":132,"path":2233,"stem":2234,"children":2235,"page":59},"Project Kanban","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban",[2236,2240,2244,2248,2252,2256],{"title":2237,"path":2238,"stem":2239},"Проєкт: Kanban Board (Trello Clone)","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fproject-overview","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F01.project-overview",{"title":2241,"path":2242,"stem":2243},"Налаштування та Типізація","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fsetup-and-types","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F02.setup-and-types",{"title":2245,"path":2246,"stem":2247},"Board Slice: Серце Дошки","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fboard-slice","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F03.board-slice",{"title":2249,"path":2250,"stem":2251},"Логіка Drag & Drop","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fdrag-and-drop-logic","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F04.drag-and-drop-logic",{"title":2253,"path":2254,"stem":2255},"Інтеграція з RTK Query","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Frtk-query-integration","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F05.rtk-query-integration",{"title":2257,"path":2258,"stem":2259},"Optimistic Updates","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Foptimistic-updates","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F06.optimistic-updates",{"title":2261,"icon":132,"path":2262,"stem":2263,"children":2264,"page":59},"Testing","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting","03.javascript\u002F04.react\u002F06.redux\u002F07.testing",[2265,2269,2273,2277,2281],{"title":2266,"path":2267,"stem":2268},"Тестування Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Fintro-testing","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F01.intro-testing",{"title":2270,"path":2271,"stem":2272},"Тестування Reducers","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-reducers","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F02.testing-reducers",{"title":2274,"path":2275,"stem":2276},"Тестування Селекторів","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-selectors","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F03.testing-selectors",{"title":2278,"path":2279,"stem":2280},"Тестування Компонентів (Integration)","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-components","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F04.testing-components",{"title":2282,"path":2283,"stem":2284},"Тестування Async Thunks","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-thunks","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F05.testing-thunks",{"title":2286,"icon":132,"path":2287,"stem":2288,"children":2289},"Ui Libraries","\u002Fjavascript\u002Freact\u002Fui-libraries","03.javascript\u002F04.react\u002F07.ui-libraries\u002Findex",[2290,2292,2296,2300,2304,2308,2312],{"title":2291,"path":2287,"stem":2288},"UI Бібліотеки в React",{"title":2293,"path":2294,"stem":2295},"Вступ до UI Бібліотек: Навіщо Винаходити Велосипед Двічі?","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fintroduction-to-ui-libraries","03.javascript\u002F04.react\u002F07.ui-libraries\u002F01.introduction-to-ui-libraries",{"title":2297,"path":2298,"stem":2299},"Філософія shadcn\u002Fui: \"Not a Component Library\"","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-philosophy","03.javascript\u002F04.react\u002F07.ui-libraries\u002F02.shadcn-philosophy",{"title":2301,"path":2302,"stem":2303},"Установка та Налаштування shadcn\u002Fui","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-installation","03.javascript\u002F04.react\u002F07.ui-libraries\u002F03.shadcn-installation",{"title":2305,"path":2306,"stem":2307},"Базові Компоненти shadcn\u002Fui: Фундамент Інтерфейсу","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-basics","03.javascript\u002F04.react\u002F07.ui-libraries\u002F04.shadcn-components-basics",{"title":2309,"path":2310,"stem":2311},"Компоненти Форм: Побудова Інтерактивних Form","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-forms","03.javascript\u002F04.react\u002F07.ui-libraries\u002F05.shadcn-components-forms",{"title":2313,"path":2314,"stem":2315},"Складні Компоненти: Dialog, Dropdown, Table та Command","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-advanced","03.javascript\u002F04.react\u002F07.ui-libraries\u002F06.shadcn-components-advanced",{"title":2317,"icon":2318,"path":2319,"stem":2320,"children":2321,"page":59},"TypeScript","i-devicon-typescript","\u002Fjavascript\u002Ftypescript","03.javascript\u002F05.typescript",[2322,2326,2330,2334,2338,2342,2346,2350],{"title":2323,"path":2324,"stem":2325},"TypeScript: Броня для вашого коду","\u002Fjavascript\u002Ftypescript\u002Fintro-and-basic-types","03.javascript\u002F05.typescript\u002F01.intro-and-basic-types",{"title":2327,"path":2328,"stem":2329},"Майстерність Моделювання Даних: Інтерфейси та Просунуті Типи","\u002Fjavascript\u002Ftypescript\u002Finterfaces-and-advanced-types","03.javascript\u002F05.typescript\u002F02.interfaces-and-advanced-types",{"title":2331,"path":2332,"stem":2333},"Алхімія Типів: Generics та Utility Types","\u002Fjavascript\u002Ftypescript\u002Fgenerics-and-utilities","03.javascript\u002F05.typescript\u002F03.generics-and-utilities",{"title":2335,"path":2336,"stem":2337},"Архітектура та Шаблони: Класи в TypeScript","\u002Fjavascript\u002Ftypescript\u002Fclasses-and-oop","03.javascript\u002F05.typescript\u002F04.classes-and-oop",{"title":2339,"path":2340,"stem":2341},"Продакшн та Екосистема: Advanced Config & Workflow","\u002Fjavascript\u002Ftypescript\u002Fadvanced-patterns-and-config","03.javascript\u002F05.typescript\u002F05.advanced-patterns-and-config",{"title":2343,"path":2344,"stem":2345},"TypeScript у світі React","\u002Fjavascript\u002Ftypescript\u002Freact-basics","03.javascript\u002F05.typescript\u002F06.react-basics",{"title":2347,"path":2348,"stem":2349},"React + TypeScript: Продвинуті патерни","\u002Fjavascript\u002Ftypescript\u002Freact-advanced","03.javascript\u002F05.typescript\u002F07.react-advanced",{"title":2351,"path":2352,"stem":2353},"React + TypeScript: Екосистема та бібліотеки","\u002Fjavascript\u002Ftypescript\u002Freact-ecosystem","03.javascript\u002F05.typescript\u002F08.react-ecosystem",{"title":2355,"path":2356,"stem":2357},"Atomic Design","\u002Fjavascript\u002Fatomic-design","03.javascript\u002F2.atomic-design",{"title":2359,"icon":2360,"path":2361,"stem":2362,"children":2363,"page":59},"Java","i-devicon-java","\u002Fjava","04.java",[2364,2367,2370,2374,2378,2382,2386],{"title":162,"path":2365,"stem":2366},"\u002Fjava\u002Fdata-mapper-part1","04.java\u002F01.data-mapper-part1",{"title":166,"path":2368,"stem":2369},"\u002Fjava\u002Fdata-mapper-part2","04.java\u002F02.data-mapper-part2",{"title":2371,"path":2372,"stem":2373},"Service Layer: Організація бізнес-логіки","\u002Fjava\u002Fservice-layer","04.java\u002F03.service-layer",{"title":2375,"path":2376,"stem":2377},"Rich Domain Model та State Pattern","\u002Fjava\u002Frich-domain-model","04.java\u002F04.rich-domain-model",{"title":2379,"path":2380,"stem":2381},"Патерни для складної бізнес-логіки","\u002Fjava\u002Fbusiness-logic-patterns","04.java\u002F05.business-logic-patterns",{"title":2383,"path":2384,"stem":2385},"Обробка помилок та валідація","\u002Fjava\u002Ferror-handling-validation","04.java\u002F06.error-handling-validation",{"title":2387,"path":2388,"stem":2389,"children":2390,"page":59},"Проектування баз даних","\u002Fjava\u002Fpr2","04.java\u002Fpr2",[2391,2395,2399,2403,2407,2411,2415,2419,2423,2427,2431,2435,2439,2443,2447,2451,2455,2459,2463,2467,2471,2475,2479,2483,2487,2491,2495,2499,2503,2507,2511,2515,2519,2523,2527,2531,2535],{"title":2392,"path":2393,"stem":2394},"Концептуальне моделювання: Мистецтво розуміння предметної області","\u002Fjava\u002Fpr2\u002Fconceptual-modeling","04.java\u002Fpr2\u002F01.conceptual-modeling",{"title":2396,"path":2397,"stem":2398},"Логічне моделювання: Від бізнес-ідей до структур даних","\u002Fjava\u002Fpr2\u002Flogical-modeling","04.java\u002Fpr2\u002F02.logical-modeling",{"title":2400,"path":2401,"stem":2402},"Нормалізація: Гігієна даних та боротьба з аномаліями","\u002Fjava\u002Fpr2\u002Fnormalization","04.java\u002Fpr2\u002F03.normalization",{"title":2404,"path":2405,"stem":2406},"Фізична схема: Від абстракції до DDL","\u002Fjava\u002Fpr2\u002Fphysical-schema","04.java\u002Fpr2\u002F04.physical-schema",{"title":2408,"path":2409,"stem":2410},"Архітектурна класифікація таблиць","\u002Fjava\u002Fpr2\u002Ftable-classification","04.java\u002Fpr2\u002F05.table-classification",{"title":2412,"path":2413,"stem":2414},"Database Migrations: Версіонування схеми з Flyway","\u002Fjava\u002Fpr2\u002Fdatabase-migrations","04.java\u002Fpr2\u002F06.database-migrations",{"title":2416,"path":2417,"stem":2418},"А що, якби це була не реляційна БД?","\u002Fjava\u002Fpr2\u002Fbeyond-relational","04.java\u002Fpr2\u002F07.beyond-relational",{"title":2420,"path":2421,"stem":2422},"Object-Relational Impedance Mismatch: Два світи, що не хочуть дружити","\u002Fjava\u002Fpr2\u002Fimpedance-mismatch","04.java\u002Fpr2\u002F09.impedance-mismatch",{"title":2424,"path":2425,"stem":2426},"JDBC: Перший контакт із базою даних","\u002Fjava\u002Fpr2\u002Fjdbc-fundamentals","04.java\u002Fpr2\u002F10.jdbc-fundamentals",{"title":2428,"path":2429,"stem":2430},"Якість коду: Spotless, SpotBugs та SonarQube","\u002Fjava\u002Fpr2\u002F10a.code-quality","04.java\u002Fpr2\u002F10a.code-quality",{"title":2432,"path":2433,"stem":2434},"Connection Pool: Патерн Object Pool для JDBC-з'єднань","\u002Fjava\u002Fpr2\u002Fconnection-pool","04.java\u002Fpr2\u002F11.connection-pool",{"title":2436,"path":2437,"stem":2438},"Row Data Gateway: Об'єкт як обгортка рядка таблиці","\u002Fjava\u002Fpr2\u002Frow-data-gateway","04.java\u002Fpr2\u002F12.row-data-gateway",{"title":2440,"path":2441,"stem":2442},"Table Data Gateway: Фасад таблиці як архітектурний відступ","\u002Fjava\u002Fpr2\u002Ftable-data-gateway","04.java\u002Fpr2\u002F13.table-data-gateway",{"title":2444,"path":2445,"stem":2446},"Repository + Data Mapper: Правильна шарова архітектура з JDBC","\u002Fjava\u002Fpr2\u002Frepository-data-mapper","04.java\u002Fpr2\u002F14.repository-data-mapper",{"title":2448,"path":2449,"stem":2450},"Identity Map: Кешування сутностей у рамках сесії","\u002Fjava\u002Fpr2\u002Fidentity-map","04.java\u002Fpr2\u002F15.identity-map",{"title":2452,"path":2453,"stem":2454},"Unit of Work: Відстеження змін і координація JDBC-транзакцій","\u002Fjava\u002Fpr2\u002Funit-of-work","04.java\u002Fpr2\u002F16.unit-of-work",{"title":2456,"path":2457,"stem":2458},"Strategy: Замінювані SQL-стратегії для підтримки різних СУБД","\u002Fjava\u002Fpr2\u002Fstrategy-sql","04.java\u002Fpr2\u002F17.strategy-sql",{"title":2460,"path":2461,"stem":2462},"Proxy: Lazy Loading для One-To-Many колекцій","\u002Fjava\u002Fpr2\u002Fproxy-lazy-loading","04.java\u002Fpr2\u002F18.proxy-lazy-loading",{"title":2464,"path":2465,"stem":2466},"Generic Repository через Java Reflection: анотації та динамічний SQL","\u002Fjava\u002Fpr2\u002Fgeneric-repository-reflection","04.java\u002Fpr2\u002F19.generic-repository-reflection",{"title":2468,"path":2469,"stem":2470},"Specification Pattern: Композиція бізнес-правил для складних запитів","\u002Fjava\u002Fpr2\u002Fspecification-pattern","04.java\u002Fpr2\u002F20.specification-pattern",{"title":2472,"path":2473,"stem":2474},"Розширені можливості Specification Pattern: підзапити, агрегації та гібридний підхід","\u002Fjava\u002Fpr2\u002F20a.advanced-specifications","04.java\u002Fpr2\u002F20a.advanced-specifications",{"title":2476,"path":2477,"stem":2478},"Асинхронність у JDBC: Від блокуючих викликів до CompletableFuture","\u002Fjava\u002Fpr2\u002Fasynchronous-jdbc","04.java\u002Fpr2\u002F21.asynchronous-jdbc",{"title":2480,"path":2481,"stem":2482},"Інтеграційне тестування JDBC-репозиторіїв: Embedded H2 та патерн AAA","\u002Fjava\u002Fpr2\u002Fintegration-testing-h2","04.java\u002Fpr2\u002F22.integration-testing-h2",{"title":2484,"path":2485,"stem":2486},"Testcontainers: Тестування з реальною PostgreSQL у Docker-контейнерах","\u002Fjava\u002Fpr2\u002Fintegration-testing-testcontainers","04.java\u002Fpr2\u002F23.integration-testing-testcontainers",{"title":2488,"path":2489,"stem":2490},"Google Guice: Впровадження залежностей у JavaFX-проєкті","\u002Fjava\u002Fpr2\u002Fdependency-injection-guice","04.java\u002Fpr2\u002F24.dependency-injection-guice",{"title":2492,"path":2493,"stem":2494},"JavaFX: Основи побудови графічних інтерфейсів","\u002Fjava\u002Fpr2\u002Fjavafx-fundamentals","04.java\u002Fpr2\u002F25.javafx-fundamentals",{"title":2496,"path":2497,"stem":2498},"Properties та Bindings: Реактивність у JavaFX","\u002Fjava\u002Fpr2\u002Fjavafx-properties-bindings","04.java\u002Fpr2\u002F26.javafx-properties-bindings",{"title":2500,"path":2501,"stem":2502},"MVC vs MVP vs MVVM: Еволюція архітектурних патернів UI","\u002Fjava\u002Fpr2\u002Fui-architecture-patterns","04.java\u002Fpr2\u002F27.ui-architecture-patterns",{"title":2504,"path":2505,"stem":2506},"MVVM на практиці: Побудова ViewModel","\u002Fjava\u002Fpr2\u002Fmvvm-viewmodel-implementation","04.java\u002Fpr2\u002F28.mvvm-viewmodel-implementation",{"title":2508,"path":2509,"stem":2510},"View та Controller: Зв'язування з ViewModel через FXML","\u002Fjava\u002Fpr2\u002Fmvvm-view-controller","04.java\u002Fpr2\u002F29.mvvm-view-controller",{"title":2512,"path":2513,"stem":2514},"Інтеграція MVVM з Guice: Автоматична ін'єкція залежностей","\u002Fjava\u002Fpr2\u002Fmvvm-guice-integration","04.java\u002Fpr2\u002F30.mvvm-guice-integration",{"title":2516,"path":2517,"stem":2518},"Валідація та обробка помилок у MVVM","\u002Fjava\u002Fpr2\u002Fmvvm-validation-error-handling","04.java\u002Fpr2\u002F31.mvvm-validation-error-handling",{"title":2520,"path":2521,"stem":2522},"Навігація та управління екранами у JavaFX MVVM","\u002Fjava\u002Fpr2\u002Fmvvm-navigation-screen-management","04.java\u002Fpr2\u002F32.mvvm-navigation-screen-management",{"title":2524,"path":2525,"stem":2526},"Тестування JavaFX MVVM-додатків","\u002Fjava\u002Fpr2\u002Fmvvm-testing","04.java\u002Fpr2\u002F33.mvvm-testing",{"title":2528,"path":2529,"stem":2530},"Стилізація та теми у JavaFX: CSS та User Experience","\u002Fjava\u002Fpr2\u002Fjavafx-styling-themes","04.java\u002Fpr2\u002F34.javafx-styling-themes",{"title":2532,"path":2533,"stem":2534},"AtlantaFX: Сучасні теми для JavaFX додатків","\u002Fjava\u002Fpr2\u002Fatlantafx-modern-themes","04.java\u002Fpr2\u002F35.atlantafx-modern-themes",{"title":2536,"path":2537,"stem":2538},"Пакування та розповсюдження JavaFX-додатків","\u002Fjava\u002Fpr2\u002Fjar-packaging-distribution","04.java\u002Fpr2\u002F36.jar-packaging-distribution",{"title":2540,"icon":2541,"path":2542,"stem":2543,"children":2544,"page":59},"Python","i-devicon-python","\u002Fpython","05.python",[2545,2549,2552,2556,2560,2564,2568,2572,2576,2580,2584,2588,2592,2596,2600,2604],{"title":2546,"path":2547,"stem":2548},"Модулі, Пакети та Віртуальні Середовища","\u002Fpython\u002Fmodules-packages-venv","05.python\u002F00.modules-packages-venv",{"title":71,"path":2550,"stem":2551},"\u002Fpython\u002Fclasses-objects","05.python\u002F01.classes-objects",{"title":2553,"path":2554,"stem":2555},"Інкапсуляція, Керування Доступом та Властивості","\u002Fpython\u002Fencapsulation","05.python\u002F02.encapsulation",{"title":2557,"path":2558,"stem":2559},"Наслідування, MRO та суперсила super()","\u002Fpython\u002Finheritance-mro","05.python\u002F03.inheritance-mro",{"title":2561,"path":2562,"stem":2563},"Абстракція — ABC проти Статичних Протоколів (PEP 544)","\u002Fpython\u002Fabstraction-protocols","05.python\u002F04.abstraction-protocols",{"title":2565,"path":2566,"stem":2567},"Магічні методи (Dunder) та Емуляція протоколів","\u002Fpython\u002Fdunder-methods","05.python\u002F05.dunder-methods",{"title":2569,"path":2570,"stem":2571},"Декоратори та Керування життєвим циклом методів","\u002Fpython\u002Fdecorators-static-class","05.python\u002F06.decorators-static-class",{"title":2573,"path":2574,"stem":2575},"Дескриптори — Магія доступу до атрибутів","\u002Fpython\u002Fdescriptors","05.python\u002F07.descriptors",{"title":2577,"path":2578,"stem":2579},"Метакласи — Динамічне створення класів під капотом CPython","\u002Fpython\u002Fmetaclasses","05.python\u002F08.metaclasses",{"title":2581,"path":2582,"stem":2583},"Dataclasses, NamedTuple та сучасні контейнери Python","\u002Fpython\u002Fmodern-containers","05.python\u002F09.modern-containers",{"title":2585,"path":2586,"stem":2587},"GIL та модель конкурентності CPython — фундамент перед потоками і процесами","\u002Fpython\u002Fgil-concurrency-intro","05.python\u002F11.gil-concurrency-intro",{"title":2589,"path":2590,"stem":2591},"Threading — конкурентність для I\u002FO-bound задач","\u002Fpython\u002Fthreading","05.python\u002F12.threading",{"title":2593,"path":2594,"stem":2595},"Multiprocessing — справжній паралелізм для CPU-bound задач","\u002Fpython\u002Fmultiprocessing","05.python\u002F13.multiprocessing",{"title":2597,"path":2598,"stem":2599},"asyncio — кооперативна конкурентність та event loop","\u002Fpython\u002Fasyncio","05.python\u002F14.asyncio",{"title":2601,"path":2602,"stem":2603},"📦 Повний посібник з модулів, пакетів та віртуальних середовищ у Python","\u002Fpython\u002Flesson_9","05.python\u002Flesson_9",{"title":2605,"path":2606,"stem":2607},"[object Object]","\u002Fpython\u002Foop-plan","05.python\u002Foop-plan",{"title":2609,"icon":2610,"path":2611,"stem":2612,"children":2613,"page":59},"Бази даних","i-lucide-database","\u002Fdatabases","06.databases",[2614,2644,2667,2704,2733,2751,2785,2797,2806],{"title":2615,"icon":2616,"path":2617,"stem":2618,"children":2619,"page":59},"Intro","i-lucide-play","\u002Fdatabases\u002Fintro","06.databases\u002F01.intro",[2620,2624,2628,2632,2636,2640],{"title":2621,"path":2622,"stem":2623},"Введення в теорію баз даних","\u002Fdatabases\u002Fintro\u002Fintroduction-to-databases","06.databases\u002F01.intro\u002F01.introduction-to-databases",{"title":2625,"path":2626,"stem":2627},"Реляційна модель даних","\u002Fdatabases\u002Fintro\u002Frelational-model-theory","06.databases\u002F01.intro\u002F02.relational-model-theory",{"title":2629,"path":2630,"stem":2631},"ER-моделювання","\u002Fdatabases\u002Fintro\u002Fer-modeling","06.databases\u002F01.intro\u002F03.er-modeling",{"title":2633,"path":2634,"stem":2635},"Логічне проектування БД","\u002Fdatabases\u002Fintro\u002Flogical-schema","06.databases\u002F01.intro\u002F04.logical-schema",{"title":2637,"path":2638,"stem":2639},"Класифікація таблиць","\u002Fdatabases\u002Fintro\u002Ftable-classification","06.databases\u002F01.intro\u002F05.table-classification",{"title":2641,"path":2642,"stem":2643},"PlantUML для баз даних","\u002Fdatabases\u002Fintro\u002Fplantuml-diagrams","06.databases\u002F01.intro\u002F06.plantuml-diagrams",{"title":2645,"icon":2610,"path":2646,"stem":2647,"children":2648,"page":59},"MS SQL Server Start","\u002Fdatabases\u002Fms-sql-server-start","06.databases\u002F02.ms-sql-server-start",[2649,2653,2659,2663],{"title":2650,"path":2651,"stem":2652},"Типи даних у MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fdata-types","06.databases\u002F02.ms-sql-server-start\u002F01.data-types",{"title":2654,"path":2655,"stem":2656,"children":2657},"Індекси у MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fsql-indexes","06.databases\u002F02.ms-sql-server-start\u002F02.sql-indexes",[2658],{"title":2654,"path":2655,"stem":2656},{"title":2660,"path":2661,"stem":2662},"Системні бази даних MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fsystem-databases","06.databases\u002F02.ms-sql-server-start\u002F03.system-databases",{"title":2664,"path":2665,"stem":2666},"Огляд мови SQL та запитів","\u002Fdatabases\u002Fms-sql-server-start\u002Fsql-queries-overview","06.databases\u002F02.ms-sql-server-start\u002F04.sql-queries-overview",{"title":2668,"icon":2610,"path":2669,"stem":2670,"children":2671,"page":59},"SQL","\u002Fdatabases\u002Fsql","06.databases\u002F03.sql",[2672,2676,2680,2684,2688,2692,2696,2700],{"title":2673,"path":2674,"stem":2675},"Налаштування демонстраційної бази даних","\u002Fdatabases\u002Fsql\u002Fsample-database-setup","06.databases\u002F03.sql\u002F00.sample-database-setup",{"title":2677,"path":2678,"stem":2679},"DDL - Створення таблиць (CREATE TABLE)","\u002Fdatabases\u002Fsql\u002Fddl-create-table","06.databases\u002F03.sql\u002F01.ddl-create-table",{"title":2681,"path":2682,"stem":2683},"DDL - Зміна та видалення таблиць (ALTER, DROP)","\u002Fdatabases\u002Fsql\u002Fddl-alter-drop-table","06.databases\u002F03.sql\u002F02.ddl-alter-drop-table",{"title":2685,"path":2686,"stem":2687},"SELECT запити - Основи","\u002Fdatabases\u002Fsql\u002Fselect-queries-fundamentals","06.databases\u002F03.sql\u002F03.select-queries-fundamentals",{"title":2689,"path":2690,"stem":2691},"SELECT запити - Розширені можливості","\u002Fdatabases\u002Fsql\u002Fselect-queries-advanced","06.databases\u002F03.sql\u002F04.select-queries-advanced",{"title":2693,"path":2694,"stem":2695},"INSERT запити - Додавання даних","\u002Fdatabases\u002Fsql\u002Finsert-queries","06.databases\u002F03.sql\u002F05.insert-queries",{"title":2697,"path":2698,"stem":2699},"UPDATE та DELETE запити","\u002Fdatabases\u002Fsql\u002Fupdate-delete-queries","06.databases\u002F03.sql\u002F06.update-delete-queries",{"title":2701,"path":2702,"stem":2703},"Транзакції в SQL","\u002Fdatabases\u002Fsql\u002Ftransactions","06.databases\u002F03.sql\u002F07.transactions",{"title":2705,"icon":2610,"path":2706,"stem":2707,"children":2708,"page":59},"Multi Table Databases","\u002Fdatabases\u002Fmulti-table-databases","06.databases\u002F04.multi-table-databases",[2709,2713,2717,2721,2725,2729],{"title":2710,"path":2711,"stem":2712},"Зв'язки та нормалізація БД","\u002Fdatabases\u002Fmulti-table-databases\u002Frelationships-and-normalization","06.databases\u002F04.multi-table-databases\u002F00.relationships-and-normalization",{"title":2714,"path":2715,"stem":2716},"INNER JOIN - З'єднання таблиць","\u002Fdatabases\u002Fmulti-table-databases\u002Finner-join","06.databases\u002F04.multi-table-databases\u002F01.inner-join",{"title":2718,"path":2719,"stem":2720},"OUTER JOINs - LEFT, RIGHT, FULL","\u002Fdatabases\u002Fmulti-table-databases\u002Fouter-joins","06.databases\u002F04.multi-table-databases\u002F02.outer-joins",{"title":2722,"path":2723,"stem":2724},"CROSS та SELF JOINs","\u002Fdatabases\u002Fmulti-table-databases\u002Fcross-self-joins","06.databases\u002F04.multi-table-databases\u002F03.cross-self-joins",{"title":2726,"path":2727,"stem":2728},"Підзапити (Subqueries)","\u002Fdatabases\u002Fmulti-table-databases\u002Fsubqueries","06.databases\u002F04.multi-table-databases\u002F04.subqueries",{"title":2730,"path":2731,"stem":2732},"Агрегації з JOIN","\u002Fdatabases\u002Fmulti-table-databases\u002Faggregations-with-joins","06.databases\u002F04.multi-table-databases\u002F05.aggregations-with-joins",{"title":2734,"icon":2735,"path":2736,"stem":2737,"children":2738,"page":59},"Aggregate Functions","i-lucide-calculator","\u002Fdatabases\u002Faggregate-functions","06.databases\u002F05.aggregate-functions",[2739,2743,2747],{"title":2740,"path":2741,"stem":2742},"Функції агрегування в MS SQL Server","\u002Fdatabases\u002Faggregate-functions\u002Fintroduction-aggregate-functions","06.databases\u002F05.aggregate-functions\u002F01.introduction-aggregate-functions",{"title":2744,"path":2745,"stem":2746},"Групування даних в MS SQL Server","\u002Fdatabases\u002Faggregate-functions\u002Fgrouping-data","06.databases\u002F05.aggregate-functions\u002F02.grouping-data",{"title":2748,"path":2749,"stem":2750},"Підзапити з агрегатними функціями","\u002Fdatabases\u002Faggregate-functions\u002Fsubqueries-aggregates","06.databases\u002F05.aggregate-functions\u002F03.subqueries-aggregates",{"title":2752,"icon":2753,"path":2754,"stem":2755,"children":2756,"page":59},"Тригери та зберігаємі процедури","i-lucide-database-zap","\u002Fdatabases\u002Ftriggers-stored-procedures","06.databases\u002F07.triggers-stored-procedures",[2757,2761,2765,2769,2773,2777,2781],{"title":2758,"path":2759,"stem":2760},"DML-тригери","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fdml-triggers","06.databases\u002F07.triggers-stored-procedures\u002F01.dml-triggers",{"title":2762,"path":2763,"stem":2764},"DDL-тригери","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fddl-triggers","06.databases\u002F07.triggers-stored-procedures\u002F02.ddl-triggers",{"title":2766,"path":2767,"stem":2768},"Transact-SQL розширення","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Ftransact-sql-extensions","06.databases\u002F07.triggers-stored-procedures\u002F03.transact-sql-extensions",{"title":2770,"path":2771,"stem":2772},"Транзакції","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Ftransactions","06.databases\u002F07.triggers-stored-procedures\u002F04.transactions",{"title":2774,"path":2775,"stem":2776},"Зберігаємі процедури","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fstored-procedures","06.databases\u002F07.triggers-stored-procedures\u002F05.stored-procedures",{"title":2778,"path":2779,"stem":2780},"Користувацькі функції","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fuser-defined-functions","06.databases\u002F07.triggers-stored-procedures\u002F06.user-defined-functions",{"title":2782,"path":2783,"stem":2784},"Безпека баз даних","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fsecurity","06.databases\u002F07.triggers-stored-procedures\u002F08.security",{"title":2782,"icon":793,"path":2786,"stem":2787,"children":2788,"page":59},"\u002Fdatabases\u002Fsecurity","06.databases\u002F08.security",[2789,2793],{"title":2790,"path":2791,"stem":2792},"Вступ до безпеки баз даних","\u002Fdatabases\u002Fsecurity\u002Fintroduction","06.databases\u002F08.security\u002F01.introduction",{"title":2794,"path":2795,"stem":2796},"Системні представлення та метадані","\u002Fdatabases\u002Fsecurity\u002Fsystem-views","06.databases\u002F08.security\u002F02.system-views",{"title":2798,"icon":2799,"path":2800,"stem":2801,"children":2802,"page":59},"Резервне копіювання та відновлення","i-lucide-database-backup","\u002Fdatabases\u002Fbackup-recovery","06.databases\u002F09.backup-recovery",[2803],{"title":2798,"path":2804,"stem":2805},"\u002Fdatabases\u002Fbackup-recovery\u002Fbackup-restore","06.databases\u002F09.backup-recovery\u002F01.backup-restore",{"title":2807,"icon":2808,"path":2809,"stem":2810,"children":2811,"page":59},"Повнотекстовий пошук","i-lucide-search","\u002Fdatabases\u002Ffull-text-search","06.databases\u002F10.full-text-search",[2812],{"title":2807,"path":2813,"stem":2814},"\u002Fdatabases\u002Ffull-text-search\u002Ffull-text-search","06.databases\u002F10.full-text-search\u002F01.full-text-search",{"title":2816,"icon":2817,"path":2818,"stem":2819,"children":2820,"page":59},"Tools","i-lucide-wrench","\u002Ftools","07.tools",[2821,2897],{"title":2822,"icon":2823,"path":2824,"stem":2825,"children":2826},"Docker","i-simple-icons-docker","\u002Ftools\u002Fdocker","07.tools\u002F01.docker\u002Findex",[2827,2829,2833,2837,2841,2845,2849,2853,2857,2861,2865,2869,2873,2877,2881,2885,2889,2893],{"title":2828,"path":2824,"stem":2825},"Docker: від нуля до production",{"title":2830,"path":2831,"stem":2832},"Контейнеризація — від проблеми до рішення","\u002Ftools\u002Fdocker\u002Fcontainerization-concept","07.tools\u002F01.docker\u002F01.containerization-concept",{"title":2834,"path":2835,"stem":2836},"Docker — що це і навіщо?","\u002Ftools\u002Fdocker\u002Fdocker-what-and-why","07.tools\u002F01.docker\u002F02.docker-what-and-why",{"title":2838,"path":2839,"stem":2840},"Архітектура Docker Engine","\u002Ftools\u002Fdocker\u002Fdocker-architecture","07.tools\u002F01.docker\u002F03.docker-architecture",{"title":2842,"path":2843,"stem":2844},"Встановлення Docker","\u002Ftools\u002Fdocker\u002Finstallation","07.tools\u002F01.docker\u002F04.installation",{"title":2846,"path":2847,"stem":2848},"Перший контейнер — docker run","\u002Ftools\u002Fdocker\u002Ffirst-container","07.tools\u002F01.docker\u002F05.first-container",{"title":2850,"path":2851,"stem":2852},"Життєвий цикл контейнера","\u002Ftools\u002Fdocker\u002Fcontainer-lifecycle","07.tools\u002F01.docker\u002F06.container-lifecycle",{"title":2854,"path":2855,"stem":2856},"Docker Images — фундаментальні концепції","\u002Ftools\u002Fdocker\u002Fdocker-images-fundamentals","07.tools\u002F01.docker\u002F07.docker-images-fundamentals",{"title":2858,"path":2859,"stem":2860},"Dockerfile — основи","\u002Ftools\u002Fdocker\u002Fdockerfile-basics","07.tools\u002F01.docker\u002F08.dockerfile-basics",{"title":2862,"path":2863,"stem":2864},"Dockerfile — просунуті техніки","\u002Ftools\u002Fdocker\u002Fdockerfile-advanced","07.tools\u002F01.docker\u002F09.dockerfile-advanced",{"title":2866,"path":2867,"stem":2868},"Build Context та кешування шарів","\u002Ftools\u002Fdocker\u002Fbuild-context-and-cache","07.tools\u002F01.docker\u002F10.build-context-and-cache",{"title":2870,"path":2871,"stem":2872},"Реєстри Docker-образів","\u002Ftools\u002Fdocker\u002Fimage-registries","07.tools\u002F01.docker\u002F11.image-registries",{"title":2874,"path":2875,"stem":2876},"Контейнеризація .NET додатків","\u002Ftools\u002Fdocker\u002Fdotnet-containerization","07.tools\u002F01.docker\u002F12.dotnet-containerization",{"title":2878,"path":2879,"stem":2880},"Томи та збереження даних","\u002Ftools\u002Fdocker\u002Fvolumes-and-data","07.tools\u002F01.docker\u002F13.volumes-and-data",{"title":2882,"path":2883,"stem":2884},"Основи мережі в Docker","\u002Ftools\u002Fdocker\u002Fnetworking-basics","07.tools\u002F01.docker\u002F14.networking-basics",{"title":2886,"path":2887,"stem":2888},"Змінні оточення та конфігурація","\u002Ftools\u002Fdocker\u002Fenvironment-and-configuration","07.tools\u002F01.docker\u002F15.environment-and-configuration",{"title":2890,"path":2891,"stem":2892},"Docker Compose — оркестрація контейнерів","\u002Ftools\u002Fdocker\u002Fdocker-compose-basics","07.tools\u002F01.docker\u002F16.docker-compose-basics",{"title":2894,"path":2895,"stem":2896},"Docker Compose — Multi-Service застосунки","\u002Ftools\u002Fdocker\u002Fcompose-multi-service","07.tools\u002F01.docker\u002F17.compose-multi-service",{"title":2898,"icon":2899,"path":2900,"stem":2901,"children":2902},"Kubernetes","simple-icons:kubernetes","\u002Ftools\u002Fkubernetes","07.tools\u002F02.kubernetes\u002Findex",[2903,2905,2909,2913,2917,2921,2925,2929,2933],{"title":2904,"path":2900,"stem":2901},"Kubernetes: від розробки до production",{"title":2906,"path":2907,"stem":2908},"Kubernetes — коли Docker Compose більше не вистачає","\u002Ftools\u002Fkubernetes\u002Fwhy-kubernetes","07.tools\u002F02.kubernetes\u002F01.why-kubernetes",{"title":2910,"path":2911,"stem":2912},"Архітектура Kubernetes — анатомія кластера","\u002Ftools\u002Fkubernetes\u002Fkubernetes-architecture","07.tools\u002F02.kubernetes\u002F02.kubernetes-architecture",{"title":2914,"path":2915,"stem":2916},"Локальне середовище — minikube, kind та k3s","\u002Ftools\u002Fkubernetes\u002Flocal-environment","07.tools\u002F02.kubernetes\u002F03.local-environment",{"title":2918,"path":2919,"stem":2920},"Pod — атомарна одиниця Kubernetes","\u002Ftools\u002Fkubernetes\u002Fpods-and-containers","07.tools\u002F02.kubernetes\u002F04.pods-and-containers",{"title":2922,"path":2923,"stem":2924},"Патерни використання Pod","\u002Ftools\u002Fkubernetes\u002Fpod-patterns","07.tools\u002F02.kubernetes\u002F05.pod-patterns",{"title":2926,"path":2927,"stem":2928},"Deployment — декларативне управління Pod","\u002Ftools\u002Fkubernetes\u002Fdeployment-basics","07.tools\u002F02.kubernetes\u002F06.deployment-basics",{"title":2930,"path":2931,"stem":2932},"Rolling Updates та управління життєвим циклом Deployment","\u002Ftools\u002Fkubernetes\u002Fdeployment-rolling-updates","07.tools\u002F02.kubernetes\u002F07.deployment-rolling-updates",{"title":2934,"path":2935,"stem":2936},"Service — мережева абстракція для Pod","\u002Ftools\u002Fkubernetes\u002Fservices-networking","07.tools\u002F02.kubernetes\u002F08.services-networking",{"title":2938,"icon":2939,"path":2940,"stem":2941,"children":2942,"page":59},"Software Engineering","i-lucide-code-2","\u002Fsoftware-engineering","09.software-engineering",[2943,2947,2951,2955,2959,2963,2967,2971,2975,2979,2983],{"title":2944,"path":2945,"stem":2946},"1. Аналіз предметної області. Експертні знання та складність","\u002Fsoftware-engineering\u002Fintro-subdomains","09.software-engineering\u002F01.intro-subdomains",{"title":2948,"path":2949,"stem":2950},"2. Обмежені контексти. Інтеграція обмежених контекстів","\u002Fsoftware-engineering\u002Fintegrating-limited-contexts","09.software-engineering\u002F02.integrating-limited-contexts",{"title":2952,"path":2953,"stem":2954},"3. Реалізація простої бізнес-логіки","\u002Fsoftware-engineering\u002Fsimple","09.software-engineering\u002F03.simple",{"title":2956,"path":2957,"stem":2958},"4. Опрацювання складної бізнес-логіки","\u002Fsoftware-engineering\u002Fcomplex-business-logic","09.software-engineering\u002F04.complex-business-logic",{"title":2960,"path":2961,"stem":2962},"5. Моделювання фактора часу. Подієво-орієнтована архітектура.","\u002Fsoftware-engineering\u002Fmodelling-the-time-factor","09.software-engineering\u002F05.modelling-the-time-factor",{"title":2964,"path":2965,"stem":2966},"6. Архітектурні патерни","\u002Fsoftware-engineering\u002Farchitectural-patterns","09.software-engineering\u002F06.architectural-patterns",{"title":2968,"path":2969,"stem":2970},"Паттерни взаємодії","\u002Fsoftware-engineering\u002Fpatterns-of-interaction","09.software-engineering\u002F07.patterns-of-interaction",{"title":2972,"path":2973,"stem":2974},"Евристика проєктування","\u002Fsoftware-engineering\u002Fdesign-heuristics","09.software-engineering\u002F08.design-heuristics",{"title":2976,"path":2977,"stem":2978},"Еволюція проєктних рішень","\u002Fsoftware-engineering\u002Fevolution-of-design-solutions","09.software-engineering\u002F09.evolution-of-design-solutions",{"title":2980,"path":2981,"stem":2982},"EventStorming","\u002Fsoftware-engineering\u002Feventstorming","09.software-engineering\u002F10.eventstorming",{"title":2984,"path":2985,"stem":2986},"DDD на практиці","\u002Fsoftware-engineering\u002Fddd-in-practice","09.software-engineering\u002F11.ddd-in-practice",{"title":2988,"icon":943,"path":2989,"stem":2990,"children":2991,"page":59},"DDD","\u002Fddd","10.ddd",[2992,2996,3000,3004,3008,3012,3016,3020,3024,3028,3032,3036,3040],{"title":2993,"path":2994,"stem":2995},"Аналіз предметної області","\u002Fddd\u002Fdomain-analysis","10.ddd\u002F01.domain-analysis",{"title":2997,"path":2998,"stem":2999},"Експертні знання про предметну область","\u002Fddd\u002Fdomain-expert-knowledge","10.ddd\u002F02.domain-expert-knowledge",{"title":3001,"path":3002,"stem":3003},"Як осмислити складність предметної області","\u002Fddd\u002Fmanaging-domain-complexity","10.ddd\u002F03.managing-domain-complexity",{"title":3005,"path":3006,"stem":3007},"Інтеграція обмежених контекстів","\u002Fddd\u002Fbounded-context-integration","10.ddd\u002F04.bounded-context-integration",{"title":3009,"path":3010,"stem":3011},"Реалізація простої бізнес-логіки","\u002Fddd\u002Fsimple-business-logic","10.ddd\u002F05.simple-business-logic",{"title":3013,"path":3014,"stem":3015},"Обробка складної бізнес-логіки","\u002Fddd\u002Fcomplex-business-logic","10.ddd\u002F06.complex-business-logic",{"title":3017,"path":3018,"stem":3019},"Моделювання фактора часу","\u002Fddd\u002Ftime-modeling","10.ddd\u002F07.time-modeling",{"title":3021,"path":3022,"stem":3023},"Глава 8. Архітектурні Патерни","\u002Fddd\u002Farchitectural-patterns","10.ddd\u002F08.architectural-patterns",{"title":3025,"path":3026,"stem":3027},"Глава 9. Патерни Взаємодії","\u002Fddd\u002Finteraction-patterns","10.ddd\u002F09.interaction-patterns",{"title":3029,"path":3030,"stem":3031},"Глава 10. Проектні Евристики","\u002Fddd\u002Fdesign-heuristics","10.ddd\u002F10.design-heuristics",{"title":3033,"path":3034,"stem":3035},"Глава 11. Еволюція Проектних Рішень","\u002Fddd\u002Fevolution-of-design-decisions","10.ddd\u002F11.evolution-of-design-decisions",{"title":3037,"path":3038,"stem":3039},"Глава 12. EventStorming","\u002Fddd\u002Fevent-storming","10.ddd\u002F12.event-storming",{"title":3041,"path":3042,"stem":3043},"Глава 13. DDD на Практиці","\u002Fddd\u002Fddd-in-practice","10.ddd\u002F13.ddd-in-practice",{"title":3045,"icon":3046,"path":3047,"stem":3048,"children":3049,"page":59},"Media Streaming","i-lucide-video","\u002Fmedia-streaming","11.media-streaming",[3050,3054,3058,3062,3066,3070,3074],{"title":3051,"path":3052,"stem":3053},"01. Магія Стрімінгу: Що відбувається, коли ви натискаєте \"Play\"","\u002Fmedia-streaming\u002Fintroduction","11.media-streaming\u002F01.introduction",{"title":3055,"path":3056,"stem":3057},"02. Анатомія Медіа: Кодеки, Контейнери та Стиснення","\u002Fmedia-streaming\u002Faudio-video-anatomy","11.media-streaming\u002F02.audio-video-anatomy",{"title":3059,"path":3060,"stem":3061},"03. The Gym: FFmpeg Deep Dive","\u002Fmedia-streaming\u002Fffmpeg-gym","11.media-streaming\u002F03.ffmpeg-gym",{"title":3063,"path":3064,"stem":3065},"04. HLS Protocol: HTTP Live Streaming у Деталях","\u002Fmedia-streaming\u002Fhls-protocol","11.media-streaming\u002F04.hls-protocol",{"title":3067,"path":3068,"stem":3069},"05. DASH Protocol: Відкритий Стандарт","\u002Fmedia-streaming\u002Fdash-protocol","11.media-streaming\u002F05.dash-protocol",{"title":3071,"path":3072,"stem":3073},"06. Масштабування: CDN та Adaptive Bitrate","\u002Fmedia-streaming\u002Fcdn-and-adaptive-bitrate","11.media-streaming\u002F06.cdn-and-adaptive-bitrate",{"title":3075,"path":3076,"stem":3077},"07. Війна із Затримкою (Latency)","\u002Fmedia-streaming\u002Frealtime-latency","11.media-streaming\u002F07.realtime-latency",{"title":3079,"icon":3080,"path":3081,"stem":3082,"children":3083,"page":59},"HTML & CSS","i-devicon-html5","\u002Fhtml-css","12.html-css",[3084,3088,3092,3096,3100,3104,3108,3112,3116,3120,3124,3128,3132,3136,3140,3144,3148,3152,3156,3160,3164,3168,3172,3176,3180,3184,3188,3192,3196,3200],{"title":3085,"path":3086,"stem":3087},"Вступ до HTML. Структура документа","\u002Fhtml-css\u002Fintro-html-structure","12.html-css\u002F01.intro-html-structure",{"title":3089,"path":3090,"stem":3091},"Форматування тексту в HTML","\u002Fhtml-css\u002Fhtml-text-formatting","12.html-css\u002F02.html-text-formatting",{"title":3093,"path":3094,"stem":3095},"Посилання та зображення в HTML","\u002Fhtml-css\u002Fhtml-links-images","12.html-css\u002F03.html-links-images",{"title":3097,"path":3098,"stem":3099},"Списки та таблиці в HTML","\u002Fhtml-css\u002Fhtml-lists-tables","12.html-css\u002F04.html-lists-tables",{"title":3101,"path":3102,"stem":3103},"Форми в HTML","\u002Fhtml-css\u002Fhtml-forms","12.html-css\u002F05.html-forms",{"title":3105,"path":3106,"stem":3107},"Семантичні елементи HTML5","\u002Fhtml-css\u002Fhtml-semantic-elements","12.html-css\u002F06.html-semantic-elements",{"title":3109,"path":3110,"stem":3111},"Мультимедіа та розширені елементи HTML","\u002Fhtml-css\u002Fhtml-multimedia-advanced","12.html-css\u002F07.html-multimedia-advanced",{"title":3113,"path":3114,"stem":3115},"Мікророзмітка та SEO в HTML","\u002Fhtml-css\u002Fhtml-microdata-seo","12.html-css\u002F08.html-microdata-seo",{"title":3117,"path":3118,"stem":3119},"Вступ до CSS. Селектори та специфічність","\u002Fhtml-css\u002Fcss-intro-selectors","12.html-css\u002F09.css-intro-selectors",{"title":3121,"path":3122,"stem":3123},"Блокова модель CSS. Відступи. Box Sizing","\u002Fhtml-css\u002Fcss-box-model","12.html-css\u002F10.css-box-model",{"title":3125,"path":3126,"stem":3127},"Розміри у CSS: повний довідник одиниць і ключових слів","\u002Fhtml-css\u002F10a.css-sizing","12.html-css\u002F10a.css-sizing",{"title":3129,"path":3130,"stem":3131},"Типографіка в CSS. Шрифти та текст","\u002Fhtml-css\u002Fcss-typography","12.html-css\u002F11.css-typography",{"title":3133,"path":3134,"stem":3135},"Кольори та фони в CSS","\u002Fhtml-css\u002Fcss-colors-backgrounds","12.html-css\u002F12.css-colors-backgrounds",{"title":3137,"path":3138,"stem":3139},"Тіні та фільтри в CSS","\u002Fhtml-css\u002F12b.css-shadows-filters","12.html-css\u002F12b.css-shadows-filters",{"title":3141,"path":3142,"stem":3143},"CSS Flexbox: Фундамент гнучких макетів","\u002Fhtml-css\u002Fcss-flexbox-fundamentals","12.html-css\u002F13.css-flexbox-fundamentals",{"title":3145,"path":3146,"stem":3147},"CSS Flexbox: Вирівнювання та Позиціонування","\u002Fhtml-css\u002Fcss-flexbox-alignment-sizing-and-patterns","12.html-css\u002F14.css-flexbox-alignment-sizing-and-patterns",{"title":3149,"path":3150,"stem":3151},"CSS Grid. Двовимірний макет. Частина 1","\u002Fhtml-css\u002Fcss-layout-grid","12.html-css\u002F15.css-layout-grid",{"title":3153,"path":3154,"stem":3155},"CSS Grid. Двовимірний макет. Частина 2","\u002Fhtml-css\u002Fcss-layout-grid-advanced","12.html-css\u002F16.css-layout-grid-advanced",{"title":3157,"path":3158,"stem":3159},"Позиціонування в CSS. Z-index. Stacking Context","\u002Fhtml-css\u002Fcss-positioning","12.html-css\u002F17.css-positioning",{"title":3161,"path":3162,"stem":3163},"CSS Анімації та Переходи","\u002Fhtml-css\u002Fcss-animations-transitions","12.html-css\u002F18.css-animations-transitions",{"title":3165,"path":3166,"stem":3167},"Адаптивний дизайн. Media Queries. Частина 1","\u002Fhtml-css\u002Fcss-responsive-media-queries","12.html-css\u002F19.css-responsive-media-queries",{"title":3169,"path":3170,"stem":3171},"Адаптивний дизайн. Частина 2: clamp(), Container Queries, @layer","\u002Fhtml-css\u002Fcss-responsive-advanced","12.html-css\u002F20.css-responsive-advanced",{"title":3173,"path":3174,"stem":3175},"CSS Custom Properties. Методології. Сучасний CSS","\u002Fhtml-css\u002Fcss-variables-methodologies","12.html-css\u002F21.css-variables-methodologies",{"title":3177,"path":3178,"stem":3179},"Сучасний CSS 2023–2025: Нові можливості","\u002Fhtml-css\u002Fcss-modern-features","12.html-css\u002F22.css-modern-features",{"title":3181,"path":3182,"stem":3183},"CSS Nesting, @layer, @scope та @property: нативний препроцесор","\u002Fhtml-css\u002F22a.css-nesting-modern-syntax","12.html-css\u002F22a.css-nesting-modern-syntax",{"title":3185,"path":3186,"stem":3187},"CSS для форм та інтерактивних станів","\u002Fhtml-css\u002Fcss-forms-interactive-states","12.html-css\u002F23.css-forms-interactive-states",{"title":3189,"path":3190,"stem":3191},"Доступність у CSS (CSS Accessibility)","\u002Fhtml-css\u002Fcss-accessibility","12.html-css\u002F24.css-accessibility",{"title":3193,"path":3194,"stem":3195},"CSS-функції та сучасні sizing primitives","\u002Fhtml-css\u002Fcss-functions-sizing","12.html-css\u002F25.css-functions-sizing",{"title":3197,"path":3198,"stem":3199},"Rendering Pipeline і CSS Performance","\u002Fhtml-css\u002Fcss-rendering-performance","12.html-css\u002F26.css-rendering-performance",{"title":3201,"path":3202,"stem":3203},"CSS Best Practices: типові ситуації та правильні рішення","\u002Fhtml-css\u002Fcss-best-practices","12.html-css\u002F27.css-best-practices",{"title":3205,"path":3206,"stem":3207,"children":3208,"page":59},"AWS","\u002Faws","13.aws",[3209,3213,3217,3221,3225,3229,3233,3237,3241,3245,3249,3253,3257,3261,3265,3269,3273,3277],{"title":3210,"path":3211,"stem":3212},"Реєстрація AWS акаунту та студентські програми","\u002Faws\u002Faccount-registration","13.aws\u002F00.account-registration",{"title":3214,"path":3215,"stem":3216},"Вступ до хмарних обчислень та AWS","\u002Faws\u002Fintroduction-to-cloud","13.aws\u002F01.introduction-to-cloud",{"title":3218,"path":3219,"stem":3220},"AWS IAM — Identity and Access Management","\u002Faws\u002Fiam","13.aws\u002F02.iam",{"title":3222,"path":3223,"stem":3224},"AWS IAM CLI — Довідник команд","\u002Faws\u002F02a.iam-doc","13.aws\u002F02a.iam-doc",{"title":3226,"path":3227,"stem":3228},"Docker та контейнеризація в AWS — ECR, ECS та Fargate","\u002Faws\u002Fdocker-ecs","13.aws\u002F03.docker-ecs",{"title":3230,"path":3231,"stem":3232},"AWS ECR \u002F ECS CLI — Довідник команд","\u002Faws\u002F03a.docker-ecs-doc","13.aws\u002F03a.docker-ecs-doc",{"title":3234,"path":3235,"stem":3236},"Amazon EC2 — Elastic Compute Cloud","\u002Faws\u002Fec2","13.aws\u002F04.ec2",{"title":3238,"path":3239,"stem":3240},"AWS EC2 CLI — Довідник команд","\u002Faws\u002F04a.ec2-doc","13.aws\u002F04a.ec2-doc",{"title":3242,"path":3243,"stem":3244},"Elastic Load Balancing та Auto Scaling","\u002Faws\u002Falb-asg","13.aws\u002F05.alb-asg",{"title":3246,"path":3247,"stem":3248},"Amazon S3 — Simple Storage Service","\u002Faws\u002Fs3","13.aws\u002F06.s3",{"title":3250,"path":3251,"stem":3252},"Amazon CloudFront — Content Delivery Network","\u002Faws\u002Fcloudfront","13.aws\u002F07.cloudfront",{"title":3254,"path":3255,"stem":3256},"Amazon RDS — Relational Database Service","\u002Faws\u002Frds","13.aws\u002F08.rds",{"title":3258,"path":3259,"stem":3260},"Amazon DynamoDB — NoSQL Database","\u002Faws\u002Fdynamodb","13.aws\u002F09.dynamodb",{"title":3262,"path":3263,"stem":3264},"AWS Lambda та Serverless Compute","\u002Faws\u002Flambda","13.aws\u002F10.lambda",{"title":3266,"path":3267,"stem":3268},"Amazon Bedrock - Foundation Models, RAG та Agents","\u002Faws\u002Fbedrock","13.aws\u002F22.bedrock",{"title":3270,"path":3271,"stem":3272},"Amazon Rekognition - Комп'ютерний зір","\u002Faws\u002Frekognition","13.aws\u002F23.rekognition",{"title":3274,"path":3275,"stem":3276},"Amazon Textract - Інтелектуальний аналіз документів","\u002Faws\u002Ftextract","13.aws\u002F24.textract",{"title":3278,"path":3279,"stem":3280},"Amazon Polly, Transcribe, Comprehend та Translate","\u002Faws\u002Faudio-nlp-services","13.aws\u002F25.audio-nlp-services",{"title":3282,"path":3283,"stem":3284,"children":3285,"page":59},"Tailwind","\u002Ftailwind","21.tailwind",[3286,3290,3294,3298,3302,3306,3310,3314,3318,3322,3326,3330],{"title":3287,"path":3288,"stem":3289},"Що таке Tailwind CSS і навіщо він потрібен","\u002Ftailwind\u002Ftailwind-intro-philosophy","21.tailwind\u002F01.tailwind-intro-philosophy",{"title":3291,"path":3292,"stem":3293},"Встановлення та налаштування Tailwind CSS v4","\u002Ftailwind\u002Ftailwind-installation-setup","21.tailwind\u002F02.tailwind-installation-setup",{"title":3295,"path":3296,"stem":3297},"Utility-класи: основи та система Tailwind","\u002Ftailwind\u002Ftailwind-utility-classes-core","21.tailwind\u002F03.tailwind-utility-classes-core",{"title":3299,"path":3300,"stem":3301},"Layout: Flexbox та Grid через Tailwind","\u002Ftailwind\u002Ftailwind-flexbox-grid","21.tailwind\u002F04.tailwind-flexbox-grid",{"title":3303,"path":3304,"stem":3305},"Кастомізація теми через @theme у Tailwind v4","\u002Ftailwind\u002Ftailwind-theme-customization","21.tailwind\u002F05.tailwind-theme-customization",{"title":3307,"path":3308,"stem":3309},"Варіанти: hover, focus, responsive, dark mode та нові v4","\u002Ftailwind\u002Ftailwind-variants-states","21.tailwind\u002F06.tailwind-variants-states",{"title":3311,"path":3312,"stem":3313},"Типографіка та система кольорів у Tailwind v4","\u002Ftailwind\u002Ftailwind-typography-colors","21.tailwind\u002F07.tailwind-typography-colors",{"title":3315,"path":3316,"stem":3317},"Компоненти та повторюваність: @apply, @utility та патерни","\u002Ftailwind\u002Ftailwind-components-patterns","21.tailwind\u002F08.tailwind-components-patterns",{"title":3319,"path":3320,"stem":3321},"Темна тема та система дизайн-токенів у Tailwind v4","\u002Ftailwind\u002Ftailwind-dark-mode-theming","21.tailwind\u002F09.tailwind-dark-mode-theming",{"title":3323,"path":3324,"stem":3325},"Довільні значення та контейнерні запити у Tailwind v4","\u002Ftailwind\u002Ftailwind-arbitrary-container-queries","21.tailwind\u002F10.tailwind-arbitrary-container-queries",{"title":3327,"path":3328,"stem":3329},"Анімації, трансформації та 3D у Tailwind v4","\u002Ftailwind\u002Ftailwind-animations-transforms","21.tailwind\u002F11.tailwind-animations-transforms",{"title":3331,"path":3332,"stem":3333},"Tailwind CLI, PostCSS та інтеграція з фреймворками","\u002Ftailwind\u002Ftailwind-cli-tooling","21.tailwind\u002F12.tailwind-cli-tooling",{"title":3335,"path":3336,"stem":3337},"Тестування компонентів діаграм","\u002Ftest-components","98.test-components",{"id":3339,"title":3262,"body":3340,"description":23013,"extension":23014,"links":23015,"meta":23016,"navigation":3419,"path":3263,"seo":23017,"stem":3264,"__hash__":23018},"docs\u002F13.aws\u002F10.lambda.md",{"type":3341,"value":3342,"toc":22905},"minimark",[3343,3347,3352,3356,3363,3369,3375,3381,3676,3683,3686,3690,3696,3703,3708,3727,3846,3850,3861,3918,3931,3935,3938,4011,4013,4017,4024,4031,4051,4262,4266,4272,4351,4358,4369,4375,4536,4538,4542,4548,4566,4655,4659,4672,4679,4793,4800,4850,4852,4856,4859,4863,4866,4967,4971,4974,5045,5052,5058,5184,5190,5192,5196,5206,5378,5382,5388,5396,5403,5407,5424,5428,5435,5664,5676,5678,5682,5685,5689,5692,5711,5717,5773,5777,5784,5887,5891,5898,5935,5943,5946,5950,5965,5970,5977,5997,6001,6004,6024,6028,6031,6064,6069,6278,6282,6293,6401,6404,6424,6428,6431,6435,6441,6665,6669,6675,6878,6880,6884,6891,6902,6905,6909,6915,6938,6942,6949,6966,6970,6973,6993,7156,7160,7167,7170,7219,7224,7231,7515,7520,7523,8306,8311,8625,8634,8636,8640,8655,8778,8783,8980,8990,8995,9924,9926,9930,9940,10115,10120,10161,10169,10715,10717,10721,10727,10741,11240,11242,11246,11250,11259,11264,11285,11290,11566,11580,11582,11586,11592,11618,11767,11772,12461,12466,12724,12726,12730,12740,12748,12882,12887,12890,13096,13101,13186,13188,13190,13194,13197,13201,13207,13566,13571,13578,13764,13768,13779,13911,13922,13926,13929,13934,14267,14272,14384,14386,14390,14396,14559,14564,14783,14788,15390,15411,15413,15417,15430,15541,15545,15548,15572,15576,15581,15767,15866,15871,15914,15986,15990,15997,16235,16237,16241,16244,16294,16299,16565,16567,16569,16573,16576,16580,16586,16670,16674,16677,16934,16938,16945,17079,17082,17086,17089,17269,17273,17276,17405,17409,17412,17600,17605,17611,17621,17659,17678,17682,17691,17694,17875,17879,17889,17922,17926,17929,17949,17956,17958,17962,17965,18085,18090,18107,18112,18129,18131,18135,18138,18142,18145,18168,18249,18253,18256,18395,18399,18402,18940,18944,18951,20106,20110,20113,20635,20639,20729,20740,20742,20746,20749,20753,20756,20776,20889,20893,20896,21092,21096,21106,21337,21341,21348,22429,22433,22587,22591,22611,22613,22626,22630,22633,22783,22785,22789,22792,22796,22829,22833,22836,22898,22901],[3344,3345,3262],"h1",{"id":3346},"aws-lambda-та-serverless-compute",[3348,3349,3351],"h2",{"id":3350},"еволюція-моделей-обчислень-від-серверів-до-функцій","Еволюція моделей обчислень: від серверів до функцій",[3353,3354,3355],"p",{},"Щоб зрозуміти місце AWS Lambda в сучасній хмарній архітектурі, необхідно простежити еволюційний шлях, який пройшла індустрія від фізичних серверів до парадигми «функції як сервіс». Кожен крок цієї еволюції вирішував конкретну проблему попереднього покоління, але водночас породжував нові класи складності.",[3353,3357,3358,3362],{},[3359,3360,3361],"strong",{},"Перше покоління: фізичні сервери (On-Premises)."," Організації купували та обслуговували власне апаратне забезпечення. Час від ухвалення рішення до введення сервера в експлуатацію вимірювався тижнями або місяцями. Ресурси були фіксованими: якщо сервер придбаний з 32 ГБ RAM, рівно стільки і доступно — незалежно від фактичного навантаження. Команди витрачали значну частину зусиль на управління інфраструктурою замість розробки бізнес-логіки.",[3353,3364,3365,3368],{},[3359,3366,3367],{},"Друге покоління: IaaS та EC2."," AWS у 2006 році запровадила модель Infrastructure as a Service, де фізичний сервер замінюється віртуальною машиною, що надається за хвилини. Це вирішило проблему тривалого розгортання (provisioning) і дозволило платити лише за час використання. Проте фундаментальна проблема залишилась: команда все одно відповідає за операційну систему, патчі безпеки, мережеву конфігурацію, моніторинг процесів та масштабування.",[3353,3370,3371,3374],{},[3359,3372,3373],{},"Третє покоління: PaaS та контейнери."," Платформи як Elastic Beanstalk або Amazon ECS абстрагували рівень операційної системи. Docker-контейнери вирішили проблему залежностей та відтворюваності середовища. Але команда все ще мала думати про кількість контейнерів, їхнє масштабування та час, протягом якого вони запущені.",[3353,3376,3377,3380],{},[3359,3378,3379],{},"Четверте покоління: Serverless та FaaS."," AWS Lambda, запущена у 2014 році, реалізує принципово іншу модель: розробник пише лише функцію — одиницю бізнес-логіки, — а вся інфраструктурна відповідальність делегується платформі. Lambda не просто приховує сервери — вона усуває саму концепцію сервера з розумової моделі розробника.",[3382,3383,3384],"plant-uml",{},[3385,3386,3391],"pre",{"className":3387,"code":3388,"language":3389,"meta":3390,"style":3390},"language-plantuml shiki shiki-themes light-plus dark-plus dark-plus","@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\ntitle \"Еволюція моделей відповідальності: що керує команда\"\n\nrectangle \"On-Premises\" as OP #fca5a5 {\n    rectangle \"Застосунок\" as APP1 #fee2e2\n    rectangle \"Runtime (.NET)\" as RT1 #fee2e2\n    rectangle \"ОС + патчі\" as OS1 #fee2e2\n    rectangle \"Гіпервізор\" as HV1 #fee2e2\n    rectangle \"Мережа\" as NET1 #fee2e2\n    rectangle \"Фізичний сервер\" as HW1 #fee2e2\n}\n\nrectangle \"EC2 (IaaS)\" as EC #fde68a {\n    rectangle \"Застосунок\" as APP2 #fee2e2\n    rectangle \"Runtime (.NET)\" as RT2 #fee2e2\n    rectangle \"ОС + патчі\" as OS2 #fee2e2\n    rectangle \"Гіпервізор\" as HV2 #d1fae5\n    rectangle \"Мережа\" as NET2 #d1fae5\n    rectangle \"Фізичний сервер\" as HW2 #d1fae5\n}\n\nrectangle \"ECS \u002F Fargate\\n(Containers)\" as ECS #bbf7d0 {\n    rectangle \"Застосунок\" as APP3 #fee2e2\n    rectangle \"Runtime (.NET)\" as RT3 #fee2e2\n    rectangle \"ОС (контейнер)\" as OS3 #d1fae5\n    rectangle \"Оркестрація\" as HV3 #d1fae5\n    rectangle \"Мережа\" as NET3 #d1fae5\n    rectangle \"Фізичний сервер\" as HW3 #d1fae5\n}\n\nrectangle \"Lambda\\n(Serverless)\" as LAM #dbeafe {\n    rectangle \"Бізнес-логіка\\n(лише код функції)\" as APP4 #fee2e2\n    rectangle \"Runtime (.NET 10)\" as RT4 #d1fae5\n    rectangle \"ОС\" as OS4 #d1fae5\n    rectangle \"Масштабування\" as HV4 #d1fae5\n    rectangle \"Мережа\" as NET4 #d1fae5\n    rectangle \"Фізичний сервер\" as HW4 #d1fae5\n}\n\nnote bottom of OP : Команда керує ВСІМ\nnote bottom of EC : AWS керує залізом\nnote bottom of ECS : AWS керує залізом + ОС\nnote bottom of LAM : Команда пише лише код функції.\\nAWS керує всім іншим.\n\n@enduml\n","plantuml","",[3392,3393,3394,3402,3408,3414,3421,3427,3432,3438,3444,3450,3456,3462,3468,3474,3480,3485,3491,3497,3503,3509,3515,3521,3527,3532,3537,3543,3549,3555,3561,3567,3573,3579,3584,3589,3595,3601,3607,3613,3619,3625,3631,3636,3641,3647,3653,3659,3665,3670],"code",{"__ignoreMap":3390},[3395,3396,3399],"span",{"class":3397,"line":3398},"line",1,[3395,3400,3401],{},"@startuml\n",[3395,3403,3405],{"class":3397,"line":3404},2,[3395,3406,3407],{},"skinparam style plain\n",[3395,3409,3411],{"class":3397,"line":3410},3,[3395,3412,3413],{},"skinparam backgroundColor #ffffff\n",[3395,3415,3417],{"class":3397,"line":3416},4,[3395,3418,3420],{"emptyLinePlaceholder":3419},true,"\n",[3395,3422,3424],{"class":3397,"line":3423},5,[3395,3425,3426],{},"title \"Еволюція моделей відповідальності: що керує команда\"\n",[3395,3428,3430],{"class":3397,"line":3429},6,[3395,3431,3420],{"emptyLinePlaceholder":3419},[3395,3433,3435],{"class":3397,"line":3434},7,[3395,3436,3437],{},"rectangle \"On-Premises\" as OP #fca5a5 {\n",[3395,3439,3441],{"class":3397,"line":3440},8,[3395,3442,3443],{},"    rectangle \"Застосунок\" as APP1 #fee2e2\n",[3395,3445,3447],{"class":3397,"line":3446},9,[3395,3448,3449],{},"    rectangle \"Runtime (.NET)\" as RT1 #fee2e2\n",[3395,3451,3453],{"class":3397,"line":3452},10,[3395,3454,3455],{},"    rectangle \"ОС + патчі\" as OS1 #fee2e2\n",[3395,3457,3459],{"class":3397,"line":3458},11,[3395,3460,3461],{},"    rectangle \"Гіпервізор\" as HV1 #fee2e2\n",[3395,3463,3465],{"class":3397,"line":3464},12,[3395,3466,3467],{},"    rectangle \"Мережа\" as NET1 #fee2e2\n",[3395,3469,3471],{"class":3397,"line":3470},13,[3395,3472,3473],{},"    rectangle \"Фізичний сервер\" as HW1 #fee2e2\n",[3395,3475,3477],{"class":3397,"line":3476},14,[3395,3478,3479],{},"}\n",[3395,3481,3483],{"class":3397,"line":3482},15,[3395,3484,3420],{"emptyLinePlaceholder":3419},[3395,3486,3488],{"class":3397,"line":3487},16,[3395,3489,3490],{},"rectangle \"EC2 (IaaS)\" as EC #fde68a {\n",[3395,3492,3494],{"class":3397,"line":3493},17,[3395,3495,3496],{},"    rectangle \"Застосунок\" as APP2 #fee2e2\n",[3395,3498,3500],{"class":3397,"line":3499},18,[3395,3501,3502],{},"    rectangle \"Runtime (.NET)\" as RT2 #fee2e2\n",[3395,3504,3506],{"class":3397,"line":3505},19,[3395,3507,3508],{},"    rectangle \"ОС + патчі\" as OS2 #fee2e2\n",[3395,3510,3512],{"class":3397,"line":3511},20,[3395,3513,3514],{},"    rectangle \"Гіпервізор\" as HV2 #d1fae5\n",[3395,3516,3518],{"class":3397,"line":3517},21,[3395,3519,3520],{},"    rectangle \"Мережа\" as NET2 #d1fae5\n",[3395,3522,3524],{"class":3397,"line":3523},22,[3395,3525,3526],{},"    rectangle \"Фізичний сервер\" as HW2 #d1fae5\n",[3395,3528,3530],{"class":3397,"line":3529},23,[3395,3531,3479],{},[3395,3533,3535],{"class":3397,"line":3534},24,[3395,3536,3420],{"emptyLinePlaceholder":3419},[3395,3538,3540],{"class":3397,"line":3539},25,[3395,3541,3542],{},"rectangle \"ECS \u002F Fargate\\n(Containers)\" as ECS #bbf7d0 {\n",[3395,3544,3546],{"class":3397,"line":3545},26,[3395,3547,3548],{},"    rectangle \"Застосунок\" as APP3 #fee2e2\n",[3395,3550,3552],{"class":3397,"line":3551},27,[3395,3553,3554],{},"    rectangle \"Runtime (.NET)\" as RT3 #fee2e2\n",[3395,3556,3558],{"class":3397,"line":3557},28,[3395,3559,3560],{},"    rectangle \"ОС (контейнер)\" as OS3 #d1fae5\n",[3395,3562,3564],{"class":3397,"line":3563},29,[3395,3565,3566],{},"    rectangle \"Оркестрація\" as HV3 #d1fae5\n",[3395,3568,3570],{"class":3397,"line":3569},30,[3395,3571,3572],{},"    rectangle \"Мережа\" as NET3 #d1fae5\n",[3395,3574,3576],{"class":3397,"line":3575},31,[3395,3577,3578],{},"    rectangle \"Фізичний сервер\" as HW3 #d1fae5\n",[3395,3580,3582],{"class":3397,"line":3581},32,[3395,3583,3479],{},[3395,3585,3587],{"class":3397,"line":3586},33,[3395,3588,3420],{"emptyLinePlaceholder":3419},[3395,3590,3592],{"class":3397,"line":3591},34,[3395,3593,3594],{},"rectangle \"Lambda\\n(Serverless)\" as LAM #dbeafe {\n",[3395,3596,3598],{"class":3397,"line":3597},35,[3395,3599,3600],{},"    rectangle \"Бізнес-логіка\\n(лише код функції)\" as APP4 #fee2e2\n",[3395,3602,3604],{"class":3397,"line":3603},36,[3395,3605,3606],{},"    rectangle \"Runtime (.NET 10)\" as RT4 #d1fae5\n",[3395,3608,3610],{"class":3397,"line":3609},37,[3395,3611,3612],{},"    rectangle \"ОС\" as OS4 #d1fae5\n",[3395,3614,3616],{"class":3397,"line":3615},38,[3395,3617,3618],{},"    rectangle \"Масштабування\" as HV4 #d1fae5\n",[3395,3620,3622],{"class":3397,"line":3621},39,[3395,3623,3624],{},"    rectangle \"Мережа\" as NET4 #d1fae5\n",[3395,3626,3628],{"class":3397,"line":3627},40,[3395,3629,3630],{},"    rectangle \"Фізичний сервер\" as HW4 #d1fae5\n",[3395,3632,3634],{"class":3397,"line":3633},41,[3395,3635,3479],{},[3395,3637,3639],{"class":3397,"line":3638},42,[3395,3640,3420],{"emptyLinePlaceholder":3419},[3395,3642,3644],{"class":3397,"line":3643},43,[3395,3645,3646],{},"note bottom of OP : Команда керує ВСІМ\n",[3395,3648,3650],{"class":3397,"line":3649},44,[3395,3651,3652],{},"note bottom of EC : AWS керує залізом\n",[3395,3654,3656],{"class":3397,"line":3655},45,[3395,3657,3658],{},"note bottom of ECS : AWS керує залізом + ОС\n",[3395,3660,3662],{"class":3397,"line":3661},46,[3395,3663,3664],{},"note bottom of LAM : Команда пише лише код функції.\\nAWS керує всім іншим.\n",[3395,3666,3668],{"class":3397,"line":3667},47,[3395,3669,3420],{"emptyLinePlaceholder":3419},[3395,3671,3673],{"class":3397,"line":3672},48,[3395,3674,3675],{},"@enduml\n",[3677,3678,3679,3682],"tip",{},[3359,3680,3681],{},"Serverless ≠ «без серверів»."," Сервери існують — просто ними керує AWS. Термін «serverless» означає, що розробник більше не моделює сервери у своїй архітектурній свідомості: немає концепції «скільки серверів нам потрібно», «коли вони запущені», «як їх масштабувати».",[3684,3685],"hr",{},[3348,3687,3689],{"id":3688},"фундаментальна-модель-aws-lambda","Фундаментальна модель AWS Lambda",[3353,3691,3692,3695],{},[3359,3693,3694],{},"AWS Lambda"," — це обчислювальний сервіс, що виконує код у відповідь на події та автоматично управляє обчислювальними ресурсами, необхідними для цього виконання. Розробник надає код (функцію), Lambda забезпечує все інше: розгортання (provisioning) серверів, масштабування, моніторинг, реєстрацію логів.",[3353,3697,3698,3699,3702],{},"Центральна концепція Lambda — ",[3359,3700,3701],{},"функція"," (Lambda Function). Функція є одиницею деплойменту та виконання. Вона містить код, конфігурацію (пам'ять, timeout, змінні середовища) та IAM роль, що визначає її права доступу до інших AWS-сервісів.",[3704,3705,3707],"h3",{"id":3706},"модель-виконання-event-handler-response","Модель виконання: Event → Handler → Response",[3353,3709,3710,3711,3714,3715,3718,3719,3722,3723,3726],{},"Кожне виклик Lambda відбувається за єдиною схемою: зовнішня система (trigger) генерує ",[3359,3712,3713],{},"подію"," (event), Lambda-сервіс ініціює ",[3359,3716,3717],{},"виконання"," функції та передає подію у ",[3359,3720,3721],{},"handler"," — точку входу коду, — а handler повертає ",[3359,3724,3725],{},"відповідь"," або завершується без повернення значення (для асинхронних тригерів).",[3382,3728,3729],{},[3385,3730,3732],{"className":3387,"code":3731,"language":3389,"meta":3390,"style":3390},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\nparticipant \"Trigger\\n(S3 \u002F API GW \u002F EventBridge)\" as TR #fef3c7\nparticipant \"Lambda Service\\n(AWS)\" as LS #dbeafe\nparticipant \"Execution Environment\\n(мікро-VM)\" as EE #d1fae5\nparticipant \"Handler\\n(.NET код)\" as H #bbf7d0\n\nTR -> LS : Подія (Event JSON)\nLS -> EE : Створити \u002F отримати Execution Environment\nEE -> H : Десеріалізувати Event\\n→ виклик Handler(event, context)\n\nalt \"Синхронний тригер (API Gateway)\"\n    H --> EE : return Response\n    EE --> LS : Відповідь\n    LS --> TR : HTTP Response\nelse \"Асинхронний тригер (S3, EventBridge)\"\n    H --> EE : return (void \u002F Task)\n    EE --> LS : Успішне завершення\n    note right of LS : Тригер не чекає відповіді.\\nLambda підтвердила отримання.\nend\n\n@enduml\n",[3392,3733,3734,3738,3742,3746,3750,3755,3760,3765,3770,3774,3779,3784,3789,3793,3798,3803,3808,3813,3818,3823,3828,3833,3838,3842],{"__ignoreMap":3390},[3395,3735,3736],{"class":3397,"line":3398},[3395,3737,3401],{},[3395,3739,3740],{"class":3397,"line":3404},[3395,3741,3407],{},[3395,3743,3744],{"class":3397,"line":3410},[3395,3745,3413],{},[3395,3747,3748],{"class":3397,"line":3416},[3395,3749,3420],{"emptyLinePlaceholder":3419},[3395,3751,3752],{"class":3397,"line":3423},[3395,3753,3754],{},"participant \"Trigger\\n(S3 \u002F API GW \u002F EventBridge)\" as TR #fef3c7\n",[3395,3756,3757],{"class":3397,"line":3429},[3395,3758,3759],{},"participant \"Lambda Service\\n(AWS)\" as LS #dbeafe\n",[3395,3761,3762],{"class":3397,"line":3434},[3395,3763,3764],{},"participant \"Execution Environment\\n(мікро-VM)\" as EE #d1fae5\n",[3395,3766,3767],{"class":3397,"line":3440},[3395,3768,3769],{},"participant \"Handler\\n(.NET код)\" as H #bbf7d0\n",[3395,3771,3772],{"class":3397,"line":3446},[3395,3773,3420],{"emptyLinePlaceholder":3419},[3395,3775,3776],{"class":3397,"line":3452},[3395,3777,3778],{},"TR -> LS : Подія (Event JSON)\n",[3395,3780,3781],{"class":3397,"line":3458},[3395,3782,3783],{},"LS -> EE : Створити \u002F отримати Execution Environment\n",[3395,3785,3786],{"class":3397,"line":3464},[3395,3787,3788],{},"EE -> H : Десеріалізувати Event\\n→ виклик Handler(event, context)\n",[3395,3790,3791],{"class":3397,"line":3470},[3395,3792,3420],{"emptyLinePlaceholder":3419},[3395,3794,3795],{"class":3397,"line":3476},[3395,3796,3797],{},"alt \"Синхронний тригер (API Gateway)\"\n",[3395,3799,3800],{"class":3397,"line":3482},[3395,3801,3802],{},"    H --> EE : return Response\n",[3395,3804,3805],{"class":3397,"line":3487},[3395,3806,3807],{},"    EE --> LS : Відповідь\n",[3395,3809,3810],{"class":3397,"line":3493},[3395,3811,3812],{},"    LS --> TR : HTTP Response\n",[3395,3814,3815],{"class":3397,"line":3499},[3395,3816,3817],{},"else \"Асинхронний тригер (S3, EventBridge)\"\n",[3395,3819,3820],{"class":3397,"line":3505},[3395,3821,3822],{},"    H --> EE : return (void \u002F Task)\n",[3395,3824,3825],{"class":3397,"line":3511},[3395,3826,3827],{},"    EE --> LS : Успішне завершення\n",[3395,3829,3830],{"class":3397,"line":3517},[3395,3831,3832],{},"    note right of LS : Тригер не чекає відповіді.\\nLambda підтвердила отримання.\n",[3395,3834,3835],{"class":3397,"line":3523},[3395,3836,3837],{},"end\n",[3395,3839,3840],{"class":3397,"line":3529},[3395,3841,3420],{"emptyLinePlaceholder":3419},[3395,3843,3844],{"class":3397,"line":3534},[3395,3845,3675],{},[3704,3847,3849],{"id":3848},"ціноутворення-оплата-за-мілісекунди-виконання","Ціноутворення: оплата за мілісекунди виконання",[3353,3851,3852,3853,3856,3857,3860],{},"Модель ціноутворення Lambda кардинально відрізняється від EC2: оплата не за час, поки сервер запущений, а виключно за ",[3359,3854,3855],{},"фактичний час виконання"," коду та ",[3359,3858,3859],{},"кількість викликів",".",[3862,3863,3864,3881,3902],"card-group",{},[3865,3866,3869,3875],"card",{"icon":3867,"title":3868},"i-heroicons-bolt","Кількість викликів",[3353,3870,3871,3874],{},[3359,3872,3873],{},"$0.20"," за 1 мільйон викликів",[3353,3876,3877,3880],{},[3359,3878,3879],{},"Безкоштовно:"," перший мільйон викликів щомісяця (постійно, не лише 12 місяців free tier)",[3865,3882,3885,3891,3897],{"icon":3883,"title":3884},"i-heroicons-clock","Тривалість виконання",[3353,3886,3887,3890],{},[3359,3888,3889],{},"$0.0000166667"," за GB-секунду",[3353,3892,3893,3894],{},"Тривалість округлюється до ",[3359,3895,3896],{},"1 мілісекунди",[3353,3898,3899,3901],{},[3359,3900,3879],{}," 400,000 GB-секунд щомісяця",[3865,3903,3906,3909],{"icon":3904,"title":3905},"i-heroicons-calculator","Приклад розрахунку",[3353,3907,3908],{},"Функція: 128 MB пам'яті, 200ms виконання, 10M викликів\u002Fмісяць",[3353,3910,3911,3914,3915],{},[3359,3912,3913],{},"Вартість:"," ~$1.67 (тривалість) + $1.80 (виклики) = ",[3359,3916,3917],{},"~$3.47\u002Fмісяць",[3677,3919,3920,3923,3924,3927,3928,3860],{},[3359,3921,3922],{},"Порівняння з EC2."," Один EC2 instance ",[3392,3925,3926],{},"t3.small"," (2 vCPU, 2 GB) коштує ~$15\u002Fмісяць і працює 24\u002F7 незалежно від навантаження. Lambda з аналогічним навантаженням (10M коротких викликів) коштуватиме менше $5 і ",[3359,3929,3930],{},"не генерує витрат у часи простою",[3704,3932,3934],{"id":3933},"lambda-limits-операційні-обмеження","Lambda Limits: операційні обмеження",[3353,3936,3937],{},"Lambda накладає жорсткі технічні обмеження, які є наслідком її архітектурної природи. Знання цих меж є обов'язковим для проектування рішень на Lambda.",[3939,3940,3941,3951,3967,3983,3992,4000],"field-group",{},[3942,3943,3947,3950],"field",{"name":3944,"type":3945,"required":3946},"Максимальний час виконання (Timeout)","integer","true",[3359,3948,3949],{},"900 секунд (15 хвилин)"," — абсолютна максимальна тривалість одного виклику. Після досягнення таймауту Lambda примусово завершує виконання. Для довготривалих задач необхідно використовувати AWS Step Functions або ECS.",[3942,3952,3955,3958,3959,3962,3963,3966],{"name":3953,"type":3954},"Максимальний розмір пакету деплойменту","string",[3359,3956,3957],{},"50 MB"," (ZIP, завантажений напряму) або ",[3359,3960,3961],{},"250 MB"," (ZIP, розпакований). Через S3 можна завантажити ZIP до ",[3359,3964,3965],{},"10 GB",". Ця межа є ключовою при роботі з .NET, де розмір publish-артефакту може бути значним.",[3942,3968,3970,3971,3974,3975,3978,3979,3982],{"name":3969,"type":3945},"Пам'ять","Від ",[3359,3972,3973],{},"128 MB"," до ",[3359,3976,3977],{},"10,240 MB"," (10 GB) з кроком 1 MB. CPU потужність масштабується ",[3359,3980,3981],{},"пропорційно"," виділеній пам'яті: при 1,769 MB функція отримує 1 повний vCPU. При 3,538 MB — 2 vCPU.",[3942,3984,3970,3986,3974,3989,3991],{"name":3985,"type":3954},"Ephemeral Storage (\u002Ftmp)",[3359,3987,3988],{},"512 MB",[3359,3990,3977],{},". Тимчасове сховище, доступне лише протягом виконання та потенційно між викликами у теплому середовищі (warm execution environment). Не є надійним постійним сховищем.",[3942,3993,3995,3996,3999],{"name":3994,"type":3945},"Паралелізм (Concurrency)","За замовчуванням ",[3359,3997,3998],{},"1,000 одночасних виконань"," на рівні акаунту AWS у регіоні. Можна запросити збільшення через AWS Support. Кожен одночасний виклик — окреме Execution Environment.",[3942,4001,4003,4006,4007,4010],{"name":4002,"type":3954},"Розмір payload",[3359,4004,4005],{},"6 MB"," для синхронних викликів (Request + Response). ",[3359,4008,4009],{},"256 KB"," для асинхронних. Для передачі великих даних необхідно використовувати S3 як проміжне сховище.",[3684,4012],{},[3348,4014,4016],{"id":4015},"execution-environment-анатомія-ізоляції","Execution Environment: анатомія ізоляції",[3353,4018,4019,4020,4023],{},"Для розуміння поведінки Lambda — зокрема феноменів Cold Start та Warm Start — необхідно детально вивчити концепцію ",[3359,4021,4022],{},"Execution Environment"," (середовища виконання).",[3353,4025,4026,4027,4030],{},"Коли Lambda-сервіс отримує виклик, він або повторно використовує наявне Execution Environment (якщо воно вільне та відповідає функції), або ініціалізує нове. Execution Environment — це ізольоване мікро-VM середовище на базі технології ",[3359,4028,4029],{},"AWS Firecracker"," (відкрита технологія легковісної віртуалізації, розроблена AWS). Кожне Execution Environment забезпечує:",[4032,4033,4034,4038,4041],"ul",{},[4035,4036,4037],"li",{},"повну ізоляцію від інших функцій та інших викликів тієї ж функції;",[4035,4039,4040],{},"стабільне середовище виконання: операційна система Amazon Linux 2, встановлений Runtime (наприклад, .NET 10), і ваш код;",[4035,4042,4043,4046,4047,4050],{},[3359,4044,4045],{},"персистентний стан між викликами"," у межах одного Execution Environment — файлову систему ",[3392,4048,4049],{},"\u002Ftmp",", статичні змінні та об'єкти, ініціалізовані поза handler-функцією.",[3382,4052,4053],{},[3385,4054,4056],{"className":3387,"code":4055,"language":3389,"meta":3390,"style":3390},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\ntitle \"Lifecycle одного Execution Environment\"\n\n[*] --> Init : Lambda отримує ПЕРШИЙ виклик\\n(Cold Start)\n\nstate Init {\n    [*] --> DownloadCode : Завантаження ZIP\u002FImage\n    DownloadCode --> StartRuntime : Запуск .NET Runtime\n    StartRuntime --> RunInitCode : Виконання коду ВНЕ handler\\n(DI container, DB connections,\\nstatic constructors)\n    RunInitCode --> [*]\n}\n\nInit --> Invoke : Init завершено → Handler доступний\n\nstate Invoke {\n    [*] --> RunHandler : Виклик Handler(event, context)\n    RunHandler --> ReturnResult : Повернення результату\n    ReturnResult --> [*]\n}\n\nInvoke --> Idle : Виклик завершено\\n(Warm, очікує наступного)\nIdle --> Invoke : Наступний виклик (Warm Start)\\n← жодних затримок ініціалізації!\nIdle --> [*] : Таймаут простою (~15-45 хвилин)\\nAWS знищує Execution Environment\n\nnote right of Init\n  Cold Start:\n  Відбувається ЛИШЕ при першому виклику\n  або після знищення середовища.\n  Тривалість: від 100ms до кількох секунд\n  (залежить від Runtime та розміру коду).\nend note\n\nnote right of Idle\n  Warm Start:\n  Наступний виклик отримує вже готове\n  середовище. Час ініціалізації = 0.\n  Статичні об'єкти зберігаються між\n  викликами (connection pooling!)\nend note\n\n@enduml\n",[3392,4057,4058,4062,4066,4070,4074,4079,4083,4088,4092,4097,4102,4107,4112,4117,4121,4125,4130,4134,4139,4144,4149,4154,4158,4162,4167,4172,4177,4181,4186,4191,4196,4201,4206,4211,4216,4220,4225,4230,4235,4240,4245,4250,4254,4258],{"__ignoreMap":3390},[3395,4059,4060],{"class":3397,"line":3398},[3395,4061,3401],{},[3395,4063,4064],{"class":3397,"line":3404},[3395,4065,3407],{},[3395,4067,4068],{"class":3397,"line":3410},[3395,4069,3413],{},[3395,4071,4072],{"class":3397,"line":3416},[3395,4073,3420],{"emptyLinePlaceholder":3419},[3395,4075,4076],{"class":3397,"line":3423},[3395,4077,4078],{},"title \"Lifecycle одного Execution Environment\"\n",[3395,4080,4081],{"class":3397,"line":3429},[3395,4082,3420],{"emptyLinePlaceholder":3419},[3395,4084,4085],{"class":3397,"line":3434},[3395,4086,4087],{},"[*] --> Init : Lambda отримує ПЕРШИЙ виклик\\n(Cold Start)\n",[3395,4089,4090],{"class":3397,"line":3440},[3395,4091,3420],{"emptyLinePlaceholder":3419},[3395,4093,4094],{"class":3397,"line":3446},[3395,4095,4096],{},"state Init {\n",[3395,4098,4099],{"class":3397,"line":3452},[3395,4100,4101],{},"    [*] --> DownloadCode : Завантаження ZIP\u002FImage\n",[3395,4103,4104],{"class":3397,"line":3458},[3395,4105,4106],{},"    DownloadCode --> StartRuntime : Запуск .NET Runtime\n",[3395,4108,4109],{"class":3397,"line":3464},[3395,4110,4111],{},"    StartRuntime --> RunInitCode : Виконання коду ВНЕ handler\\n(DI container, DB connections,\\nstatic constructors)\n",[3395,4113,4114],{"class":3397,"line":3470},[3395,4115,4116],{},"    RunInitCode --> [*]\n",[3395,4118,4119],{"class":3397,"line":3476},[3395,4120,3479],{},[3395,4122,4123],{"class":3397,"line":3482},[3395,4124,3420],{"emptyLinePlaceholder":3419},[3395,4126,4127],{"class":3397,"line":3487},[3395,4128,4129],{},"Init --> Invoke : Init завершено → Handler доступний\n",[3395,4131,4132],{"class":3397,"line":3493},[3395,4133,3420],{"emptyLinePlaceholder":3419},[3395,4135,4136],{"class":3397,"line":3499},[3395,4137,4138],{},"state Invoke {\n",[3395,4140,4141],{"class":3397,"line":3505},[3395,4142,4143],{},"    [*] --> RunHandler : Виклик Handler(event, context)\n",[3395,4145,4146],{"class":3397,"line":3511},[3395,4147,4148],{},"    RunHandler --> ReturnResult : Повернення результату\n",[3395,4150,4151],{"class":3397,"line":3517},[3395,4152,4153],{},"    ReturnResult --> [*]\n",[3395,4155,4156],{"class":3397,"line":3523},[3395,4157,3479],{},[3395,4159,4160],{"class":3397,"line":3529},[3395,4161,3420],{"emptyLinePlaceholder":3419},[3395,4163,4164],{"class":3397,"line":3534},[3395,4165,4166],{},"Invoke --> Idle : Виклик завершено\\n(Warm, очікує наступного)\n",[3395,4168,4169],{"class":3397,"line":3539},[3395,4170,4171],{},"Idle --> Invoke : Наступний виклик (Warm Start)\\n← жодних затримок ініціалізації!\n",[3395,4173,4174],{"class":3397,"line":3545},[3395,4175,4176],{},"Idle --> [*] : Таймаут простою (~15-45 хвилин)\\nAWS знищує Execution Environment\n",[3395,4178,4179],{"class":3397,"line":3551},[3395,4180,3420],{"emptyLinePlaceholder":3419},[3395,4182,4183],{"class":3397,"line":3557},[3395,4184,4185],{},"note right of Init\n",[3395,4187,4188],{"class":3397,"line":3563},[3395,4189,4190],{},"  Cold Start:\n",[3395,4192,4193],{"class":3397,"line":3569},[3395,4194,4195],{},"  Відбувається ЛИШЕ при першому виклику\n",[3395,4197,4198],{"class":3397,"line":3575},[3395,4199,4200],{},"  або після знищення середовища.\n",[3395,4202,4203],{"class":3397,"line":3581},[3395,4204,4205],{},"  Тривалість: від 100ms до кількох секунд\n",[3395,4207,4208],{"class":3397,"line":3586},[3395,4209,4210],{},"  (залежить від Runtime та розміру коду).\n",[3395,4212,4213],{"class":3397,"line":3591},[3395,4214,4215],{},"end note\n",[3395,4217,4218],{"class":3397,"line":3597},[3395,4219,3420],{"emptyLinePlaceholder":3419},[3395,4221,4222],{"class":3397,"line":3603},[3395,4223,4224],{},"note right of Idle\n",[3395,4226,4227],{"class":3397,"line":3609},[3395,4228,4229],{},"  Warm Start:\n",[3395,4231,4232],{"class":3397,"line":3615},[3395,4233,4234],{},"  Наступний виклик отримує вже готове\n",[3395,4236,4237],{"class":3397,"line":3621},[3395,4238,4239],{},"  середовище. Час ініціалізації = 0.\n",[3395,4241,4242],{"class":3397,"line":3627},[3395,4243,4244],{},"  Статичні об'єкти зберігаються між\n",[3395,4246,4247],{"class":3397,"line":3633},[3395,4248,4249],{},"  викликами (connection pooling!)\n",[3395,4251,4252],{"class":3397,"line":3638},[3395,4253,4215],{},[3395,4255,4256],{"class":3397,"line":3643},[3395,4257,3420],{"emptyLinePlaceholder":3419},[3395,4259,4260],{"class":3397,"line":3649},[3395,4261,3675],{},[3704,4263,4265],{"id":4264},"cold-start-vs-warm-start-детальний-аналіз","Cold Start vs Warm Start: детальний аналіз",[3353,4267,4268,4271],{},[3359,4269,4270],{},"Cold Start"," — це затримка, що виникає при ініціалізації нового Execution Environment. Вона складається з кількох фаз, кожна з яких додає свою частину до загального часу:",[4273,4274,4275,4291],"table",{},[4276,4277,4278],"thead",{},[4279,4280,4281,4285,4288],"tr",{},[4282,4283,4284],"th",{},"Фаза",[4282,4286,4287],{},"Опис",[4282,4289,4290],{},"Типовий час",[4292,4293,4294,4308,4321,4338],"tbody",{},[4279,4295,4296,4302,4305],{},[4297,4298,4299],"td",{},[3359,4300,4301],{},"Download Code",[4297,4303,4304],{},"Завантаження ZIP-артефакту з S3",[4297,4306,4307],{},"10–200ms",[4279,4309,4310,4315,4318],{},[4297,4311,4312],{},[3359,4313,4314],{},"Start Runtime",[4297,4316,4317],{},"Запуск JVM, .NET CLR або інтерпретатора",[4297,4319,4320],{},"50–500ms",[4279,4322,4323,4328,4335],{},[4297,4324,4325],{},[3359,4326,4327],{},"Run Init Code",[4297,4329,4330,4331,4334],{},"Виконання ",[3392,4332,4333],{},"static"," конструкторів, DI container",[4297,4336,4337],{},"10–5000ms",[4279,4339,4340,4345,4348],{},[4297,4341,4342],{},[3359,4343,4344],{},"Run Handler",[4297,4346,4347],{},"Перший виклик обробника",[4297,4349,4350],{},"час функції",[3353,4352,4353,4354,4357],{},"Критично важливо розуміти: ",[3359,4355,4356],{},"Cold Start — не просто «перший виклик повільніший»",". Cold Start відбувається кожного разу, коли Lambda масштабується горизонтально. Якщо одночасно надходить 100 запитів, а є лише 10 теплих Execution Environments, Lambda ініціалізує 90 нових — 90 одночасних Cold Starts.",[4359,4360,4361,4364,4365,4368],"warning",{},[3359,4362,4363],{},"Cold Start для .NET — особлива проблема."," .NET Runtime (CLR) має значний час ініціалізації порівняно з Python або Node.js. Нативний .NET 10 Cold Start типово займає ",[3359,4366,4367],{},"800ms–3s"," залежно від розміру застосунку та кількості ініціалізованих компонентів. Це є головним викликом для .NET Lambda розробників і вимагає спеціальних технік оптимізації.",[3353,4370,4371,4374],{},[3359,4372,4373],{},"Warm Start"," — виклик функції, коли Lambda-сервіс знаходить вже ініціалізоване (але вільне) Execution Environment. У цьому випадку фаза ініціалізації повністю пропускається, і виконання починається безпосередньо з Handler. Час Warm Start практично дорівнює часу виконання самої бізнес-логіки.",[3382,4376,4377],{},[3385,4378,4380],{"className":3387,"code":4379,"language":3389,"meta":3390,"style":3390},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\ntitle \"Cold Start vs Warm Start: часова шкала виклику\"\n\nskinparam sequence {\n    ParticipantBackgroundColor #f8fafc\n}\n\nparticipant \"Виклик 1\\n(Cold Start)\" as C1\nparticipant \"Виклик 2\\n(Warm Start)\" as C2\n\nnote over C1\n  **COLD START**\n  Завантаження коду: 150ms ████████\n  Старт .NET CLR: 400ms ████████████████████\n  Init код (DI тощо): 600ms ████████████████████████████████\n  Handler: 50ms ███\n  ────────────────────────────────────\n  ЗАГАЛОМ: ~1200ms\nend note\n\nnote over C2\n  **WARM START**\n  (середовище вже готове)\n  Handler: 50ms ███\n  ────────────────────────────────────\n  ЗАГАЛОМ: ~50ms\n\n  Економія: 1150ms (95.8%)!\nend note\n\n@enduml\n",[3392,4381,4382,4386,4390,4394,4398,4403,4407,4412,4417,4421,4425,4430,4435,4439,4444,4449,4454,4459,4464,4469,4474,4479,4483,4487,4492,4497,4502,4506,4510,4515,4519,4524,4528,4532],{"__ignoreMap":3390},[3395,4383,4384],{"class":3397,"line":3398},[3395,4385,3401],{},[3395,4387,4388],{"class":3397,"line":3404},[3395,4389,3407],{},[3395,4391,4392],{"class":3397,"line":3410},[3395,4393,3413],{},[3395,4395,4396],{"class":3397,"line":3416},[3395,4397,3420],{"emptyLinePlaceholder":3419},[3395,4399,4400],{"class":3397,"line":3423},[3395,4401,4402],{},"title \"Cold Start vs Warm Start: часова шкала виклику\"\n",[3395,4404,4405],{"class":3397,"line":3429},[3395,4406,3420],{"emptyLinePlaceholder":3419},[3395,4408,4409],{"class":3397,"line":3434},[3395,4410,4411],{},"skinparam sequence {\n",[3395,4413,4414],{"class":3397,"line":3440},[3395,4415,4416],{},"    ParticipantBackgroundColor #f8fafc\n",[3395,4418,4419],{"class":3397,"line":3446},[3395,4420,3479],{},[3395,4422,4423],{"class":3397,"line":3452},[3395,4424,3420],{"emptyLinePlaceholder":3419},[3395,4426,4427],{"class":3397,"line":3458},[3395,4428,4429],{},"participant \"Виклик 1\\n(Cold Start)\" as C1\n",[3395,4431,4432],{"class":3397,"line":3464},[3395,4433,4434],{},"participant \"Виклик 2\\n(Warm Start)\" as C2\n",[3395,4436,4437],{"class":3397,"line":3470},[3395,4438,3420],{"emptyLinePlaceholder":3419},[3395,4440,4441],{"class":3397,"line":3476},[3395,4442,4443],{},"note over C1\n",[3395,4445,4446],{"class":3397,"line":3482},[3395,4447,4448],{},"  **COLD START**\n",[3395,4450,4451],{"class":3397,"line":3487},[3395,4452,4453],{},"  Завантаження коду: 150ms ████████\n",[3395,4455,4456],{"class":3397,"line":3493},[3395,4457,4458],{},"  Старт .NET CLR: 400ms ████████████████████\n",[3395,4460,4461],{"class":3397,"line":3499},[3395,4462,4463],{},"  Init код (DI тощо): 600ms ████████████████████████████████\n",[3395,4465,4466],{"class":3397,"line":3505},[3395,4467,4468],{},"  Handler: 50ms ███\n",[3395,4470,4471],{"class":3397,"line":3511},[3395,4472,4473],{},"  ────────────────────────────────────\n",[3395,4475,4476],{"class":3397,"line":3517},[3395,4477,4478],{},"  ЗАГАЛОМ: ~1200ms\n",[3395,4480,4481],{"class":3397,"line":3523},[3395,4482,4215],{},[3395,4484,4485],{"class":3397,"line":3529},[3395,4486,3420],{"emptyLinePlaceholder":3419},[3395,4488,4489],{"class":3397,"line":3534},[3395,4490,4491],{},"note over C2\n",[3395,4493,4494],{"class":3397,"line":3539},[3395,4495,4496],{},"  **WARM START**\n",[3395,4498,4499],{"class":3397,"line":3545},[3395,4500,4501],{},"  (середовище вже готове)\n",[3395,4503,4504],{"class":3397,"line":3551},[3395,4505,4468],{},[3395,4507,4508],{"class":3397,"line":3557},[3395,4509,4473],{},[3395,4511,4512],{"class":3397,"line":3563},[3395,4513,4514],{},"  ЗАГАЛОМ: ~50ms\n",[3395,4516,4517],{"class":3397,"line":3569},[3395,4518,3420],{"emptyLinePlaceholder":3419},[3395,4520,4521],{"class":3397,"line":3575},[3395,4522,4523],{},"  Економія: 1150ms (95.8%)!\n",[3395,4525,4526],{"class":3397,"line":3581},[3395,4527,4215],{},[3395,4529,4530],{"class":3397,"line":3586},[3395,4531,3420],{"emptyLinePlaceholder":3419},[3395,4533,4534],{"class":3397,"line":3591},[3395,4535,3675],{},[3684,4537],{},[3348,4539,4541],{"id":4540},"lambda-runtimes-середовища-виконання","Lambda Runtimes: середовища виконання",[3353,4543,4544,4547],{},[3359,4545,4546],{},"Runtime"," — це компонент Execution Environment, що забезпечує взаємодію між Lambda-сервісом та кодом функції. Runtime відповідає за: отримання події від Lambda-сервісу, десеріалізацію JSON-payload у нативні об'єкти, виклик handler-функції та серіалізацію відповіді назад у JSON.",[3353,4549,4550,4551,4554,4555,4558,4559,3860],{},"AWS надає ",[3359,4552,4553],{},"керовані Runtime"," для більшості популярних мов програмування. У разі, коли жоден із керованих Runtime не підходить, розробник може створити ",[3359,4556,4557],{},"Custom Runtime"," — довільний виконуваний файл, що реалізує ",[4560,4561,4565],"a",{"href":4562,"rel":4563},"https:\u002F\u002Fdocs.aws.amazon.com\u002Flambda\u002Flatest\u002Fdg\u002Fruntimes-api.html",[4564],"nofollow","Lambda Runtime API",[3862,4567,4568,4584,4600,4614,4628,4642],{},[3865,4569,4572,4581],{"icon":4570,"title":4571},"i-simple-icons-dotnet",".NET 10",[3353,4573,4574,4577,4578],{},[3359,4575,4576],{},"Identifier:"," ",[3392,4579,4580],{},"dotnet10",[3353,4582,4583],{},"Офіційний керований Runtime від AWS. LTS-версія .NET. Оптимальний вибір для нових .NET Lambda проектів. Підтримує Native AOT компіляцію для мінімізації Cold Start.",[3865,4585,4587,4594],{"icon":4570,"title":4586},".NET 6",[3353,4588,4589,4577,4591],{},[3359,4590,4576],{},[3392,4592,4593],{},"dotnet6",[3353,4595,4596,4597],{},"Попередня LTS-версія. Підтримується до листопада 2024. ",[3359,4598,4599],{},"Рекомендується міграція на .NET 10.",[3865,4601,4604,4611],{"icon":4602,"title":4603},"i-simple-icons-nodedotjs","Node.js 20",[3353,4605,4606,4577,4608],{},[3359,4607,4576],{},[3392,4609,4610],{},"nodejs20.x",[3353,4612,4613],{},"Найпопулярніший Runtime для serverless. Мінімальний Cold Start (~100ms). Ідеальний для простих обробників подій та glue-коду.",[3865,4615,4618,4625],{"icon":4616,"title":4617},"i-simple-icons-python","Python 3.12",[3353,4619,4620,4577,4622],{},[3359,4621,4576],{},[3392,4623,4624],{},"python3.12",[3353,4626,4627],{},"Широко використовується у ML\u002FData pipelines та скриптах автоматизації. Дуже короткий Cold Start.",[3865,4629,4632,4639],{"icon":4630,"title":4631},"i-simple-icons-openjdk","Java 21",[3353,4633,4634,4577,4636],{},[3359,4635,4576],{},[3392,4637,4638],{},"java21",[3353,4640,4641],{},"Підтримує GraalVM Native Image для зменшення Cold Start. Аналогічна до .NET ситуація з часом ініціалізації JVM.",[3865,4643,4645,4652],{"icon":4644,"title":4557},"i-heroicons-code-bracket",[3353,4646,4647,4577,4649],{},[3359,4648,4576],{},[3392,4650,4651],{},"provided.al2023",[3353,4653,4654],{},"Будь-яка мова, що може скомпілюватися у Linux-бінарник (Rust, Go, C++, .NET Native AOT). Максимальна гнучкість та мінімальний Cold Start.",[3704,4656,4658],{"id":4657},"net-runtime-для-lambda-специфіка-та-особливості",".NET Runtime для Lambda: специфіка та особливості",[3353,4660,4550,4661,4664,4665,4668,4669,3860],{},[3359,4662,4663],{},"Amazon.Lambda.Core"," NuGet-пакет, який є центральним компонентом для написання Lambda функцій на .NET. Він визначає інтерфейс ",[3392,4666,4667],{},"ILambdaContext"," та базовий клас ",[3392,4670,4671],{},"ILambdaSerializer",[3353,4673,4674,4675,4678],{},"Виклик Lambda-функції на .NET відбувається через механізм ",[3359,4676,4677],{},"Function Handler"," — метод зі специфічною сигнатурою:",[3385,4680,4684],{"className":4681,"code":4682,"language":4683,"meta":3390,"style":3390},"language-csharp shiki shiki-themes light-plus dark-plus dark-plus","\u002F\u002F Варіант 1: синхронний handler з поверненням значення\npublic TOutput FunctionHandler(TInput input, ILambdaContext context)\n\n\u002F\u002F Варіант 2: асинхронний handler (рекомендується для .NET)\npublic async Task\u003CTOutput> FunctionHandlerAsync(TInput input, ILambdaContext context)\n\n\u002F\u002F Варіант 3: handler без вхідних даних\npublic async Task\u003CTOutput> FunctionHandlerAsync(ILambdaContext context)\n\n\u002F\u002F Варіант 4: handler без вхідних даних та без повернення\npublic async Task FunctionHandlerAsync(ILambdaContext context)\n","csharp",[3392,4685,4686,4692,4728,4732,4737,4754,4758,4763,4773,4777,4782],{"__ignoreMap":3390},[3395,4687,4688],{"class":3397,"line":3398},[3395,4689,4691],{"class":4690},"spJ8K","\u002F\u002F Варіант 1: синхронний handler з поверненням значення\n",[3395,4693,4694,4698,4702,4706,4710,4713,4717,4720,4722,4725],{"class":3397,"line":3404},[3395,4695,4697],{"class":4696},"su1O8","public",[3395,4699,4701],{"class":4700},"sN1BT"," TOutput",[3395,4703,4705],{"class":4704},"s8Opu"," FunctionHandler",[3395,4707,4709],{"class":4708},"sHH4Y","(",[3395,4711,4712],{"class":4700},"TInput",[3395,4714,4716],{"class":4715},"siwwj"," input",[3395,4718,4719],{"class":4708},", ",[3395,4721,4667],{"class":4700},[3395,4723,4724],{"class":4715}," context",[3395,4726,4727],{"class":4708},")\n",[3395,4729,4730],{"class":3397,"line":3410},[3395,4731,3420],{"emptyLinePlaceholder":3419},[3395,4733,4734],{"class":3397,"line":3416},[3395,4735,4736],{"class":4690},"\u002F\u002F Варіант 2: асинхронний handler (рекомендується для .NET)\n",[3395,4738,4739,4742,4744,4746,4748,4750,4752],{"class":3397,"line":3423},[3395,4740,4741],{"class":4708},"public async Task\u003CTOutput> FunctionHandlerAsync(",[3395,4743,4712],{"class":4700},[3395,4745,4716],{"class":4715},[3395,4747,4719],{"class":4708},[3395,4749,4667],{"class":4700},[3395,4751,4724],{"class":4715},[3395,4753,4727],{"class":4708},[3395,4755,4756],{"class":3397,"line":3429},[3395,4757,3420],{"emptyLinePlaceholder":3419},[3395,4759,4760],{"class":3397,"line":3434},[3395,4761,4762],{"class":4690},"\u002F\u002F Варіант 3: handler без вхідних даних\n",[3395,4764,4765,4767,4769,4771],{"class":3397,"line":3440},[3395,4766,4741],{"class":4708},[3395,4768,4667],{"class":4700},[3395,4770,4724],{"class":4715},[3395,4772,4727],{"class":4708},[3395,4774,4775],{"class":3397,"line":3446},[3395,4776,3420],{"emptyLinePlaceholder":3419},[3395,4778,4779],{"class":3397,"line":3452},[3395,4780,4781],{"class":4690},"\u002F\u002F Варіант 4: handler без вхідних даних та без повернення\n",[3395,4783,4784,4787,4789,4791],{"class":3397,"line":3458},[3395,4785,4786],{"class":4708},"public async Task FunctionHandlerAsync(",[3395,4788,4667],{"class":4700},[3395,4790,4724],{"class":4715},[3395,4792,4727],{"class":4708},[3353,4794,4795,4799],{},[3359,4796,4797],{},[3392,4798,4667],{}," надає метаданих про поточний виклик:",[3939,4801,4802,4806,4810,4818,4822],{},[3942,4803,4805],{"name":4804,"type":3954},"AwsRequestId","Унікальний ідентифікатор поточного виклику. Використовується для кореляції логів у CloudWatch та для ідемпотентності (уникнення повторної обробки).",[3942,4807,4809],{"name":4808,"type":3954},"FunctionName","Назва Lambda-функції. Корисна при використанні одного handler для кількох функцій або для умовної логіки на основі контексту деплойменту.",[3942,4811,4814,4815,4817],{"name":4812,"type":4813},"RemainingTime","TimeSpan","Час, що залишився до досягнення Timeout. Критично важливо для реалізації graceful shutdown: функція може перевіряти ",[3392,4816,4812],{}," та коректно завершувати роботу до примусового знищення.",[3942,4819,4821],{"name":4820,"type":3945},"MemoryLimitInMB","Кількість пам'яті, виділеної для функції. Корисна для динамічного налаштування буферів або розміру пакетів обробки.",[3942,4823,4826,4827,4719,4830,4719,4833,4719,4836,4719,4839,4719,4842,4845,4846,4849],{"name":4824,"type":4825},"Logger","ILambdaLogger","Базовий логер, що записує у CloudWatch Logs. Підтримує рівні: ",[3392,4828,4829],{},"LogTrace",[3392,4831,4832],{},"LogDebug",[3392,4834,4835],{},"LogInformation",[3392,4837,4838],{},"LogWarning",[3392,4840,4841],{},"LogError",[3392,4843,4844],{},"LogCritical",". Для продакшн-систем рекомендується використовувати ",[3392,4847,4848],{},"Microsoft.Extensions.Logging"," з відповідним Lambda-провайдером.",[3684,4851],{},[3348,4853,4855],{"id":4854},"створення-lambda-проекту-від-порожньої-папки-до-hello-world","Створення Lambda-проекту: від порожньої папки до Hello World",[3353,4857,4858],{},"Для розробника .NET існує три основні шляхи створення проекту. Вибір залежить від того, чи хочете ви контролювати кожен файл, чи використати готові кращі практики від AWS.",[3704,4860,4862],{"id":4861},"варіант-а-ручне-створення-manual-для-повного-контролю","Варіант А: Ручне створення (Manual) — для повного контролю",[3353,4864,4865],{},"Це дозволяє зрозуміти, як саме працює Lambda без \"магії\" шаблонів.",[4867,4868,4869,4910,4944,4957],"ol",{},[4035,4870,4871,4874],{},[3359,4872,4873],{},"Створіть директорію та проект:",[3385,4875,4879],{"className":4876,"code":4877,"language":4878,"meta":3390,"style":3390},"language-bash shiki shiki-themes light-plus dark-plus dark-plus","mkdir MyLambda && cd MyLambda\ndotnet new classlib\n","bash",[3392,4880,4881,4899],{"__ignoreMap":3390},[3395,4882,4883,4886,4890,4893,4896],{"class":3397,"line":3398},[3395,4884,4885],{"class":4704},"mkdir",[3395,4887,4889],{"class":4888},"sbdoH"," MyLambda",[3395,4891,4892],{"class":4708}," && ",[3395,4894,4895],{"class":4704},"cd",[3395,4897,4898],{"class":4888}," MyLambda\n",[3395,4900,4901,4904,4907],{"class":3397,"line":3404},[3395,4902,4903],{"class":4704},"dotnet",[3395,4905,4906],{"class":4888}," new",[3395,4908,4909],{"class":4888}," classlib\n",[4035,4911,4912,4915],{},[3359,4913,4914],{},"Додайте ядро SDK:",[3385,4916,4918],{"className":4876,"code":4917,"language":4878,"meta":3390,"style":3390},"dotnet add package Amazon.Lambda.Core\ndotnet add package Amazon.Lambda.Serialization.SystemTextJson\n",[3392,4919,4920,4933],{"__ignoreMap":3390},[3395,4921,4922,4924,4927,4930],{"class":3397,"line":3398},[3395,4923,4903],{"class":4704},[3395,4925,4926],{"class":4888}," add",[3395,4928,4929],{"class":4888}," package",[3395,4931,4932],{"class":4888}," Amazon.Lambda.Core\n",[3395,4934,4935,4937,4939,4941],{"class":3397,"line":3404},[3395,4936,4903],{"class":4704},[3395,4938,4926],{"class":4888},[3395,4940,4929],{"class":4888},[3395,4942,4943],{"class":4888}," Amazon.Lambda.Serialization.SystemTextJson\n",[4035,4945,4946,4949,4950,4953,4954,4956],{},[3359,4947,4948],{},"Напишіть код:"," Створіть клас ",[3392,4951,4952],{},"Function.cs"," з методом, який приймає ",[3392,4955,3954],{}," або об'єкт.",[4035,4958,4959,4962,4963,4966],{},[3359,4960,4961],{},"Зареєструйте серіалізатор:"," Додайте атрибут ",[3392,4964,4965],{},"[assembly: LambdaSerializer(...)]"," над namespace.",[3704,4968,4970],{"id":4969},"варіант-б-використання-aws-templates-рекомендовано","Варіант Б: Використання AWS Templates (Рекомендовано)",[3353,4972,4973],{},"AWS надає набір шаблонів, які автоматично створюють правильну структуру, включаючи конфігураційні файли.",[4867,4975,4976,4998,5020],{},[4035,4977,4978,4981],{},[3359,4979,4980],{},"Встановіть шаблони:",[3385,4982,4984],{"className":4876,"code":4983,"language":4878,"meta":3390,"style":3390},"dotnet new install Amazon.Lambda.Templates\n",[3392,4985,4986],{"__ignoreMap":3390},[3395,4987,4988,4990,4992,4995],{"class":3397,"line":3398},[3395,4989,4903],{"class":4704},[3395,4991,4906],{"class":4888},[3395,4993,4994],{"class":4888}," install",[3395,4996,4997],{"class":4888}," Amazon.Lambda.Templates\n",[4035,4999,5000,5003],{},[3359,5001,5002],{},"Перегляньте список доступних типів:",[3385,5004,5006],{"className":4876,"code":5005,"language":4878,"meta":3390,"style":3390},"dotnet new lambda --list\n",[3392,5007,5008],{"__ignoreMap":3390},[3395,5009,5010,5012,5014,5017],{"class":3397,"line":3398},[3395,5011,4903],{"class":4704},[3395,5013,4906],{"class":4888},[3395,5015,5016],{"class":4888}," lambda",[3395,5018,5019],{"class":4696}," --list\n",[4035,5021,5022,5025],{},[3359,5023,5024],{},"Створіть проект (наприклад, для S3 подій):",[3385,5026,5028],{"className":4876,"code":5027,"language":4878,"meta":3390,"style":3390},"dotnet new lambda.S3 -n MyS3Processor\n",[3392,5029,5030],{"__ignoreMap":3390},[3395,5031,5032,5034,5036,5039,5042],{"class":3397,"line":3398},[3395,5033,4903],{"class":4704},[3395,5035,4906],{"class":4888},[3395,5037,5038],{"class":4888}," lambda.S3",[3395,5040,5041],{"class":4696}," -n",[3395,5043,5044],{"class":4888}," MyS3Processor\n",[3704,5046,5048,5049],{"id":5047},"структура-проекту-файл-aws-lambda-tools-defaultsjson","Структура проекту: Файл ",[3392,5050,5051],{},"aws-lambda-tools-defaults.json",[3353,5053,5054,5055,3860],{},"При створенні через шаблони ви знайдете цей файл. Він є критично важливим, бо зберігає налаштування для ",[3392,5056,5057],{},"dotnet lambda cli",[3385,5059,5063],{"className":5060,"code":5061,"language":5062,"meta":3390,"style":3390},"language-json shiki shiki-themes light-plus dark-plus dark-plus","{\n    \"Information\": \"This file saves default values for the dotnet lambda CLI.\",\n    \"profile\": \"default\",\n    \"region\": \"eu-central-1\",\n    \"configuration\": \"Release\",\n    \"framework\": \"net10.0\",\n    \"function-runtime\": \"dotnet10\",\n    \"function-memory-size\": 256,\n    \"function-timeout\": 30,\n    \"function-handler\": \"MyProject::MyProject.Function::Handler\"\n}\n","json",[3392,5064,5065,5070,5085,5097,5109,5121,5133,5145,5158,5170,5180],{"__ignoreMap":3390},[3395,5066,5067],{"class":3397,"line":3398},[3395,5068,5069],{"class":4708},"{\n",[3395,5071,5072,5076,5079,5082],{"class":3397,"line":3404},[3395,5073,5075],{"class":5074},"sLwNe","    \"Information\"",[3395,5077,5078],{"class":4708},": ",[3395,5080,5081],{"class":4888},"\"This file saves default values for the dotnet lambda CLI.\"",[3395,5083,5084],{"class":4708},",\n",[3395,5086,5087,5090,5092,5095],{"class":3397,"line":3410},[3395,5088,5089],{"class":5074},"    \"profile\"",[3395,5091,5078],{"class":4708},[3395,5093,5094],{"class":4888},"\"default\"",[3395,5096,5084],{"class":4708},[3395,5098,5099,5102,5104,5107],{"class":3397,"line":3416},[3395,5100,5101],{"class":5074},"    \"region\"",[3395,5103,5078],{"class":4708},[3395,5105,5106],{"class":4888},"\"eu-central-1\"",[3395,5108,5084],{"class":4708},[3395,5110,5111,5114,5116,5119],{"class":3397,"line":3423},[3395,5112,5113],{"class":5074},"    \"configuration\"",[3395,5115,5078],{"class":4708},[3395,5117,5118],{"class":4888},"\"Release\"",[3395,5120,5084],{"class":4708},[3395,5122,5123,5126,5128,5131],{"class":3397,"line":3429},[3395,5124,5125],{"class":5074},"    \"framework\"",[3395,5127,5078],{"class":4708},[3395,5129,5130],{"class":4888},"\"net10.0\"",[3395,5132,5084],{"class":4708},[3395,5134,5135,5138,5140,5143],{"class":3397,"line":3434},[3395,5136,5137],{"class":5074},"    \"function-runtime\"",[3395,5139,5078],{"class":4708},[3395,5141,5142],{"class":4888},"\"dotnet10\"",[3395,5144,5084],{"class":4708},[3395,5146,5147,5150,5152,5156],{"class":3397,"line":3440},[3395,5148,5149],{"class":5074},"    \"function-memory-size\"",[3395,5151,5078],{"class":4708},[3395,5153,5155],{"class":5154},"sJj4R","256",[3395,5157,5084],{"class":4708},[3395,5159,5160,5163,5165,5168],{"class":3397,"line":3446},[3395,5161,5162],{"class":5074},"    \"function-timeout\"",[3395,5164,5078],{"class":4708},[3395,5166,5167],{"class":5154},"30",[3395,5169,5084],{"class":4708},[3395,5171,5172,5175,5177],{"class":3397,"line":3452},[3395,5173,5174],{"class":5074},"    \"function-handler\"",[3395,5176,5078],{"class":4708},[3395,5178,5179],{"class":4888},"\"MyProject::MyProject.Function::Handler\"\n",[3395,5181,5182],{"class":3397,"line":3458},[3395,5183,3479],{"class":4708},[3353,5185,5186],{},[5187,5188,5189],"em",{},"Завдяки цьому файлу вам не потрібно щоразу вводити довгі параметри в терміналі.",[3684,5191],{},[3348,5193,5195],{"id":5194},"lambda-layers-механізм-спільного-використання-коду","Lambda Layers: механізм спільного використання коду",[3353,5197,5198,5201,5202,5205],{},[3359,5199,5200],{},"Lambda Layer"," — це ZIP-архів, що містить бібліотеки, кастомний Runtime, конфігурацію або будь-які інші файли, які можна розділити між кількома Lambda-функціями. Layer монтується в директорію ",[3392,5203,5204],{},"\u002Fopt"," Execution Environment і стає доступним для функції під час виконання.",[3382,5207,5208],{},[3385,5209,5211],{"className":3387,"code":5210,"language":3389,"meta":3390,"style":3390},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\ntitle \"Lambda Layers: структура та монтування\"\n\npackage \"Layer 1: Shared .NET Libraries (v2.3)\" as L1 #dbeafe {\n    rectangle \"Newtonsoft.Json 13.0\" as NJ\n    rectangle \"Serilog + Sinks\" as SL\n    rectangle \"FluentValidation 11.x\" as FV\n}\n\npackage \"Layer 2: AWS SDK Extensions (v1.1)\" as L2 #fef3c7 {\n    rectangle \"AWSSDK.S3\" as S3LIB\n    rectangle \"AWSSDK.DynamoDBv2\" as DYNLIB\n    rectangle \"Amazon.Lambda.Core\" as LCORE\n}\n\npackage \"Execution Environment\" as EE #f0fdf4 {\n    rectangle \"\u002Fvar\u002Ftask\\n(Код функції — лише ваш код!)\" as TASK #bbf7d0\n    rectangle \"\u002Fopt\u002Fdotnet\u002Fpackages\\n(Layer 1 + Layer 2)\" as OPT #d1fae5\n    rectangle \".NET Runtime\" as DOTNET\n}\n\nL1 -down-> OPT : Монтується при ініціалізації\nL2 -down-> OPT : Монтується при ініціалізації\nTASK -right-> OPT : Імпортує бібліотеки\n\nnote bottom of EE\n  Без Layers: ZIP функції = 45MB\n  З Layers: ZIP функції = 2MB\n  Бібліотеки оновлюються незалежно\n  від коду функції!\nend note\n\n@enduml\n",[3392,5212,5213,5217,5221,5225,5229,5234,5238,5243,5248,5253,5258,5262,5266,5271,5276,5281,5286,5290,5294,5299,5304,5309,5314,5318,5322,5327,5332,5337,5341,5346,5351,5356,5361,5366,5370,5374],{"__ignoreMap":3390},[3395,5214,5215],{"class":3397,"line":3398},[3395,5216,3401],{},[3395,5218,5219],{"class":3397,"line":3404},[3395,5220,3407],{},[3395,5222,5223],{"class":3397,"line":3410},[3395,5224,3413],{},[3395,5226,5227],{"class":3397,"line":3416},[3395,5228,3420],{"emptyLinePlaceholder":3419},[3395,5230,5231],{"class":3397,"line":3423},[3395,5232,5233],{},"title \"Lambda Layers: структура та монтування\"\n",[3395,5235,5236],{"class":3397,"line":3429},[3395,5237,3420],{"emptyLinePlaceholder":3419},[3395,5239,5240],{"class":3397,"line":3434},[3395,5241,5242],{},"package \"Layer 1: Shared .NET Libraries (v2.3)\" as L1 #dbeafe {\n",[3395,5244,5245],{"class":3397,"line":3440},[3395,5246,5247],{},"    rectangle \"Newtonsoft.Json 13.0\" as NJ\n",[3395,5249,5250],{"class":3397,"line":3446},[3395,5251,5252],{},"    rectangle \"Serilog + Sinks\" as SL\n",[3395,5254,5255],{"class":3397,"line":3452},[3395,5256,5257],{},"    rectangle \"FluentValidation 11.x\" as FV\n",[3395,5259,5260],{"class":3397,"line":3458},[3395,5261,3479],{},[3395,5263,5264],{"class":3397,"line":3464},[3395,5265,3420],{"emptyLinePlaceholder":3419},[3395,5267,5268],{"class":3397,"line":3470},[3395,5269,5270],{},"package \"Layer 2: AWS SDK Extensions (v1.1)\" as L2 #fef3c7 {\n",[3395,5272,5273],{"class":3397,"line":3476},[3395,5274,5275],{},"    rectangle \"AWSSDK.S3\" as S3LIB\n",[3395,5277,5278],{"class":3397,"line":3482},[3395,5279,5280],{},"    rectangle \"AWSSDK.DynamoDBv2\" as DYNLIB\n",[3395,5282,5283],{"class":3397,"line":3487},[3395,5284,5285],{},"    rectangle \"Amazon.Lambda.Core\" as LCORE\n",[3395,5287,5288],{"class":3397,"line":3493},[3395,5289,3479],{},[3395,5291,5292],{"class":3397,"line":3499},[3395,5293,3420],{"emptyLinePlaceholder":3419},[3395,5295,5296],{"class":3397,"line":3505},[3395,5297,5298],{},"package \"Execution Environment\" as EE #f0fdf4 {\n",[3395,5300,5301],{"class":3397,"line":3511},[3395,5302,5303],{},"    rectangle \"\u002Fvar\u002Ftask\\n(Код функції — лише ваш код!)\" as TASK #bbf7d0\n",[3395,5305,5306],{"class":3397,"line":3517},[3395,5307,5308],{},"    rectangle \"\u002Fopt\u002Fdotnet\u002Fpackages\\n(Layer 1 + Layer 2)\" as OPT #d1fae5\n",[3395,5310,5311],{"class":3397,"line":3523},[3395,5312,5313],{},"    rectangle \".NET Runtime\" as DOTNET\n",[3395,5315,5316],{"class":3397,"line":3529},[3395,5317,3479],{},[3395,5319,5320],{"class":3397,"line":3534},[3395,5321,3420],{"emptyLinePlaceholder":3419},[3395,5323,5324],{"class":3397,"line":3539},[3395,5325,5326],{},"L1 -down-> OPT : Монтується при ініціалізації\n",[3395,5328,5329],{"class":3397,"line":3545},[3395,5330,5331],{},"L2 -down-> OPT : Монтується при ініціалізації\n",[3395,5333,5334],{"class":3397,"line":3551},[3395,5335,5336],{},"TASK -right-> OPT : Імпортує бібліотеки\n",[3395,5338,5339],{"class":3397,"line":3557},[3395,5340,3420],{"emptyLinePlaceholder":3419},[3395,5342,5343],{"class":3397,"line":3563},[3395,5344,5345],{},"note bottom of EE\n",[3395,5347,5348],{"class":3397,"line":3569},[3395,5349,5350],{},"  Без Layers: ZIP функції = 45MB\n",[3395,5352,5353],{"class":3397,"line":3575},[3395,5354,5355],{},"  З Layers: ZIP функції = 2MB\n",[3395,5357,5358],{"class":3397,"line":3581},[3395,5359,5360],{},"  Бібліотеки оновлюються незалежно\n",[3395,5362,5363],{"class":3397,"line":3586},[3395,5364,5365],{},"  від коду функції!\n",[3395,5367,5368],{"class":3397,"line":3591},[3395,5369,4215],{},[3395,5371,5372],{"class":3397,"line":3597},[3395,5373,3420],{"emptyLinePlaceholder":3419},[3395,5375,5376],{"class":3397,"line":3603},[3395,5377,3675],{},[3704,5379,5381],{"id":5380},"технічна-реалізація-для-net","Технічна реалізація для .NET",[3353,5383,5384,5385,5387],{},"Коли ви додаєте Layer до Lambda, AWS розпаковує його в папку ",[3392,5386,5204],{},". Для того, щоб .NET Runtime міг знайти ваші бібліотеки (DLL), вони мають бути розміщені у специфічній підпапці.",[3353,5389,5390,4577,5393],{},[3359,5391,5392],{},"Шлях пошуку за замовчуванням:",[3392,5394,5395],{},"\u002Fopt\u002Fdotnet\u002Fpackages",[3353,5397,5398,5399,5402],{},"Коли .NET Lambda ініціалізується, вона автоматично додає цей шлях до ",[3392,5400,5401],{},"DOTNET_SHARED_STORE"," або використовує механізм Assembly Resolution для пошуку залежностей у цій локації.",[3704,5404,5406],{"id":5405},"переваги-використання-layers","Переваги використання Layers",[3862,5408,5409,5414,5419],{},[3865,5410,5413],{"icon":5411,"title":5412},"i-heroicons-archive-box","Зменшення пакетів","Виносьте важкі NuGet-пакети (наприклад, Entity Framework або ImageSharp) у шари. Це скорочує час завантаження коду функції з S3 під час Cold Start.",[3865,5415,5418],{"icon":5416,"title":5417},"i-heroicons-arrows-pointing-in","Централізація","Змінюйте версію спільної бібліотеки в одному шарі, замість того щоб перезбирати та деплоїти 50 різних функцій.",[3865,5420,5423],{"icon":5421,"title":5422},"i-heroicons-users","Розподіл праці","DevOps команда може підготувати шар з налаштованим логуванням та безпекою, а розробники просто підключать його до своїх функцій.",[3704,5425,5427],{"id":5426},"mini-workshop-створення-та-деплой-layer-для-net","Mini-Workshop: Створення та деплой Layer для .NET",[3353,5429,5430,5431,5434],{},"Розглянемо процес винесення бібліотеки ",[3392,5432,5433],{},"Newtonsoft.Json"," у окремий шар.",[5436,5437,5438,5442,5445,5466,5470,5473,5522,5527,5531,5623,5627,5630],"steps",{},[3704,5439,5441],{"id":5440},"підготовка-структури","Підготовка структури",[3353,5443,5444],{},"Створіть папку зі специфічною структурою для .NET:",[3385,5446,5448],{"className":4876,"code":5447,"language":4878,"meta":3390,"style":3390},"mkdir -p my-layer\u002Fdotnet\u002Fpackages\ncd my-layer\u002Fdotnet\u002Fpackages\n",[3392,5449,5450,5460],{"__ignoreMap":3390},[3395,5451,5452,5454,5457],{"class":3397,"line":3398},[3395,5453,4885],{"class":4704},[3395,5455,5456],{"class":4696}," -p",[3395,5458,5459],{"class":4888}," my-layer\u002Fdotnet\u002Fpackages\n",[3395,5461,5462,5464],{"class":3397,"line":3404},[3395,5463,4895],{"class":4704},[3395,5465,5459],{"class":4888},[3704,5467,5469],{"id":5468},"публікація-залежностей","Публікація залежностей",[3353,5471,5472],{},"Створіть тимчасовий проект і опублікуйте його DLL у цю папку:",[3385,5474,5476],{"className":4876,"code":5475,"language":4878,"meta":3390,"style":3390},"dotnet new classlib -n TempLayer\ndotnet add package Newtonsoft.Json\ndotnet publish -c Release -o .\n",[3392,5477,5478,5492,5503],{"__ignoreMap":3390},[3395,5479,5480,5482,5484,5487,5489],{"class":3397,"line":3398},[3395,5481,4903],{"class":4704},[3395,5483,4906],{"class":4888},[3395,5485,5486],{"class":4888}," classlib",[3395,5488,5041],{"class":4696},[3395,5490,5491],{"class":4888}," TempLayer\n",[3395,5493,5494,5496,5498,5500],{"class":3397,"line":3404},[3395,5495,4903],{"class":4704},[3395,5497,4926],{"class":4888},[3395,5499,4929],{"class":4888},[3395,5501,5502],{"class":4888}," Newtonsoft.Json\n",[3395,5504,5505,5507,5510,5513,5516,5519],{"class":3397,"line":3410},[3395,5506,4903],{"class":4704},[3395,5508,5509],{"class":4888}," publish",[3395,5511,5512],{"class":4696}," -c",[3395,5514,5515],{"class":4888}," Release",[3395,5517,5518],{"class":4696}," -o",[3395,5520,5521],{"class":4888}," .\n",[3353,5523,5524],{},[5187,5525,5526],{},"Після цього видаліть зайві файли (.csproj, .json), залишивши лише потрібні .dll.",[3704,5528,5530],{"id":5529},"створення-та-завантаження-шару","Створення та завантаження шару",[3385,5532,5534],{"className":4876,"code":5533,"language":4878,"meta":3390,"style":3390},"# Пакуємо папку 'dotnet' у ZIP\ncd ..\u002F..\nzip -r my-layer.zip dotnet\u002F\n\n# Завантажуємо в AWS\naws lambda publish-layer-version \\\n    --layer-name SharedLibraries \\\n    --description \"Common NuGet packages\" \\\n    --zip-file fileb:\u002F\u002Fmy-layer.zip \\\n    --compatible-runtimes dotnet10\n",[3392,5535,5536,5541,5548,5562,5566,5571,5585,5595,5605,5615],{"__ignoreMap":3390},[3395,5537,5538],{"class":3397,"line":3398},[3395,5539,5540],{"class":4690},"# Пакуємо папку 'dotnet' у ZIP\n",[3395,5542,5543,5545],{"class":3397,"line":3404},[3395,5544,4895],{"class":4704},[3395,5546,5547],{"class":4888}," ..\u002F..\n",[3395,5549,5550,5553,5556,5559],{"class":3397,"line":3410},[3395,5551,5552],{"class":4704},"zip",[3395,5554,5555],{"class":4696}," -r",[3395,5557,5558],{"class":4888}," my-layer.zip",[3395,5560,5561],{"class":4888}," dotnet\u002F\n",[3395,5563,5564],{"class":3397,"line":3416},[3395,5565,3420],{"emptyLinePlaceholder":3419},[3395,5567,5568],{"class":3397,"line":3423},[3395,5569,5570],{"class":4690},"# Завантажуємо в AWS\n",[3395,5572,5573,5576,5578,5581],{"class":3397,"line":3429},[3395,5574,5575],{"class":4704},"aws",[3395,5577,5016],{"class":4888},[3395,5579,5580],{"class":4888}," publish-layer-version",[3395,5582,5584],{"class":5583},"sjcCO"," \\\n",[3395,5586,5587,5590,5593],{"class":3397,"line":3434},[3395,5588,5589],{"class":4696},"    --layer-name",[3395,5591,5592],{"class":4888}," SharedLibraries",[3395,5594,5584],{"class":5583},[3395,5596,5597,5600,5603],{"class":3397,"line":3440},[3395,5598,5599],{"class":4696},"    --description",[3395,5601,5602],{"class":4888}," \"Common NuGet packages\"",[3395,5604,5584],{"class":5583},[3395,5606,5607,5610,5613],{"class":3397,"line":3446},[3395,5608,5609],{"class":4696},"    --zip-file",[3395,5611,5612],{"class":4888}," fileb:\u002F\u002Fmy-layer.zip",[3395,5614,5584],{"class":5583},[3395,5616,5617,5620],{"class":3397,"line":3452},[3395,5618,5619],{"class":4696},"    --compatible-runtimes",[3395,5621,5622],{"class":4888}," dotnet10\n",[3704,5624,5626],{"id":5625},"підключення-до-функції","Підключення до функції",[3353,5628,5629],{},"Тепер у конфігурації вашої Lambda додайте ARN отриманого шару:",[3385,5631,5633],{"className":4876,"code":5632,"language":4878,"meta":3390,"style":3390},"aws lambda update-function-configuration \\\n    --function-name MyFunction \\\n    --layers arn:aws:lambda:eu-central-1:123456789012:layer:SharedLibraries:1\n",[3392,5634,5635,5646,5656],{"__ignoreMap":3390},[3395,5636,5637,5639,5641,5644],{"class":3397,"line":3398},[3395,5638,5575],{"class":4704},[3395,5640,5016],{"class":4888},[3395,5642,5643],{"class":4888}," update-function-configuration",[3395,5645,5584],{"class":5583},[3395,5647,5648,5651,5654],{"class":3397,"line":3404},[3395,5649,5650],{"class":4696},"    --function-name",[3395,5652,5653],{"class":4888}," MyFunction",[3395,5655,5584],{"class":5583},[3395,5657,5658,5661],{"class":3397,"line":3410},[3395,5659,5660],{"class":4696},"    --layers",[3395,5662,5663],{"class":4888}," arn:aws:lambda:eu-central-1:123456789012:layer:SharedLibraries:1\n",[4359,5665,5666,5669,5670,5673,5674,3860],{},[3359,5667,5668],{},"Ліміти Layers."," Ви можете підключити до ",[3359,5671,5672],{},"5 шарів"," одночасно. Сумарний розпакований розмір коду функції + всіх шарів не повинен перевищувати ",[3359,5675,3961],{},[3684,5677],{},[3348,5679,5681],{"id":5680},"aws-sdk-for-lambda-глибоке-занурення-в-екосистему-net-пакетів","AWS SDK for Lambda: Глибоке занурення в екосистему .NET пакетів",[3353,5683,5684],{},"Для ефективної розробки Lambda-функцій на .NET недостатньо базового знання мови; необхідно розуміти структуру та призначення офіційних бібліотек від AWS. Екосистема SDK для Lambda складається з трьох рівнів: ядро (Core), серіалізація (Serialization) та бібліотеки подій (Event Libraries).",[3704,5686,5688],{"id":5687},"_1-фундаментальні-пакети-core-serialization","1. Фундаментальні пакети (Core & Serialization)",[3353,5690,5691],{},"Ці пакети є обов'язковими для будь-якого проекту Lambda.",[3862,5693,5694,5703],{},[3865,5695,5697,5698,4719,5700,5702],{"icon":5696,"title":4663},"i-heroicons-cpu-chip","Визначає базові інтерфейси: ",[3392,5699,4667],{},[3392,5701,4671],{}," та базові атрибути логування. Без цього пакету неможливо створити коректну сигнатуру Handler.",[3865,5704,5707,5708,3860],{"icon":5705,"title":5706},"i-heroicons-arrows-right-left","Amazon.Lambda.Serialization.SystemTextJson","Реалізує логіку перетворення вхідного JSON від AWS-сервісів у ваші C# об'єкти. Використовує високоефективний ",[3392,5709,5710],{},"System.Text.Json",[3353,5712,5713,5716],{},[3359,5714,5715],{},"Механізм реєстрації серіалізатора:","\nAWS Lambda не знає за замовчуванням, як десеріалізувати вхідні дані. Ви ПОВИННІ вказати серіалізатор на рівні assembly (найкраща практика) або конкретного методу:",[3385,5718,5720],{"className":4681,"code":5719,"language":4683,"meta":3390,"style":3390},"\u002F\u002F Реєстрація на рівні всього проекту (assembly)\n[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]\n",[3392,5721,5722,5727],{"__ignoreMap":3390},[3395,5723,5724],{"class":3397,"line":3398},[3395,5725,5726],{"class":4690},"\u002F\u002F Реєстрація на рівні всього проекту (assembly)\n",[3395,5728,5729,5732,5735,5737,5740,5742,5745,5747,5750,5752,5755,5757,5760,5762,5765,5767,5770],{"class":3397,"line":3404},[3395,5730,5731],{"class":4708},"[",[3395,5733,5734],{"class":4696},"assembly",[3395,5736,5078],{"class":4708},[3395,5738,5739],{"class":4700},"LambdaSerializer",[3395,5741,4709],{"class":4708},[3395,5743,5744],{"class":4696},"typeof",[3395,5746,4709],{"class":4708},[3395,5748,5749],{"class":4700},"Amazon",[3395,5751,3860],{"class":4708},[3395,5753,5754],{"class":4700},"Lambda",[3395,5756,3860],{"class":4708},[3395,5758,5759],{"class":4700},"Serialization",[3395,5761,3860],{"class":4708},[3395,5763,5764],{"class":4700},"SystemTextJson",[3395,5766,3860],{"class":4708},[3395,5768,5769],{"class":4700},"DefaultLambdaJsonSerializer",[3395,5771,5772],{"class":4708},"))]\n",[3704,5774,5776],{"id":5775},"_2-бібліотеки-подій-event-libraries","2. Бібліотеки подій (Event Libraries)",[3353,5778,5779,5780,5783],{},"AWS не передає \"просто JSON\". Кожен сервіс-тригер має строго визначену схему даних. Пакети серії ",[3392,5781,5782],{},"Amazon.Lambda.*Events"," містять готові класи (DTO), які відповідають цим схемам.",[4273,5785,5786,5800],{},[4276,5787,5788],{},[4279,5789,5790,5794,5797],{},[4282,5791,5793],{"align":5792},"left","Сервіс-тригер",[4282,5795,5796],{"align":5792},"Пакет NuGet",[4282,5798,5799],{"align":5792},"Ключовий клас події",[4292,5801,5802,5819,5836,5853,5870],{},[4279,5803,5804,5809,5814],{},[4297,5805,5806],{"align":5792},[3359,5807,5808],{},"API Gateway (HTTP)",[4297,5810,5811],{"align":5792},[3392,5812,5813],{},"Amazon.Lambda.APIGatewayEvents",[4297,5815,5816],{"align":5792},[3392,5817,5818],{},"APIGatewayHttpApiV2ProxyRequest",[4279,5820,5821,5826,5831],{},[4297,5822,5823],{"align":5792},[3359,5824,5825],{},"S3 Storage",[4297,5827,5828],{"align":5792},[3392,5829,5830],{},"Amazon.Lambda.S3Events",[4297,5832,5833],{"align":5792},[3392,5834,5835],{},"S3Event",[4279,5837,5838,5843,5848],{},[4297,5839,5840],{"align":5792},[3359,5841,5842],{},"Simple Queue (SQS)",[4297,5844,5845],{"align":5792},[3392,5846,5847],{},"Amazon.Lambda.SQSEvents",[4297,5849,5850],{"align":5792},[3392,5851,5852],{},"SQSEvent",[4279,5854,5855,5860,5865],{},[4297,5856,5857],{"align":5792},[3359,5858,5859],{},"DynamoDB Streams",[4297,5861,5862],{"align":5792},[3392,5863,5864],{},"Amazon.Lambda.DynamoDBEvents",[4297,5866,5867],{"align":5792},[3392,5868,5869],{},"DynamoDBEvent",[4279,5871,5872,5877,5882],{},[4297,5873,5874],{"align":5792},[3359,5875,5876],{},"EventBridge \u002F Cron",[4297,5878,5879],{"align":5792},[3392,5880,5881],{},"Amazon.Lambda.CloudWatchEvents",[4297,5883,5884],{"align":5792},[3392,5885,5886],{},"ScheduledEvent",[3704,5888,5890],{"id":5889},"_3-анатомія-ilambdacontext","3. Анатомія ILambdaContext",[3353,5892,5893,5894,5897],{},"Об'єкт ",[3392,5895,5896],{},"context",", що передається у кожен виклик, є \"вікном\" у Runtime-середовище Lambda. Він надає метадані, необхідні для моніторингу та управління життєвим циклом виконання.",[3939,5899,5900,5907],{},[3942,5901,5902,5903,5906],{"name":4804,"type":3954},"Унікальний ідентифікатор запису (GUID). Це ",[3359,5904,5905],{},"найважливіше"," поле для відладки. Завжди логуйте його на початку обробки для кореляції логів.",[3942,5908,5909,5912,5924],{"name":4812,"type":4813},[3353,5910,5911],{},"Динамічний лічильник часу до примусового завершення (Timeout).",[4032,5913,5914],{},[4035,5915,5916,5919,5920,5923],{},[3359,5917,5918],{},"Сценарій:"," якщо ви обробляєте батч з 100 елементів, перевіряйте ",[3392,5921,5922],{},"context.RemainingTime"," після кожного елемента. Якщо залишилось \u003C 2 секунд — зупиніться і збережіть стан.\n::",[3942,5925,5926,5927,5930,5931,5934],{"name":4824,"type":4825},"Прямий доступ до CloudWatch Logs. Методи ",[3392,5928,5929],{},"LogLine"," та ",[3392,5932,5933],{},"Log"," пишуть у стандартний потік, додаючи метадані Lambda.",[3942,5936,5938,5939,5942],{"name":5937,"type":3954},"InvokedFunctionArn","Повний ARN функції, включаючи Alias або Version (наприклад, ",[3392,5940,5941],{},"...:function:my-func:PROD","). Дозволяє коду знати, в якому середовищі він запущений.",[3353,5944,5945],{},"::",[3704,5947,5949],{"id":5948},"_4-просунута-розробка-lambda-annotations-повна-документація","4. Просунута розробка: Lambda Annotations (Повна документація)",[3353,5951,5952,5953,5956,5957,5960,5961,5964],{},"Фреймворк ",[3359,5954,5955],{},"AWS Lambda Annotations"," (",[3392,5958,5959],{},"Amazon.Lambda.Annotations",") — це сучасна модель програмування для .NET Lambda, яка кардинально спрощує створення REST та HTTP API. Замість того, щоб вручну парсити JSON-запити через низькорівневий об'єкт ",[3392,5962,5963],{},"APIGatewayProxyRequest",", ви використовуєте звичні атрибути в стилі ASP.NET Core Minimal APIs.",[5966,5967,5969],"h4",{"id":5968},"як-це-працює-під-капотом","Як це працює під капотом?",[3353,5971,5972,5973,5976],{},"Фреймворк використовує ",[3359,5974,5975],{},"C# Source Generators",". Під час компіляції вашого коду (Build), він автоматично:",[4867,5978,5979,5985,5988],{},[4035,5980,5981,5982,3860],{},"Аналізує ваші методи, помічені атрибутом ",[3392,5983,5984],{},"[LambdaFunction]",[4035,5986,5987],{},"Генерує \"приховані\" обгортки (wrapper classes), які виконують всю \"брудну\" роботу: десеріалізацію вхідних HTTP-запитів, обробку помилок та форматування HTTP-відповідей.",[4035,5989,5990,5996],{},[3359,5991,5992,5993],{},"Автоматично оновлює файл ",[3392,5994,5995],{},"serverless.template"," (шаблон AWS CloudFormation \u002F SAM), записуючи туди всі маршрути (routes) та конфігурацію інфраструктури.",[5966,5998,6000],{"id":5999},"ключові-атрибути-для-маршрутизації","Ключові атрибути для маршрутизації",[3353,6002,6003],{},"Фреймворк надає атрибути для прив'язки методів до API Gateway:",[4032,6005,6006,6012,6018],{},[4035,6007,6008,6011],{},[3392,6009,6010],{},"[LambdaFunction(ResourceName = \"MyFunc\", MemorySize = 512)]"," — перетворює метод на Lambda-функцію. Можна задати пам'ять, таймаут, ролі.",[4035,6013,6014,6017],{},[3392,6015,6016],{},"[HttpApi(LambdaHttpMethod.Get, \"\u002Fusers\u002F{id}\")]"," — реєструє маршрут для сучасного та швидкого HTTP API.",[4035,6019,6020,6023],{},[3392,6021,6022],{},"[RestApi(LambdaHttpMethod.Post, \"\u002Forders\")]"," — реєструє маршрут для класичного REST API (з підтримкою WAF, Usage Plans).",[5966,6025,6027],{"id":6026},"біндинг-параметрів-parameter-binding","Біндинг параметрів (Parameter Binding)",[3353,6029,6030],{},"Подібно до ASP.NET, ви можете вказувати, звідки брати дані, за допомогою атрибутів:",[4032,6032,6033,6043,6052,6058],{},[4035,6034,6035,6038,6039,6042],{},[3392,6036,6037],{},"[FromQuery] string status"," — з URL параметру (",[3392,6040,6041],{},"?status=active",").",[4035,6044,6045,6048,6049,6042],{},[3392,6046,6047],{},"[FromRoute] int id"," — зі змінної в шляху (",[3392,6050,6051],{},"\u002Fusers\u002F{id}",[4035,6053,6054,6057],{},[3392,6055,6056],{},"[FromBody] Order order"," — автоматично десеріалізує JSON-тіло запиту.",[4035,6059,6060,6063],{},[3392,6061,6062],{},"[FromHeader(\"Authorization\")] string token"," — з HTTP-заголовка.",[3353,6065,6066],{},[3359,6067,6068],{},"Приклад коду:",[3385,6070,6072],{"className":4681,"code":6071,"language":4683,"meta":3390,"style":3390},"[LambdaFunction(MemorySize = 256)]\n[HttpApi(LambdaHttpMethod.Post, \"\u002Fusers\u002F{userId}\u002Froles\")]\npublic async Task\u003CIHttpResult> AssignRole(\n    [FromRoute] string userId,\n    [FromQuery] bool notify,\n    [FromBody] RoleRequest request,\n    ILambdaContext context) \u002F\u002F ILambdaContext завжди доступний\n{\n    \u002F\u002F Ваша логіка...\n    return HttpResults.Ok(new { success = true, user = userId, role = request.Role });\n}\n",[3392,6073,6074,6094,6118,6143,6161,6178,6195,6208,6212,6217,6274],{"__ignoreMap":3390},[3395,6075,6076,6078,6081,6083,6086,6089,6091],{"class":3397,"line":3398},[3395,6077,5731],{"class":4708},[3395,6079,6080],{"class":4700},"LambdaFunction",[3395,6082,4709],{"class":4708},[3395,6084,6085],{"class":4715},"MemorySize",[3395,6087,6088],{"class":4708}," = ",[3395,6090,5155],{"class":5154},[3395,6092,6093],{"class":4708},")]\n",[3395,6095,6096,6098,6101,6103,6106,6108,6111,6113,6116],{"class":3397,"line":3404},[3395,6097,5731],{"class":4708},[3395,6099,6100],{"class":4700},"HttpApi",[3395,6102,4709],{"class":4708},[3395,6104,6105],{"class":4715},"LambdaHttpMethod",[3395,6107,3860],{"class":4708},[3395,6109,6110],{"class":4715},"Post",[3395,6112,4719],{"class":4708},[3395,6114,6115],{"class":4888},"\"\u002Fusers\u002F{userId}\u002Froles\"",[3395,6117,6093],{"class":4708},[3395,6119,6120,6122,6125,6128,6131,6134,6137,6140],{"class":3397,"line":3410},[3395,6121,4697],{"class":4696},[3395,6123,6124],{"class":4696}," async",[3395,6126,6127],{"class":4700}," Task",[3395,6129,6130],{"class":4708},"\u003C",[3395,6132,6133],{"class":4700},"IHttpResult",[3395,6135,6136],{"class":4708},"> ",[3395,6138,6139],{"class":4704},"AssignRole",[3395,6141,6142],{"class":4708},"(\n",[3395,6144,6145,6148,6151,6154,6156,6159],{"class":3397,"line":3416},[3395,6146,6147],{"class":4708},"    [",[3395,6149,6150],{"class":4700},"FromRoute",[3395,6152,6153],{"class":4708},"] ",[3395,6155,3954],{"class":4696},[3395,6157,6158],{"class":4715}," userId",[3395,6160,5084],{"class":4708},[3395,6162,6163,6165,6168,6170,6173,6176],{"class":3397,"line":3423},[3395,6164,6147],{"class":4708},[3395,6166,6167],{"class":4700},"FromQuery",[3395,6169,6153],{"class":4708},[3395,6171,6172],{"class":4696},"bool",[3395,6174,6175],{"class":4715}," notify",[3395,6177,5084],{"class":4708},[3395,6179,6180,6182,6185,6187,6190,6193],{"class":3397,"line":3429},[3395,6181,6147],{"class":4708},[3395,6183,6184],{"class":4700},"FromBody",[3395,6186,6153],{"class":4708},[3395,6188,6189],{"class":4700},"RoleRequest",[3395,6191,6192],{"class":4715}," request",[3395,6194,5084],{"class":4708},[3395,6196,6197,6200,6202,6205],{"class":3397,"line":3434},[3395,6198,6199],{"class":4700},"    ILambdaContext",[3395,6201,4724],{"class":4715},[3395,6203,6204],{"class":4708},") ",[3395,6206,6207],{"class":4690},"\u002F\u002F ILambdaContext завжди доступний\n",[3395,6209,6210],{"class":3397,"line":3440},[3395,6211,5069],{"class":4708},[3395,6213,6214],{"class":3397,"line":3446},[3395,6215,6216],{"class":4690},"    \u002F\u002F Ваша логіка...\n",[3395,6218,6219,6223,6226,6228,6231,6233,6236,6239,6242,6244,6246,6248,6251,6253,6256,6258,6261,6263,6266,6268,6271],{"class":3397,"line":3452},[3395,6220,6222],{"class":6221},"s8xlr","    return",[3395,6224,6225],{"class":4715}," HttpResults",[3395,6227,3860],{"class":4708},[3395,6229,6230],{"class":4704},"Ok",[3395,6232,4709],{"class":4708},[3395,6234,6235],{"class":4696},"new",[3395,6237,6238],{"class":4708}," { ",[3395,6240,6241],{"class":4715},"success",[3395,6243,6088],{"class":4708},[3395,6245,3946],{"class":4696},[3395,6247,4719],{"class":4708},[3395,6249,6250],{"class":4715},"user",[3395,6252,6088],{"class":4708},[3395,6254,6255],{"class":4715},"userId",[3395,6257,4719],{"class":4708},[3395,6259,6260],{"class":4715},"role",[3395,6262,6088],{"class":4708},[3395,6264,6265],{"class":4715},"request",[3395,6267,3860],{"class":4708},[3395,6269,6270],{"class":4715},"Role",[3395,6272,6273],{"class":4708}," });\n",[3395,6275,6276],{"class":3397,"line":3458},[3395,6277,3479],{"class":4708},[5966,6279,6281],{"id":6280},"впровадження-залежностей-dependency-injection","Впровадження залежностей (Dependency Injection)",[3353,6283,6284,6285,6288,6289,6292],{},"У звичайній Lambda налаштування DI-контейнера є неочевидним завданням. З Annotations ви створюєте клас із атрибутом ",[3392,6286,6287],{},"[LambdaStartup]",", який виглядає точнісінько як ",[3392,6290,6291],{},"Startup.cs"," в ASP.NET:",[3385,6294,6296],{"className":4681,"code":6295,"language":4683,"meta":3390,"style":3390},"[LambdaStartup]\npublic class Startup\n{\n    public void ConfigureServices(IServiceCollection services)\n    {\n        \u002F\u002F Ці сервіси будуть автоматично ініціалізовані під час Cold Start\n        services.AddAWSService\u003CIAmazonDynamoDB>();\n        services.AddScoped\u003CIUserRepository, UserRepository>();\n    }\n}\n",[3392,6297,6298,6308,6318,6322,6343,6348,6353,6371,6392,6397],{"__ignoreMap":3390},[3395,6299,6300,6302,6305],{"class":3397,"line":3398},[3395,6301,5731],{"class":4708},[3395,6303,6304],{"class":4700},"LambdaStartup",[3395,6306,6307],{"class":4708},"]\n",[3395,6309,6310,6312,6315],{"class":3397,"line":3404},[3395,6311,4697],{"class":4696},[3395,6313,6314],{"class":4696}," class",[3395,6316,6317],{"class":4700}," Startup\n",[3395,6319,6320],{"class":3397,"line":3410},[3395,6321,5069],{"class":4708},[3395,6323,6324,6327,6330,6333,6335,6338,6341],{"class":3397,"line":3416},[3395,6325,6326],{"class":4696},"    public",[3395,6328,6329],{"class":4696}," void",[3395,6331,6332],{"class":4704}," ConfigureServices",[3395,6334,4709],{"class":4708},[3395,6336,6337],{"class":4700},"IServiceCollection",[3395,6339,6340],{"class":4715}," services",[3395,6342,4727],{"class":4708},[3395,6344,6345],{"class":3397,"line":3423},[3395,6346,6347],{"class":4708},"    {\n",[3395,6349,6350],{"class":3397,"line":3429},[3395,6351,6352],{"class":4690},"        \u002F\u002F Ці сервіси будуть автоматично ініціалізовані під час Cold Start\n",[3395,6354,6355,6358,6360,6363,6365,6368],{"class":3397,"line":3434},[3395,6356,6357],{"class":4715},"        services",[3395,6359,3860],{"class":4708},[3395,6361,6362],{"class":4704},"AddAWSService",[3395,6364,6130],{"class":4708},[3395,6366,6367],{"class":4700},"IAmazonDynamoDB",[3395,6369,6370],{"class":4708},">();\n",[3395,6372,6373,6375,6377,6380,6382,6385,6387,6390],{"class":3397,"line":3440},[3395,6374,6357],{"class":4715},[3395,6376,3860],{"class":4708},[3395,6378,6379],{"class":4704},"AddScoped",[3395,6381,6130],{"class":4708},[3395,6383,6384],{"class":4700},"IUserRepository",[3395,6386,4719],{"class":4708},[3395,6388,6389],{"class":4700},"UserRepository",[3395,6391,6370],{"class":4708},[3395,6393,6394],{"class":3397,"line":3446},[3395,6395,6396],{"class":4708},"    }\n",[3395,6398,6399],{"class":3397,"line":3452},[3395,6400,3479],{"class":4708},[3353,6402,6403],{},"Після цього ви можете використовувати ін'єкцію через конструктор (Constructor Injection) у класі вашої функції.",[4359,6405,6406,6409,6410,6412,6413,6416,6417,6420,6421],{},[3359,6407,6408],{},"Особливість деплойменту:"," Оскільки Lambda Annotations генерує конфігурацію у файл ",[3392,6411,5995],{},", ви ",[3359,6414,6415],{},"не можете"," деплоїти такі функції звичайною командою ",[3392,6418,6419],{},"dotnet lambda deploy-function",". Ви ПОВИННІ використовувати команду деплою всього стеку:\n",[3392,6422,6423],{},"dotnet lambda deploy-serverless --stack-name my-api-stack --s3-bucket my-bucket --region eu-central-1",[3704,6425,6427],{"id":6426},"_5-sdk-у-дії-практичні-приклади-реалізації","5. SDK у дії: Практичні приклади реалізації",[3353,6429,6430],{},"Розглянемо поширені сценарії використання SDK для вирішення типових задач.",[5966,6432,6434],{"id":6433},"а-логування-та-контекст-виконання","А. Логування та контекст виконання",[3353,6436,6437,6438,6440],{},"Використання ",[3392,6439,4667],{}," для відстеження стану та лімітів.",[3385,6442,6444],{"className":4681,"code":6443,"language":4683,"meta":3390,"style":3390},"public async Task\u003Cstring> Handler(string input, ILambdaContext context)\n{\n    \u002F\u002F 1. Логування з метаданими\n    context.Logger.LogInformation($\"Request ID: {context.AwsRequestId}\");\n    context.Logger.LogInformation($\"Remaining Time: {context.RemainingTime.TotalMilliseconds}ms\");\n\n    \u002F\u002F 2. Логіка захисту від таймауту\n    if (context.RemainingTime \u003C TimeSpan.FromSeconds(1))\n    {\n         context.Logger.LogWarning(\"Running out of time! Aborting...\");\n         return \"Timeout Imminent\";\n    }\n\n    return $\"Processed: {input}\";\n}\n",[3392,6445,6446,6477,6481,6486,6523,6560,6564,6569,6600,6604,6624,6635,6639,6643,6661],{"__ignoreMap":3390},[3395,6447,6448,6450,6452,6454,6456,6458,6460,6463,6465,6467,6469,6471,6473,6475],{"class":3397,"line":3398},[3395,6449,4697],{"class":4696},[3395,6451,6124],{"class":4696},[3395,6453,6127],{"class":4700},[3395,6455,6130],{"class":4708},[3395,6457,3954],{"class":4696},[3395,6459,6136],{"class":4708},[3395,6461,6462],{"class":4704},"Handler",[3395,6464,4709],{"class":4708},[3395,6466,3954],{"class":4696},[3395,6468,4716],{"class":4715},[3395,6470,4719],{"class":4708},[3395,6472,4667],{"class":4700},[3395,6474,4724],{"class":4715},[3395,6476,4727],{"class":4708},[3395,6478,6479],{"class":3397,"line":3404},[3395,6480,5069],{"class":4708},[3395,6482,6483],{"class":3397,"line":3410},[3395,6484,6485],{"class":4690},"    \u002F\u002F 1. Логування з метаданими\n",[3395,6487,6488,6491,6493,6495,6497,6499,6501,6504,6508,6510,6512,6514,6517,6520],{"class":3397,"line":3416},[3395,6489,6490],{"class":4715},"    context",[3395,6492,3860],{"class":4708},[3395,6494,4824],{"class":4715},[3395,6496,3860],{"class":4708},[3395,6498,4835],{"class":4704},[3395,6500,4709],{"class":4708},[3395,6502,6503],{"class":4888},"$\"Request ID: ",[3395,6505,6507],{"class":6506},"sD7JJ","{",[3395,6509,5896],{"class":4715},[3395,6511,3860],{"class":6506},[3395,6513,4804],{"class":4715},[3395,6515,6516],{"class":6506},"}",[3395,6518,6519],{"class":4888},"\"",[3395,6521,6522],{"class":4708},");\n",[3395,6524,6525,6527,6529,6531,6533,6535,6537,6540,6542,6544,6546,6548,6550,6553,6555,6558],{"class":3397,"line":3423},[3395,6526,6490],{"class":4715},[3395,6528,3860],{"class":4708},[3395,6530,4824],{"class":4715},[3395,6532,3860],{"class":4708},[3395,6534,4835],{"class":4704},[3395,6536,4709],{"class":4708},[3395,6538,6539],{"class":4888},"$\"Remaining Time: ",[3395,6541,6507],{"class":6506},[3395,6543,5896],{"class":4715},[3395,6545,3860],{"class":6506},[3395,6547,4812],{"class":4715},[3395,6549,3860],{"class":6506},[3395,6551,6552],{"class":4715},"TotalMilliseconds",[3395,6554,6516],{"class":6506},[3395,6556,6557],{"class":4888},"ms\"",[3395,6559,6522],{"class":4708},[3395,6561,6562],{"class":3397,"line":3429},[3395,6563,3420],{"emptyLinePlaceholder":3419},[3395,6565,6566],{"class":3397,"line":3434},[3395,6567,6568],{"class":4690},"    \u002F\u002F 2. Логіка захисту від таймауту\n",[3395,6570,6571,6574,6576,6578,6580,6582,6585,6587,6589,6592,6594,6597],{"class":3397,"line":3440},[3395,6572,6573],{"class":6221},"    if",[3395,6575,5956],{"class":4708},[3395,6577,5896],{"class":4715},[3395,6579,3860],{"class":4708},[3395,6581,4812],{"class":4715},[3395,6583,6584],{"class":4708}," \u003C ",[3395,6586,4813],{"class":4715},[3395,6588,3860],{"class":4708},[3395,6590,6591],{"class":4704},"FromSeconds",[3395,6593,4709],{"class":4708},[3395,6595,6596],{"class":5154},"1",[3395,6598,6599],{"class":4708},"))\n",[3395,6601,6602],{"class":3397,"line":3446},[3395,6603,6347],{"class":4708},[3395,6605,6606,6609,6611,6613,6615,6617,6619,6622],{"class":3397,"line":3452},[3395,6607,6608],{"class":4715},"         context",[3395,6610,3860],{"class":4708},[3395,6612,4824],{"class":4715},[3395,6614,3860],{"class":4708},[3395,6616,4838],{"class":4704},[3395,6618,4709],{"class":4708},[3395,6620,6621],{"class":4888},"\"Running out of time! Aborting...\"",[3395,6623,6522],{"class":4708},[3395,6625,6626,6629,6632],{"class":3397,"line":3458},[3395,6627,6628],{"class":6221},"         return",[3395,6630,6631],{"class":4888}," \"Timeout Imminent\"",[3395,6633,6634],{"class":4708},";\n",[3395,6636,6637],{"class":3397,"line":3464},[3395,6638,6396],{"class":4708},[3395,6640,6641],{"class":3397,"line":3470},[3395,6642,3420],{"emptyLinePlaceholder":3419},[3395,6644,6645,6647,6650,6652,6655,6657,6659],{"class":3397,"line":3476},[3395,6646,6222],{"class":6221},[3395,6648,6649],{"class":4888}," $\"Processed: ",[3395,6651,6507],{"class":6506},[3395,6653,6654],{"class":4715},"input",[3395,6656,6516],{"class":6506},[3395,6658,6519],{"class":4888},[3395,6660,6634],{"class":4708},[3395,6662,6663],{"class":3397,"line":3482},[3395,6664,3479],{"class":4708},[5966,6666,6668],{"id":6667},"б-десеріалізація-складних-обєктів-poco","Б. Десеріалізація складних об'єктів (POCO)",[3353,6670,6671,6672,6674],{},"Завдяки серіалізатору ",[3392,6673,5764],{}," ви можете приймати будь-які C# класи.",[3385,6676,6678],{"className":4681,"code":6677,"language":4683,"meta":3390,"style":3390},"public record UserRequest(string Name, int Age, List\u003Cstring> Roles);\npublic record UserResponse(string Message, bool IsAdult);\n\npublic UserResponse HandleUser(UserRequest request, ILambdaContext context)\n{\n    context.Logger.LogInformation($\"Processing user: {request.Name}\");\n\n    return new UserResponse(\n        Message: $\"Hello, {request.Name}!\",\n        IsAdult: request.Age >= 18\n    );\n}\n",[3392,6679,6680,6721,6746,6750,6774,6778,6810,6814,6824,6849,6869,6874],{"__ignoreMap":3390},[3395,6681,6682,6684,6687,6690,6692,6694,6697,6699,6702,6705,6707,6710,6712,6714,6716,6719],{"class":3397,"line":3398},[3395,6683,4697],{"class":4696},[3395,6685,6686],{"class":4696}," record",[3395,6688,6689],{"class":4700}," UserRequest",[3395,6691,4709],{"class":4708},[3395,6693,3954],{"class":4696},[3395,6695,6696],{"class":4715}," Name",[3395,6698,4719],{"class":4708},[3395,6700,6701],{"class":4696},"int",[3395,6703,6704],{"class":4715}," Age",[3395,6706,4719],{"class":4708},[3395,6708,6709],{"class":4700},"List",[3395,6711,6130],{"class":4708},[3395,6713,3954],{"class":4696},[3395,6715,6136],{"class":4708},[3395,6717,6718],{"class":4715},"Roles",[3395,6720,6522],{"class":4708},[3395,6722,6723,6725,6727,6730,6732,6734,6737,6739,6741,6744],{"class":3397,"line":3404},[3395,6724,4697],{"class":4696},[3395,6726,6686],{"class":4696},[3395,6728,6729],{"class":4700}," UserResponse",[3395,6731,4709],{"class":4708},[3395,6733,3954],{"class":4696},[3395,6735,6736],{"class":4715}," Message",[3395,6738,4719],{"class":4708},[3395,6740,6172],{"class":4696},[3395,6742,6743],{"class":4715}," IsAdult",[3395,6745,6522],{"class":4708},[3395,6747,6748],{"class":3397,"line":3410},[3395,6749,3420],{"emptyLinePlaceholder":3419},[3395,6751,6752,6754,6756,6759,6761,6764,6766,6768,6770,6772],{"class":3397,"line":3416},[3395,6753,4697],{"class":4696},[3395,6755,6729],{"class":4700},[3395,6757,6758],{"class":4704}," HandleUser",[3395,6760,4709],{"class":4708},[3395,6762,6763],{"class":4700},"UserRequest",[3395,6765,6192],{"class":4715},[3395,6767,4719],{"class":4708},[3395,6769,4667],{"class":4700},[3395,6771,4724],{"class":4715},[3395,6773,4727],{"class":4708},[3395,6775,6776],{"class":3397,"line":3423},[3395,6777,5069],{"class":4708},[3395,6779,6780,6782,6784,6786,6788,6790,6792,6795,6797,6799,6801,6804,6806,6808],{"class":3397,"line":3429},[3395,6781,6490],{"class":4715},[3395,6783,3860],{"class":4708},[3395,6785,4824],{"class":4715},[3395,6787,3860],{"class":4708},[3395,6789,4835],{"class":4704},[3395,6791,4709],{"class":4708},[3395,6793,6794],{"class":4888},"$\"Processing user: ",[3395,6796,6507],{"class":6506},[3395,6798,6265],{"class":4715},[3395,6800,3860],{"class":6506},[3395,6802,6803],{"class":4715},"Name",[3395,6805,6516],{"class":6506},[3395,6807,6519],{"class":4888},[3395,6809,6522],{"class":4708},[3395,6811,6812],{"class":3397,"line":3434},[3395,6813,3420],{"emptyLinePlaceholder":3419},[3395,6815,6816,6818,6820,6822],{"class":3397,"line":3440},[3395,6817,6222],{"class":6221},[3395,6819,4906],{"class":4696},[3395,6821,6729],{"class":4700},[3395,6823,6142],{"class":4708},[3395,6825,6826,6829,6831,6834,6836,6838,6840,6842,6844,6847],{"class":3397,"line":3446},[3395,6827,6828],{"class":4715},"        Message",[3395,6830,5078],{"class":4708},[3395,6832,6833],{"class":4888},"$\"Hello, ",[3395,6835,6507],{"class":6506},[3395,6837,6265],{"class":4715},[3395,6839,3860],{"class":6506},[3395,6841,6803],{"class":4715},[3395,6843,6516],{"class":6506},[3395,6845,6846],{"class":4888},"!\"",[3395,6848,5084],{"class":4708},[3395,6850,6851,6854,6856,6858,6860,6863,6866],{"class":3397,"line":3452},[3395,6852,6853],{"class":4715},"        IsAdult",[3395,6855,5078],{"class":4708},[3395,6857,6265],{"class":4715},[3395,6859,3860],{"class":4708},[3395,6861,6862],{"class":4715},"Age",[3395,6864,6865],{"class":4708}," >= ",[3395,6867,6868],{"class":5154},"18\n",[3395,6870,6871],{"class":3397,"line":3458},[3395,6872,6873],{"class":4708},"    );\n",[3395,6875,6876],{"class":3397,"line":3464},[3395,6877,3479],{"class":4708},[3684,6879],{},[3348,6881,6883],{"id":6882},"lambda-triggers-архітектура-подієво-орієнтованої-інтеграції","Lambda Triggers: архітектура подієво-орієнтованої інтеграції",[3353,6885,6886,6887,6890],{},"У хмарній екосистемі AWS Lambda ніколи не працює у вакуумі. Функція завжди ініціюється певною подією (Event) ззовні. Цей механізм ініціалізації називається ",[3359,6888,6889],{},"Trigger"," (тригер).",[3353,6892,6893,6894,6897,6898,6901],{},"Сучасні архітектури використовують подієво-орієнтований підхід (Event-Driven Architecture), де сервіси не викликають один одного напряму, а реагують на зміни стану. AWS пропонує понад 200 нативних інтеграцій з Lambda. Проте, незважаючи на таку кількість, архітектурно всі вони поділяються на дві фундаментальні моделі доставки подій: ",[3359,6895,6896],{},"Push-модель"," (коли сервіс сам \"штовхає\" подію в Lambda) та ",[3359,6899,6900],{},"Pull-модель"," (коли Lambda \"витягує\" події з джерела).",[3353,6903,6904],{},"Важливо розуміти, що Push-модель додатково ділиться на синхронну та асинхронну. Ваш підхід до обробки помилок, ретраїв та масштабування буде кардинально відрізнятися залежно від обраної моделі.",[3704,6906,6908],{"id":6907},"_1-модель-push-синхронний-виклик-requestresponse","1. Модель Push: Синхронний виклик (RequestResponse)",[3353,6910,6911,6912,3860],{},"У цій моделі сервіс-тригер (або клієнт) робить прямий HTTP-запит до Lambda Service API і ",[3359,6913,6914],{},"блокується, очікуючи на відповідь",[4032,6916,6917,6923,6932],{},[4035,6918,6919,6922],{},[3359,6920,6921],{},"Хто керує помилками:"," Клієнт. Якщо функція впала або сталася помилка таймауту, AWS Lambda не буде робити автоматичний retry. Клієнт отримує 5xx помилку і сам вирішує, чи повторювати запит.",[4035,6924,6925,6928,6929,6042],{},[3359,6926,6927],{},"Типові сервіси:"," Amazon API Gateway, Application Load Balancer, Amazon Cognito, або прямий виклик через AWS SDK (",[3392,6930,6931],{},"InvokeType = RequestResponse",[4035,6933,6934,6937],{},[3359,6935,6936],{},"Use-case:"," HTTP API, де користувачу потрібна миттєва відповідь (наприклад, отримання профілю користувача).",[3704,6939,6941],{"id":6940},"_2-модель-push-асинхронний-виклик-event","2. Модель Push: Асинхронний виклик (Event)",[3353,6943,6944,6945,6948],{},"У цій моделі сервіс-тригер відправляє подію до внутрішньої черги AWS Lambda Service і відразу отримує підтвердження \"Подія прийнята\" (HTTP 202). Він ",[3359,6946,6947],{},"не чекає"," на завершення виконання коду вашої функції.",[4032,6950,6951,6956,6961],{},[4035,6952,6953,6955],{},[3359,6954,6921],{}," AWS Lambda Service. Внутрішня система автоматично робить 2 повторні спроби (Retries) з експоненційною затримкою (backoff), якщо ваш код кидає exception. Якщо всі спроби вичерпано, подія може бути відправлена у Dead Letter Queue (DLQ) або Lambda Destination.",[4035,6957,6958,6960],{},[3359,6959,6927],{}," Amazon S3, Amazon SNS, Amazon EventBridge.",[4035,6962,6963,6965],{},[3359,6964,6936],{}," Фонова обробка. Наприклад, користувач завантажив відео в S3, і нам потрібно згенерувати прев'ю. Користувач не повинен чекати 3 хвилини; S3 асинхронно тригерить Lambda.",[3704,6967,6969],{"id":6968},"_3-модель-pull-event-source-mapping-poll-based","3. Модель Pull: Event Source Mapping (Poll-based)",[3353,6971,6972],{},"Тут Lambda Service виступає в ролі активного \"споживача\". Спеціальний компонент (Event Source Mapping) безперервно опитує (polls) джерело даних на наявність нових записів, групує їх у \"батчі\" (Batches) і відправляє у вашу функцію одним синхронним викликом.",[4032,6974,6975,6983,6988],{},[4035,6976,6977,6979,6980,6042],{},[3359,6978,6921],{}," Event Source Mapping. Якщо ваша функція падає під час обробки батчу, весь батч повертається в чергу або потік, і AWS буде намагатися передати його знову (поки не вийде термін дії повідомлення, або поки ви не налаштуєте часткову обробку відмов — ",[3392,6981,6982],{},"ReportBatchItemFailures",[4035,6984,6985,6987],{},[3359,6986,6927],{}," Amazon SQS, DynamoDB Streams, Amazon Kinesis, Kafka (MSK).",[4035,6989,6990,6992],{},[3359,6991,6936],{}," Обробка великих потоків даних, де важливий порядок повідомлень або потрібно контролювати швидкість (throttling), з якою Lambda споживає дані (через налаштування Batch Size).",[3382,6994,6995],{},[3385,6996,6998],{"className":3387,"code":6997,"language":3389,"meta":3390,"style":3390},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\ntitle \"Дві моделі виклику Lambda: синхронна та асинхронна\"\n\npackage \"Синхронні тригери\\n(Invoke Type: RequestResponse)\" as SYNC #dbeafe {\n    rectangle \"API Gateway\\n(HTTP API \u002F REST API)\" as APIGW #bbf7d0\n    rectangle \"Application\\nLoad Balancer\" as ALBT #bbf7d0\n    rectangle \"Amazon Cognito\\n(Pre\u002FPost triggers)\" as COG #bbf7d0\n    rectangle \"AWS SDK\\n(прямий виклик)\" as SDK #bbf7d0\n}\n\npackage \"Асинхронні тригери\\n(Invoke Type: Event)\" as ASYNC #fef3c7 {\n    rectangle \"Amazon S3\\n(Object events)\" as S3T #fde68a\n    rectangle \"Amazon SNS\\n(Push notifications)\" as SNS #fde68a\n    rectangle \"EventBridge\\n(Scheduled \u002F Rules)\" as EB #fde68a\n    rectangle \"CloudWatch Logs\\n(Log subscriptions)\" as CWL #fde68a\n}\n\npackage \"Poll-based тригери\\n(Lambda опитує чергу)\" as POLL #f3e8ff {\n    rectangle \"Amazon SQS\\n(Standard \u002F FIFO)\" as SQST #e9d5ff\n    rectangle \"DynamoDB Streams\\n(Change Data Capture)\" as DYNSTR #e9d5ff\n    rectangle \"Amazon Kinesis\\n(Data Streams)\" as KIN #e9d5ff\n    rectangle \"Amazon MSK \u002F Kafka\\n(Event Source Mapping)\" as MSK #e9d5ff\n}\n\nrectangle \"Lambda Function\\n.NET 10\" as LAM #d1fae5\n\nSYNC --> LAM : Виклик + очікування відповіді\\n(клієнт блокується)\nASYNC --> LAM : Подія поставлена у чергу Lambda\\n(клієнт НЕ чекає)\nPOLL --> LAM : Lambda сама читає батч записів\\nз черги або потоку\n\n@enduml\n",[3392,6999,7000,7004,7008,7012,7016,7021,7025,7030,7035,7040,7045,7050,7054,7058,7063,7068,7073,7078,7083,7087,7091,7096,7101,7106,7111,7116,7120,7124,7129,7133,7138,7143,7148,7152],{"__ignoreMap":3390},[3395,7001,7002],{"class":3397,"line":3398},[3395,7003,3401],{},[3395,7005,7006],{"class":3397,"line":3404},[3395,7007,3407],{},[3395,7009,7010],{"class":3397,"line":3410},[3395,7011,3413],{},[3395,7013,7014],{"class":3397,"line":3416},[3395,7015,3420],{"emptyLinePlaceholder":3419},[3395,7017,7018],{"class":3397,"line":3423},[3395,7019,7020],{},"title \"Дві моделі виклику Lambda: синхронна та асинхронна\"\n",[3395,7022,7023],{"class":3397,"line":3429},[3395,7024,3420],{"emptyLinePlaceholder":3419},[3395,7026,7027],{"class":3397,"line":3434},[3395,7028,7029],{},"package \"Синхронні тригери\\n(Invoke Type: RequestResponse)\" as SYNC #dbeafe {\n",[3395,7031,7032],{"class":3397,"line":3440},[3395,7033,7034],{},"    rectangle \"API Gateway\\n(HTTP API \u002F REST API)\" as APIGW #bbf7d0\n",[3395,7036,7037],{"class":3397,"line":3446},[3395,7038,7039],{},"    rectangle \"Application\\nLoad Balancer\" as ALBT #bbf7d0\n",[3395,7041,7042],{"class":3397,"line":3452},[3395,7043,7044],{},"    rectangle \"Amazon Cognito\\n(Pre\u002FPost triggers)\" as COG #bbf7d0\n",[3395,7046,7047],{"class":3397,"line":3458},[3395,7048,7049],{},"    rectangle \"AWS SDK\\n(прямий виклик)\" as SDK #bbf7d0\n",[3395,7051,7052],{"class":3397,"line":3464},[3395,7053,3479],{},[3395,7055,7056],{"class":3397,"line":3470},[3395,7057,3420],{"emptyLinePlaceholder":3419},[3395,7059,7060],{"class":3397,"line":3476},[3395,7061,7062],{},"package \"Асинхронні тригери\\n(Invoke Type: Event)\" as ASYNC #fef3c7 {\n",[3395,7064,7065],{"class":3397,"line":3482},[3395,7066,7067],{},"    rectangle \"Amazon S3\\n(Object events)\" as S3T #fde68a\n",[3395,7069,7070],{"class":3397,"line":3487},[3395,7071,7072],{},"    rectangle \"Amazon SNS\\n(Push notifications)\" as SNS #fde68a\n",[3395,7074,7075],{"class":3397,"line":3493},[3395,7076,7077],{},"    rectangle \"EventBridge\\n(Scheduled \u002F Rules)\" as EB #fde68a\n",[3395,7079,7080],{"class":3397,"line":3499},[3395,7081,7082],{},"    rectangle \"CloudWatch Logs\\n(Log subscriptions)\" as CWL #fde68a\n",[3395,7084,7085],{"class":3397,"line":3505},[3395,7086,3479],{},[3395,7088,7089],{"class":3397,"line":3511},[3395,7090,3420],{"emptyLinePlaceholder":3419},[3395,7092,7093],{"class":3397,"line":3517},[3395,7094,7095],{},"package \"Poll-based тригери\\n(Lambda опитує чергу)\" as POLL #f3e8ff {\n",[3395,7097,7098],{"class":3397,"line":3523},[3395,7099,7100],{},"    rectangle \"Amazon SQS\\n(Standard \u002F FIFO)\" as SQST #e9d5ff\n",[3395,7102,7103],{"class":3397,"line":3529},[3395,7104,7105],{},"    rectangle \"DynamoDB Streams\\n(Change Data Capture)\" as DYNSTR #e9d5ff\n",[3395,7107,7108],{"class":3397,"line":3534},[3395,7109,7110],{},"    rectangle \"Amazon Kinesis\\n(Data Streams)\" as KIN #e9d5ff\n",[3395,7112,7113],{"class":3397,"line":3539},[3395,7114,7115],{},"    rectangle \"Amazon MSK \u002F Kafka\\n(Event Source Mapping)\" as MSK #e9d5ff\n",[3395,7117,7118],{"class":3397,"line":3545},[3395,7119,3479],{},[3395,7121,7122],{"class":3397,"line":3551},[3395,7123,3420],{"emptyLinePlaceholder":3419},[3395,7125,7126],{"class":3397,"line":3557},[3395,7127,7128],{},"rectangle \"Lambda Function\\n.NET 10\" as LAM #d1fae5\n",[3395,7130,7131],{"class":3397,"line":3563},[3395,7132,3420],{"emptyLinePlaceholder":3419},[3395,7134,7135],{"class":3397,"line":3569},[3395,7136,7137],{},"SYNC --> LAM : Виклик + очікування відповіді\\n(клієнт блокується)\n",[3395,7139,7140],{"class":3397,"line":3575},[3395,7141,7142],{},"ASYNC --> LAM : Подія поставлена у чергу Lambda\\n(клієнт НЕ чекає)\n",[3395,7144,7145],{"class":3397,"line":3581},[3395,7146,7147],{},"POLL --> LAM : Lambda сама читає батч записів\\nз черги або потоку\n",[3395,7149,7150],{"class":3397,"line":3586},[3395,7151,3420],{"emptyLinePlaceholder":3419},[3395,7153,7154],{"class":3397,"line":3591},[3395,7155,3675],{},[3704,7157,7159],{"id":7158},"синхронний-тригер-api-gateway-lambda","Синхронний тригер: API Gateway + Lambda",[3353,7161,7162,7163,7166],{},"Інтеграція ",[3359,7164,7165],{},"Amazon API Gateway"," з Lambda є фундаментальним патерном побудови serverless HTTP API. API Gateway виступає проксі, що приймає HTTP-запити від клієнтів, трансформує їх у Lambda-події та повертає Lambda-відповідь клієнту.",[3353,7168,7169],{},"AWS надає два типи API Gateway для інтеграції з Lambda:",[3862,7171,7172,7198],{},[3865,7173,7175,7181],{"icon":3867,"title":7174},"HTTP API (v2)",[3353,7176,7177,7180],{},[3359,7178,7179],{},"Рекомендований вибір"," для більшості .NET Lambda сценаріїв.",[4032,7182,7183,7186,7189,7192,7195],{},[4035,7184,7185],{},"Нижча вартість (~70% дешевше за REST API)",[4035,7187,7188],{},"Нижча латентність",[4035,7190,7191],{},"Спрощена конфігурація",[4035,7193,7194],{},"Підтримка JWT авторизації «з коробки»",[4035,7196,7197],{},"Обмежена функціональність (немає трансформацій запитів\u002Fвідповідей)",[3865,7199,7202,7205],{"icon":7200,"title":7201},"i-heroicons-cog-6-tooth","REST API (v1)",[3353,7203,7204],{},"Для складних сценаріїв з потребою у:",[4032,7206,7207,7210,7213,7216],{},[4035,7208,7209],{},"Трансформації request\u002Fresponse (Mapping Templates)",[4035,7211,7212],{},"API Keys та Usage Plans",[4035,7214,7215],{},"Детального контролю над схемою запитів (Request Validation)",[4035,7217,7218],{},"AWS WAF інтеграції на рівні API",[3353,7220,7221],{},[3359,7222,7223],{},"Структура події від API Gateway (HTTP API):",[3353,7225,7226,7227,7230],{},"Коли клієнт надсилає ",[3392,7228,7229],{},"GET \u002Fusers\u002F42?format=json",", API Gateway трансформує запит у таку JSON-структуру, яку Lambda отримує як event:",[3385,7232,7234],{"className":5060,"code":7233,"language":5062,"meta":3390,"style":3390},"{\n    \"version\": \"2.0\",\n    \"routeKey\": \"GET \u002Fusers\u002F{id}\",\n    \"rawPath\": \"\u002Fusers\u002F42\",\n    \"rawQueryString\": \"format=json\",\n    \"headers\": {\n        \"accept\": \"application\u002Fjson\",\n        \"authorization\": \"Bearer eyJ...\",\n        \"content-type\": \"application\u002Fjson\",\n        \"x-forwarded-for\": \"203.0.113.5\"\n    },\n    \"queryStringParameters\": {\n        \"format\": \"json\"\n    },\n    \"pathParameters\": {\n        \"id\": \"42\"\n    },\n    \"requestContext\": {\n        \"accountId\": \"123456789012\",\n        \"apiId\": \"abc123\",\n        \"http\": {\n            \"method\": \"GET\",\n            \"path\": \"\u002Fusers\u002F42\",\n            \"sourceIp\": \"203.0.113.5\"\n        },\n        \"requestId\": \"JKJaXmPLvHcESHA=\",\n        \"stage\": \"$default\"\n    },\n    \"body\": null,\n    \"isBase64Encoded\": false\n}\n",[3392,7235,7236,7240,7252,7264,7276,7288,7296,7308,7320,7331,7341,7346,7353,7363,7367,7374,7384,7388,7395,7407,7419,7426,7438,7449,7458,7463,7475,7485,7489,7501,7511],{"__ignoreMap":3390},[3395,7237,7238],{"class":3397,"line":3398},[3395,7239,5069],{"class":4708},[3395,7241,7242,7245,7247,7250],{"class":3397,"line":3404},[3395,7243,7244],{"class":5074},"    \"version\"",[3395,7246,5078],{"class":4708},[3395,7248,7249],{"class":4888},"\"2.0\"",[3395,7251,5084],{"class":4708},[3395,7253,7254,7257,7259,7262],{"class":3397,"line":3410},[3395,7255,7256],{"class":5074},"    \"routeKey\"",[3395,7258,5078],{"class":4708},[3395,7260,7261],{"class":4888},"\"GET \u002Fusers\u002F{id}\"",[3395,7263,5084],{"class":4708},[3395,7265,7266,7269,7271,7274],{"class":3397,"line":3416},[3395,7267,7268],{"class":5074},"    \"rawPath\"",[3395,7270,5078],{"class":4708},[3395,7272,7273],{"class":4888},"\"\u002Fusers\u002F42\"",[3395,7275,5084],{"class":4708},[3395,7277,7278,7281,7283,7286],{"class":3397,"line":3423},[3395,7279,7280],{"class":5074},"    \"rawQueryString\"",[3395,7282,5078],{"class":4708},[3395,7284,7285],{"class":4888},"\"format=json\"",[3395,7287,5084],{"class":4708},[3395,7289,7290,7293],{"class":3397,"line":3429},[3395,7291,7292],{"class":5074},"    \"headers\"",[3395,7294,7295],{"class":4708},": {\n",[3395,7297,7298,7301,7303,7306],{"class":3397,"line":3434},[3395,7299,7300],{"class":5074},"        \"accept\"",[3395,7302,5078],{"class":4708},[3395,7304,7305],{"class":4888},"\"application\u002Fjson\"",[3395,7307,5084],{"class":4708},[3395,7309,7310,7313,7315,7318],{"class":3397,"line":3440},[3395,7311,7312],{"class":5074},"        \"authorization\"",[3395,7314,5078],{"class":4708},[3395,7316,7317],{"class":4888},"\"Bearer eyJ...\"",[3395,7319,5084],{"class":4708},[3395,7321,7322,7325,7327,7329],{"class":3397,"line":3446},[3395,7323,7324],{"class":5074},"        \"content-type\"",[3395,7326,5078],{"class":4708},[3395,7328,7305],{"class":4888},[3395,7330,5084],{"class":4708},[3395,7332,7333,7336,7338],{"class":3397,"line":3452},[3395,7334,7335],{"class":5074},"        \"x-forwarded-for\"",[3395,7337,5078],{"class":4708},[3395,7339,7340],{"class":4888},"\"203.0.113.5\"\n",[3395,7342,7343],{"class":3397,"line":3458},[3395,7344,7345],{"class":4708},"    },\n",[3395,7347,7348,7351],{"class":3397,"line":3464},[3395,7349,7350],{"class":5074},"    \"queryStringParameters\"",[3395,7352,7295],{"class":4708},[3395,7354,7355,7358,7360],{"class":3397,"line":3470},[3395,7356,7357],{"class":5074},"        \"format\"",[3395,7359,5078],{"class":4708},[3395,7361,7362],{"class":4888},"\"json\"\n",[3395,7364,7365],{"class":3397,"line":3476},[3395,7366,7345],{"class":4708},[3395,7368,7369,7372],{"class":3397,"line":3482},[3395,7370,7371],{"class":5074},"    \"pathParameters\"",[3395,7373,7295],{"class":4708},[3395,7375,7376,7379,7381],{"class":3397,"line":3487},[3395,7377,7378],{"class":5074},"        \"id\"",[3395,7380,5078],{"class":4708},[3395,7382,7383],{"class":4888},"\"42\"\n",[3395,7385,7386],{"class":3397,"line":3493},[3395,7387,7345],{"class":4708},[3395,7389,7390,7393],{"class":3397,"line":3499},[3395,7391,7392],{"class":5074},"    \"requestContext\"",[3395,7394,7295],{"class":4708},[3395,7396,7397,7400,7402,7405],{"class":3397,"line":3505},[3395,7398,7399],{"class":5074},"        \"accountId\"",[3395,7401,5078],{"class":4708},[3395,7403,7404],{"class":4888},"\"123456789012\"",[3395,7406,5084],{"class":4708},[3395,7408,7409,7412,7414,7417],{"class":3397,"line":3511},[3395,7410,7411],{"class":5074},"        \"apiId\"",[3395,7413,5078],{"class":4708},[3395,7415,7416],{"class":4888},"\"abc123\"",[3395,7418,5084],{"class":4708},[3395,7420,7421,7424],{"class":3397,"line":3517},[3395,7422,7423],{"class":5074},"        \"http\"",[3395,7425,7295],{"class":4708},[3395,7427,7428,7431,7433,7436],{"class":3397,"line":3523},[3395,7429,7430],{"class":5074},"            \"method\"",[3395,7432,5078],{"class":4708},[3395,7434,7435],{"class":4888},"\"GET\"",[3395,7437,5084],{"class":4708},[3395,7439,7440,7443,7445,7447],{"class":3397,"line":3529},[3395,7441,7442],{"class":5074},"            \"path\"",[3395,7444,5078],{"class":4708},[3395,7446,7273],{"class":4888},[3395,7448,5084],{"class":4708},[3395,7450,7451,7454,7456],{"class":3397,"line":3534},[3395,7452,7453],{"class":5074},"            \"sourceIp\"",[3395,7455,5078],{"class":4708},[3395,7457,7340],{"class":4888},[3395,7459,7460],{"class":3397,"line":3539},[3395,7461,7462],{"class":4708},"        },\n",[3395,7464,7465,7468,7470,7473],{"class":3397,"line":3545},[3395,7466,7467],{"class":5074},"        \"requestId\"",[3395,7469,5078],{"class":4708},[3395,7471,7472],{"class":4888},"\"JKJaXmPLvHcESHA=\"",[3395,7474,5084],{"class":4708},[3395,7476,7477,7480,7482],{"class":3397,"line":3551},[3395,7478,7479],{"class":5074},"        \"stage\"",[3395,7481,5078],{"class":4708},[3395,7483,7484],{"class":4888},"\"$default\"\n",[3395,7486,7487],{"class":3397,"line":3557},[3395,7488,7345],{"class":4708},[3395,7490,7491,7494,7496,7499],{"class":3397,"line":3563},[3395,7492,7493],{"class":5074},"    \"body\"",[3395,7495,5078],{"class":4708},[3395,7497,7498],{"class":4696},"null",[3395,7500,5084],{"class":4708},[3395,7502,7503,7506,7508],{"class":3397,"line":3569},[3395,7504,7505],{"class":5074},"    \"isBase64Encoded\"",[3395,7507,5078],{"class":4708},[3395,7509,7510],{"class":4696},"false\n",[3395,7512,7513],{"class":3397,"line":3575},[3395,7514,3479],{"class":4708},[3353,7516,7517],{},[3359,7518,7519],{},"Реалізація HTTP API handler на .NET 10 з Lambda Annotations:",[3353,7521,7522],{},"Lambda Annotations — це фреймворк від AWS, що генерує boilerplate-код через Source Generators і дозволяє писати Lambda-функції у стилі ASP.NET Core Minimal API:",[3385,7524,7527],{"className":4681,"code":7525,"filename":7526,"language":4683,"meta":3390,"style":3390},"using Amazon.Lambda.Annotations;\nusing Amazon.Lambda.Annotations.APIGateway;\nusing Amazon.Lambda.Core;\nusing Microsoft.Extensions.Logging;\n\n\u002F\u002F Атрибут реєструє assembly як Lambda-функцію\n[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]\n\nnamespace MyApi.Lambda;\n\n\u002F\u002F У стандартній Lambda вам довелося б вручну створювати ресурси в AWS (наприклад, через веб-консоль)\n\u002F\u002F та налаштовувати, який URL викликає яку функцію.\n\u002F\u002F Завдяки фреймворку Lambda Annotations ви пишете код у стилі ASP.NET Core Controller.\n\u002F\u002F Під час компіляції генератор коду сам створить конфігурацію інфраструктури\n\u002F\u002F (CloudFormation шаблон) та налаштує всі URL-маршрути (routing) автоматично.\npublic class UserFunctions\n{\n    private readonly IUserRepository _repository;\n    private readonly ILogger\u003CUserFunctions> _logger;\n\n    \u002F\u002F DI через конструктор — повністю підтримується!\n    public UserFunctions(IUserRepository repository, ILogger\u003CUserFunctions> logger)\n    {\n        _repository = repository;\n        _logger = logger;\n    }\n\n    \u002F\u002F GET \u002Fusers\u002F{id} → HTTP API Lambda Integration\n    [LambdaFunction(ResourceName = \"GetUser\")]\n    [HttpApi(LambdaHttpMethod.Get, \"\u002Fusers\u002F{id}\")]\n    public async Task\u003CIHttpResult> GetUserAsync(\n        int id,\n        ILambdaContext context)\n    {\n        _logger.LogInformation(\n            \"GetUser called. RequestId={RequestId}, UserId={UserId}\",\n            context.AwsRequestId, id);\n\n        var user = await _repository.GetByIdAsync(id);\n\n        if (user is null)\n            return HttpResults.NotFound(new { message = $\"User {id} not found\" });\n\n        return HttpResults.Ok(user);\n    }\n\n    \u002F\u002F POST \u002Fusers → створення нового користувача\n    [LambdaFunction(ResourceName = \"CreateUser\")]\n    [HttpApi(LambdaHttpMethod.Post, \"\u002Fusers\")]\n    public async Task\u003CIHttpResult> CreateUserAsync(\n        [FromBody] CreateUserRequest request,\n        ILambdaContext context)\n    {\n        \u002F\u002F Перевірка RemainingTime для graceful shutdown\n        if (context.RemainingTime \u003C TimeSpan.FromSeconds(2))\n        {\n            _logger.LogWarning(\"Approaching timeout, aborting operation\");\n            return HttpResults.InternalServerError();\n        }\n\n        var user = await _repository.CreateAsync(request);\n        return HttpResults.Created($\"\u002Fusers\u002F{user.Id}\", user);\n    }\n}\n","Functions.cs",[3392,7528,7529,7548,7569,7586,7605,7609,7614,7650,7654,7668,7672,7677,7682,7687,7692,7697,7706,7710,7726,7747,7751,7756,7786,7790,7802,7813,7817,7821,7826,7844,7866,7885,7895,7904,7908,7918,7925,7941,7945,7971,7975,7992,8029,8033,8050,8054,8058,8063,8080,8102,8122,8139,8148,8153,8159,8187,8193,8210,8225,8231,8236,8260,8296,8301],{"__ignoreMap":3390},[3395,7530,7531,7534,7537,7539,7541,7543,7546],{"class":3397,"line":3398},[3395,7532,7533],{"class":6221},"using",[3395,7535,7536],{"class":4700}," Amazon",[3395,7538,3860],{"class":4708},[3395,7540,5754],{"class":4700},[3395,7542,3860],{"class":4708},[3395,7544,7545],{"class":4700},"Annotations",[3395,7547,6634],{"class":4708},[3395,7549,7550,7552,7554,7556,7558,7560,7562,7564,7567],{"class":3397,"line":3404},[3395,7551,7533],{"class":6221},[3395,7553,7536],{"class":4700},[3395,7555,3860],{"class":4708},[3395,7557,5754],{"class":4700},[3395,7559,3860],{"class":4708},[3395,7561,7545],{"class":4700},[3395,7563,3860],{"class":4708},[3395,7565,7566],{"class":4700},"APIGateway",[3395,7568,6634],{"class":4708},[3395,7570,7571,7573,7575,7577,7579,7581,7584],{"class":3397,"line":3410},[3395,7572,7533],{"class":6221},[3395,7574,7536],{"class":4700},[3395,7576,3860],{"class":4708},[3395,7578,5754],{"class":4700},[3395,7580,3860],{"class":4708},[3395,7582,7583],{"class":4700},"Core",[3395,7585,6634],{"class":4708},[3395,7587,7588,7590,7593,7595,7598,7600,7603],{"class":3397,"line":3416},[3395,7589,7533],{"class":6221},[3395,7591,7592],{"class":4700}," Microsoft",[3395,7594,3860],{"class":4708},[3395,7596,7597],{"class":4700},"Extensions",[3395,7599,3860],{"class":4708},[3395,7601,7602],{"class":4700},"Logging",[3395,7604,6634],{"class":4708},[3395,7606,7607],{"class":3397,"line":3423},[3395,7608,3420],{"emptyLinePlaceholder":3419},[3395,7610,7611],{"class":3397,"line":3429},[3395,7612,7613],{"class":4690},"\u002F\u002F Атрибут реєструє assembly як Lambda-функцію\n",[3395,7615,7616,7618,7620,7622,7624,7626,7628,7630,7632,7634,7636,7638,7640,7642,7644,7646,7648],{"class":3397,"line":3434},[3395,7617,5731],{"class":4708},[3395,7619,5734],{"class":4696},[3395,7621,5078],{"class":4708},[3395,7623,5739],{"class":4700},[3395,7625,4709],{"class":4708},[3395,7627,5744],{"class":4696},[3395,7629,4709],{"class":4708},[3395,7631,5749],{"class":4700},[3395,7633,3860],{"class":4708},[3395,7635,5754],{"class":4700},[3395,7637,3860],{"class":4708},[3395,7639,5759],{"class":4700},[3395,7641,3860],{"class":4708},[3395,7643,5764],{"class":4700},[3395,7645,3860],{"class":4708},[3395,7647,5769],{"class":4700},[3395,7649,5772],{"class":4708},[3395,7651,7652],{"class":3397,"line":3440},[3395,7653,3420],{"emptyLinePlaceholder":3419},[3395,7655,7656,7659,7662,7664,7666],{"class":3397,"line":3446},[3395,7657,7658],{"class":4696},"namespace",[3395,7660,7661],{"class":4700}," MyApi",[3395,7663,3860],{"class":4708},[3395,7665,5754],{"class":4700},[3395,7667,6634],{"class":4708},[3395,7669,7670],{"class":3397,"line":3452},[3395,7671,3420],{"emptyLinePlaceholder":3419},[3395,7673,7674],{"class":3397,"line":3458},[3395,7675,7676],{"class":4690},"\u002F\u002F У стандартній Lambda вам довелося б вручну створювати ресурси в AWS (наприклад, через веб-консоль)\n",[3395,7678,7679],{"class":3397,"line":3464},[3395,7680,7681],{"class":4690},"\u002F\u002F та налаштовувати, який URL викликає яку функцію.\n",[3395,7683,7684],{"class":3397,"line":3470},[3395,7685,7686],{"class":4690},"\u002F\u002F Завдяки фреймворку Lambda Annotations ви пишете код у стилі ASP.NET Core Controller.\n",[3395,7688,7689],{"class":3397,"line":3476},[3395,7690,7691],{"class":4690},"\u002F\u002F Під час компіляції генератор коду сам створить конфігурацію інфраструктури\n",[3395,7693,7694],{"class":3397,"line":3482},[3395,7695,7696],{"class":4690},"\u002F\u002F (CloudFormation шаблон) та налаштує всі URL-маршрути (routing) автоматично.\n",[3395,7698,7699,7701,7703],{"class":3397,"line":3487},[3395,7700,4697],{"class":4696},[3395,7702,6314],{"class":4696},[3395,7704,7705],{"class":4700}," UserFunctions\n",[3395,7707,7708],{"class":3397,"line":3493},[3395,7709,5069],{"class":4708},[3395,7711,7712,7715,7718,7721,7724],{"class":3397,"line":3499},[3395,7713,7714],{"class":4696},"    private",[3395,7716,7717],{"class":4696}," readonly",[3395,7719,7720],{"class":4700}," IUserRepository",[3395,7722,7723],{"class":4715}," _repository",[3395,7725,6634],{"class":4708},[3395,7727,7728,7730,7732,7735,7737,7740,7742,7745],{"class":3397,"line":3505},[3395,7729,7714],{"class":4696},[3395,7731,7717],{"class":4696},[3395,7733,7734],{"class":4700}," ILogger",[3395,7736,6130],{"class":4708},[3395,7738,7739],{"class":4700},"UserFunctions",[3395,7741,6136],{"class":4708},[3395,7743,7744],{"class":4715},"_logger",[3395,7746,6634],{"class":4708},[3395,7748,7749],{"class":3397,"line":3511},[3395,7750,3420],{"emptyLinePlaceholder":3419},[3395,7752,7753],{"class":3397,"line":3517},[3395,7754,7755],{"class":4690},"    \u002F\u002F DI через конструктор — повністю підтримується!\n",[3395,7757,7758,7760,7763,7765,7767,7770,7772,7775,7777,7779,7781,7784],{"class":3397,"line":3523},[3395,7759,6326],{"class":4696},[3395,7761,7762],{"class":4704}," UserFunctions",[3395,7764,4709],{"class":4708},[3395,7766,6384],{"class":4700},[3395,7768,7769],{"class":4715}," repository",[3395,7771,4719],{"class":4708},[3395,7773,7774],{"class":4700},"ILogger",[3395,7776,6130],{"class":4708},[3395,7778,7739],{"class":4700},[3395,7780,6136],{"class":4708},[3395,7782,7783],{"class":4715},"logger",[3395,7785,4727],{"class":4708},[3395,7787,7788],{"class":3397,"line":3529},[3395,7789,6347],{"class":4708},[3395,7791,7792,7795,7797,7800],{"class":3397,"line":3534},[3395,7793,7794],{"class":4715},"        _repository",[3395,7796,6088],{"class":4708},[3395,7798,7799],{"class":4715},"repository",[3395,7801,6634],{"class":4708},[3395,7803,7804,7807,7809,7811],{"class":3397,"line":3539},[3395,7805,7806],{"class":4715},"        _logger",[3395,7808,6088],{"class":4708},[3395,7810,7783],{"class":4715},[3395,7812,6634],{"class":4708},[3395,7814,7815],{"class":3397,"line":3545},[3395,7816,6396],{"class":4708},[3395,7818,7819],{"class":3397,"line":3551},[3395,7820,3420],{"emptyLinePlaceholder":3419},[3395,7822,7823],{"class":3397,"line":3557},[3395,7824,7825],{"class":4690},"    \u002F\u002F GET \u002Fusers\u002F{id} → HTTP API Lambda Integration\n",[3395,7827,7828,7830,7832,7834,7837,7839,7842],{"class":3397,"line":3563},[3395,7829,6147],{"class":4708},[3395,7831,6080],{"class":4700},[3395,7833,4709],{"class":4708},[3395,7835,7836],{"class":4715},"ResourceName",[3395,7838,6088],{"class":4708},[3395,7840,7841],{"class":4888},"\"GetUser\"",[3395,7843,6093],{"class":4708},[3395,7845,7846,7848,7850,7852,7854,7856,7859,7861,7864],{"class":3397,"line":3569},[3395,7847,6147],{"class":4708},[3395,7849,6100],{"class":4700},[3395,7851,4709],{"class":4708},[3395,7853,6105],{"class":4715},[3395,7855,3860],{"class":4708},[3395,7857,7858],{"class":4715},"Get",[3395,7860,4719],{"class":4708},[3395,7862,7863],{"class":4888},"\"\u002Fusers\u002F{id}\"",[3395,7865,6093],{"class":4708},[3395,7867,7868,7870,7872,7874,7876,7878,7880,7883],{"class":3397,"line":3575},[3395,7869,6326],{"class":4696},[3395,7871,6124],{"class":4696},[3395,7873,6127],{"class":4700},[3395,7875,6130],{"class":4708},[3395,7877,6133],{"class":4700},[3395,7879,6136],{"class":4708},[3395,7881,7882],{"class":4704},"GetUserAsync",[3395,7884,6142],{"class":4708},[3395,7886,7887,7890,7893],{"class":3397,"line":3581},[3395,7888,7889],{"class":4696},"        int",[3395,7891,7892],{"class":4715}," id",[3395,7894,5084],{"class":4708},[3395,7896,7897,7900,7902],{"class":3397,"line":3586},[3395,7898,7899],{"class":4700},"        ILambdaContext",[3395,7901,4724],{"class":4715},[3395,7903,4727],{"class":4708},[3395,7905,7906],{"class":3397,"line":3591},[3395,7907,6347],{"class":4708},[3395,7909,7910,7912,7914,7916],{"class":3397,"line":3597},[3395,7911,7806],{"class":4715},[3395,7913,3860],{"class":4708},[3395,7915,4835],{"class":4704},[3395,7917,6142],{"class":4708},[3395,7919,7920,7923],{"class":3397,"line":3603},[3395,7921,7922],{"class":4888},"            \"GetUser called. RequestId={RequestId}, UserId={UserId}\"",[3395,7924,5084],{"class":4708},[3395,7926,7927,7930,7932,7934,7936,7939],{"class":3397,"line":3609},[3395,7928,7929],{"class":4715},"            context",[3395,7931,3860],{"class":4708},[3395,7933,4804],{"class":4715},[3395,7935,4719],{"class":4708},[3395,7937,7938],{"class":4715},"id",[3395,7940,6522],{"class":4708},[3395,7942,7943],{"class":3397,"line":3615},[3395,7944,3420],{"emptyLinePlaceholder":3419},[3395,7946,7947,7950,7953,7955,7958,7960,7962,7965,7967,7969],{"class":3397,"line":3621},[3395,7948,7949],{"class":4696},"        var",[3395,7951,7952],{"class":4715}," user",[3395,7954,6088],{"class":4708},[3395,7956,7957],{"class":4696},"await",[3395,7959,7723],{"class":4715},[3395,7961,3860],{"class":4708},[3395,7963,7964],{"class":4704},"GetByIdAsync",[3395,7966,4709],{"class":4708},[3395,7968,7938],{"class":4715},[3395,7970,6522],{"class":4708},[3395,7972,7973],{"class":3397,"line":3627},[3395,7974,3420],{"emptyLinePlaceholder":3419},[3395,7976,7977,7980,7982,7984,7987,7990],{"class":3397,"line":3633},[3395,7978,7979],{"class":6221},"        if",[3395,7981,5956],{"class":4708},[3395,7983,6250],{"class":4715},[3395,7985,7986],{"class":4696}," is",[3395,7988,7989],{"class":4696}," null",[3395,7991,4727],{"class":4708},[3395,7993,7994,7997,7999,8001,8004,8006,8008,8010,8013,8015,8018,8020,8022,8024,8027],{"class":3397,"line":3638},[3395,7995,7996],{"class":6221},"            return",[3395,7998,6225],{"class":4715},[3395,8000,3860],{"class":4708},[3395,8002,8003],{"class":4704},"NotFound",[3395,8005,4709],{"class":4708},[3395,8007,6235],{"class":4696},[3395,8009,6238],{"class":4708},[3395,8011,8012],{"class":4715},"message",[3395,8014,6088],{"class":4708},[3395,8016,8017],{"class":4888},"$\"User ",[3395,8019,6507],{"class":6506},[3395,8021,7938],{"class":4715},[3395,8023,6516],{"class":6506},[3395,8025,8026],{"class":4888}," not found\"",[3395,8028,6273],{"class":4708},[3395,8030,8031],{"class":3397,"line":3643},[3395,8032,3420],{"emptyLinePlaceholder":3419},[3395,8034,8035,8038,8040,8042,8044,8046,8048],{"class":3397,"line":3649},[3395,8036,8037],{"class":6221},"        return",[3395,8039,6225],{"class":4715},[3395,8041,3860],{"class":4708},[3395,8043,6230],{"class":4704},[3395,8045,4709],{"class":4708},[3395,8047,6250],{"class":4715},[3395,8049,6522],{"class":4708},[3395,8051,8052],{"class":3397,"line":3655},[3395,8053,6396],{"class":4708},[3395,8055,8056],{"class":3397,"line":3661},[3395,8057,3420],{"emptyLinePlaceholder":3419},[3395,8059,8060],{"class":3397,"line":3667},[3395,8061,8062],{"class":4690},"    \u002F\u002F POST \u002Fusers → створення нового користувача\n",[3395,8064,8065,8067,8069,8071,8073,8075,8078],{"class":3397,"line":3672},[3395,8066,6147],{"class":4708},[3395,8068,6080],{"class":4700},[3395,8070,4709],{"class":4708},[3395,8072,7836],{"class":4715},[3395,8074,6088],{"class":4708},[3395,8076,8077],{"class":4888},"\"CreateUser\"",[3395,8079,6093],{"class":4708},[3395,8081,8083,8085,8087,8089,8091,8093,8095,8097,8100],{"class":3397,"line":8082},49,[3395,8084,6147],{"class":4708},[3395,8086,6100],{"class":4700},[3395,8088,4709],{"class":4708},[3395,8090,6105],{"class":4715},[3395,8092,3860],{"class":4708},[3395,8094,6110],{"class":4715},[3395,8096,4719],{"class":4708},[3395,8098,8099],{"class":4888},"\"\u002Fusers\"",[3395,8101,6093],{"class":4708},[3395,8103,8105,8107,8109,8111,8113,8115,8117,8120],{"class":3397,"line":8104},50,[3395,8106,6326],{"class":4696},[3395,8108,6124],{"class":4696},[3395,8110,6127],{"class":4700},[3395,8112,6130],{"class":4708},[3395,8114,6133],{"class":4700},[3395,8116,6136],{"class":4708},[3395,8118,8119],{"class":4704},"CreateUserAsync",[3395,8121,6142],{"class":4708},[3395,8123,8125,8128,8130,8132,8135,8137],{"class":3397,"line":8124},51,[3395,8126,8127],{"class":4708},"        [",[3395,8129,6184],{"class":4700},[3395,8131,6153],{"class":4708},[3395,8133,8134],{"class":4700},"CreateUserRequest",[3395,8136,6192],{"class":4715},[3395,8138,5084],{"class":4708},[3395,8140,8142,8144,8146],{"class":3397,"line":8141},52,[3395,8143,7899],{"class":4700},[3395,8145,4724],{"class":4715},[3395,8147,4727],{"class":4708},[3395,8149,8151],{"class":3397,"line":8150},53,[3395,8152,6347],{"class":4708},[3395,8154,8156],{"class":3397,"line":8155},54,[3395,8157,8158],{"class":4690},"        \u002F\u002F Перевірка RemainingTime для graceful shutdown\n",[3395,8160,8162,8164,8166,8168,8170,8172,8174,8176,8178,8180,8182,8185],{"class":3397,"line":8161},55,[3395,8163,7979],{"class":6221},[3395,8165,5956],{"class":4708},[3395,8167,5896],{"class":4715},[3395,8169,3860],{"class":4708},[3395,8171,4812],{"class":4715},[3395,8173,6584],{"class":4708},[3395,8175,4813],{"class":4715},[3395,8177,3860],{"class":4708},[3395,8179,6591],{"class":4704},[3395,8181,4709],{"class":4708},[3395,8183,8184],{"class":5154},"2",[3395,8186,6599],{"class":4708},[3395,8188,8190],{"class":3397,"line":8189},56,[3395,8191,8192],{"class":4708},"        {\n",[3395,8194,8196,8199,8201,8203,8205,8208],{"class":3397,"line":8195},57,[3395,8197,8198],{"class":4715},"            _logger",[3395,8200,3860],{"class":4708},[3395,8202,4838],{"class":4704},[3395,8204,4709],{"class":4708},[3395,8206,8207],{"class":4888},"\"Approaching timeout, aborting operation\"",[3395,8209,6522],{"class":4708},[3395,8211,8213,8215,8217,8219,8222],{"class":3397,"line":8212},58,[3395,8214,7996],{"class":6221},[3395,8216,6225],{"class":4715},[3395,8218,3860],{"class":4708},[3395,8220,8221],{"class":4704},"InternalServerError",[3395,8223,8224],{"class":4708},"();\n",[3395,8226,8228],{"class":3397,"line":8227},59,[3395,8229,8230],{"class":4708},"        }\n",[3395,8232,8234],{"class":3397,"line":8233},60,[3395,8235,3420],{"emptyLinePlaceholder":3419},[3395,8237,8239,8241,8243,8245,8247,8249,8251,8254,8256,8258],{"class":3397,"line":8238},61,[3395,8240,7949],{"class":4696},[3395,8242,7952],{"class":4715},[3395,8244,6088],{"class":4708},[3395,8246,7957],{"class":4696},[3395,8248,7723],{"class":4715},[3395,8250,3860],{"class":4708},[3395,8252,8253],{"class":4704},"CreateAsync",[3395,8255,4709],{"class":4708},[3395,8257,6265],{"class":4715},[3395,8259,6522],{"class":4708},[3395,8261,8263,8265,8267,8269,8272,8274,8277,8279,8281,8283,8286,8288,8290,8292,8294],{"class":3397,"line":8262},62,[3395,8264,8037],{"class":6221},[3395,8266,6225],{"class":4715},[3395,8268,3860],{"class":4708},[3395,8270,8271],{"class":4704},"Created",[3395,8273,4709],{"class":4708},[3395,8275,8276],{"class":4888},"$\"\u002Fusers\u002F",[3395,8278,6507],{"class":6506},[3395,8280,6250],{"class":4715},[3395,8282,3860],{"class":6506},[3395,8284,8285],{"class":4715},"Id",[3395,8287,6516],{"class":6506},[3395,8289,6519],{"class":4888},[3395,8291,4719],{"class":4708},[3395,8293,6250],{"class":4715},[3395,8295,6522],{"class":4708},[3395,8297,8299],{"class":3397,"line":8298},63,[3395,8300,6396],{"class":4708},[3395,8302,8304],{"class":3397,"line":8303},64,[3395,8305,3479],{"class":4708},[3353,8307,8308],{},[3359,8309,8310],{},"Налаштування Startup (DI Container) для Lambda:",[3385,8312,8314],{"className":4681,"code":8313,"filename":6291,"language":4683,"meta":3390,"style":3390},"using Amazon.Lambda.Annotations;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace MyApi.Lambda;\n\n\u002F\u002F LambdaStartup — аналог Program.cs для Lambda Annotations\n[LambdaStartup]\npublic class Startup\n{\n    public void ConfigureServices(IServiceCollection services)\n    {\n        \u002F\u002F Реєстрація сервісів — виконується ОДНОРАЗОВО при Cold Start\n        \u002F\u002F Всі наступні виклики (Warm Start) повторно використовують цей контейнер\n        services.AddAWSService\u003CIAmazonDynamoDB>();\n        services.AddScoped\u003CIUserRepository, DynamoDbUserRepository>();\n\n        \u002F\u002F HttpClient з правильним connection pooling для Lambda\n        services.AddHttpClient(\"PaymentApi\", client =>\n        {\n            client.BaseAddress = new Uri(Environment.GetEnvironmentVariable(\"PAYMENT_API_URL\")!);\n            client.Timeout = TimeSpan.FromSeconds(10);\n        });\n\n        services.AddLogging(logging =>\n        {\n            logging.AddLambdaLogger();\n            logging.SetMinimumLevel(LogLevel.Information);\n        });\n    }\n}\n",[3392,8315,8316,8332,8349,8353,8365,8369,8374,8382,8390,8394,8410,8414,8419,8424,8438,8457,8461,8466,8488,8492,8527,8551,8556,8560,8576,8580,8592,8613,8617,8621],{"__ignoreMap":3390},[3395,8317,8318,8320,8322,8324,8326,8328,8330],{"class":3397,"line":3398},[3395,8319,7533],{"class":6221},[3395,8321,7536],{"class":4700},[3395,8323,3860],{"class":4708},[3395,8325,5754],{"class":4700},[3395,8327,3860],{"class":4708},[3395,8329,7545],{"class":4700},[3395,8331,6634],{"class":4708},[3395,8333,8334,8336,8338,8340,8342,8344,8347],{"class":3397,"line":3404},[3395,8335,7533],{"class":6221},[3395,8337,7592],{"class":4700},[3395,8339,3860],{"class":4708},[3395,8341,7597],{"class":4700},[3395,8343,3860],{"class":4708},[3395,8345,8346],{"class":4700},"DependencyInjection",[3395,8348,6634],{"class":4708},[3395,8350,8351],{"class":3397,"line":3410},[3395,8352,3420],{"emptyLinePlaceholder":3419},[3395,8354,8355,8357,8359,8361,8363],{"class":3397,"line":3416},[3395,8356,7658],{"class":4696},[3395,8358,7661],{"class":4700},[3395,8360,3860],{"class":4708},[3395,8362,5754],{"class":4700},[3395,8364,6634],{"class":4708},[3395,8366,8367],{"class":3397,"line":3423},[3395,8368,3420],{"emptyLinePlaceholder":3419},[3395,8370,8371],{"class":3397,"line":3429},[3395,8372,8373],{"class":4690},"\u002F\u002F LambdaStartup — аналог Program.cs для Lambda Annotations\n",[3395,8375,8376,8378,8380],{"class":3397,"line":3434},[3395,8377,5731],{"class":4708},[3395,8379,6304],{"class":4700},[3395,8381,6307],{"class":4708},[3395,8383,8384,8386,8388],{"class":3397,"line":3440},[3395,8385,4697],{"class":4696},[3395,8387,6314],{"class":4696},[3395,8389,6317],{"class":4700},[3395,8391,8392],{"class":3397,"line":3446},[3395,8393,5069],{"class":4708},[3395,8395,8396,8398,8400,8402,8404,8406,8408],{"class":3397,"line":3452},[3395,8397,6326],{"class":4696},[3395,8399,6329],{"class":4696},[3395,8401,6332],{"class":4704},[3395,8403,4709],{"class":4708},[3395,8405,6337],{"class":4700},[3395,8407,6340],{"class":4715},[3395,8409,4727],{"class":4708},[3395,8411,8412],{"class":3397,"line":3458},[3395,8413,6347],{"class":4708},[3395,8415,8416],{"class":3397,"line":3464},[3395,8417,8418],{"class":4690},"        \u002F\u002F Реєстрація сервісів — виконується ОДНОРАЗОВО при Cold Start\n",[3395,8420,8421],{"class":3397,"line":3470},[3395,8422,8423],{"class":4690},"        \u002F\u002F Всі наступні виклики (Warm Start) повторно використовують цей контейнер\n",[3395,8425,8426,8428,8430,8432,8434,8436],{"class":3397,"line":3476},[3395,8427,6357],{"class":4715},[3395,8429,3860],{"class":4708},[3395,8431,6362],{"class":4704},[3395,8433,6130],{"class":4708},[3395,8435,6367],{"class":4700},[3395,8437,6370],{"class":4708},[3395,8439,8440,8442,8444,8446,8448,8450,8452,8455],{"class":3397,"line":3482},[3395,8441,6357],{"class":4715},[3395,8443,3860],{"class":4708},[3395,8445,6379],{"class":4704},[3395,8447,6130],{"class":4708},[3395,8449,6384],{"class":4700},[3395,8451,4719],{"class":4708},[3395,8453,8454],{"class":4700},"DynamoDbUserRepository",[3395,8456,6370],{"class":4708},[3395,8458,8459],{"class":3397,"line":3487},[3395,8460,3420],{"emptyLinePlaceholder":3419},[3395,8462,8463],{"class":3397,"line":3493},[3395,8464,8465],{"class":4690},"        \u002F\u002F HttpClient з правильним connection pooling для Lambda\n",[3395,8467,8468,8470,8472,8475,8477,8480,8482,8485],{"class":3397,"line":3499},[3395,8469,6357],{"class":4715},[3395,8471,3860],{"class":4708},[3395,8473,8474],{"class":4704},"AddHttpClient",[3395,8476,4709],{"class":4708},[3395,8478,8479],{"class":4888},"\"PaymentApi\"",[3395,8481,4719],{"class":4708},[3395,8483,8484],{"class":4715},"client",[3395,8486,8487],{"class":4708}," =>\n",[3395,8489,8490],{"class":3397,"line":3505},[3395,8491,8192],{"class":4708},[3395,8493,8494,8497,8499,8502,8504,8506,8509,8511,8514,8516,8519,8521,8524],{"class":3397,"line":3511},[3395,8495,8496],{"class":4715},"            client",[3395,8498,3860],{"class":4708},[3395,8500,8501],{"class":4715},"BaseAddress",[3395,8503,6088],{"class":4708},[3395,8505,6235],{"class":4696},[3395,8507,8508],{"class":4700}," Uri",[3395,8510,4709],{"class":4708},[3395,8512,8513],{"class":4715},"Environment",[3395,8515,3860],{"class":4708},[3395,8517,8518],{"class":4704},"GetEnvironmentVariable",[3395,8520,4709],{"class":4708},[3395,8522,8523],{"class":4888},"\"PAYMENT_API_URL\"",[3395,8525,8526],{"class":4708},")!);\n",[3395,8528,8529,8531,8533,8536,8538,8540,8542,8544,8546,8549],{"class":3397,"line":3517},[3395,8530,8496],{"class":4715},[3395,8532,3860],{"class":4708},[3395,8534,8535],{"class":4715},"Timeout",[3395,8537,6088],{"class":4708},[3395,8539,4813],{"class":4715},[3395,8541,3860],{"class":4708},[3395,8543,6591],{"class":4704},[3395,8545,4709],{"class":4708},[3395,8547,8548],{"class":5154},"10",[3395,8550,6522],{"class":4708},[3395,8552,8553],{"class":3397,"line":3523},[3395,8554,8555],{"class":4708},"        });\n",[3395,8557,8558],{"class":3397,"line":3529},[3395,8559,3420],{"emptyLinePlaceholder":3419},[3395,8561,8562,8564,8566,8569,8571,8574],{"class":3397,"line":3534},[3395,8563,6357],{"class":4715},[3395,8565,3860],{"class":4708},[3395,8567,8568],{"class":4704},"AddLogging",[3395,8570,4709],{"class":4708},[3395,8572,8573],{"class":4715},"logging",[3395,8575,8487],{"class":4708},[3395,8577,8578],{"class":3397,"line":3539},[3395,8579,8192],{"class":4708},[3395,8581,8582,8585,8587,8590],{"class":3397,"line":3545},[3395,8583,8584],{"class":4715},"            logging",[3395,8586,3860],{"class":4708},[3395,8588,8589],{"class":4704},"AddLambdaLogger",[3395,8591,8224],{"class":4708},[3395,8593,8594,8596,8598,8601,8603,8606,8608,8611],{"class":3397,"line":3551},[3395,8595,8584],{"class":4715},[3395,8597,3860],{"class":4708},[3395,8599,8600],{"class":4704},"SetMinimumLevel",[3395,8602,4709],{"class":4708},[3395,8604,8605],{"class":4715},"LogLevel",[3395,8607,3860],{"class":4708},[3395,8609,8610],{"class":4715},"Information",[3395,8612,6522],{"class":4708},[3395,8614,8615],{"class":3397,"line":3557},[3395,8616,8555],{"class":4708},[3395,8618,8619],{"class":3397,"line":3563},[3395,8620,6396],{"class":4708},[3395,8622,8623],{"class":3397,"line":3569},[3395,8624,3479],{"class":4708},[3677,8626,8627,8630,8631,8633],{},[3359,8628,8629],{},"DI Container у Lambda."," Завдяки persistence Execution Environment між Warm Start викликами, ",[3392,8632,6337],{}," реєструється лише один раз — під час Cold Start. Усі Scoped та Transient сервіси при кожному виклику створюються заново (що є коректною поведінкою), але Singleton'и живуть протягом усього часу існування Execution Environment.",[3684,8635],{},[3704,8637,8639],{"id":8638},"асинхронний-тригер-s3-events","Асинхронний тригер: S3 Events",[3353,8641,8642,8643,8646,8647,8650,8651,8654],{},"Інтеграція з ",[3359,8644,8645],{},"Amazon S3"," є одним із найпоширеніших сценаріїв використання Lambda. S3 автоматично надсилає повідомлення Lambda, коли в bucket відбуваються певні дії: завантаження об'єкта (",[3392,8648,8649],{},"s3:ObjectCreated:*","), видалення (",[3392,8652,8653],{},"s3:ObjectRemoved:*","), відновлення з Glacier та інші.",[3382,8656,8657],{},[3385,8658,8660],{"className":3387,"code":8659,"language":3389,"meta":3390,"style":3390},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\ntitle \"S3 → Lambda: асинхронна обробка файлів\"\n\nactor \"Клієнт\" as CL\nrectangle \"Amazon S3\\nsource-images-bucket\" as S3SRC #fef3c7\nrectangle \"Lambda Function\\nImageProcessorFunction\" as LAM #d1fae5\nrectangle \"Amazon S3\\nprocessed-images-bucket\" as S3DST #dbeafe\nrectangle \"Amazon DynamoDB\\nimage-metadata\" as DYN #f3e8ff\n\nCL -> S3SRC : PUT image.jpg\\n(оригінальне зображення)\nS3SRC -> LAM : S3 Event\\n(ObjectCreated)\\n[асинхронно]\nnote right of S3SRC\n  S3 підтверджує завантаження\n  клієнту НЕГАЙНО,\n  не чекаючи обробки Lambda\nend note\nLAM -> S3SRC : GetObject\\n(завантажує оригінал)\nLAM -> LAM : Resize \u002F Compress\\n\u002F Watermark\nLAM -> S3DST : PutObject\\n(оброблене зображення)\nLAM -> DYN : PutItem\\n(метадані: розмір, хеш, URL)\n\n@enduml\n",[3392,8661,8662,8666,8670,8674,8678,8683,8687,8692,8697,8702,8707,8712,8716,8721,8726,8731,8736,8741,8746,8750,8755,8760,8765,8770,8774],{"__ignoreMap":3390},[3395,8663,8664],{"class":3397,"line":3398},[3395,8665,3401],{},[3395,8667,8668],{"class":3397,"line":3404},[3395,8669,3407],{},[3395,8671,8672],{"class":3397,"line":3410},[3395,8673,3413],{},[3395,8675,8676],{"class":3397,"line":3416},[3395,8677,3420],{"emptyLinePlaceholder":3419},[3395,8679,8680],{"class":3397,"line":3423},[3395,8681,8682],{},"title \"S3 → Lambda: асинхронна обробка файлів\"\n",[3395,8684,8685],{"class":3397,"line":3429},[3395,8686,3420],{"emptyLinePlaceholder":3419},[3395,8688,8689],{"class":3397,"line":3434},[3395,8690,8691],{},"actor \"Клієнт\" as CL\n",[3395,8693,8694],{"class":3397,"line":3440},[3395,8695,8696],{},"rectangle \"Amazon S3\\nsource-images-bucket\" as S3SRC #fef3c7\n",[3395,8698,8699],{"class":3397,"line":3446},[3395,8700,8701],{},"rectangle \"Lambda Function\\nImageProcessorFunction\" as LAM #d1fae5\n",[3395,8703,8704],{"class":3397,"line":3452},[3395,8705,8706],{},"rectangle \"Amazon S3\\nprocessed-images-bucket\" as S3DST #dbeafe\n",[3395,8708,8709],{"class":3397,"line":3458},[3395,8710,8711],{},"rectangle \"Amazon DynamoDB\\nimage-metadata\" as DYN #f3e8ff\n",[3395,8713,8714],{"class":3397,"line":3464},[3395,8715,3420],{"emptyLinePlaceholder":3419},[3395,8717,8718],{"class":3397,"line":3470},[3395,8719,8720],{},"CL -> S3SRC : PUT image.jpg\\n(оригінальне зображення)\n",[3395,8722,8723],{"class":3397,"line":3476},[3395,8724,8725],{},"S3SRC -> LAM : S3 Event\\n(ObjectCreated)\\n[асинхронно]\n",[3395,8727,8728],{"class":3397,"line":3482},[3395,8729,8730],{},"note right of S3SRC\n",[3395,8732,8733],{"class":3397,"line":3487},[3395,8734,8735],{},"  S3 підтверджує завантаження\n",[3395,8737,8738],{"class":3397,"line":3493},[3395,8739,8740],{},"  клієнту НЕГАЙНО,\n",[3395,8742,8743],{"class":3397,"line":3499},[3395,8744,8745],{},"  не чекаючи обробки Lambda\n",[3395,8747,8748],{"class":3397,"line":3505},[3395,8749,4215],{},[3395,8751,8752],{"class":3397,"line":3511},[3395,8753,8754],{},"LAM -> S3SRC : GetObject\\n(завантажує оригінал)\n",[3395,8756,8757],{"class":3397,"line":3517},[3395,8758,8759],{},"LAM -> LAM : Resize \u002F Compress\\n\u002F Watermark\n",[3395,8761,8762],{"class":3397,"line":3523},[3395,8763,8764],{},"LAM -> S3DST : PutObject\\n(оброблене зображення)\n",[3395,8766,8767],{"class":3397,"line":3529},[3395,8768,8769],{},"LAM -> DYN : PutItem\\n(метадані: розмір, хеш, URL)\n",[3395,8771,8772],{"class":3397,"line":3534},[3395,8773,3420],{"emptyLinePlaceholder":3419},[3395,8775,8776],{"class":3397,"line":3539},[3395,8777,3675],{},[3353,8779,8780],{},[3359,8781,8782],{},"Структура S3 Event, що надходить у Lambda:",[3385,8784,8786],{"className":5060,"code":8785,"language":5062,"meta":3390,"style":3390},"{\n    \"Records\": [\n        {\n            \"eventVersion\": \"2.1\",\n            \"eventSource\": \"aws:s3\",\n            \"awsRegion\": \"eu-central-1\",\n            \"eventTime\": \"2024-03-15T10:30:00.000Z\",\n            \"eventName\": \"ObjectCreated:Put\",\n            \"s3\": {\n                \"s3SchemaVersion\": \"1.0\",\n                \"bucket\": {\n                    \"name\": \"source-images-bucket\",\n                    \"arn\": \"arn:aws:s3:::source-images-bucket\"\n                },\n                \"object\": {\n                    \"key\": \"uploads\u002Fuser-123\u002Fprofile.jpg\",\n                    \"size\": 2048576,\n                    \"eTag\": \"d8e8fca2dc0f896fd7cb4cb0031ba249\"\n                }\n            }\n        }\n    ]\n}\n",[3392,8787,8788,8792,8800,8804,8816,8828,8839,8851,8863,8870,8882,8889,8901,8911,8916,8923,8935,8947,8957,8962,8967,8971,8976],{"__ignoreMap":3390},[3395,8789,8790],{"class":3397,"line":3398},[3395,8791,5069],{"class":4708},[3395,8793,8794,8797],{"class":3397,"line":3404},[3395,8795,8796],{"class":5074},"    \"Records\"",[3395,8798,8799],{"class":4708},": [\n",[3395,8801,8802],{"class":3397,"line":3410},[3395,8803,8192],{"class":4708},[3395,8805,8806,8809,8811,8814],{"class":3397,"line":3416},[3395,8807,8808],{"class":5074},"            \"eventVersion\"",[3395,8810,5078],{"class":4708},[3395,8812,8813],{"class":4888},"\"2.1\"",[3395,8815,5084],{"class":4708},[3395,8817,8818,8821,8823,8826],{"class":3397,"line":3423},[3395,8819,8820],{"class":5074},"            \"eventSource\"",[3395,8822,5078],{"class":4708},[3395,8824,8825],{"class":4888},"\"aws:s3\"",[3395,8827,5084],{"class":4708},[3395,8829,8830,8833,8835,8837],{"class":3397,"line":3429},[3395,8831,8832],{"class":5074},"            \"awsRegion\"",[3395,8834,5078],{"class":4708},[3395,8836,5106],{"class":4888},[3395,8838,5084],{"class":4708},[3395,8840,8841,8844,8846,8849],{"class":3397,"line":3434},[3395,8842,8843],{"class":5074},"            \"eventTime\"",[3395,8845,5078],{"class":4708},[3395,8847,8848],{"class":4888},"\"2024-03-15T10:30:00.000Z\"",[3395,8850,5084],{"class":4708},[3395,8852,8853,8856,8858,8861],{"class":3397,"line":3440},[3395,8854,8855],{"class":5074},"            \"eventName\"",[3395,8857,5078],{"class":4708},[3395,8859,8860],{"class":4888},"\"ObjectCreated:Put\"",[3395,8862,5084],{"class":4708},[3395,8864,8865,8868],{"class":3397,"line":3446},[3395,8866,8867],{"class":5074},"            \"s3\"",[3395,8869,7295],{"class":4708},[3395,8871,8872,8875,8877,8880],{"class":3397,"line":3452},[3395,8873,8874],{"class":5074},"                \"s3SchemaVersion\"",[3395,8876,5078],{"class":4708},[3395,8878,8879],{"class":4888},"\"1.0\"",[3395,8881,5084],{"class":4708},[3395,8883,8884,8887],{"class":3397,"line":3458},[3395,8885,8886],{"class":5074},"                \"bucket\"",[3395,8888,7295],{"class":4708},[3395,8890,8891,8894,8896,8899],{"class":3397,"line":3464},[3395,8892,8893],{"class":5074},"                    \"name\"",[3395,8895,5078],{"class":4708},[3395,8897,8898],{"class":4888},"\"source-images-bucket\"",[3395,8900,5084],{"class":4708},[3395,8902,8903,8906,8908],{"class":3397,"line":3470},[3395,8904,8905],{"class":5074},"                    \"arn\"",[3395,8907,5078],{"class":4708},[3395,8909,8910],{"class":4888},"\"arn:aws:s3:::source-images-bucket\"\n",[3395,8912,8913],{"class":3397,"line":3476},[3395,8914,8915],{"class":4708},"                },\n",[3395,8917,8918,8921],{"class":3397,"line":3482},[3395,8919,8920],{"class":5074},"                \"object\"",[3395,8922,7295],{"class":4708},[3395,8924,8925,8928,8930,8933],{"class":3397,"line":3487},[3395,8926,8927],{"class":5074},"                    \"key\"",[3395,8929,5078],{"class":4708},[3395,8931,8932],{"class":4888},"\"uploads\u002Fuser-123\u002Fprofile.jpg\"",[3395,8934,5084],{"class":4708},[3395,8936,8937,8940,8942,8945],{"class":3397,"line":3493},[3395,8938,8939],{"class":5074},"                    \"size\"",[3395,8941,5078],{"class":4708},[3395,8943,8944],{"class":5154},"2048576",[3395,8946,5084],{"class":4708},[3395,8948,8949,8952,8954],{"class":3397,"line":3499},[3395,8950,8951],{"class":5074},"                    \"eTag\"",[3395,8953,5078],{"class":4708},[3395,8955,8956],{"class":4888},"\"d8e8fca2dc0f896fd7cb4cb0031ba249\"\n",[3395,8958,8959],{"class":3397,"line":3505},[3395,8960,8961],{"class":4708},"                }\n",[3395,8963,8964],{"class":3397,"line":3511},[3395,8965,8966],{"class":4708},"            }\n",[3395,8968,8969],{"class":3397,"line":3517},[3395,8970,8230],{"class":4708},[3395,8972,8973],{"class":3397,"line":3523},[3395,8974,8975],{"class":4708},"    ]\n",[3395,8977,8978],{"class":3397,"line":3529},[3395,8979,3479],{"class":4708},[3353,8981,8982,8985,8986,8989],{},[3359,8983,8984],{},"Зверніть увагу:"," S3 Event завжди містить масив ",[3392,8987,8988],{},"Records",", і теоретично може містити більше одного запису (хоча на практиці S3 зазвичай надсилає по одному запису). Обробник повинен ітерувати по всіх записах.",[3353,8991,8992],{},[3359,8993,8994],{},"Handler для обробки S3 подій на .NET 10:",[3385,8996,8999],{"className":4681,"code":8997,"filename":8998,"language":4683,"meta":3390,"style":3390},"using Amazon.Lambda.Core;\nusing Amazon.Lambda.S3Events;\nusing Amazon.S3;\nusing Amazon.S3.Model;\n\n[assembly: LambdaSerializer(\n    typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]\n\nnamespace ImageProcessor.Lambda;\n\npublic class ImageProcessorFunction\n{\n    \u002F\u002F IAmazonS3 ініціалізується ОДНОРАЗОВО при Cold Start\n    \u002F\u002F та повторно використовується між Warm Start викликами\n    private static readonly IAmazonS3 S3Client = new AmazonS3Client();\n    private const string DestinationBucket = \"processed-images-bucket\";\n\n    public async Task FunctionHandler(S3Event evnt, ILambdaContext context)\n    {\n        \u002F\u002F S3Event може містити кілька Records — обробляємо всі\n        foreach (var record in evnt.Records)\n        {\n            var srcBucket = record.S3.Bucket.Name;\n            var srcKey = Uri.UnescapeDataString(record.S3.Object.Key.Replace(\"+\", \" \"));\n\n            context.Logger.LogInformation(\n                \"Processing: s3:\u002F\u002F{Bucket}\u002F{Key} ({Size} bytes)\",\n                srcBucket, srcKey, record.S3.Object.Size);\n\n            try\n            {\n                \u002F\u002F Завантажуємо оригінальний файл з S3\n                var getRequest = new GetObjectRequest\n                {\n                    BucketName = srcBucket,\n                    Key = srcKey\n                };\n\n                using var response = await S3Client.GetObjectAsync(getRequest);\n                using var inputStream = response.ResponseStream;\n\n                \u002F\u002F Обробка зображення (resize, compress тощо)\n                using var processedStream = await ProcessImageAsync(inputStream, context);\n\n                \u002F\u002F Зберігаємо результат у destination bucket\n                var dstKey = $\"processed\u002F{srcKey}\";\n                var putRequest = new PutObjectRequest\n                {\n                    BucketName = DestinationBucket,\n                    Key = dstKey,\n                    InputStream = processedStream,\n                    ContentType = \"image\u002Fwebp\",\n                    \u002F\u002F Server-side encryption\n                    ServerSideEncryptionMethod = ServerSideEncryptionMethod.AES256\n                };\n\n                await S3Client.PutObjectAsync(putRequest);\n\n                context.Logger.LogInformation(\n                    \"Successfully processed: s3:\u002F\u002F{Bucket}\u002F{Key}\",\n                    DestinationBucket, dstKey);\n            }\n            catch (Exception ex)\n            {\n                context.Logger.LogError(ex,\n                    \"Failed to process s3:\u002F\u002F{Bucket}\u002F{Key}\",\n                    srcBucket, srcKey);\n                \u002F\u002F При асинхронному тригері — Lambda повторить виклик\n                \u002F\u002F (до 2 разів за замовчуванням)\n                throw;\n            }\n        }\n    }\n\n    private static async Task\u003CStream> ProcessImageAsync(\n        Stream input, ILambdaContext context)\n    {\n        \u002F\u002F ... логіка обробки зображення\n        \u002F\u002F Можна використовувати SixLabors.ImageSharp або аналоги\n        return await Task.FromResult(input); \u002F\u002F placeholder\n    }\n}\n","ImageProcessorFunction.cs",[3392,9000,9001,9017,9034,9047,9064,9068,9080,9107,9111,9124,9128,9137,9141,9146,9151,9175,9195,9199,9224,9228,9233,9256,9260,9288,9341,9345,9359,9366,9395,9399,9404,9409,9414,9429,9434,9446,9456,9461,9465,9494,9515,9519,9524,9551,9555,9560,9582,9596,9600,9611,9622,9634,9646,9651,9666,9670,9674,9693,9697,9712,9719,9730,9734,9749,9753,9773,9781,9793,9799,9805,9813,9818,9823,9828,9833,9856,9872,9877,9883,9889,9914,9919],{"__ignoreMap":3390},[3395,9002,9003,9005,9007,9009,9011,9013,9015],{"class":3397,"line":3398},[3395,9004,7533],{"class":6221},[3395,9006,7536],{"class":4700},[3395,9008,3860],{"class":4708},[3395,9010,5754],{"class":4700},[3395,9012,3860],{"class":4708},[3395,9014,7583],{"class":4700},[3395,9016,6634],{"class":4708},[3395,9018,9019,9021,9023,9025,9027,9029,9032],{"class":3397,"line":3404},[3395,9020,7533],{"class":6221},[3395,9022,7536],{"class":4700},[3395,9024,3860],{"class":4708},[3395,9026,5754],{"class":4700},[3395,9028,3860],{"class":4708},[3395,9030,9031],{"class":4700},"S3Events",[3395,9033,6634],{"class":4708},[3395,9035,9036,9038,9040,9042,9045],{"class":3397,"line":3410},[3395,9037,7533],{"class":6221},[3395,9039,7536],{"class":4700},[3395,9041,3860],{"class":4708},[3395,9043,9044],{"class":4700},"S3",[3395,9046,6634],{"class":4708},[3395,9048,9049,9051,9053,9055,9057,9059,9062],{"class":3397,"line":3416},[3395,9050,7533],{"class":6221},[3395,9052,7536],{"class":4700},[3395,9054,3860],{"class":4708},[3395,9056,9044],{"class":4700},[3395,9058,3860],{"class":4708},[3395,9060,9061],{"class":4700},"Model",[3395,9063,6634],{"class":4708},[3395,9065,9066],{"class":3397,"line":3423},[3395,9067,3420],{"emptyLinePlaceholder":3419},[3395,9069,9070,9072,9074,9076,9078],{"class":3397,"line":3429},[3395,9071,5731],{"class":4708},[3395,9073,5734],{"class":4696},[3395,9075,5078],{"class":4708},[3395,9077,5739],{"class":4700},[3395,9079,6142],{"class":4708},[3395,9081,9082,9085,9087,9089,9091,9093,9095,9097,9099,9101,9103,9105],{"class":3397,"line":3434},[3395,9083,9084],{"class":4696},"    typeof",[3395,9086,4709],{"class":4708},[3395,9088,5749],{"class":4700},[3395,9090,3860],{"class":4708},[3395,9092,5754],{"class":4700},[3395,9094,3860],{"class":4708},[3395,9096,5759],{"class":4700},[3395,9098,3860],{"class":4708},[3395,9100,5764],{"class":4700},[3395,9102,3860],{"class":4708},[3395,9104,5769],{"class":4700},[3395,9106,5772],{"class":4708},[3395,9108,9109],{"class":3397,"line":3440},[3395,9110,3420],{"emptyLinePlaceholder":3419},[3395,9112,9113,9115,9118,9120,9122],{"class":3397,"line":3446},[3395,9114,7658],{"class":4696},[3395,9116,9117],{"class":4700}," ImageProcessor",[3395,9119,3860],{"class":4708},[3395,9121,5754],{"class":4700},[3395,9123,6634],{"class":4708},[3395,9125,9126],{"class":3397,"line":3452},[3395,9127,3420],{"emptyLinePlaceholder":3419},[3395,9129,9130,9132,9134],{"class":3397,"line":3458},[3395,9131,4697],{"class":4696},[3395,9133,6314],{"class":4696},[3395,9135,9136],{"class":4700}," ImageProcessorFunction\n",[3395,9138,9139],{"class":3397,"line":3464},[3395,9140,5069],{"class":4708},[3395,9142,9143],{"class":3397,"line":3470},[3395,9144,9145],{"class":4690},"    \u002F\u002F IAmazonS3 ініціалізується ОДНОРАЗОВО при Cold Start\n",[3395,9147,9148],{"class":3397,"line":3476},[3395,9149,9150],{"class":4690},"    \u002F\u002F та повторно використовується між Warm Start викликами\n",[3395,9152,9153,9155,9158,9160,9163,9166,9168,9170,9173],{"class":3397,"line":3482},[3395,9154,7714],{"class":4696},[3395,9156,9157],{"class":4696}," static",[3395,9159,7717],{"class":4696},[3395,9161,9162],{"class":4700}," IAmazonS3",[3395,9164,9165],{"class":4715}," S3Client",[3395,9167,6088],{"class":4708},[3395,9169,6235],{"class":4696},[3395,9171,9172],{"class":4700}," AmazonS3Client",[3395,9174,8224],{"class":4708},[3395,9176,9177,9179,9182,9185,9188,9190,9193],{"class":3397,"line":3487},[3395,9178,7714],{"class":4696},[3395,9180,9181],{"class":4696}," const",[3395,9183,9184],{"class":4696}," string",[3395,9186,9187],{"class":4715}," DestinationBucket",[3395,9189,6088],{"class":4708},[3395,9191,9192],{"class":4888},"\"processed-images-bucket\"",[3395,9194,6634],{"class":4708},[3395,9196,9197],{"class":3397,"line":3493},[3395,9198,3420],{"emptyLinePlaceholder":3419},[3395,9200,9201,9203,9205,9207,9209,9211,9213,9216,9218,9220,9222],{"class":3397,"line":3499},[3395,9202,6326],{"class":4696},[3395,9204,6124],{"class":4696},[3395,9206,6127],{"class":4700},[3395,9208,4705],{"class":4704},[3395,9210,4709],{"class":4708},[3395,9212,5835],{"class":4700},[3395,9214,9215],{"class":4715}," evnt",[3395,9217,4719],{"class":4708},[3395,9219,4667],{"class":4700},[3395,9221,4724],{"class":4715},[3395,9223,4727],{"class":4708},[3395,9225,9226],{"class":3397,"line":3505},[3395,9227,6347],{"class":4708},[3395,9229,9230],{"class":3397,"line":3511},[3395,9231,9232],{"class":4690},"        \u002F\u002F S3Event може містити кілька Records — обробляємо всі\n",[3395,9234,9235,9238,9240,9243,9245,9248,9250,9252,9254],{"class":3397,"line":3517},[3395,9236,9237],{"class":6221},"        foreach",[3395,9239,5956],{"class":4708},[3395,9241,9242],{"class":4696},"var",[3395,9244,6686],{"class":4715},[3395,9246,9247],{"class":6221}," in",[3395,9249,9215],{"class":4715},[3395,9251,3860],{"class":4708},[3395,9253,8988],{"class":4715},[3395,9255,4727],{"class":4708},[3395,9257,9258],{"class":3397,"line":3523},[3395,9259,8192],{"class":4708},[3395,9261,9262,9265,9268,9270,9273,9275,9277,9279,9282,9284,9286],{"class":3397,"line":3529},[3395,9263,9264],{"class":4696},"            var",[3395,9266,9267],{"class":4715}," srcBucket",[3395,9269,6088],{"class":4708},[3395,9271,9272],{"class":4715},"record",[3395,9274,3860],{"class":4708},[3395,9276,9044],{"class":4715},[3395,9278,3860],{"class":4708},[3395,9280,9281],{"class":4715},"Bucket",[3395,9283,3860],{"class":4708},[3395,9285,6803],{"class":4715},[3395,9287,6634],{"class":4708},[3395,9289,9290,9292,9295,9297,9300,9302,9305,9307,9309,9311,9313,9315,9318,9320,9323,9325,9328,9330,9333,9335,9338],{"class":3397,"line":3534},[3395,9291,9264],{"class":4696},[3395,9293,9294],{"class":4715}," srcKey",[3395,9296,6088],{"class":4708},[3395,9298,9299],{"class":4715},"Uri",[3395,9301,3860],{"class":4708},[3395,9303,9304],{"class":4704},"UnescapeDataString",[3395,9306,4709],{"class":4708},[3395,9308,9272],{"class":4715},[3395,9310,3860],{"class":4708},[3395,9312,9044],{"class":4715},[3395,9314,3860],{"class":4708},[3395,9316,9317],{"class":4715},"Object",[3395,9319,3860],{"class":4708},[3395,9321,9322],{"class":4715},"Key",[3395,9324,3860],{"class":4708},[3395,9326,9327],{"class":4704},"Replace",[3395,9329,4709],{"class":4708},[3395,9331,9332],{"class":4888},"\"+\"",[3395,9334,4719],{"class":4708},[3395,9336,9337],{"class":4888},"\" \"",[3395,9339,9340],{"class":4708},"));\n",[3395,9342,9343],{"class":3397,"line":3539},[3395,9344,3420],{"emptyLinePlaceholder":3419},[3395,9346,9347,9349,9351,9353,9355,9357],{"class":3397,"line":3545},[3395,9348,7929],{"class":4715},[3395,9350,3860],{"class":4708},[3395,9352,4824],{"class":4715},[3395,9354,3860],{"class":4708},[3395,9356,4835],{"class":4704},[3395,9358,6142],{"class":4708},[3395,9360,9361,9364],{"class":3397,"line":3551},[3395,9362,9363],{"class":4888},"                \"Processing: s3:\u002F\u002F{Bucket}\u002F{Key} ({Size} bytes)\"",[3395,9365,5084],{"class":4708},[3395,9367,9368,9371,9373,9376,9378,9380,9382,9384,9386,9388,9390,9393],{"class":3397,"line":3557},[3395,9369,9370],{"class":4715},"                srcBucket",[3395,9372,4719],{"class":4708},[3395,9374,9375],{"class":4715},"srcKey",[3395,9377,4719],{"class":4708},[3395,9379,9272],{"class":4715},[3395,9381,3860],{"class":4708},[3395,9383,9044],{"class":4715},[3395,9385,3860],{"class":4708},[3395,9387,9317],{"class":4715},[3395,9389,3860],{"class":4708},[3395,9391,9392],{"class":4715},"Size",[3395,9394,6522],{"class":4708},[3395,9396,9397],{"class":3397,"line":3563},[3395,9398,3420],{"emptyLinePlaceholder":3419},[3395,9400,9401],{"class":3397,"line":3569},[3395,9402,9403],{"class":6221},"            try\n",[3395,9405,9406],{"class":3397,"line":3575},[3395,9407,9408],{"class":4708},"            {\n",[3395,9410,9411],{"class":3397,"line":3581},[3395,9412,9413],{"class":4690},"                \u002F\u002F Завантажуємо оригінальний файл з S3\n",[3395,9415,9416,9419,9422,9424,9426],{"class":3397,"line":3586},[3395,9417,9418],{"class":4696},"                var",[3395,9420,9421],{"class":4715}," getRequest",[3395,9423,6088],{"class":4708},[3395,9425,6235],{"class":4696},[3395,9427,9428],{"class":4700}," GetObjectRequest\n",[3395,9430,9431],{"class":3397,"line":3591},[3395,9432,9433],{"class":4708},"                {\n",[3395,9435,9436,9439,9441,9444],{"class":3397,"line":3597},[3395,9437,9438],{"class":4715},"                    BucketName",[3395,9440,6088],{"class":4708},[3395,9442,9443],{"class":4715},"srcBucket",[3395,9445,5084],{"class":4708},[3395,9447,9448,9451,9453],{"class":3397,"line":3603},[3395,9449,9450],{"class":4715},"                    Key",[3395,9452,6088],{"class":4708},[3395,9454,9455],{"class":4715},"srcKey\n",[3395,9457,9458],{"class":3397,"line":3609},[3395,9459,9460],{"class":4708},"                };\n",[3395,9462,9463],{"class":3397,"line":3615},[3395,9464,3420],{"emptyLinePlaceholder":3419},[3395,9466,9467,9470,9473,9476,9478,9480,9482,9484,9487,9489,9492],{"class":3397,"line":3621},[3395,9468,9469],{"class":6221},"                using",[3395,9471,9472],{"class":4696}," var",[3395,9474,9475],{"class":4715}," response",[3395,9477,6088],{"class":4708},[3395,9479,7957],{"class":4696},[3395,9481,9165],{"class":4715},[3395,9483,3860],{"class":4708},[3395,9485,9486],{"class":4704},"GetObjectAsync",[3395,9488,4709],{"class":4708},[3395,9490,9491],{"class":4715},"getRequest",[3395,9493,6522],{"class":4708},[3395,9495,9496,9498,9500,9503,9505,9508,9510,9513],{"class":3397,"line":3627},[3395,9497,9469],{"class":6221},[3395,9499,9472],{"class":4696},[3395,9501,9502],{"class":4715}," inputStream",[3395,9504,6088],{"class":4708},[3395,9506,9507],{"class":4715},"response",[3395,9509,3860],{"class":4708},[3395,9511,9512],{"class":4715},"ResponseStream",[3395,9514,6634],{"class":4708},[3395,9516,9517],{"class":3397,"line":3633},[3395,9518,3420],{"emptyLinePlaceholder":3419},[3395,9520,9521],{"class":3397,"line":3638},[3395,9522,9523],{"class":4690},"                \u002F\u002F Обробка зображення (resize, compress тощо)\n",[3395,9525,9526,9528,9530,9533,9535,9537,9540,9542,9545,9547,9549],{"class":3397,"line":3643},[3395,9527,9469],{"class":6221},[3395,9529,9472],{"class":4696},[3395,9531,9532],{"class":4715}," processedStream",[3395,9534,6088],{"class":4708},[3395,9536,7957],{"class":4696},[3395,9538,9539],{"class":4704}," ProcessImageAsync",[3395,9541,4709],{"class":4708},[3395,9543,9544],{"class":4715},"inputStream",[3395,9546,4719],{"class":4708},[3395,9548,5896],{"class":4715},[3395,9550,6522],{"class":4708},[3395,9552,9553],{"class":3397,"line":3649},[3395,9554,3420],{"emptyLinePlaceholder":3419},[3395,9556,9557],{"class":3397,"line":3655},[3395,9558,9559],{"class":4690},"                \u002F\u002F Зберігаємо результат у destination bucket\n",[3395,9561,9562,9564,9567,9569,9572,9574,9576,9578,9580],{"class":3397,"line":3661},[3395,9563,9418],{"class":4696},[3395,9565,9566],{"class":4715}," dstKey",[3395,9568,6088],{"class":4708},[3395,9570,9571],{"class":4888},"$\"processed\u002F",[3395,9573,6507],{"class":6506},[3395,9575,9375],{"class":4715},[3395,9577,6516],{"class":6506},[3395,9579,6519],{"class":4888},[3395,9581,6634],{"class":4708},[3395,9583,9584,9586,9589,9591,9593],{"class":3397,"line":3667},[3395,9585,9418],{"class":4696},[3395,9587,9588],{"class":4715}," putRequest",[3395,9590,6088],{"class":4708},[3395,9592,6235],{"class":4696},[3395,9594,9595],{"class":4700}," PutObjectRequest\n",[3395,9597,9598],{"class":3397,"line":3672},[3395,9599,9433],{"class":4708},[3395,9601,9602,9604,9606,9609],{"class":3397,"line":8082},[3395,9603,9438],{"class":4715},[3395,9605,6088],{"class":4708},[3395,9607,9608],{"class":4715},"DestinationBucket",[3395,9610,5084],{"class":4708},[3395,9612,9613,9615,9617,9620],{"class":3397,"line":8104},[3395,9614,9450],{"class":4715},[3395,9616,6088],{"class":4708},[3395,9618,9619],{"class":4715},"dstKey",[3395,9621,5084],{"class":4708},[3395,9623,9624,9627,9629,9632],{"class":3397,"line":8124},[3395,9625,9626],{"class":4715},"                    InputStream",[3395,9628,6088],{"class":4708},[3395,9630,9631],{"class":4715},"processedStream",[3395,9633,5084],{"class":4708},[3395,9635,9636,9639,9641,9644],{"class":3397,"line":8141},[3395,9637,9638],{"class":4715},"                    ContentType",[3395,9640,6088],{"class":4708},[3395,9642,9643],{"class":4888},"\"image\u002Fwebp\"",[3395,9645,5084],{"class":4708},[3395,9647,9648],{"class":3397,"line":8150},[3395,9649,9650],{"class":4690},"                    \u002F\u002F Server-side encryption\n",[3395,9652,9653,9656,9658,9661,9663],{"class":3397,"line":8155},[3395,9654,9655],{"class":4715},"                    ServerSideEncryptionMethod",[3395,9657,6088],{"class":4708},[3395,9659,9660],{"class":4715},"ServerSideEncryptionMethod",[3395,9662,3860],{"class":4708},[3395,9664,9665],{"class":4715},"AES256\n",[3395,9667,9668],{"class":3397,"line":8161},[3395,9669,9460],{"class":4708},[3395,9671,9672],{"class":3397,"line":8189},[3395,9673,3420],{"emptyLinePlaceholder":3419},[3395,9675,9676,9679,9681,9683,9686,9688,9691],{"class":3397,"line":8195},[3395,9677,9678],{"class":4696},"                await",[3395,9680,9165],{"class":4715},[3395,9682,3860],{"class":4708},[3395,9684,9685],{"class":4704},"PutObjectAsync",[3395,9687,4709],{"class":4708},[3395,9689,9690],{"class":4715},"putRequest",[3395,9692,6522],{"class":4708},[3395,9694,9695],{"class":3397,"line":8212},[3395,9696,3420],{"emptyLinePlaceholder":3419},[3395,9698,9699,9702,9704,9706,9708,9710],{"class":3397,"line":8227},[3395,9700,9701],{"class":4715},"                context",[3395,9703,3860],{"class":4708},[3395,9705,4824],{"class":4715},[3395,9707,3860],{"class":4708},[3395,9709,4835],{"class":4704},[3395,9711,6142],{"class":4708},[3395,9713,9714,9717],{"class":3397,"line":8233},[3395,9715,9716],{"class":4888},"                    \"Successfully processed: s3:\u002F\u002F{Bucket}\u002F{Key}\"",[3395,9718,5084],{"class":4708},[3395,9720,9721,9724,9726,9728],{"class":3397,"line":8238},[3395,9722,9723],{"class":4715},"                    DestinationBucket",[3395,9725,4719],{"class":4708},[3395,9727,9619],{"class":4715},[3395,9729,6522],{"class":4708},[3395,9731,9732],{"class":3397,"line":8262},[3395,9733,8966],{"class":4708},[3395,9735,9736,9739,9741,9744,9747],{"class":3397,"line":8298},[3395,9737,9738],{"class":6221},"            catch",[3395,9740,5956],{"class":4708},[3395,9742,9743],{"class":4700},"Exception",[3395,9745,9746],{"class":4715}," ex",[3395,9748,4727],{"class":4708},[3395,9750,9751],{"class":3397,"line":8303},[3395,9752,9408],{"class":4708},[3395,9754,9756,9758,9760,9762,9764,9766,9768,9771],{"class":3397,"line":9755},65,[3395,9757,9701],{"class":4715},[3395,9759,3860],{"class":4708},[3395,9761,4824],{"class":4715},[3395,9763,3860],{"class":4708},[3395,9765,4841],{"class":4704},[3395,9767,4709],{"class":4708},[3395,9769,9770],{"class":4715},"ex",[3395,9772,5084],{"class":4708},[3395,9774,9776,9779],{"class":3397,"line":9775},66,[3395,9777,9778],{"class":4888},"                    \"Failed to process s3:\u002F\u002F{Bucket}\u002F{Key}\"",[3395,9780,5084],{"class":4708},[3395,9782,9784,9787,9789,9791],{"class":3397,"line":9783},67,[3395,9785,9786],{"class":4715},"                    srcBucket",[3395,9788,4719],{"class":4708},[3395,9790,9375],{"class":4715},[3395,9792,6522],{"class":4708},[3395,9794,9796],{"class":3397,"line":9795},68,[3395,9797,9798],{"class":4690},"                \u002F\u002F При асинхронному тригері — Lambda повторить виклик\n",[3395,9800,9802],{"class":3397,"line":9801},69,[3395,9803,9804],{"class":4690},"                \u002F\u002F (до 2 разів за замовчуванням)\n",[3395,9806,9808,9811],{"class":3397,"line":9807},70,[3395,9809,9810],{"class":6221},"                throw",[3395,9812,6634],{"class":4708},[3395,9814,9816],{"class":3397,"line":9815},71,[3395,9817,8966],{"class":4708},[3395,9819,9821],{"class":3397,"line":9820},72,[3395,9822,8230],{"class":4708},[3395,9824,9826],{"class":3397,"line":9825},73,[3395,9827,6396],{"class":4708},[3395,9829,9831],{"class":3397,"line":9830},74,[3395,9832,3420],{"emptyLinePlaceholder":3419},[3395,9834,9836,9838,9840,9842,9844,9846,9849,9851,9854],{"class":3397,"line":9835},75,[3395,9837,7714],{"class":4696},[3395,9839,9157],{"class":4696},[3395,9841,6124],{"class":4696},[3395,9843,6127],{"class":4700},[3395,9845,6130],{"class":4708},[3395,9847,9848],{"class":4700},"Stream",[3395,9850,6136],{"class":4708},[3395,9852,9853],{"class":4704},"ProcessImageAsync",[3395,9855,6142],{"class":4708},[3395,9857,9859,9862,9864,9866,9868,9870],{"class":3397,"line":9858},76,[3395,9860,9861],{"class":4700},"        Stream",[3395,9863,4716],{"class":4715},[3395,9865,4719],{"class":4708},[3395,9867,4667],{"class":4700},[3395,9869,4724],{"class":4715},[3395,9871,4727],{"class":4708},[3395,9873,9875],{"class":3397,"line":9874},77,[3395,9876,6347],{"class":4708},[3395,9878,9880],{"class":3397,"line":9879},78,[3395,9881,9882],{"class":4690},"        \u002F\u002F ... логіка обробки зображення\n",[3395,9884,9886],{"class":3397,"line":9885},79,[3395,9887,9888],{"class":4690},"        \u002F\u002F Можна використовувати SixLabors.ImageSharp або аналоги\n",[3395,9890,9892,9894,9897,9899,9901,9904,9906,9908,9911],{"class":3397,"line":9891},80,[3395,9893,8037],{"class":6221},[3395,9895,9896],{"class":4696}," await",[3395,9898,6127],{"class":4715},[3395,9900,3860],{"class":4708},[3395,9902,9903],{"class":4704},"FromResult",[3395,9905,4709],{"class":4708},[3395,9907,6654],{"class":4715},[3395,9909,9910],{"class":4708},"); ",[3395,9912,9913],{"class":4690},"\u002F\u002F placeholder\n",[3395,9915,9917],{"class":3397,"line":9916},81,[3395,9918,6396],{"class":4708},[3395,9920,9922],{"class":3397,"line":9921},82,[3395,9923,3479],{"class":4708},[3684,9925],{},[3704,9927,9929],{"id":9928},"poll-based-тригер-sqs-та-dynamodb-streams","Poll-based тригер: SQS та DynamoDB Streams",[3353,9931,9932,9935,9936,9939],{},[3359,9933,9934],{},"Poll-based тригери"," реалізуються через механізм ",[3359,9937,9938],{},"Event Source Mapping"," — компонент Lambda-сервісу, що безперервно опитує джерело подій (SQS черга, DynamoDB Stream, Kinesis Stream) та автоматично викликає Lambda при появі нових записів.",[3382,9941,9942],{},[3385,9943,9945],{"className":3387,"code":9944,"language":3389,"meta":3390,"style":3390},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\ntitle \"Event Source Mapping: Lambda опитує SQS чергу\"\n\nrectangle \"Producer\\n(.NET API)\" as PROD #fef3c7\nrectangle \"Amazon SQS\\norder-processing-queue\\n(Standard Queue)\" as SQS #fde68a\nrectangle \"Event Source\\nMapping\\n(AWS Lambda Service)\" as ESM #dbeafe\nrectangle \"Lambda Function\\nOrderProcessorFunction\" as LAM #d1fae5\nrectangle \"Amazon RDS\\nPostgreSQL\" as RDS #f3e8ff\n\nPROD -> SQS : SendMessage\\n(OrderCreated JSON)\nESM -> SQS : ReceiveMessage\\n(polling кожні 1-20 сек)\nSQS --> ESM : Batch of messages\\n(до 10 000 повідомлень)\nESM -> LAM : Invoke з батчем\\n(SQSEvent)\nLAM -> RDS : INSERT INTO orders\nLAM --> ESM : success\nESM -> SQS : DeleteMessage\\n(видаляє успішно оброблені)\n\nnote right of ESM\n  ESM автоматично:\n  - масштабує кількість\n    паралельних викликів\n  - повторює невдалі батчі\n  - моніторить метрики черги\nend note\n\nnote bottom of SQS\n  Повідомлення залишаються\n  у черзі до підтвердження\n  успішної обробки.\n  Visibility Timeout: 300s\nend note\n\n@enduml\n",[3392,9946,9947,9951,9955,9959,9963,9968,9972,9977,9982,9987,9992,9997,10001,10006,10011,10016,10021,10026,10031,10036,10040,10045,10050,10055,10060,10065,10070,10074,10078,10083,10088,10093,10098,10103,10107,10111],{"__ignoreMap":3390},[3395,9948,9949],{"class":3397,"line":3398},[3395,9950,3401],{},[3395,9952,9953],{"class":3397,"line":3404},[3395,9954,3407],{},[3395,9956,9957],{"class":3397,"line":3410},[3395,9958,3413],{},[3395,9960,9961],{"class":3397,"line":3416},[3395,9962,3420],{"emptyLinePlaceholder":3419},[3395,9964,9965],{"class":3397,"line":3423},[3395,9966,9967],{},"title \"Event Source Mapping: Lambda опитує SQS чергу\"\n",[3395,9969,9970],{"class":3397,"line":3429},[3395,9971,3420],{"emptyLinePlaceholder":3419},[3395,9973,9974],{"class":3397,"line":3434},[3395,9975,9976],{},"rectangle \"Producer\\n(.NET API)\" as PROD #fef3c7\n",[3395,9978,9979],{"class":3397,"line":3440},[3395,9980,9981],{},"rectangle \"Amazon SQS\\norder-processing-queue\\n(Standard Queue)\" as SQS #fde68a\n",[3395,9983,9984],{"class":3397,"line":3446},[3395,9985,9986],{},"rectangle \"Event Source\\nMapping\\n(AWS Lambda Service)\" as ESM #dbeafe\n",[3395,9988,9989],{"class":3397,"line":3452},[3395,9990,9991],{},"rectangle \"Lambda Function\\nOrderProcessorFunction\" as LAM #d1fae5\n",[3395,9993,9994],{"class":3397,"line":3458},[3395,9995,9996],{},"rectangle \"Amazon RDS\\nPostgreSQL\" as RDS #f3e8ff\n",[3395,9998,9999],{"class":3397,"line":3464},[3395,10000,3420],{"emptyLinePlaceholder":3419},[3395,10002,10003],{"class":3397,"line":3470},[3395,10004,10005],{},"PROD -> SQS : SendMessage\\n(OrderCreated JSON)\n",[3395,10007,10008],{"class":3397,"line":3476},[3395,10009,10010],{},"ESM -> SQS : ReceiveMessage\\n(polling кожні 1-20 сек)\n",[3395,10012,10013],{"class":3397,"line":3482},[3395,10014,10015],{},"SQS --> ESM : Batch of messages\\n(до 10 000 повідомлень)\n",[3395,10017,10018],{"class":3397,"line":3487},[3395,10019,10020],{},"ESM -> LAM : Invoke з батчем\\n(SQSEvent)\n",[3395,10022,10023],{"class":3397,"line":3493},[3395,10024,10025],{},"LAM -> RDS : INSERT INTO orders\n",[3395,10027,10028],{"class":3397,"line":3499},[3395,10029,10030],{},"LAM --> ESM : success\n",[3395,10032,10033],{"class":3397,"line":3505},[3395,10034,10035],{},"ESM -> SQS : DeleteMessage\\n(видаляє успішно оброблені)\n",[3395,10037,10038],{"class":3397,"line":3511},[3395,10039,3420],{"emptyLinePlaceholder":3419},[3395,10041,10042],{"class":3397,"line":3517},[3395,10043,10044],{},"note right of ESM\n",[3395,10046,10047],{"class":3397,"line":3523},[3395,10048,10049],{},"  ESM автоматично:\n",[3395,10051,10052],{"class":3397,"line":3529},[3395,10053,10054],{},"  - масштабує кількість\n",[3395,10056,10057],{"class":3397,"line":3534},[3395,10058,10059],{},"    паралельних викликів\n",[3395,10061,10062],{"class":3397,"line":3539},[3395,10063,10064],{},"  - повторює невдалі батчі\n",[3395,10066,10067],{"class":3397,"line":3545},[3395,10068,10069],{},"  - моніторить метрики черги\n",[3395,10071,10072],{"class":3397,"line":3551},[3395,10073,4215],{},[3395,10075,10076],{"class":3397,"line":3557},[3395,10077,3420],{"emptyLinePlaceholder":3419},[3395,10079,10080],{"class":3397,"line":3563},[3395,10081,10082],{},"note bottom of SQS\n",[3395,10084,10085],{"class":3397,"line":3569},[3395,10086,10087],{},"  Повідомлення залишаються\n",[3395,10089,10090],{"class":3397,"line":3575},[3395,10091,10092],{},"  у черзі до підтвердження\n",[3395,10094,10095],{"class":3397,"line":3581},[3395,10096,10097],{},"  успішної обробки.\n",[3395,10099,10100],{"class":3397,"line":3586},[3395,10101,10102],{},"  Visibility Timeout: 300s\n",[3395,10104,10105],{"class":3397,"line":3591},[3395,10106,4215],{},[3395,10108,10109],{"class":3397,"line":3597},[3395,10110,3420],{"emptyLinePlaceholder":3419},[3395,10112,10113],{"class":3397,"line":3603},[3395,10114,3675],{},[3353,10116,10117],{},[3359,10118,10119],{},"Конфігурація Event Source Mapping для SQS:",[3939,10121,10122,10136,10140,10151],{},[3942,10123,10125,10126,3974,10128,10131,10132,10135],{"name":10124,"type":3945},"BatchSize","Кількість повідомлень SQS, що передаються в один виклик Lambda. Від ",[3359,10127,6596],{},[3359,10129,10130],{},"10,000",". Більший батч — менше викликів Lambda (дешевше), але якщо один запис невалідний — весь батч потрібно повторити. Рекомендоване значення: ",[3359,10133,10134],{},"10–100"," для типових сценаріїв.",[3942,10137,10139],{"name":10138,"type":3945},"MaximumBatchingWindowInSeconds","Час очікування накопичення батчу до MaxBatchSize. Lambda чекає до цього значення (0–300 секунд) перш ніж викликати функцію, навіть якщо батч ще не заповнений. Дозволяє зменшити кількість викликів при нерівномірному потоці.",[3942,10141,10144,10146,10147,10150],{"name":10142,"type":10143},"FunctionResponseTypes","array",[3392,10145,6982],{}," — дозволяє Lambda повертати часткові успіхи. Замість відкидання всього батчу при помилці одного запису, функція може повернути список ",[3392,10148,10149],{},"batchItemFailures",", і лише вказані записи повернуться у чергу для повторної обробки.",[3942,10152,10155,10156,10158,10159,3860],{"name":10153,"type":10154},"BisectBatchOnFunctionError","boolean","При ",[3392,10157,3946],{},": якщо Lambda завершилась з помилкою, ESM автоматично ділить батч навпіл та повторює кожну половину окремо — рекурсивно, доки не знайде проблемне повідомлення. Корисно при відсутності ",[3392,10160,6982],{},[3353,10162,10163],{},[3359,10164,10165,10166,10168],{},"Handler для SQS з підтримкою часткових збоїв (",[3392,10167,6982],{},"):",[3385,10170,10173],{"className":4681,"code":10171,"filename":10172,"language":4683,"meta":3390,"style":3390},"using Amazon.Lambda.Core;\nusing Amazon.Lambda.SQSEvents;\n\nnamespace OrderProcessor.Lambda;\n\npublic class OrderProcessorFunction\n{\n    private readonly IOrderService _orderService;\n\n    public OrderProcessorFunction(IOrderService orderService)\n    {\n        _orderService = orderService;\n    }\n\n    \u002F\u002F Повертаємо SQSBatchResponse замість void\u002FTask\n    \u002F\u002F щоб Lambda знала, які записи потрібно повторити\n    public async Task\u003CSQSBatchResponse> FunctionHandler(\n        SQSEvent sqsEvent,\n        ILambdaContext context)\n    {\n        var batchItemFailures = new List\u003CSQSBatchResponse.BatchItemFailure>();\n\n        \u002F\u002F Обробляємо кожне повідомлення НЕЗАЛЕЖНО\n        foreach (var message in sqsEvent.Records)\n        {\n            try\n            {\n                context.Logger.LogInformation(\n                    \"Processing SQS message: {MessageId}\", message.MessageId);\n\n                var order = System.Text.Json.JsonSerializer\n                    .Deserialize\u003COrderCreatedEvent>(message.Body)!;\n\n                await _orderService.ProcessOrderAsync(order);\n\n                context.Logger.LogInformation(\n                    \"Successfully processed order: {OrderId}\", order.OrderId);\n            }\n            catch (Exception ex)\n            {\n                \u002F\u002F НЕ перекидаємо виключення — додаємо до списку невдалих\n                context.Logger.LogError(ex,\n                    \"Failed to process message {MessageId}\", message.MessageId);\n\n                \u002F\u002F Це повідомлення повернеться у SQS для повторної обробки\n                batchItemFailures.Add(new SQSBatchResponse.BatchItemFailure\n                {\n                    ItemIdentifier = message.MessageId\n                });\n            }\n        }\n\n        return new SQSBatchResponse { BatchItemFailures = batchItemFailures };\n    }\n}\n","OrderProcessorFunction.cs",[3392,10174,10175,10191,10208,10212,10225,10229,10238,10242,10256,10260,10277,10281,10293,10297,10301,10306,10311,10331,10341,10349,10353,10378,10382,10387,10408,10412,10416,10420,10434,10450,10454,10481,10507,10511,10529,10533,10547,10563,10567,10579,10583,10588,10606,10621,10625,10630,10652,10656,10670,10675,10679,10683,10687,10707,10711],{"__ignoreMap":3390},[3395,10176,10177,10179,10181,10183,10185,10187,10189],{"class":3397,"line":3398},[3395,10178,7533],{"class":6221},[3395,10180,7536],{"class":4700},[3395,10182,3860],{"class":4708},[3395,10184,5754],{"class":4700},[3395,10186,3860],{"class":4708},[3395,10188,7583],{"class":4700},[3395,10190,6634],{"class":4708},[3395,10192,10193,10195,10197,10199,10201,10203,10206],{"class":3397,"line":3404},[3395,10194,7533],{"class":6221},[3395,10196,7536],{"class":4700},[3395,10198,3860],{"class":4708},[3395,10200,5754],{"class":4700},[3395,10202,3860],{"class":4708},[3395,10204,10205],{"class":4700},"SQSEvents",[3395,10207,6634],{"class":4708},[3395,10209,10210],{"class":3397,"line":3410},[3395,10211,3420],{"emptyLinePlaceholder":3419},[3395,10213,10214,10216,10219,10221,10223],{"class":3397,"line":3416},[3395,10215,7658],{"class":4696},[3395,10217,10218],{"class":4700}," OrderProcessor",[3395,10220,3860],{"class":4708},[3395,10222,5754],{"class":4700},[3395,10224,6634],{"class":4708},[3395,10226,10227],{"class":3397,"line":3423},[3395,10228,3420],{"emptyLinePlaceholder":3419},[3395,10230,10231,10233,10235],{"class":3397,"line":3429},[3395,10232,4697],{"class":4696},[3395,10234,6314],{"class":4696},[3395,10236,10237],{"class":4700}," OrderProcessorFunction\n",[3395,10239,10240],{"class":3397,"line":3434},[3395,10241,5069],{"class":4708},[3395,10243,10244,10246,10248,10251,10254],{"class":3397,"line":3440},[3395,10245,7714],{"class":4696},[3395,10247,7717],{"class":4696},[3395,10249,10250],{"class":4700}," IOrderService",[3395,10252,10253],{"class":4715}," _orderService",[3395,10255,6634],{"class":4708},[3395,10257,10258],{"class":3397,"line":3446},[3395,10259,3420],{"emptyLinePlaceholder":3419},[3395,10261,10262,10264,10267,10269,10272,10275],{"class":3397,"line":3452},[3395,10263,6326],{"class":4696},[3395,10265,10266],{"class":4704}," OrderProcessorFunction",[3395,10268,4709],{"class":4708},[3395,10270,10271],{"class":4700},"IOrderService",[3395,10273,10274],{"class":4715}," orderService",[3395,10276,4727],{"class":4708},[3395,10278,10279],{"class":3397,"line":3458},[3395,10280,6347],{"class":4708},[3395,10282,10283,10286,10288,10291],{"class":3397,"line":3464},[3395,10284,10285],{"class":4715},"        _orderService",[3395,10287,6088],{"class":4708},[3395,10289,10290],{"class":4715},"orderService",[3395,10292,6634],{"class":4708},[3395,10294,10295],{"class":3397,"line":3470},[3395,10296,6396],{"class":4708},[3395,10298,10299],{"class":3397,"line":3476},[3395,10300,3420],{"emptyLinePlaceholder":3419},[3395,10302,10303],{"class":3397,"line":3482},[3395,10304,10305],{"class":4690},"    \u002F\u002F Повертаємо SQSBatchResponse замість void\u002FTask\n",[3395,10307,10308],{"class":3397,"line":3487},[3395,10309,10310],{"class":4690},"    \u002F\u002F щоб Lambda знала, які записи потрібно повторити\n",[3395,10312,10313,10315,10317,10319,10321,10324,10326,10329],{"class":3397,"line":3493},[3395,10314,6326],{"class":4696},[3395,10316,6124],{"class":4696},[3395,10318,6127],{"class":4700},[3395,10320,6130],{"class":4708},[3395,10322,10323],{"class":4700},"SQSBatchResponse",[3395,10325,6136],{"class":4708},[3395,10327,10328],{"class":4704},"FunctionHandler",[3395,10330,6142],{"class":4708},[3395,10332,10333,10336,10339],{"class":3397,"line":3499},[3395,10334,10335],{"class":4700},"        SQSEvent",[3395,10337,10338],{"class":4715}," sqsEvent",[3395,10340,5084],{"class":4708},[3395,10342,10343,10345,10347],{"class":3397,"line":3505},[3395,10344,7899],{"class":4700},[3395,10346,4724],{"class":4715},[3395,10348,4727],{"class":4708},[3395,10350,10351],{"class":3397,"line":3511},[3395,10352,6347],{"class":4708},[3395,10354,10355,10357,10360,10362,10364,10367,10369,10371,10373,10376],{"class":3397,"line":3517},[3395,10356,7949],{"class":4696},[3395,10358,10359],{"class":4715}," batchItemFailures",[3395,10361,6088],{"class":4708},[3395,10363,6235],{"class":4696},[3395,10365,10366],{"class":4700}," List",[3395,10368,6130],{"class":4708},[3395,10370,10323],{"class":4700},[3395,10372,3860],{"class":4708},[3395,10374,10375],{"class":4700},"BatchItemFailure",[3395,10377,6370],{"class":4708},[3395,10379,10380],{"class":3397,"line":3523},[3395,10381,3420],{"emptyLinePlaceholder":3419},[3395,10383,10384],{"class":3397,"line":3529},[3395,10385,10386],{"class":4690},"        \u002F\u002F Обробляємо кожне повідомлення НЕЗАЛЕЖНО\n",[3395,10388,10389,10391,10393,10395,10398,10400,10402,10404,10406],{"class":3397,"line":3534},[3395,10390,9237],{"class":6221},[3395,10392,5956],{"class":4708},[3395,10394,9242],{"class":4696},[3395,10396,10397],{"class":4715}," message",[3395,10399,9247],{"class":6221},[3395,10401,10338],{"class":4715},[3395,10403,3860],{"class":4708},[3395,10405,8988],{"class":4715},[3395,10407,4727],{"class":4708},[3395,10409,10410],{"class":3397,"line":3539},[3395,10411,8192],{"class":4708},[3395,10413,10414],{"class":3397,"line":3545},[3395,10415,9403],{"class":6221},[3395,10417,10418],{"class":3397,"line":3551},[3395,10419,9408],{"class":4708},[3395,10421,10422,10424,10426,10428,10430,10432],{"class":3397,"line":3557},[3395,10423,9701],{"class":4715},[3395,10425,3860],{"class":4708},[3395,10427,4824],{"class":4715},[3395,10429,3860],{"class":4708},[3395,10431,4835],{"class":4704},[3395,10433,6142],{"class":4708},[3395,10435,10436,10439,10441,10443,10445,10448],{"class":3397,"line":3563},[3395,10437,10438],{"class":4888},"                    \"Processing SQS message: {MessageId}\"",[3395,10440,4719],{"class":4708},[3395,10442,8012],{"class":4715},[3395,10444,3860],{"class":4708},[3395,10446,10447],{"class":4715},"MessageId",[3395,10449,6522],{"class":4708},[3395,10451,10452],{"class":3397,"line":3569},[3395,10453,3420],{"emptyLinePlaceholder":3419},[3395,10455,10456,10458,10461,10463,10466,10468,10471,10473,10476,10478],{"class":3397,"line":3575},[3395,10457,9418],{"class":4696},[3395,10459,10460],{"class":4715}," order",[3395,10462,6088],{"class":4708},[3395,10464,10465],{"class":4715},"System",[3395,10467,3860],{"class":4708},[3395,10469,10470],{"class":4715},"Text",[3395,10472,3860],{"class":4708},[3395,10474,10475],{"class":4715},"Json",[3395,10477,3860],{"class":4708},[3395,10479,10480],{"class":4715},"JsonSerializer\n",[3395,10482,10483,10486,10489,10491,10494,10497,10499,10501,10504],{"class":3397,"line":3581},[3395,10484,10485],{"class":4708},"                    .",[3395,10487,10488],{"class":4704},"Deserialize",[3395,10490,6130],{"class":4708},[3395,10492,10493],{"class":4700},"OrderCreatedEvent",[3395,10495,10496],{"class":4708},">(",[3395,10498,8012],{"class":4715},[3395,10500,3860],{"class":4708},[3395,10502,10503],{"class":4715},"Body",[3395,10505,10506],{"class":4708},")!;\n",[3395,10508,10509],{"class":3397,"line":3586},[3395,10510,3420],{"emptyLinePlaceholder":3419},[3395,10512,10513,10515,10517,10519,10522,10524,10527],{"class":3397,"line":3591},[3395,10514,9678],{"class":4696},[3395,10516,10253],{"class":4715},[3395,10518,3860],{"class":4708},[3395,10520,10521],{"class":4704},"ProcessOrderAsync",[3395,10523,4709],{"class":4708},[3395,10525,10526],{"class":4715},"order",[3395,10528,6522],{"class":4708},[3395,10530,10531],{"class":3397,"line":3597},[3395,10532,3420],{"emptyLinePlaceholder":3419},[3395,10534,10535,10537,10539,10541,10543,10545],{"class":3397,"line":3603},[3395,10536,9701],{"class":4715},[3395,10538,3860],{"class":4708},[3395,10540,4824],{"class":4715},[3395,10542,3860],{"class":4708},[3395,10544,4835],{"class":4704},[3395,10546,6142],{"class":4708},[3395,10548,10549,10552,10554,10556,10558,10561],{"class":3397,"line":3609},[3395,10550,10551],{"class":4888},"                    \"Successfully processed order: {OrderId}\"",[3395,10553,4719],{"class":4708},[3395,10555,10526],{"class":4715},[3395,10557,3860],{"class":4708},[3395,10559,10560],{"class":4715},"OrderId",[3395,10562,6522],{"class":4708},[3395,10564,10565],{"class":3397,"line":3615},[3395,10566,8966],{"class":4708},[3395,10568,10569,10571,10573,10575,10577],{"class":3397,"line":3621},[3395,10570,9738],{"class":6221},[3395,10572,5956],{"class":4708},[3395,10574,9743],{"class":4700},[3395,10576,9746],{"class":4715},[3395,10578,4727],{"class":4708},[3395,10580,10581],{"class":3397,"line":3627},[3395,10582,9408],{"class":4708},[3395,10584,10585],{"class":3397,"line":3633},[3395,10586,10587],{"class":4690},"                \u002F\u002F НЕ перекидаємо виключення — додаємо до списку невдалих\n",[3395,10589,10590,10592,10594,10596,10598,10600,10602,10604],{"class":3397,"line":3638},[3395,10591,9701],{"class":4715},[3395,10593,3860],{"class":4708},[3395,10595,4824],{"class":4715},[3395,10597,3860],{"class":4708},[3395,10599,4841],{"class":4704},[3395,10601,4709],{"class":4708},[3395,10603,9770],{"class":4715},[3395,10605,5084],{"class":4708},[3395,10607,10608,10611,10613,10615,10617,10619],{"class":3397,"line":3643},[3395,10609,10610],{"class":4888},"                    \"Failed to process message {MessageId}\"",[3395,10612,4719],{"class":4708},[3395,10614,8012],{"class":4715},[3395,10616,3860],{"class":4708},[3395,10618,10447],{"class":4715},[3395,10620,6522],{"class":4708},[3395,10622,10623],{"class":3397,"line":3649},[3395,10624,3420],{"emptyLinePlaceholder":3419},[3395,10626,10627],{"class":3397,"line":3655},[3395,10628,10629],{"class":4690},"                \u002F\u002F Це повідомлення повернеться у SQS для повторної обробки\n",[3395,10631,10632,10635,10637,10640,10642,10644,10647,10649],{"class":3397,"line":3661},[3395,10633,10634],{"class":4715},"                batchItemFailures",[3395,10636,3860],{"class":4708},[3395,10638,10639],{"class":4704},"Add",[3395,10641,4709],{"class":4708},[3395,10643,6235],{"class":4696},[3395,10645,10646],{"class":4700}," SQSBatchResponse",[3395,10648,3860],{"class":4708},[3395,10650,10651],{"class":4700},"BatchItemFailure\n",[3395,10653,10654],{"class":3397,"line":3667},[3395,10655,9433],{"class":4708},[3395,10657,10658,10661,10663,10665,10667],{"class":3397,"line":3672},[3395,10659,10660],{"class":4715},"                    ItemIdentifier",[3395,10662,6088],{"class":4708},[3395,10664,8012],{"class":4715},[3395,10666,3860],{"class":4708},[3395,10668,10669],{"class":4715},"MessageId\n",[3395,10671,10672],{"class":3397,"line":8082},[3395,10673,10674],{"class":4708},"                });\n",[3395,10676,10677],{"class":3397,"line":8104},[3395,10678,8966],{"class":4708},[3395,10680,10681],{"class":3397,"line":8124},[3395,10682,8230],{"class":4708},[3395,10684,10685],{"class":3397,"line":8141},[3395,10686,3420],{"emptyLinePlaceholder":3419},[3395,10688,10689,10691,10693,10695,10697,10700,10702,10704],{"class":3397,"line":8150},[3395,10690,8037],{"class":6221},[3395,10692,4906],{"class":4696},[3395,10694,10646],{"class":4700},[3395,10696,6238],{"class":4708},[3395,10698,10699],{"class":4715},"BatchItemFailures",[3395,10701,6088],{"class":4708},[3395,10703,10149],{"class":4715},[3395,10705,10706],{"class":4708}," };\n",[3395,10708,10709],{"class":3397,"line":8155},[3395,10710,6396],{"class":4708},[3395,10712,10713],{"class":3397,"line":8161},[3395,10714,3479],{"class":4708},[3684,10716],{},[3704,10718,10720],{"id":10719},"тригер-eventbridge-планові-та-подієво-орієнтовані-задачі","Тригер EventBridge: планові та подієво-орієнтовані задачі",[3353,10722,10723,10726],{},[3359,10724,10725],{},"Amazon EventBridge"," (раніше CloudWatch Events) — це serverless шина подій, що дозволяє маршрутизувати події між AWS-сервісами та власними застосунками. З точки зору Lambda, EventBridge надає два ключових патерни:",[4867,10728,10729,10735],{},[4035,10730,10731,10734],{},[3359,10732,10733],{},"Scheduled Events (Cron)"," — виклик Lambda за розкладом: щохвилини, щогодини, за cron-виразом",[4035,10736,10737,10740],{},[3359,10738,10739],{},"Event Pattern Rules"," — виклик Lambda при настанні певної події в AWS-акаунті (наприклад, новий EC2 instance, зміна стану RDS, Custom Events від власних мікросервісів)",[3385,10742,10745],{"className":4681,"code":10743,"filename":10744,"language":4683,"meta":3390,"style":3390},"using Amazon.Lambda.Core;\nusing Amazon.Lambda.CloudWatchEvents.ScheduledEvents;\n\nnamespace Scheduler.Lambda;\n\npublic class ScheduledCleanupFunction\n{\n    private readonly ICleanupService _cleanupService;\n\n    public ScheduledCleanupFunction(ICleanupService cleanupService)\n    {\n        _cleanupService = cleanupService;\n    }\n\n    \u002F\u002F ScheduledEvent — типізована обгортка для EventBridge Scheduled Events\n    public async Task FunctionHandler(\n        ScheduledEvent scheduledEvent,\n        ILambdaContext context)\n    {\n        context.Logger.LogInformation(\n            \"Scheduled cleanup started. Time={Time}, Source={Source}\",\n            scheduledEvent.Time, scheduledEvent.Source);\n\n        \u002F\u002F Перевіряємо достатність часу до Timeout\n        \u002F\u002F Для завдань cleanup це критично\n        if (context.RemainingTime \u003C TimeSpan.FromMinutes(2))\n        {\n            context.Logger.LogWarning(\n                \"Insufficient time remaining ({Remaining}), skipping cleanup\",\n                context.RemainingTime);\n            return;\n        }\n\n        var result = await _cleanupService.CleanupExpiredSessionsAsync(\n            olderThan: TimeSpan.FromDays(30),\n            cancellationToken: CreateCancellationToken(context));\n\n        context.Logger.LogInformation(\n            \"Cleanup complete. Deleted={Count} sessions\", result.DeletedCount);\n    }\n\n    private static CancellationToken CreateCancellationToken(ILambdaContext context)\n    {\n        \u002F\u002F Автоматично скасовуємо операцію за 30 секунд до Timeout\n        var cts = new CancellationTokenSource(\n            context.RemainingTime - TimeSpan.FromSeconds(30));\n        return cts.Token;\n    }\n}\n","ScheduledCleanupFunction.cs",[3392,10746,10747,10763,10785,10789,10802,10806,10815,10819,10833,10837,10854,10858,10870,10874,10878,10883,10895,10905,10913,10917,10932,10939,10961,10965,10970,10975,11002,11006,11020,11027,11037,11043,11047,11051,11071,11092,11108,11112,11126,11143,11147,11151,11171,11175,11180,11196,11219,11232,11236],{"__ignoreMap":3390},[3395,10748,10749,10751,10753,10755,10757,10759,10761],{"class":3397,"line":3398},[3395,10750,7533],{"class":6221},[3395,10752,7536],{"class":4700},[3395,10754,3860],{"class":4708},[3395,10756,5754],{"class":4700},[3395,10758,3860],{"class":4708},[3395,10760,7583],{"class":4700},[3395,10762,6634],{"class":4708},[3395,10764,10765,10767,10769,10771,10773,10775,10778,10780,10783],{"class":3397,"line":3404},[3395,10766,7533],{"class":6221},[3395,10768,7536],{"class":4700},[3395,10770,3860],{"class":4708},[3395,10772,5754],{"class":4700},[3395,10774,3860],{"class":4708},[3395,10776,10777],{"class":4700},"CloudWatchEvents",[3395,10779,3860],{"class":4708},[3395,10781,10782],{"class":4700},"ScheduledEvents",[3395,10784,6634],{"class":4708},[3395,10786,10787],{"class":3397,"line":3410},[3395,10788,3420],{"emptyLinePlaceholder":3419},[3395,10790,10791,10793,10796,10798,10800],{"class":3397,"line":3416},[3395,10792,7658],{"class":4696},[3395,10794,10795],{"class":4700}," Scheduler",[3395,10797,3860],{"class":4708},[3395,10799,5754],{"class":4700},[3395,10801,6634],{"class":4708},[3395,10803,10804],{"class":3397,"line":3423},[3395,10805,3420],{"emptyLinePlaceholder":3419},[3395,10807,10808,10810,10812],{"class":3397,"line":3429},[3395,10809,4697],{"class":4696},[3395,10811,6314],{"class":4696},[3395,10813,10814],{"class":4700}," ScheduledCleanupFunction\n",[3395,10816,10817],{"class":3397,"line":3434},[3395,10818,5069],{"class":4708},[3395,10820,10821,10823,10825,10828,10831],{"class":3397,"line":3440},[3395,10822,7714],{"class":4696},[3395,10824,7717],{"class":4696},[3395,10826,10827],{"class":4700}," ICleanupService",[3395,10829,10830],{"class":4715}," _cleanupService",[3395,10832,6634],{"class":4708},[3395,10834,10835],{"class":3397,"line":3446},[3395,10836,3420],{"emptyLinePlaceholder":3419},[3395,10838,10839,10841,10844,10846,10849,10852],{"class":3397,"line":3452},[3395,10840,6326],{"class":4696},[3395,10842,10843],{"class":4704}," ScheduledCleanupFunction",[3395,10845,4709],{"class":4708},[3395,10847,10848],{"class":4700},"ICleanupService",[3395,10850,10851],{"class":4715}," cleanupService",[3395,10853,4727],{"class":4708},[3395,10855,10856],{"class":3397,"line":3458},[3395,10857,6347],{"class":4708},[3395,10859,10860,10863,10865,10868],{"class":3397,"line":3464},[3395,10861,10862],{"class":4715},"        _cleanupService",[3395,10864,6088],{"class":4708},[3395,10866,10867],{"class":4715},"cleanupService",[3395,10869,6634],{"class":4708},[3395,10871,10872],{"class":3397,"line":3470},[3395,10873,6396],{"class":4708},[3395,10875,10876],{"class":3397,"line":3476},[3395,10877,3420],{"emptyLinePlaceholder":3419},[3395,10879,10880],{"class":3397,"line":3482},[3395,10881,10882],{"class":4690},"    \u002F\u002F ScheduledEvent — типізована обгортка для EventBridge Scheduled Events\n",[3395,10884,10885,10887,10889,10891,10893],{"class":3397,"line":3487},[3395,10886,6326],{"class":4696},[3395,10888,6124],{"class":4696},[3395,10890,6127],{"class":4700},[3395,10892,4705],{"class":4704},[3395,10894,6142],{"class":4708},[3395,10896,10897,10900,10903],{"class":3397,"line":3493},[3395,10898,10899],{"class":4700},"        ScheduledEvent",[3395,10901,10902],{"class":4715}," scheduledEvent",[3395,10904,5084],{"class":4708},[3395,10906,10907,10909,10911],{"class":3397,"line":3499},[3395,10908,7899],{"class":4700},[3395,10910,4724],{"class":4715},[3395,10912,4727],{"class":4708},[3395,10914,10915],{"class":3397,"line":3505},[3395,10916,6347],{"class":4708},[3395,10918,10919,10922,10924,10926,10928,10930],{"class":3397,"line":3511},[3395,10920,10921],{"class":4715},"        context",[3395,10923,3860],{"class":4708},[3395,10925,4824],{"class":4715},[3395,10927,3860],{"class":4708},[3395,10929,4835],{"class":4704},[3395,10931,6142],{"class":4708},[3395,10933,10934,10937],{"class":3397,"line":3517},[3395,10935,10936],{"class":4888},"            \"Scheduled cleanup started. Time={Time}, Source={Source}\"",[3395,10938,5084],{"class":4708},[3395,10940,10941,10944,10946,10949,10951,10954,10956,10959],{"class":3397,"line":3523},[3395,10942,10943],{"class":4715},"            scheduledEvent",[3395,10945,3860],{"class":4708},[3395,10947,10948],{"class":4715},"Time",[3395,10950,4719],{"class":4708},[3395,10952,10953],{"class":4715},"scheduledEvent",[3395,10955,3860],{"class":4708},[3395,10957,10958],{"class":4715},"Source",[3395,10960,6522],{"class":4708},[3395,10962,10963],{"class":3397,"line":3529},[3395,10964,3420],{"emptyLinePlaceholder":3419},[3395,10966,10967],{"class":3397,"line":3534},[3395,10968,10969],{"class":4690},"        \u002F\u002F Перевіряємо достатність часу до Timeout\n",[3395,10971,10972],{"class":3397,"line":3539},[3395,10973,10974],{"class":4690},"        \u002F\u002F Для завдань cleanup це критично\n",[3395,10976,10977,10979,10981,10983,10985,10987,10989,10991,10993,10996,10998,11000],{"class":3397,"line":3545},[3395,10978,7979],{"class":6221},[3395,10980,5956],{"class":4708},[3395,10982,5896],{"class":4715},[3395,10984,3860],{"class":4708},[3395,10986,4812],{"class":4715},[3395,10988,6584],{"class":4708},[3395,10990,4813],{"class":4715},[3395,10992,3860],{"class":4708},[3395,10994,10995],{"class":4704},"FromMinutes",[3395,10997,4709],{"class":4708},[3395,10999,8184],{"class":5154},[3395,11001,6599],{"class":4708},[3395,11003,11004],{"class":3397,"line":3551},[3395,11005,8192],{"class":4708},[3395,11007,11008,11010,11012,11014,11016,11018],{"class":3397,"line":3557},[3395,11009,7929],{"class":4715},[3395,11011,3860],{"class":4708},[3395,11013,4824],{"class":4715},[3395,11015,3860],{"class":4708},[3395,11017,4838],{"class":4704},[3395,11019,6142],{"class":4708},[3395,11021,11022,11025],{"class":3397,"line":3563},[3395,11023,11024],{"class":4888},"                \"Insufficient time remaining ({Remaining}), skipping cleanup\"",[3395,11026,5084],{"class":4708},[3395,11028,11029,11031,11033,11035],{"class":3397,"line":3569},[3395,11030,9701],{"class":4715},[3395,11032,3860],{"class":4708},[3395,11034,4812],{"class":4715},[3395,11036,6522],{"class":4708},[3395,11038,11039,11041],{"class":3397,"line":3575},[3395,11040,7996],{"class":6221},[3395,11042,6634],{"class":4708},[3395,11044,11045],{"class":3397,"line":3581},[3395,11046,8230],{"class":4708},[3395,11048,11049],{"class":3397,"line":3586},[3395,11050,3420],{"emptyLinePlaceholder":3419},[3395,11052,11053,11055,11058,11060,11062,11064,11066,11069],{"class":3397,"line":3591},[3395,11054,7949],{"class":4696},[3395,11056,11057],{"class":4715}," result",[3395,11059,6088],{"class":4708},[3395,11061,7957],{"class":4696},[3395,11063,10830],{"class":4715},[3395,11065,3860],{"class":4708},[3395,11067,11068],{"class":4704},"CleanupExpiredSessionsAsync",[3395,11070,6142],{"class":4708},[3395,11072,11073,11076,11078,11080,11082,11085,11087,11089],{"class":3397,"line":3597},[3395,11074,11075],{"class":4715},"            olderThan",[3395,11077,5078],{"class":4708},[3395,11079,4813],{"class":4715},[3395,11081,3860],{"class":4708},[3395,11083,11084],{"class":4704},"FromDays",[3395,11086,4709],{"class":4708},[3395,11088,5167],{"class":5154},[3395,11090,11091],{"class":4708},"),\n",[3395,11093,11094,11097,11099,11102,11104,11106],{"class":3397,"line":3603},[3395,11095,11096],{"class":4715},"            cancellationToken",[3395,11098,5078],{"class":4708},[3395,11100,11101],{"class":4704},"CreateCancellationToken",[3395,11103,4709],{"class":4708},[3395,11105,5896],{"class":4715},[3395,11107,9340],{"class":4708},[3395,11109,11110],{"class":3397,"line":3609},[3395,11111,3420],{"emptyLinePlaceholder":3419},[3395,11113,11114,11116,11118,11120,11122,11124],{"class":3397,"line":3615},[3395,11115,10921],{"class":4715},[3395,11117,3860],{"class":4708},[3395,11119,4824],{"class":4715},[3395,11121,3860],{"class":4708},[3395,11123,4835],{"class":4704},[3395,11125,6142],{"class":4708},[3395,11127,11128,11131,11133,11136,11138,11141],{"class":3397,"line":3621},[3395,11129,11130],{"class":4888},"            \"Cleanup complete. Deleted={Count} sessions\"",[3395,11132,4719],{"class":4708},[3395,11134,11135],{"class":4715},"result",[3395,11137,3860],{"class":4708},[3395,11139,11140],{"class":4715},"DeletedCount",[3395,11142,6522],{"class":4708},[3395,11144,11145],{"class":3397,"line":3627},[3395,11146,6396],{"class":4708},[3395,11148,11149],{"class":3397,"line":3633},[3395,11150,3420],{"emptyLinePlaceholder":3419},[3395,11152,11153,11155,11157,11160,11163,11165,11167,11169],{"class":3397,"line":3638},[3395,11154,7714],{"class":4696},[3395,11156,9157],{"class":4696},[3395,11158,11159],{"class":4700}," CancellationToken",[3395,11161,11162],{"class":4704}," CreateCancellationToken",[3395,11164,4709],{"class":4708},[3395,11166,4667],{"class":4700},[3395,11168,4724],{"class":4715},[3395,11170,4727],{"class":4708},[3395,11172,11173],{"class":3397,"line":3643},[3395,11174,6347],{"class":4708},[3395,11176,11177],{"class":3397,"line":3649},[3395,11178,11179],{"class":4690},"        \u002F\u002F Автоматично скасовуємо операцію за 30 секунд до Timeout\n",[3395,11181,11182,11184,11187,11189,11191,11194],{"class":3397,"line":3655},[3395,11183,7949],{"class":4696},[3395,11185,11186],{"class":4715}," cts",[3395,11188,6088],{"class":4708},[3395,11190,6235],{"class":4696},[3395,11192,11193],{"class":4700}," CancellationTokenSource",[3395,11195,6142],{"class":4708},[3395,11197,11198,11200,11202,11204,11207,11209,11211,11213,11215,11217],{"class":3397,"line":3661},[3395,11199,7929],{"class":4715},[3395,11201,3860],{"class":4708},[3395,11203,4812],{"class":4715},[3395,11205,11206],{"class":4708}," - ",[3395,11208,4813],{"class":4715},[3395,11210,3860],{"class":4708},[3395,11212,6591],{"class":4704},[3395,11214,4709],{"class":4708},[3395,11216,5167],{"class":5154},[3395,11218,9340],{"class":4708},[3395,11220,11221,11223,11225,11227,11230],{"class":3397,"line":3667},[3395,11222,8037],{"class":6221},[3395,11224,11186],{"class":4715},[3395,11226,3860],{"class":4708},[3395,11228,11229],{"class":4715},"Token",[3395,11231,6634],{"class":4708},[3395,11233,11234],{"class":3397,"line":3672},[3395,11235,6396],{"class":4708},[3395,11237,11238],{"class":3397,"line":8082},[3395,11239,3479],{"class":4708},[3684,11241],{},[3348,11243,11245],{"id":11244},"environment-variables-та-secrets-management","Environment Variables та Secrets Management",[3704,11247,11249],{"id":11248},"environment-variables-зовнішня-конфігурація-функції","Environment Variables: зовнішня конфігурація функції",[3353,11251,11252,11255,11256,3860],{},[3359,11253,11254],{},"Environment Variables"," у Lambda виконують ту саму роль, що і у традиційних серверних застосунках: вони забезпечують механізм зовнішньої конфігурації без необхідності змінювати код функції. Lambda дозволяє визначити довільний набір пар ключ-значення, що стають доступними у коді через стандартний ",[3392,11257,11258],{},"Environment.GetEnvironmentVariable()",[3353,11260,11261],{},[3359,11262,11263],{},"Ключові характеристики Environment Variables у Lambda:",[4032,11265,11266,11269,11276,11282],{},[4035,11267,11268],{},"Зберігаються як частина конфігурації функції та автоматично присутні в кожному Execution Environment",[4035,11270,11271,11272,11275],{},"Значення ",[3359,11273,11274],{},"шифруються"," AWS KMS (за замовчуванням — AWS Managed Key, можна вказати власний KMS ключ)",[4035,11277,11278,11279],{},"Максимальний сумарний розмір усіх змінних — ",[3359,11280,11281],{},"4 KB",[4035,11283,11284],{},"Змінюються без необхідності нового деплойменту коду (але потребують нового Execution Environment — тобто спричиняють Cold Start)",[3353,11286,11287],{},[3359,11288,11289],{},"Доступ до Environment Variables з .NET:",[3385,11291,11294],{"className":4681,"code":11292,"filename":11293,"language":4683,"meta":3390,"style":3390},"namespace MyApi.Lambda;\n\n\u002F\u002F Рекомендована практика: типізований клас конфігурації\n\u002F\u002F замість прямих викликів Environment.GetEnvironmentVariable скрізь у коді\npublic sealed class LambdaConfiguration\n{\n    \u002F\u002F Назва таблиці DynamoDB — змінюється між mid\u002Fprod оточеннями\n    public string UsersTableName { get; } =\n        Environment.GetEnvironmentVariable(\"USERS_TABLE_NAME\")\n        ?? throw new InvalidOperationException(\n            \"USERS_TABLE_NAME environment variable is not set\");\n\n    \u002F\u002F URL зовнішнього API — різний для staging та production\n    public string PaymentApiBaseUrl { get; } =\n        Environment.GetEnvironmentVariable(\"PAYMENT_API_BASE_URL\")\n        ?? \"https:\u002F\u002Fapi.payment.example.com\";\n\n    \u002F\u002F Рівень логування\n    public string LogLevel { get; } =\n        Environment.GetEnvironmentVariable(\"LOG_LEVEL\") ?? \"Information\";\n\n    \u002F\u002F Feature flag\n    public bool EnableDetailedLogging { get; } =\n        bool.TryParse(\n            Environment.GetEnvironmentVariable(\"ENABLE_DETAILED_LOGGING\"),\n            out var value) && value;\n}\n","Configuration.cs",[3392,11295,11296,11308,11312,11317,11322,11334,11338,11343,11360,11376,11391,11398,11402,11407,11422,11437,11446,11450,11455,11470,11491,11495,11500,11516,11528,11544,11562],{"__ignoreMap":3390},[3395,11297,11298,11300,11302,11304,11306],{"class":3397,"line":3398},[3395,11299,7658],{"class":4696},[3395,11301,7661],{"class":4700},[3395,11303,3860],{"class":4708},[3395,11305,5754],{"class":4700},[3395,11307,6634],{"class":4708},[3395,11309,11310],{"class":3397,"line":3404},[3395,11311,3420],{"emptyLinePlaceholder":3419},[3395,11313,11314],{"class":3397,"line":3410},[3395,11315,11316],{"class":4690},"\u002F\u002F Рекомендована практика: типізований клас конфігурації\n",[3395,11318,11319],{"class":3397,"line":3416},[3395,11320,11321],{"class":4690},"\u002F\u002F замість прямих викликів Environment.GetEnvironmentVariable скрізь у коді\n",[3395,11323,11324,11326,11329,11331],{"class":3397,"line":3423},[3395,11325,4697],{"class":4696},[3395,11327,11328],{"class":4696}," sealed",[3395,11330,6314],{"class":4696},[3395,11332,11333],{"class":4700}," LambdaConfiguration\n",[3395,11335,11336],{"class":3397,"line":3429},[3395,11337,5069],{"class":4708},[3395,11339,11340],{"class":3397,"line":3434},[3395,11341,11342],{"class":4690},"    \u002F\u002F Назва таблиці DynamoDB — змінюється між mid\u002Fprod оточеннями\n",[3395,11344,11345,11347,11349,11352,11354,11357],{"class":3397,"line":3440},[3395,11346,6326],{"class":4696},[3395,11348,9184],{"class":4696},[3395,11350,11351],{"class":4715}," UsersTableName",[3395,11353,6238],{"class":4708},[3395,11355,11356],{"class":4696},"get",[3395,11358,11359],{"class":4708},"; } =\n",[3395,11361,11362,11365,11367,11369,11371,11374],{"class":3397,"line":3446},[3395,11363,11364],{"class":4715},"        Environment",[3395,11366,3860],{"class":4708},[3395,11368,8518],{"class":4704},[3395,11370,4709],{"class":4708},[3395,11372,11373],{"class":4888},"\"USERS_TABLE_NAME\"",[3395,11375,4727],{"class":4708},[3395,11377,11378,11381,11384,11386,11389],{"class":3397,"line":3452},[3395,11379,11380],{"class":4708},"        ?? ",[3395,11382,11383],{"class":6221},"throw",[3395,11385,4906],{"class":4696},[3395,11387,11388],{"class":4700}," InvalidOperationException",[3395,11390,6142],{"class":4708},[3395,11392,11393,11396],{"class":3397,"line":3458},[3395,11394,11395],{"class":4888},"            \"USERS_TABLE_NAME environment variable is not set\"",[3395,11397,6522],{"class":4708},[3395,11399,11400],{"class":3397,"line":3464},[3395,11401,3420],{"emptyLinePlaceholder":3419},[3395,11403,11404],{"class":3397,"line":3470},[3395,11405,11406],{"class":4690},"    \u002F\u002F URL зовнішнього API — різний для staging та production\n",[3395,11408,11409,11411,11413,11416,11418,11420],{"class":3397,"line":3476},[3395,11410,6326],{"class":4696},[3395,11412,9184],{"class":4696},[3395,11414,11415],{"class":4715}," PaymentApiBaseUrl",[3395,11417,6238],{"class":4708},[3395,11419,11356],{"class":4696},[3395,11421,11359],{"class":4708},[3395,11423,11424,11426,11428,11430,11432,11435],{"class":3397,"line":3482},[3395,11425,11364],{"class":4715},[3395,11427,3860],{"class":4708},[3395,11429,8518],{"class":4704},[3395,11431,4709],{"class":4708},[3395,11433,11434],{"class":4888},"\"PAYMENT_API_BASE_URL\"",[3395,11436,4727],{"class":4708},[3395,11438,11439,11441,11444],{"class":3397,"line":3487},[3395,11440,11380],{"class":4708},[3395,11442,11443],{"class":4888},"\"https:\u002F\u002Fapi.payment.example.com\"",[3395,11445,6634],{"class":4708},[3395,11447,11448],{"class":3397,"line":3493},[3395,11449,3420],{"emptyLinePlaceholder":3419},[3395,11451,11452],{"class":3397,"line":3499},[3395,11453,11454],{"class":4690},"    \u002F\u002F Рівень логування\n",[3395,11456,11457,11459,11461,11464,11466,11468],{"class":3397,"line":3505},[3395,11458,6326],{"class":4696},[3395,11460,9184],{"class":4696},[3395,11462,11463],{"class":4715}," LogLevel",[3395,11465,6238],{"class":4708},[3395,11467,11356],{"class":4696},[3395,11469,11359],{"class":4708},[3395,11471,11472,11474,11476,11478,11480,11483,11486,11489],{"class":3397,"line":3511},[3395,11473,11364],{"class":4715},[3395,11475,3860],{"class":4708},[3395,11477,8518],{"class":4704},[3395,11479,4709],{"class":4708},[3395,11481,11482],{"class":4888},"\"LOG_LEVEL\"",[3395,11484,11485],{"class":4708},") ?? ",[3395,11487,11488],{"class":4888},"\"Information\"",[3395,11490,6634],{"class":4708},[3395,11492,11493],{"class":3397,"line":3517},[3395,11494,3420],{"emptyLinePlaceholder":3419},[3395,11496,11497],{"class":3397,"line":3523},[3395,11498,11499],{"class":4690},"    \u002F\u002F Feature flag\n",[3395,11501,11502,11504,11507,11510,11512,11514],{"class":3397,"line":3529},[3395,11503,6326],{"class":4696},[3395,11505,11506],{"class":4696}," bool",[3395,11508,11509],{"class":4715}," EnableDetailedLogging",[3395,11511,6238],{"class":4708},[3395,11513,11356],{"class":4696},[3395,11515,11359],{"class":4708},[3395,11517,11518,11521,11523,11526],{"class":3397,"line":3534},[3395,11519,11520],{"class":4696},"        bool",[3395,11522,3860],{"class":4708},[3395,11524,11525],{"class":4704},"TryParse",[3395,11527,6142],{"class":4708},[3395,11529,11530,11533,11535,11537,11539,11542],{"class":3397,"line":3539},[3395,11531,11532],{"class":4715},"            Environment",[3395,11534,3860],{"class":4708},[3395,11536,8518],{"class":4704},[3395,11538,4709],{"class":4708},[3395,11540,11541],{"class":4888},"\"ENABLE_DETAILED_LOGGING\"",[3395,11543,11091],{"class":4708},[3395,11545,11546,11549,11551,11554,11557,11560],{"class":3397,"line":3545},[3395,11547,11548],{"class":4696},"            out",[3395,11550,9472],{"class":4696},[3395,11552,11553],{"class":4715}," value",[3395,11555,11556],{"class":4708},") && ",[3395,11558,11559],{"class":4715},"value",[3395,11561,6634],{"class":4708},[3395,11563,11564],{"class":3397,"line":3551},[3395,11565,3479],{"class":4708},[4359,11567,11568,11571,11572,11575,11576,11579],{},[3359,11569,11570],{},"Чутливі дані у Environment Variables."," Хоча AWS шифрує значення Environment Variables «у спокої» (at rest), вони відображаються у відкритому вигляді у консолі AWS та через AWS CLI для будь-кого з правами ",[3392,11573,11574],{},"lambda:GetFunctionConfiguration",". Паролі, API ключі та токени ",[3359,11577,11578],{},"не слід"," зберігати у Environment Variables у відкритому вигляді. Для секретів використовуйте AWS Secrets Manager або AWS Parameter Store (SSM).",[3684,11581],{},[3704,11583,11585],{"id":11584},"aws-secrets-manager-безпечне-зберігання-секретів","AWS Secrets Manager: безпечне зберігання секретів",[3353,11587,11588,11591],{},[3359,11589,11590],{},"AWS Secrets Manager"," — це спеціалізований сервіс для зберігання, ротації та надання доступу до секретних значень: паролів баз даних, API ключів, OAuth токенів. На відміну від Environment Variables, Secrets Manager:",[4032,11593,11594,11601,11608,11615],{},[4035,11595,11596,11597,11600],{},"Підтримує ",[3359,11598,11599],{},"автоматичну ротацію"," секрету (наприклад, щомісячне автоматичне оновлення пароля RDS)",[4035,11602,11603,11604,11607],{},"Зберігає ",[3359,11605,11606],{},"версії"," секрету та дозволяє атомарне оновлення без простою",[4035,11609,11610,11611,11614],{},"Надає ",[3359,11612,11613],{},"аудит доступу"," через CloudTrail",[4035,11616,11617],{},"Інтегрується з IAM для гранулярного контролю доступу до конкретних секретів",[3382,11619,11620],{},[3385,11621,11623],{"className":3387,"code":11622,"language":3389,"meta":3390,"style":3390},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\ntitle \"Lambda + Secrets Manager: безпечне отримання секретів\"\n\nparticipant \"Lambda\\n(Cold Start)\" as LAM #d1fae5\nparticipant \"AWS Secrets Manager\" as SM #fef3c7\nparticipant \"AWS KMS\\n(шифрування)\" as KMS #dbeafe\nparticipant \"Amazon RDS\\nPostgreSQL\" as RDS #f3e8ff\n\nnote over LAM : Init фаза (Cold Start)\n\nLAM -> SM : GetSecretValue\\n(\"prod\u002Fmyapp\u002Fdb-password\")\nSM -> KMS : Decrypt(encrypted_secret)\nKMS --> SM : Розшифроване значення\nSM --> LAM : {\"username\":\"app_user\",\\n\"password\":\"S3cr3t!Passw0rd\",\\n\"host\":\"db.cluster...rds.amazonaws.com\",\\n\"port\":5432}\n\nLAM -> LAM : Створити connection string\\nПідключитися до RDS\\n(зберегти підключення як static)\n\nnote over LAM : Warm Start (наступні виклики)\nLAM -> RDS : Використовує збережене підключення\\n(Secrets Manager НЕ викликається повторно!)\n\nnote right of LAM\n  ВАЖЛИВО: кешуємо секрет у пам'яті!\n  Виклик Secrets Manager при кожному\n  запиті = +10-50ms latency та\n  додаткові витрати (~$0.05\u002F10K calls)\nend note\n\n@enduml\n",[3392,11624,11625,11629,11633,11637,11641,11646,11650,11655,11660,11665,11670,11674,11679,11683,11688,11693,11698,11703,11707,11712,11716,11721,11726,11730,11735,11740,11745,11750,11755,11759,11763],{"__ignoreMap":3390},[3395,11626,11627],{"class":3397,"line":3398},[3395,11628,3401],{},[3395,11630,11631],{"class":3397,"line":3404},[3395,11632,3407],{},[3395,11634,11635],{"class":3397,"line":3410},[3395,11636,3413],{},[3395,11638,11639],{"class":3397,"line":3416},[3395,11640,3420],{"emptyLinePlaceholder":3419},[3395,11642,11643],{"class":3397,"line":3423},[3395,11644,11645],{},"title \"Lambda + Secrets Manager: безпечне отримання секретів\"\n",[3395,11647,11648],{"class":3397,"line":3429},[3395,11649,3420],{"emptyLinePlaceholder":3419},[3395,11651,11652],{"class":3397,"line":3434},[3395,11653,11654],{},"participant \"Lambda\\n(Cold Start)\" as LAM #d1fae5\n",[3395,11656,11657],{"class":3397,"line":3440},[3395,11658,11659],{},"participant \"AWS Secrets Manager\" as SM #fef3c7\n",[3395,11661,11662],{"class":3397,"line":3446},[3395,11663,11664],{},"participant \"AWS KMS\\n(шифрування)\" as KMS #dbeafe\n",[3395,11666,11667],{"class":3397,"line":3452},[3395,11668,11669],{},"participant \"Amazon RDS\\nPostgreSQL\" as RDS #f3e8ff\n",[3395,11671,11672],{"class":3397,"line":3458},[3395,11673,3420],{"emptyLinePlaceholder":3419},[3395,11675,11676],{"class":3397,"line":3464},[3395,11677,11678],{},"note over LAM : Init фаза (Cold Start)\n",[3395,11680,11681],{"class":3397,"line":3470},[3395,11682,3420],{"emptyLinePlaceholder":3419},[3395,11684,11685],{"class":3397,"line":3476},[3395,11686,11687],{},"LAM -> SM : GetSecretValue\\n(\"prod\u002Fmyapp\u002Fdb-password\")\n",[3395,11689,11690],{"class":3397,"line":3482},[3395,11691,11692],{},"SM -> KMS : Decrypt(encrypted_secret)\n",[3395,11694,11695],{"class":3397,"line":3487},[3395,11696,11697],{},"KMS --> SM : Розшифроване значення\n",[3395,11699,11700],{"class":3397,"line":3493},[3395,11701,11702],{},"SM --> LAM : {\"username\":\"app_user\",\\n\"password\":\"S3cr3t!Passw0rd\",\\n\"host\":\"db.cluster...rds.amazonaws.com\",\\n\"port\":5432}\n",[3395,11704,11705],{"class":3397,"line":3499},[3395,11706,3420],{"emptyLinePlaceholder":3419},[3395,11708,11709],{"class":3397,"line":3505},[3395,11710,11711],{},"LAM -> LAM : Створити connection string\\nПідключитися до RDS\\n(зберегти підключення як static)\n",[3395,11713,11714],{"class":3397,"line":3511},[3395,11715,3420],{"emptyLinePlaceholder":3419},[3395,11717,11718],{"class":3397,"line":3517},[3395,11719,11720],{},"note over LAM : Warm Start (наступні виклики)\n",[3395,11722,11723],{"class":3397,"line":3523},[3395,11724,11725],{},"LAM -> RDS : Використовує збережене підключення\\n(Secrets Manager НЕ викликається повторно!)\n",[3395,11727,11728],{"class":3397,"line":3529},[3395,11729,3420],{"emptyLinePlaceholder":3419},[3395,11731,11732],{"class":3397,"line":3534},[3395,11733,11734],{},"note right of LAM\n",[3395,11736,11737],{"class":3397,"line":3539},[3395,11738,11739],{},"  ВАЖЛИВО: кешуємо секрет у пам'яті!\n",[3395,11741,11742],{"class":3397,"line":3545},[3395,11743,11744],{},"  Виклик Secrets Manager при кожному\n",[3395,11746,11747],{"class":3397,"line":3551},[3395,11748,11749],{},"  запиті = +10-50ms latency та\n",[3395,11751,11752],{"class":3397,"line":3557},[3395,11753,11754],{},"  додаткові витрати (~$0.05\u002F10K calls)\n",[3395,11756,11757],{"class":3397,"line":3563},[3395,11758,4215],{},[3395,11760,11761],{"class":3397,"line":3569},[3395,11762,3420],{"emptyLinePlaceholder":3419},[3395,11764,11765],{"class":3397,"line":3575},[3395,11766,3675],{},[3353,11768,11769],{},[3359,11770,11771],{},"Реалізація безпечного отримання секрету з кешуванням у .NET:",[3385,11773,11776],{"className":4681,"code":11774,"filename":11775,"language":4683,"meta":3390,"style":3390},"using Amazon.SecretsManager;\nusing Amazon.SecretsManager.Model;\nusing System.Text.Json;\n\nnamespace MyApi.Lambda.Infrastructure;\n\npublic sealed class SecretsManagerService : ISecretsManagerService\n{\n    private readonly IAmazonSecretsManager _client;\n\n    \u002F\u002F Кеш секретів — статичний, живе протягом усього Execution Environment\n    \u002F\u002F Ключ: ARN секрету, Значення: (розшифроване значення, час кешування)\n    private static readonly Dictionary\u003Cstring, (string Value, DateTime CachedAt)>\n        _secretsCache = new();\n\n    \u002F\u002F Час жизні кешу — 5 хвилин\n    \u002F\u002F Довше = менше витрат, але затримка оновлення при ротації\n    private static readonly TimeSpan CacheTtl = TimeSpan.FromMinutes(5);\n\n    public SecretsManagerService(IAmazonSecretsManager client)\n    {\n        _client = client;\n    }\n\n    public async Task\u003CT> GetSecretAsync\u003CT>(string secretArn) where T : class\n    {\n        \u002F\u002F Перевіряємо кеш\n        if (_secretsCache.TryGetValue(secretArn, out var cached))\n        {\n            if (DateTime.UtcNow - cached.CachedAt \u003C CacheTtl)\n                return JsonSerializer.Deserialize\u003CT>(cached.Value)!;\n        }\n\n        \u002F\u002F Запит до Secrets Manager (лише при Cache Miss або протермінованому кеші)\n        var request = new GetSecretValueRequest { SecretId = secretArn };\n        var response = await _client.GetSecretValueAsync(request);\n        var secretValue = response.SecretString;\n\n        \u002F\u002F Оновлюємо кеш\n        _secretsCache[secretArn] = (secretValue, DateTime.UtcNow);\n\n        return JsonSerializer.Deserialize\u003CT>(secretValue)!;\n    }\n}\n\n\u002F\u002F Типізований record для секрету бази даних\npublic record DatabaseSecret(\n    string Username,\n    string Password,\n    string Host,\n    int Port,\n    string DbName)\n{\n    public string ToConnectionString() =>\n        $\"Host={Host};Port={Port};Database={DbName};\" +\n        $\"Username={Username};Password={Password};SSL Mode=Require;\";\n}\n","SecretsManager.cs",[3392,11777,11778,11791,11807,11824,11828,11845,11849,11866,11870,11884,11888,11893,11898,11925,11936,11940,11945,11950,11979,11983,11999,12003,12014,12018,12022,12064,12068,12073,12104,12108,12139,12166,12170,12174,12179,12203,12226,12244,12248,12253,12277,12281,12301,12305,12309,12313,12318,12329,12339,12348,12357,12367,12376,12380,12392,12430,12457],{"__ignoreMap":3390},[3395,11779,11780,11782,11784,11786,11789],{"class":3397,"line":3398},[3395,11781,7533],{"class":6221},[3395,11783,7536],{"class":4700},[3395,11785,3860],{"class":4708},[3395,11787,11788],{"class":4700},"SecretsManager",[3395,11790,6634],{"class":4708},[3395,11792,11793,11795,11797,11799,11801,11803,11805],{"class":3397,"line":3404},[3395,11794,7533],{"class":6221},[3395,11796,7536],{"class":4700},[3395,11798,3860],{"class":4708},[3395,11800,11788],{"class":4700},[3395,11802,3860],{"class":4708},[3395,11804,9061],{"class":4700},[3395,11806,6634],{"class":4708},[3395,11808,11809,11811,11814,11816,11818,11820,11822],{"class":3397,"line":3410},[3395,11810,7533],{"class":6221},[3395,11812,11813],{"class":4700}," System",[3395,11815,3860],{"class":4708},[3395,11817,10470],{"class":4700},[3395,11819,3860],{"class":4708},[3395,11821,10475],{"class":4700},[3395,11823,6634],{"class":4708},[3395,11825,11826],{"class":3397,"line":3416},[3395,11827,3420],{"emptyLinePlaceholder":3419},[3395,11829,11830,11832,11834,11836,11838,11840,11843],{"class":3397,"line":3423},[3395,11831,7658],{"class":4696},[3395,11833,7661],{"class":4700},[3395,11835,3860],{"class":4708},[3395,11837,5754],{"class":4700},[3395,11839,3860],{"class":4708},[3395,11841,11842],{"class":4700},"Infrastructure",[3395,11844,6634],{"class":4708},[3395,11846,11847],{"class":3397,"line":3429},[3395,11848,3420],{"emptyLinePlaceholder":3419},[3395,11850,11851,11853,11855,11857,11860,11863],{"class":3397,"line":3434},[3395,11852,4697],{"class":4696},[3395,11854,11328],{"class":4696},[3395,11856,6314],{"class":4696},[3395,11858,11859],{"class":4700}," SecretsManagerService",[3395,11861,11862],{"class":4708}," : ",[3395,11864,11865],{"class":4700},"ISecretsManagerService\n",[3395,11867,11868],{"class":3397,"line":3440},[3395,11869,5069],{"class":4708},[3395,11871,11872,11874,11876,11879,11882],{"class":3397,"line":3446},[3395,11873,7714],{"class":4696},[3395,11875,7717],{"class":4696},[3395,11877,11878],{"class":4700}," IAmazonSecretsManager",[3395,11880,11881],{"class":4715}," _client",[3395,11883,6634],{"class":4708},[3395,11885,11886],{"class":3397,"line":3452},[3395,11887,3420],{"emptyLinePlaceholder":3419},[3395,11889,11890],{"class":3397,"line":3458},[3395,11891,11892],{"class":4690},"    \u002F\u002F Кеш секретів — статичний, живе протягом усього Execution Environment\n",[3395,11894,11895],{"class":3397,"line":3464},[3395,11896,11897],{"class":4690},"    \u002F\u002F Ключ: ARN секрету, Значення: (розшифроване значення, час кешування)\n",[3395,11899,11900,11902,11904,11906,11909,11911,11914,11916,11919,11922],{"class":3397,"line":3470},[3395,11901,7714],{"class":4696},[3395,11903,9157],{"class":4696},[3395,11905,7717],{"class":4696},[3395,11907,11908],{"class":4708}," Dictionary\u003Cstring, (",[3395,11910,3954],{"class":4696},[3395,11912,11913],{"class":4715}," Value",[3395,11915,4719],{"class":4708},[3395,11917,11918],{"class":4715},"DateTime",[3395,11920,11921],{"class":4715}," CachedAt",[3395,11923,11924],{"class":4708},")>\n",[3395,11926,11927,11930,11932,11934],{"class":3397,"line":3476},[3395,11928,11929],{"class":4715},"        _secretsCache",[3395,11931,6088],{"class":4708},[3395,11933,6235],{"class":4696},[3395,11935,8224],{"class":4708},[3395,11937,11938],{"class":3397,"line":3482},[3395,11939,3420],{"emptyLinePlaceholder":3419},[3395,11941,11942],{"class":3397,"line":3487},[3395,11943,11944],{"class":4690},"    \u002F\u002F Час жизні кешу — 5 хвилин\n",[3395,11946,11947],{"class":3397,"line":3493},[3395,11948,11949],{"class":4690},"    \u002F\u002F Довше = менше витрат, але затримка оновлення при ротації\n",[3395,11951,11952,11954,11956,11958,11961,11964,11966,11968,11970,11972,11974,11977],{"class":3397,"line":3499},[3395,11953,7714],{"class":4696},[3395,11955,9157],{"class":4696},[3395,11957,7717],{"class":4696},[3395,11959,11960],{"class":4700}," TimeSpan",[3395,11962,11963],{"class":4715}," CacheTtl",[3395,11965,6088],{"class":4708},[3395,11967,4813],{"class":4715},[3395,11969,3860],{"class":4708},[3395,11971,10995],{"class":4704},[3395,11973,4709],{"class":4708},[3395,11975,11976],{"class":5154},"5",[3395,11978,6522],{"class":4708},[3395,11980,11981],{"class":3397,"line":3505},[3395,11982,3420],{"emptyLinePlaceholder":3419},[3395,11984,11985,11987,11989,11991,11994,11997],{"class":3397,"line":3511},[3395,11986,6326],{"class":4696},[3395,11988,11859],{"class":4704},[3395,11990,4709],{"class":4708},[3395,11992,11993],{"class":4700},"IAmazonSecretsManager",[3395,11995,11996],{"class":4715}," client",[3395,11998,4727],{"class":4708},[3395,12000,12001],{"class":3397,"line":3517},[3395,12002,6347],{"class":4708},[3395,12004,12005,12008,12010,12012],{"class":3397,"line":3523},[3395,12006,12007],{"class":4715},"        _client",[3395,12009,6088],{"class":4708},[3395,12011,8484],{"class":4715},[3395,12013,6634],{"class":4708},[3395,12015,12016],{"class":3397,"line":3529},[3395,12017,6396],{"class":4708},[3395,12019,12020],{"class":3397,"line":3534},[3395,12021,3420],{"emptyLinePlaceholder":3419},[3395,12023,12024,12026,12028,12030,12032,12035,12037,12040,12042,12044,12046,12048,12051,12053,12056,12059,12061],{"class":3397,"line":3539},[3395,12025,6326],{"class":4696},[3395,12027,6124],{"class":4696},[3395,12029,6127],{"class":4700},[3395,12031,6130],{"class":4708},[3395,12033,12034],{"class":4700},"T",[3395,12036,6136],{"class":4708},[3395,12038,12039],{"class":4704},"GetSecretAsync",[3395,12041,6130],{"class":4708},[3395,12043,12034],{"class":4700},[3395,12045,10496],{"class":4708},[3395,12047,3954],{"class":4696},[3395,12049,12050],{"class":4715}," secretArn",[3395,12052,6204],{"class":4708},[3395,12054,12055],{"class":4696},"where",[3395,12057,12058],{"class":4700}," T",[3395,12060,11862],{"class":4708},[3395,12062,12063],{"class":4696},"class\n",[3395,12065,12066],{"class":3397,"line":3545},[3395,12067,6347],{"class":4708},[3395,12069,12070],{"class":3397,"line":3551},[3395,12071,12072],{"class":4690},"        \u002F\u002F Перевіряємо кеш\n",[3395,12074,12075,12077,12079,12082,12084,12087,12089,12092,12094,12097,12099,12102],{"class":3397,"line":3557},[3395,12076,7979],{"class":6221},[3395,12078,5956],{"class":4708},[3395,12080,12081],{"class":4715},"_secretsCache",[3395,12083,3860],{"class":4708},[3395,12085,12086],{"class":4704},"TryGetValue",[3395,12088,4709],{"class":4708},[3395,12090,12091],{"class":4715},"secretArn",[3395,12093,4719],{"class":4708},[3395,12095,12096],{"class":4696},"out",[3395,12098,9472],{"class":4696},[3395,12100,12101],{"class":4715}," cached",[3395,12103,6599],{"class":4708},[3395,12105,12106],{"class":3397,"line":3563},[3395,12107,8192],{"class":4708},[3395,12109,12110,12113,12115,12117,12119,12122,12124,12127,12129,12132,12134,12137],{"class":3397,"line":3569},[3395,12111,12112],{"class":6221},"            if",[3395,12114,5956],{"class":4708},[3395,12116,11918],{"class":4715},[3395,12118,3860],{"class":4708},[3395,12120,12121],{"class":4715},"UtcNow",[3395,12123,11206],{"class":4708},[3395,12125,12126],{"class":4715},"cached",[3395,12128,3860],{"class":4708},[3395,12130,12131],{"class":4715},"CachedAt",[3395,12133,6584],{"class":4708},[3395,12135,12136],{"class":4715},"CacheTtl",[3395,12138,4727],{"class":4708},[3395,12140,12141,12144,12147,12149,12151,12153,12155,12157,12159,12161,12164],{"class":3397,"line":3575},[3395,12142,12143],{"class":6221},"                return",[3395,12145,12146],{"class":4715}," JsonSerializer",[3395,12148,3860],{"class":4708},[3395,12150,10488],{"class":4704},[3395,12152,6130],{"class":4708},[3395,12154,12034],{"class":4700},[3395,12156,10496],{"class":4708},[3395,12158,12126],{"class":4715},[3395,12160,3860],{"class":4708},[3395,12162,12163],{"class":4715},"Value",[3395,12165,10506],{"class":4708},[3395,12167,12168],{"class":3397,"line":3581},[3395,12169,8230],{"class":4708},[3395,12171,12172],{"class":3397,"line":3586},[3395,12173,3420],{"emptyLinePlaceholder":3419},[3395,12175,12176],{"class":3397,"line":3591},[3395,12177,12178],{"class":4690},"        \u002F\u002F Запит до Secrets Manager (лише при Cache Miss або протермінованому кеші)\n",[3395,12180,12181,12183,12185,12187,12189,12192,12194,12197,12199,12201],{"class":3397,"line":3597},[3395,12182,7949],{"class":4696},[3395,12184,6192],{"class":4715},[3395,12186,6088],{"class":4708},[3395,12188,6235],{"class":4696},[3395,12190,12191],{"class":4700}," GetSecretValueRequest",[3395,12193,6238],{"class":4708},[3395,12195,12196],{"class":4715},"SecretId",[3395,12198,6088],{"class":4708},[3395,12200,12091],{"class":4715},[3395,12202,10706],{"class":4708},[3395,12204,12205,12207,12209,12211,12213,12215,12217,12220,12222,12224],{"class":3397,"line":3603},[3395,12206,7949],{"class":4696},[3395,12208,9475],{"class":4715},[3395,12210,6088],{"class":4708},[3395,12212,7957],{"class":4696},[3395,12214,11881],{"class":4715},[3395,12216,3860],{"class":4708},[3395,12218,12219],{"class":4704},"GetSecretValueAsync",[3395,12221,4709],{"class":4708},[3395,12223,6265],{"class":4715},[3395,12225,6522],{"class":4708},[3395,12227,12228,12230,12233,12235,12237,12239,12242],{"class":3397,"line":3609},[3395,12229,7949],{"class":4696},[3395,12231,12232],{"class":4715}," secretValue",[3395,12234,6088],{"class":4708},[3395,12236,9507],{"class":4715},[3395,12238,3860],{"class":4708},[3395,12240,12241],{"class":4715},"SecretString",[3395,12243,6634],{"class":4708},[3395,12245,12246],{"class":3397,"line":3615},[3395,12247,3420],{"emptyLinePlaceholder":3419},[3395,12249,12250],{"class":3397,"line":3621},[3395,12251,12252],{"class":4690},"        \u002F\u002F Оновлюємо кеш\n",[3395,12254,12255,12257,12259,12261,12264,12267,12269,12271,12273,12275],{"class":3397,"line":3627},[3395,12256,11929],{"class":4715},[3395,12258,5731],{"class":4708},[3395,12260,12091],{"class":4715},[3395,12262,12263],{"class":4708},"] = (",[3395,12265,12266],{"class":4715},"secretValue",[3395,12268,4719],{"class":4708},[3395,12270,11918],{"class":4715},[3395,12272,3860],{"class":4708},[3395,12274,12121],{"class":4715},[3395,12276,6522],{"class":4708},[3395,12278,12279],{"class":3397,"line":3633},[3395,12280,3420],{"emptyLinePlaceholder":3419},[3395,12282,12283,12285,12287,12289,12291,12293,12295,12297,12299],{"class":3397,"line":3638},[3395,12284,8037],{"class":6221},[3395,12286,12146],{"class":4715},[3395,12288,3860],{"class":4708},[3395,12290,10488],{"class":4704},[3395,12292,6130],{"class":4708},[3395,12294,12034],{"class":4700},[3395,12296,10496],{"class":4708},[3395,12298,12266],{"class":4715},[3395,12300,10506],{"class":4708},[3395,12302,12303],{"class":3397,"line":3643},[3395,12304,6396],{"class":4708},[3395,12306,12307],{"class":3397,"line":3649},[3395,12308,3479],{"class":4708},[3395,12310,12311],{"class":3397,"line":3655},[3395,12312,3420],{"emptyLinePlaceholder":3419},[3395,12314,12315],{"class":3397,"line":3661},[3395,12316,12317],{"class":4690},"\u002F\u002F Типізований record для секрету бази даних\n",[3395,12319,12320,12322,12324,12327],{"class":3397,"line":3667},[3395,12321,4697],{"class":4696},[3395,12323,6686],{"class":4696},[3395,12325,12326],{"class":4700}," DatabaseSecret",[3395,12328,6142],{"class":4708},[3395,12330,12331,12334,12337],{"class":3397,"line":3672},[3395,12332,12333],{"class":4696},"    string",[3395,12335,12336],{"class":4715}," Username",[3395,12338,5084],{"class":4708},[3395,12340,12341,12343,12346],{"class":3397,"line":8082},[3395,12342,12333],{"class":4696},[3395,12344,12345],{"class":4715}," Password",[3395,12347,5084],{"class":4708},[3395,12349,12350,12352,12355],{"class":3397,"line":8104},[3395,12351,12333],{"class":4696},[3395,12353,12354],{"class":4715}," Host",[3395,12356,5084],{"class":4708},[3395,12358,12359,12362,12365],{"class":3397,"line":8124},[3395,12360,12361],{"class":4696},"    int",[3395,12363,12364],{"class":4715}," Port",[3395,12366,5084],{"class":4708},[3395,12368,12369,12371,12374],{"class":3397,"line":8141},[3395,12370,12333],{"class":4696},[3395,12372,12373],{"class":4715}," DbName",[3395,12375,4727],{"class":4708},[3395,12377,12378],{"class":3397,"line":8150},[3395,12379,5069],{"class":4708},[3395,12381,12382,12384,12386,12389],{"class":3397,"line":8155},[3395,12383,6326],{"class":4696},[3395,12385,9184],{"class":4696},[3395,12387,12388],{"class":4704}," ToConnectionString",[3395,12390,12391],{"class":4708},"() =>\n",[3395,12393,12394,12397,12399,12402,12404,12407,12409,12412,12414,12417,12419,12422,12424,12427],{"class":3397,"line":8161},[3395,12395,12396],{"class":4888},"        $\"Host=",[3395,12398,6507],{"class":6506},[3395,12400,12401],{"class":4715},"Host",[3395,12403,6516],{"class":6506},[3395,12405,12406],{"class":4888},";Port=",[3395,12408,6507],{"class":6506},[3395,12410,12411],{"class":4715},"Port",[3395,12413,6516],{"class":6506},[3395,12415,12416],{"class":4888},";Database=",[3395,12418,6507],{"class":6506},[3395,12420,12421],{"class":4715},"DbName",[3395,12423,6516],{"class":6506},[3395,12425,12426],{"class":4888},";\"",[3395,12428,12429],{"class":4708}," +\n",[3395,12431,12432,12435,12437,12440,12442,12445,12447,12450,12452,12455],{"class":3397,"line":8189},[3395,12433,12434],{"class":4888},"        $\"Username=",[3395,12436,6507],{"class":6506},[3395,12438,12439],{"class":4715},"Username",[3395,12441,6516],{"class":6506},[3395,12443,12444],{"class":4888},";Password=",[3395,12446,6507],{"class":6506},[3395,12448,12449],{"class":4715},"Password",[3395,12451,6516],{"class":6506},[3395,12453,12454],{"class":4888},";SSL Mode=Require;\"",[3395,12456,6634],{"class":4708},[3395,12458,12459],{"class":3397,"line":8195},[3395,12460,3479],{"class":4708},[3353,12462,12463],{},[3359,12464,12465],{},"Інтеграція у Startup з отриманням секрету при Cold Start:",[3385,12467,12469],{"className":4681,"code":12468,"filename":6291,"language":4683,"meta":3390,"style":3390},"[LambdaStartup]\npublic class Startup\n{\n    public void ConfigureServices(IServiceCollection services)\n    {\n        services.AddAWSService\u003CIAmazonSecretsManager>();\n        services.AddSingleton\u003CISecretsManagerService, SecretsManagerService>();\n\n        \u002F\u002F Синхронне отримання рядка підключення при ініціалізації DI Container\n        \u002F\u002F Виконується ОДНОРАЗОВО у Cold Start — не при кожному виклику\n        services.AddSingleton\u003CIDbConnectionFactory>(provider =>\n        {\n            var secretsManager = provider.GetRequiredService\u003CISecretsManagerService>();\n            var secretArn = Environment.GetEnvironmentVariable(\"DB_SECRET_ARN\")!;\n\n            \u002F\u002F GetAwaiter().GetResult() допустимий у Cold Start\n            \u002F\u002F (не в handler — там завжди async!)\n            var dbSecret = secretsManager\n                .GetSecretAsync\u003CDatabaseSecret>(secretArn)\n                .GetAwaiter().GetResult();\n\n            return new NpgsqlConnectionFactory(dbSecret.ToConnectionString());\n        });\n    }\n}\n",[3392,12470,12471,12479,12487,12491,12507,12511,12525,12546,12550,12555,12560,12580,12584,12606,12627,12631,12636,12641,12653,12671,12686,12690,12712,12716,12720],{"__ignoreMap":3390},[3395,12472,12473,12475,12477],{"class":3397,"line":3398},[3395,12474,5731],{"class":4708},[3395,12476,6304],{"class":4700},[3395,12478,6307],{"class":4708},[3395,12480,12481,12483,12485],{"class":3397,"line":3404},[3395,12482,4697],{"class":4696},[3395,12484,6314],{"class":4696},[3395,12486,6317],{"class":4700},[3395,12488,12489],{"class":3397,"line":3410},[3395,12490,5069],{"class":4708},[3395,12492,12493,12495,12497,12499,12501,12503,12505],{"class":3397,"line":3416},[3395,12494,6326],{"class":4696},[3395,12496,6329],{"class":4696},[3395,12498,6332],{"class":4704},[3395,12500,4709],{"class":4708},[3395,12502,6337],{"class":4700},[3395,12504,6340],{"class":4715},[3395,12506,4727],{"class":4708},[3395,12508,12509],{"class":3397,"line":3423},[3395,12510,6347],{"class":4708},[3395,12512,12513,12515,12517,12519,12521,12523],{"class":3397,"line":3429},[3395,12514,6357],{"class":4715},[3395,12516,3860],{"class":4708},[3395,12518,6362],{"class":4704},[3395,12520,6130],{"class":4708},[3395,12522,11993],{"class":4700},[3395,12524,6370],{"class":4708},[3395,12526,12527,12529,12531,12534,12536,12539,12541,12544],{"class":3397,"line":3434},[3395,12528,6357],{"class":4715},[3395,12530,3860],{"class":4708},[3395,12532,12533],{"class":4704},"AddSingleton",[3395,12535,6130],{"class":4708},[3395,12537,12538],{"class":4700},"ISecretsManagerService",[3395,12540,4719],{"class":4708},[3395,12542,12543],{"class":4700},"SecretsManagerService",[3395,12545,6370],{"class":4708},[3395,12547,12548],{"class":3397,"line":3440},[3395,12549,3420],{"emptyLinePlaceholder":3419},[3395,12551,12552],{"class":3397,"line":3446},[3395,12553,12554],{"class":4690},"        \u002F\u002F Синхронне отримання рядка підключення при ініціалізації DI Container\n",[3395,12556,12557],{"class":3397,"line":3452},[3395,12558,12559],{"class":4690},"        \u002F\u002F Виконується ОДНОРАЗОВО у Cold Start — не при кожному виклику\n",[3395,12561,12562,12564,12566,12568,12570,12573,12575,12578],{"class":3397,"line":3458},[3395,12563,6357],{"class":4715},[3395,12565,3860],{"class":4708},[3395,12567,12533],{"class":4704},[3395,12569,6130],{"class":4708},[3395,12571,12572],{"class":4700},"IDbConnectionFactory",[3395,12574,10496],{"class":4708},[3395,12576,12577],{"class":4715},"provider",[3395,12579,8487],{"class":4708},[3395,12581,12582],{"class":3397,"line":3464},[3395,12583,8192],{"class":4708},[3395,12585,12586,12588,12591,12593,12595,12597,12600,12602,12604],{"class":3397,"line":3470},[3395,12587,9264],{"class":4696},[3395,12589,12590],{"class":4715}," secretsManager",[3395,12592,6088],{"class":4708},[3395,12594,12577],{"class":4715},[3395,12596,3860],{"class":4708},[3395,12598,12599],{"class":4704},"GetRequiredService",[3395,12601,6130],{"class":4708},[3395,12603,12538],{"class":4700},[3395,12605,6370],{"class":4708},[3395,12607,12608,12610,12612,12614,12616,12618,12620,12622,12625],{"class":3397,"line":3476},[3395,12609,9264],{"class":4696},[3395,12611,12050],{"class":4715},[3395,12613,6088],{"class":4708},[3395,12615,8513],{"class":4715},[3395,12617,3860],{"class":4708},[3395,12619,8518],{"class":4704},[3395,12621,4709],{"class":4708},[3395,12623,12624],{"class":4888},"\"DB_SECRET_ARN\"",[3395,12626,10506],{"class":4708},[3395,12628,12629],{"class":3397,"line":3482},[3395,12630,3420],{"emptyLinePlaceholder":3419},[3395,12632,12633],{"class":3397,"line":3487},[3395,12634,12635],{"class":4690},"            \u002F\u002F GetAwaiter().GetResult() допустимий у Cold Start\n",[3395,12637,12638],{"class":3397,"line":3493},[3395,12639,12640],{"class":4690},"            \u002F\u002F (не в handler — там завжди async!)\n",[3395,12642,12643,12645,12648,12650],{"class":3397,"line":3499},[3395,12644,9264],{"class":4696},[3395,12646,12647],{"class":4715}," dbSecret",[3395,12649,6088],{"class":4708},[3395,12651,12652],{"class":4715},"secretsManager\n",[3395,12654,12655,12658,12660,12662,12665,12667,12669],{"class":3397,"line":3505},[3395,12656,12657],{"class":4708},"                .",[3395,12659,12039],{"class":4704},[3395,12661,6130],{"class":4708},[3395,12663,12664],{"class":4700},"DatabaseSecret",[3395,12666,10496],{"class":4708},[3395,12668,12091],{"class":4715},[3395,12670,4727],{"class":4708},[3395,12672,12673,12675,12678,12681,12684],{"class":3397,"line":3511},[3395,12674,12657],{"class":4708},[3395,12676,12677],{"class":4704},"GetAwaiter",[3395,12679,12680],{"class":4708},"().",[3395,12682,12683],{"class":4704},"GetResult",[3395,12685,8224],{"class":4708},[3395,12687,12688],{"class":3397,"line":3517},[3395,12689,3420],{"emptyLinePlaceholder":3419},[3395,12691,12692,12694,12696,12699,12701,12704,12706,12709],{"class":3397,"line":3523},[3395,12693,7996],{"class":6221},[3395,12695,4906],{"class":4696},[3395,12697,12698],{"class":4700}," NpgsqlConnectionFactory",[3395,12700,4709],{"class":4708},[3395,12702,12703],{"class":4715},"dbSecret",[3395,12705,3860],{"class":4708},[3395,12707,12708],{"class":4704},"ToConnectionString",[3395,12710,12711],{"class":4708},"());\n",[3395,12713,12714],{"class":3397,"line":3529},[3395,12715,8555],{"class":4708},[3395,12717,12718],{"class":3397,"line":3534},[3395,12719,6396],{"class":4708},[3395,12721,12722],{"class":3397,"line":3539},[3395,12723,3479],{"class":4708},[3684,12725],{},[3348,12727,12729],{"id":12728},"lambda-destinations-маршрутизація-результатів-асинхронних-викликів","Lambda Destinations: маршрутизація результатів асинхронних викликів",[3353,12731,12732,12735,12736,12739],{},[3359,12733,12734],{},"Lambda Destinations"," — це конфігурація, що визначає, куди Lambda-сервіс автоматично надсилає результат ",[3359,12737,12738],{},"асинхронного"," виклику залежно від того, завершилась функція успіхом чи помилкою. Destinations усувають необхідність вручну реалізовувати логіку маршрутизації результатів безпосередньо в коді функції.",[12741,12742,12743,12744,12747],"note",{},"Lambda Destinations працюють ",[3359,12745,12746],{},"виключно"," для асинхронних викликів (S3, SNS, EventBridge, прямий асинхронний виклик SDK) та poll-based тригерів (SQS, DynamoDB Streams). Для синхронних тригерів (API Gateway) Destinations недоступні — відповідь повертається напряму клієнту.",[3382,12749,12750],{},[3385,12751,12753],{"className":3387,"code":12752,"language":3389,"meta":3390,"style":3390},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\ntitle \"Lambda Destinations: маршрутизація результатів\"\n\nrectangle \"S3 Event\\n(Trigger)\" as S3T #fef3c7\nrectangle \"Lambda Function\\nFileProcessor\" as LAM #d1fae5\n\nrectangle \"On Success Destination\" as OSD #d1fae5 {\n    rectangle \"EventBridge\\n(для оркестрації наступного кроку)\" as EB #dbeafe\n    rectangle \"SQS Queue\\n(для подальшої обробки)\" as SQSSUC #bbf7d0\n    rectangle \"SNS Topic\\n(для нотифікацій)\" as SNSSUC #bbf7d0\n    rectangle \"Інша Lambda\\n(ланцюжок функцій)\" as LAMDST #bbf7d0\n}\n\nrectangle \"On Failure Destination\" as OFD #fee2e2 {\n    rectangle \"SQS Dead Letter Queue\\n(для аналізу невдалих подій)\" as DLQ #fca5a5\n    rectangle \"SNS Topic\\n(алерт команді DevOps)\" as SNSFAIL #fca5a5\n    rectangle \"EventBridge\\n(для автоматичного rollback)\" as EBFAIL #fca5a5\n}\n\nS3T -down-> LAM : Асинхронний виклик\n\nLAM -right-> OSD : SUCCESS\\n(функція завершилась без виключення)\nLAM -left-> OFD : FAILURE\\n(вичерпано retry attempts\\nабо невідновлювана помилка)\n\n@enduml\n",[3392,12754,12755,12759,12763,12767,12771,12776,12780,12785,12790,12794,12799,12804,12809,12814,12819,12823,12827,12832,12837,12842,12847,12851,12855,12860,12864,12869,12874,12878],{"__ignoreMap":3390},[3395,12756,12757],{"class":3397,"line":3398},[3395,12758,3401],{},[3395,12760,12761],{"class":3397,"line":3404},[3395,12762,3407],{},[3395,12764,12765],{"class":3397,"line":3410},[3395,12766,3413],{},[3395,12768,12769],{"class":3397,"line":3416},[3395,12770,3420],{"emptyLinePlaceholder":3419},[3395,12772,12773],{"class":3397,"line":3423},[3395,12774,12775],{},"title \"Lambda Destinations: маршрутизація результатів\"\n",[3395,12777,12778],{"class":3397,"line":3429},[3395,12779,3420],{"emptyLinePlaceholder":3419},[3395,12781,12782],{"class":3397,"line":3434},[3395,12783,12784],{},"rectangle \"S3 Event\\n(Trigger)\" as S3T #fef3c7\n",[3395,12786,12787],{"class":3397,"line":3440},[3395,12788,12789],{},"rectangle \"Lambda Function\\nFileProcessor\" as LAM #d1fae5\n",[3395,12791,12792],{"class":3397,"line":3446},[3395,12793,3420],{"emptyLinePlaceholder":3419},[3395,12795,12796],{"class":3397,"line":3452},[3395,12797,12798],{},"rectangle \"On Success Destination\" as OSD #d1fae5 {\n",[3395,12800,12801],{"class":3397,"line":3458},[3395,12802,12803],{},"    rectangle \"EventBridge\\n(для оркестрації наступного кроку)\" as EB #dbeafe\n",[3395,12805,12806],{"class":3397,"line":3464},[3395,12807,12808],{},"    rectangle \"SQS Queue\\n(для подальшої обробки)\" as SQSSUC #bbf7d0\n",[3395,12810,12811],{"class":3397,"line":3470},[3395,12812,12813],{},"    rectangle \"SNS Topic\\n(для нотифікацій)\" as SNSSUC #bbf7d0\n",[3395,12815,12816],{"class":3397,"line":3476},[3395,12817,12818],{},"    rectangle \"Інша Lambda\\n(ланцюжок функцій)\" as LAMDST #bbf7d0\n",[3395,12820,12821],{"class":3397,"line":3482},[3395,12822,3479],{},[3395,12824,12825],{"class":3397,"line":3487},[3395,12826,3420],{"emptyLinePlaceholder":3419},[3395,12828,12829],{"class":3397,"line":3493},[3395,12830,12831],{},"rectangle \"On Failure Destination\" as OFD #fee2e2 {\n",[3395,12833,12834],{"class":3397,"line":3499},[3395,12835,12836],{},"    rectangle \"SQS Dead Letter Queue\\n(для аналізу невдалих подій)\" as DLQ #fca5a5\n",[3395,12838,12839],{"class":3397,"line":3505},[3395,12840,12841],{},"    rectangle \"SNS Topic\\n(алерт команді DevOps)\" as SNSFAIL #fca5a5\n",[3395,12843,12844],{"class":3397,"line":3511},[3395,12845,12846],{},"    rectangle \"EventBridge\\n(для автоматичного rollback)\" as EBFAIL #fca5a5\n",[3395,12848,12849],{"class":3397,"line":3517},[3395,12850,3479],{},[3395,12852,12853],{"class":3397,"line":3523},[3395,12854,3420],{"emptyLinePlaceholder":3419},[3395,12856,12857],{"class":3397,"line":3529},[3395,12858,12859],{},"S3T -down-> LAM : Асинхронний виклик\n",[3395,12861,12862],{"class":3397,"line":3534},[3395,12863,3420],{"emptyLinePlaceholder":3419},[3395,12865,12866],{"class":3397,"line":3539},[3395,12867,12868],{},"LAM -right-> OSD : SUCCESS\\n(функція завершилась без виключення)\n",[3395,12870,12871],{"class":3397,"line":3545},[3395,12872,12873],{},"LAM -left-> OFD : FAILURE\\n(вичерпано retry attempts\\nабо невідновлювана помилка)\n",[3395,12875,12876],{"class":3397,"line":3551},[3395,12877,3420],{"emptyLinePlaceholder":3419},[3395,12879,12880],{"class":3397,"line":3557},[3395,12881,3675],{},[3353,12883,12884],{},[3359,12885,12886],{},"Що Lambda автоматично надсилає у Destination:",[3353,12888,12889],{},"Lambda формує збагачений JSON-payload, що містить повний контекст виклику — не лише результат, але й метадані про саму функцію та оригінальну подію. Це усуває необхідність ручного збору контексту у коді.",[3385,12891,12893],{"className":5060,"code":12892,"language":5062,"meta":3390,"style":3390},"{\n    \"version\": \"1.0\",\n    \"timestamp\": \"2024-03-15T10:30:00.123Z\",\n    \"requestContext\": {\n        \"requestId\": \"a1b2c3d4-e5f6-7890-abcd-ef1234567890\",\n        \"functionArn\": \"arn:aws:lambda:eu-central-1:123456789012:function:FileProcessor\",\n        \"condition\": \"Success\",\n        \"approximateInvokeCount\": 1\n    },\n    \"requestPayload\": {\n        \"Records\": [{ \"eventSource\": \"aws:s3\", \"s3\": { \"object\": { \"key\": \"report.csv\" } } }]\n    },\n    \"responseContext\": {\n        \"statusCode\": 200,\n        \"executedVersion\": \"$LATEST\"\n    },\n    \"responsePayload\": {\n        \"processedRows\": 15420,\n        \"outputKey\": \"processed\u002Freport-2024-03-15.parquet\"\n    }\n}\n",[3392,12894,12895,12899,12909,12921,12927,12938,12950,12962,12972,12976,12983,13022,13026,13033,13045,13055,13059,13066,13078,13088,13092],{"__ignoreMap":3390},[3395,12896,12897],{"class":3397,"line":3398},[3395,12898,5069],{"class":4708},[3395,12900,12901,12903,12905,12907],{"class":3397,"line":3404},[3395,12902,7244],{"class":5074},[3395,12904,5078],{"class":4708},[3395,12906,8879],{"class":4888},[3395,12908,5084],{"class":4708},[3395,12910,12911,12914,12916,12919],{"class":3397,"line":3410},[3395,12912,12913],{"class":5074},"    \"timestamp\"",[3395,12915,5078],{"class":4708},[3395,12917,12918],{"class":4888},"\"2024-03-15T10:30:00.123Z\"",[3395,12920,5084],{"class":4708},[3395,12922,12923,12925],{"class":3397,"line":3416},[3395,12924,7392],{"class":5074},[3395,12926,7295],{"class":4708},[3395,12928,12929,12931,12933,12936],{"class":3397,"line":3423},[3395,12930,7467],{"class":5074},[3395,12932,5078],{"class":4708},[3395,12934,12935],{"class":4888},"\"a1b2c3d4-e5f6-7890-abcd-ef1234567890\"",[3395,12937,5084],{"class":4708},[3395,12939,12940,12943,12945,12948],{"class":3397,"line":3429},[3395,12941,12942],{"class":5074},"        \"functionArn\"",[3395,12944,5078],{"class":4708},[3395,12946,12947],{"class":4888},"\"arn:aws:lambda:eu-central-1:123456789012:function:FileProcessor\"",[3395,12949,5084],{"class":4708},[3395,12951,12952,12955,12957,12960],{"class":3397,"line":3434},[3395,12953,12954],{"class":5074},"        \"condition\"",[3395,12956,5078],{"class":4708},[3395,12958,12959],{"class":4888},"\"Success\"",[3395,12961,5084],{"class":4708},[3395,12963,12964,12967,12969],{"class":3397,"line":3440},[3395,12965,12966],{"class":5074},"        \"approximateInvokeCount\"",[3395,12968,5078],{"class":4708},[3395,12970,12971],{"class":5154},"1\n",[3395,12973,12974],{"class":3397,"line":3446},[3395,12975,7345],{"class":4708},[3395,12977,12978,12981],{"class":3397,"line":3452},[3395,12979,12980],{"class":5074},"    \"requestPayload\"",[3395,12982,7295],{"class":4708},[3395,12984,12985,12988,12991,12994,12996,12998,13000,13003,13006,13009,13011,13014,13016,13019],{"class":3397,"line":3458},[3395,12986,12987],{"class":5074},"        \"Records\"",[3395,12989,12990],{"class":4708},": [{ ",[3395,12992,12993],{"class":5074},"\"eventSource\"",[3395,12995,5078],{"class":4708},[3395,12997,8825],{"class":4888},[3395,12999,4719],{"class":4708},[3395,13001,13002],{"class":5074},"\"s3\"",[3395,13004,13005],{"class":4708},": { ",[3395,13007,13008],{"class":5074},"\"object\"",[3395,13010,13005],{"class":4708},[3395,13012,13013],{"class":5074},"\"key\"",[3395,13015,5078],{"class":4708},[3395,13017,13018],{"class":4888},"\"report.csv\"",[3395,13020,13021],{"class":4708}," } } }]\n",[3395,13023,13024],{"class":3397,"line":3464},[3395,13025,7345],{"class":4708},[3395,13027,13028,13031],{"class":3397,"line":3470},[3395,13029,13030],{"class":5074},"    \"responseContext\"",[3395,13032,7295],{"class":4708},[3395,13034,13035,13038,13040,13043],{"class":3397,"line":3476},[3395,13036,13037],{"class":5074},"        \"statusCode\"",[3395,13039,5078],{"class":4708},[3395,13041,13042],{"class":5154},"200",[3395,13044,5084],{"class":4708},[3395,13046,13047,13050,13052],{"class":3397,"line":3482},[3395,13048,13049],{"class":5074},"        \"executedVersion\"",[3395,13051,5078],{"class":4708},[3395,13053,13054],{"class":4888},"\"$LATEST\"\n",[3395,13056,13057],{"class":3397,"line":3487},[3395,13058,7345],{"class":4708},[3395,13060,13061,13064],{"class":3397,"line":3493},[3395,13062,13063],{"class":5074},"    \"responsePayload\"",[3395,13065,7295],{"class":4708},[3395,13067,13068,13071,13073,13076],{"class":3397,"line":3499},[3395,13069,13070],{"class":5074},"        \"processedRows\"",[3395,13072,5078],{"class":4708},[3395,13074,13075],{"class":5154},"15420",[3395,13077,5084],{"class":4708},[3395,13079,13080,13083,13085],{"class":3397,"line":3505},[3395,13081,13082],{"class":5074},"        \"outputKey\"",[3395,13084,5078],{"class":4708},[3395,13086,13087],{"class":4888},"\"processed\u002Freport-2024-03-15.parquet\"\n",[3395,13089,13090],{"class":3397,"line":3511},[3395,13091,6396],{"class":4708},[3395,13093,13094],{"class":3397,"line":3517},[3395,13095,3479],{"class":4708},[3353,13097,13098],{},[3359,13099,13100],{},"Порівняння з Dead Letter Queue (DLQ):",[4273,13102,13103,13115],{},[4276,13104,13105],{},[4279,13106,13107,13110,13112],{},[4282,13108,13109],{},"Характеристика",[4282,13111,12734],{},[4282,13113,13114],{},"Dead Letter Queue",[4292,13116,13117,13134,13147,13160,13173],{},[4279,13118,13119,13124,13131],{},[4297,13120,13121],{},[3359,13122,13123],{},"Де спрацьовує",[4297,13125,13126,13127,13130],{},"On Success ",[3359,13128,13129],{},"та"," On Failure",[4297,13132,13133],{},"Лише On Failure",[4279,13135,13136,13141,13144],{},[4297,13137,13138],{},[3359,13139,13140],{},"Що передається",[4297,13142,13143],{},"Повний контекст: input + output + metadata",[4297,13145,13146],{},"Лише оригінальний input event",[4279,13148,13149,13154,13157],{},[4297,13150,13151],{},[3359,13152,13153],{},"Підтримувані цілі",[4297,13155,13156],{},"SQS, SNS, EventBridge, Lambda",[4297,13158,13159],{},"SQS, SNS",[4279,13161,13162,13167,13170],{},[4297,13163,13164],{},[3359,13165,13166],{},"Коли з'явилось",[4297,13168,13169],{},"2019 (новіший підхід)",[4297,13171,13172],{},"2016 (legacy підхід)",[4279,13174,13175,13180,13183],{},[4297,13176,13177],{},[3359,13178,13179],{},"Рекомендація",[4297,13181,13182],{},"✅ Використовуйте для нових проектів",[4297,13184,13185],{},"⚠️ Тільки для зворотної сумісності",[3684,13187],{},[3684,13189],{},[3348,13191,13193],{"id":13192},"lambda-performance-optimization-стратегії-мінімізації-cold-start","Lambda Performance Optimization: стратегії мінімізації Cold Start",[3353,13195,13196],{},"Оптимізація продуктивності Lambda для .NET є комплексним завданням, що охоплює декілька незалежних рівнів: архітектуру коду, конфігурацію Runtime, розмір deployment package та апаратні ресурси. Розглянемо кожен рівень детально.",[3704,13198,13200],{"id":13199},"стратегія-1-оптимізація-коду-init-фази","Стратегія 1: оптимізація коду Init-фази",[3353,13202,13203,13204,3860],{},"Найефективніший підхід — мінімізувати обсяг роботи, що виконується поза handler-функцією (тобто у Init-фазі Cold Start). Кожен об'єкт, ініціалізований у Init-фазі, живе протягом усього Execution Environment і використовується повторно при Warm Start. Це є перевагою, але Init-фаза повинна ініціалізувати ",[3359,13205,13206],{},"лише те, що справді потрібно",[3385,13208,13211],{"className":4681,"code":13209,"filename":13210,"language":4683,"meta":3390,"style":3390},"\u002F\u002F ❌ ПОГАНО: Lazy ініціалізація у handler — Cold Start при КОЖНОМУ виклику,\n\u002F\u002F якщо об'єкт ще не ініціалізований\npublic class BadFunction\n{\n    public async Task Handler(S3Event evt, ILambdaContext ctx)\n    {\n        \u002F\u002F Новий клієнт створюється при першому виклику кожного Execution Environment\n        \u002F\u002F Але також — при кожному Cold Start нового Execution Environment\n        var s3Client = new AmazonS3Client(); \u002F\u002F ❌\n        var result = await s3Client.ListBucketsAsync();\n    }\n}\n\n\u002F\u002F ✅ ДОБРЕ: Статична ініціалізація — виконується ОДНОРАЗОВО при Cold Start\n\u002F\u002F Повторно використовується при всіх Warm Start викликах\npublic class GoodFunction\n{\n    \u002F\u002F static readonly — ініціалізується при завантаженні класу (Init-фаза)\n    private static readonly IAmazonS3 S3Client = new AmazonS3Client();\n    private static readonly IAmazonDynamoDB DynamoClient = new AmazonDynamoDBClient();\n\n    \u002F\u002F HttpClient НІКОЛИ не створюється у handler — connection pooling!\n    private static readonly HttpClient HttpClient = new HttpClient\n    {\n        BaseAddress = new Uri(Environment.GetEnvironmentVariable(\"API_BASE_URL\")!),\n        Timeout = TimeSpan.FromSeconds(10)\n    };\n\n    public async Task\u003Cstring> Handler(APIGatewayHttpApiV2ProxyRequest req, ILambdaContext ctx)\n    {\n        \u002F\u002F Handler лише використовує вже ініціалізовані об'єкти ✅\n        var response = await HttpClient.GetStringAsync(\"\u002Fhealth\");\n        return response;\n    }\n}\n","Оптимальна структура ініціалізації",[3392,13212,13213,13218,13223,13232,13236,13263,13267,13272,13277,13296,13315,13319,13323,13327,13332,13337,13346,13350,13355,13375,13398,13402,13407,13427,13431,13458,13477,13482,13486,13517,13521,13526,13550,13558,13562],{"__ignoreMap":3390},[3395,13214,13215],{"class":3397,"line":3398},[3395,13216,13217],{"class":4690},"\u002F\u002F ❌ ПОГАНО: Lazy ініціалізація у handler — Cold Start при КОЖНОМУ виклику,\n",[3395,13219,13220],{"class":3397,"line":3404},[3395,13221,13222],{"class":4690},"\u002F\u002F якщо об'єкт ще не ініціалізований\n",[3395,13224,13225,13227,13229],{"class":3397,"line":3410},[3395,13226,4697],{"class":4696},[3395,13228,6314],{"class":4696},[3395,13230,13231],{"class":4700}," BadFunction\n",[3395,13233,13234],{"class":3397,"line":3416},[3395,13235,5069],{"class":4708},[3395,13237,13238,13240,13242,13244,13247,13249,13251,13254,13256,13258,13261],{"class":3397,"line":3423},[3395,13239,6326],{"class":4696},[3395,13241,6124],{"class":4696},[3395,13243,6127],{"class":4700},[3395,13245,13246],{"class":4704}," Handler",[3395,13248,4709],{"class":4708},[3395,13250,5835],{"class":4700},[3395,13252,13253],{"class":4715}," evt",[3395,13255,4719],{"class":4708},[3395,13257,4667],{"class":4700},[3395,13259,13260],{"class":4715}," ctx",[3395,13262,4727],{"class":4708},[3395,13264,13265],{"class":3397,"line":3429},[3395,13266,6347],{"class":4708},[3395,13268,13269],{"class":3397,"line":3434},[3395,13270,13271],{"class":4690},"        \u002F\u002F Новий клієнт створюється при першому виклику кожного Execution Environment\n",[3395,13273,13274],{"class":3397,"line":3440},[3395,13275,13276],{"class":4690},"        \u002F\u002F Але також — при кожному Cold Start нового Execution Environment\n",[3395,13278,13279,13281,13284,13286,13288,13290,13293],{"class":3397,"line":3446},[3395,13280,7949],{"class":4696},[3395,13282,13283],{"class":4715}," s3Client",[3395,13285,6088],{"class":4708},[3395,13287,6235],{"class":4696},[3395,13289,9172],{"class":4700},[3395,13291,13292],{"class":4708},"(); ",[3395,13294,13295],{"class":4690},"\u002F\u002F ❌\n",[3395,13297,13298,13300,13302,13304,13306,13308,13310,13313],{"class":3397,"line":3452},[3395,13299,7949],{"class":4696},[3395,13301,11057],{"class":4715},[3395,13303,6088],{"class":4708},[3395,13305,7957],{"class":4696},[3395,13307,13283],{"class":4715},[3395,13309,3860],{"class":4708},[3395,13311,13312],{"class":4704},"ListBucketsAsync",[3395,13314,8224],{"class":4708},[3395,13316,13317],{"class":3397,"line":3458},[3395,13318,6396],{"class":4708},[3395,13320,13321],{"class":3397,"line":3464},[3395,13322,3479],{"class":4708},[3395,13324,13325],{"class":3397,"line":3470},[3395,13326,3420],{"emptyLinePlaceholder":3419},[3395,13328,13329],{"class":3397,"line":3476},[3395,13330,13331],{"class":4690},"\u002F\u002F ✅ ДОБРЕ: Статична ініціалізація — виконується ОДНОРАЗОВО при Cold Start\n",[3395,13333,13334],{"class":3397,"line":3482},[3395,13335,13336],{"class":4690},"\u002F\u002F Повторно використовується при всіх Warm Start викликах\n",[3395,13338,13339,13341,13343],{"class":3397,"line":3487},[3395,13340,4697],{"class":4696},[3395,13342,6314],{"class":4696},[3395,13344,13345],{"class":4700}," GoodFunction\n",[3395,13347,13348],{"class":3397,"line":3493},[3395,13349,5069],{"class":4708},[3395,13351,13352],{"class":3397,"line":3499},[3395,13353,13354],{"class":4690},"    \u002F\u002F static readonly — ініціалізується при завантаженні класу (Init-фаза)\n",[3395,13356,13357,13359,13361,13363,13365,13367,13369,13371,13373],{"class":3397,"line":3505},[3395,13358,7714],{"class":4696},[3395,13360,9157],{"class":4696},[3395,13362,7717],{"class":4696},[3395,13364,9162],{"class":4700},[3395,13366,9165],{"class":4715},[3395,13368,6088],{"class":4708},[3395,13370,6235],{"class":4696},[3395,13372,9172],{"class":4700},[3395,13374,8224],{"class":4708},[3395,13376,13377,13379,13381,13383,13386,13389,13391,13393,13396],{"class":3397,"line":3511},[3395,13378,7714],{"class":4696},[3395,13380,9157],{"class":4696},[3395,13382,7717],{"class":4696},[3395,13384,13385],{"class":4700}," IAmazonDynamoDB",[3395,13387,13388],{"class":4715}," DynamoClient",[3395,13390,6088],{"class":4708},[3395,13392,6235],{"class":4696},[3395,13394,13395],{"class":4700}," AmazonDynamoDBClient",[3395,13397,8224],{"class":4708},[3395,13399,13400],{"class":3397,"line":3517},[3395,13401,3420],{"emptyLinePlaceholder":3419},[3395,13403,13404],{"class":3397,"line":3523},[3395,13405,13406],{"class":4690},"    \u002F\u002F HttpClient НІКОЛИ не створюється у handler — connection pooling!\n",[3395,13408,13409,13411,13413,13415,13418,13420,13422,13424],{"class":3397,"line":3529},[3395,13410,7714],{"class":4696},[3395,13412,9157],{"class":4696},[3395,13414,7717],{"class":4696},[3395,13416,13417],{"class":4700}," HttpClient",[3395,13419,13417],{"class":4715},[3395,13421,6088],{"class":4708},[3395,13423,6235],{"class":4696},[3395,13425,13426],{"class":4700}," HttpClient\n",[3395,13428,13429],{"class":3397,"line":3534},[3395,13430,6347],{"class":4708},[3395,13432,13433,13436,13438,13440,13442,13444,13446,13448,13450,13452,13455],{"class":3397,"line":3539},[3395,13434,13435],{"class":4715},"        BaseAddress",[3395,13437,6088],{"class":4708},[3395,13439,6235],{"class":4696},[3395,13441,8508],{"class":4700},[3395,13443,4709],{"class":4708},[3395,13445,8513],{"class":4715},[3395,13447,3860],{"class":4708},[3395,13449,8518],{"class":4704},[3395,13451,4709],{"class":4708},[3395,13453,13454],{"class":4888},"\"API_BASE_URL\"",[3395,13456,13457],{"class":4708},")!),\n",[3395,13459,13460,13463,13465,13467,13469,13471,13473,13475],{"class":3397,"line":3545},[3395,13461,13462],{"class":4715},"        Timeout",[3395,13464,6088],{"class":4708},[3395,13466,4813],{"class":4715},[3395,13468,3860],{"class":4708},[3395,13470,6591],{"class":4704},[3395,13472,4709],{"class":4708},[3395,13474,8548],{"class":5154},[3395,13476,4727],{"class":4708},[3395,13478,13479],{"class":3397,"line":3551},[3395,13480,13481],{"class":4708},"    };\n",[3395,13483,13484],{"class":3397,"line":3557},[3395,13485,3420],{"emptyLinePlaceholder":3419},[3395,13487,13488,13490,13492,13494,13496,13498,13500,13502,13504,13506,13509,13511,13513,13515],{"class":3397,"line":3563},[3395,13489,6326],{"class":4696},[3395,13491,6124],{"class":4696},[3395,13493,6127],{"class":4700},[3395,13495,6130],{"class":4708},[3395,13497,3954],{"class":4696},[3395,13499,6136],{"class":4708},[3395,13501,6462],{"class":4704},[3395,13503,4709],{"class":4708},[3395,13505,5818],{"class":4700},[3395,13507,13508],{"class":4715}," req",[3395,13510,4719],{"class":4708},[3395,13512,4667],{"class":4700},[3395,13514,13260],{"class":4715},[3395,13516,4727],{"class":4708},[3395,13518,13519],{"class":3397,"line":3569},[3395,13520,6347],{"class":4708},[3395,13522,13523],{"class":3397,"line":3575},[3395,13524,13525],{"class":4690},"        \u002F\u002F Handler лише використовує вже ініціалізовані об'єкти ✅\n",[3395,13527,13528,13530,13532,13534,13536,13538,13540,13543,13545,13548],{"class":3397,"line":3581},[3395,13529,7949],{"class":4696},[3395,13531,9475],{"class":4715},[3395,13533,6088],{"class":4708},[3395,13535,7957],{"class":4696},[3395,13537,13417],{"class":4715},[3395,13539,3860],{"class":4708},[3395,13541,13542],{"class":4704},"GetStringAsync",[3395,13544,4709],{"class":4708},[3395,13546,13547],{"class":4888},"\"\u002Fhealth\"",[3395,13549,6522],{"class":4708},[3395,13551,13552,13554,13556],{"class":3397,"line":3586},[3395,13553,8037],{"class":6221},[3395,13555,9475],{"class":4715},[3395,13557,6634],{"class":4708},[3395,13559,13560],{"class":3397,"line":3591},[3395,13561,6396],{"class":4708},[3395,13563,13564],{"class":3397,"line":3597},[3395,13565,3479],{"class":4708},[3353,13567,13568],{},[3359,13569,13570],{},"Lazy initialization для важких залежностей:",[3353,13572,13573,13574,13577],{},"Якщо певна залежність використовується не у кожному виклику (наприклад, лише при конкретному типі події), можна застосувати ",[3392,13575,13576],{},"Lazy\u003CT>"," для відкладеної ініціалізації — вона виконається при першому зверненні, але лише один раз протягом Execution Environment:",[3385,13579,13581],{"className":4681,"code":13580,"language":4683,"meta":3390,"style":3390},"public class OptimizedFunction\n{\n    \u002F\u002F Lazy ініціалізація — підключення до ElasticSearch виконується\n    \u002F\u002F лише при першому зверненні, але не затримує Init-фазу\n    private static readonly Lazy\u003CIElasticClient> ElasticClient = new(() =>\n    {\n        var settings = new ConnectionSettings(\n            new Uri(Environment.GetEnvironmentVariable(\"ELASTICSEARCH_URL\")!));\n        return new ElasticClient(settings);\n    });\n\n    public async Task Handler(SQSEvent evt, ILambdaContext ctx)\n    {\n        \u002F\u002F Lazy.Value ініціалізує клієнт лише один раз\n        var client = ElasticClient.Value;\n        \u002F\u002F ...\n    }\n}\n",[3392,13582,13583,13592,13596,13601,13606,13634,13638,13654,13677,13693,13698,13702,13726,13730,13735,13751,13756,13760],{"__ignoreMap":3390},[3395,13584,13585,13587,13589],{"class":3397,"line":3398},[3395,13586,4697],{"class":4696},[3395,13588,6314],{"class":4696},[3395,13590,13591],{"class":4700}," OptimizedFunction\n",[3395,13593,13594],{"class":3397,"line":3404},[3395,13595,5069],{"class":4708},[3395,13597,13598],{"class":3397,"line":3410},[3395,13599,13600],{"class":4690},"    \u002F\u002F Lazy ініціалізація — підключення до ElasticSearch виконується\n",[3395,13602,13603],{"class":3397,"line":3416},[3395,13604,13605],{"class":4690},"    \u002F\u002F лише при першому зверненні, але не затримує Init-фазу\n",[3395,13607,13608,13610,13612,13614,13617,13619,13622,13624,13627,13629,13631],{"class":3397,"line":3423},[3395,13609,7714],{"class":4696},[3395,13611,9157],{"class":4696},[3395,13613,7717],{"class":4696},[3395,13615,13616],{"class":4700}," Lazy",[3395,13618,6130],{"class":4708},[3395,13620,13621],{"class":4700},"IElasticClient",[3395,13623,6136],{"class":4708},[3395,13625,13626],{"class":4715},"ElasticClient",[3395,13628,6088],{"class":4708},[3395,13630,6235],{"class":4696},[3395,13632,13633],{"class":4708},"(() =>\n",[3395,13635,13636],{"class":3397,"line":3429},[3395,13637,6347],{"class":4708},[3395,13639,13640,13642,13645,13647,13649,13652],{"class":3397,"line":3434},[3395,13641,7949],{"class":4696},[3395,13643,13644],{"class":4715}," settings",[3395,13646,6088],{"class":4708},[3395,13648,6235],{"class":4696},[3395,13650,13651],{"class":4700}," ConnectionSettings",[3395,13653,6142],{"class":4708},[3395,13655,13656,13659,13661,13663,13665,13667,13669,13671,13674],{"class":3397,"line":3440},[3395,13657,13658],{"class":4696},"            new",[3395,13660,8508],{"class":4700},[3395,13662,4709],{"class":4708},[3395,13664,8513],{"class":4715},[3395,13666,3860],{"class":4708},[3395,13668,8518],{"class":4704},[3395,13670,4709],{"class":4708},[3395,13672,13673],{"class":4888},"\"ELASTICSEARCH_URL\"",[3395,13675,13676],{"class":4708},")!));\n",[3395,13678,13679,13681,13683,13686,13688,13691],{"class":3397,"line":3446},[3395,13680,8037],{"class":6221},[3395,13682,4906],{"class":4696},[3395,13684,13685],{"class":4700}," ElasticClient",[3395,13687,4709],{"class":4708},[3395,13689,13690],{"class":4715},"settings",[3395,13692,6522],{"class":4708},[3395,13694,13695],{"class":3397,"line":3452},[3395,13696,13697],{"class":4708},"    });\n",[3395,13699,13700],{"class":3397,"line":3458},[3395,13701,3420],{"emptyLinePlaceholder":3419},[3395,13703,13704,13706,13708,13710,13712,13714,13716,13718,13720,13722,13724],{"class":3397,"line":3464},[3395,13705,6326],{"class":4696},[3395,13707,6124],{"class":4696},[3395,13709,6127],{"class":4700},[3395,13711,13246],{"class":4704},[3395,13713,4709],{"class":4708},[3395,13715,5852],{"class":4700},[3395,13717,13253],{"class":4715},[3395,13719,4719],{"class":4708},[3395,13721,4667],{"class":4700},[3395,13723,13260],{"class":4715},[3395,13725,4727],{"class":4708},[3395,13727,13728],{"class":3397,"line":3470},[3395,13729,6347],{"class":4708},[3395,13731,13732],{"class":3397,"line":3476},[3395,13733,13734],{"class":4690},"        \u002F\u002F Lazy.Value ініціалізує клієнт лише один раз\n",[3395,13736,13737,13739,13741,13743,13745,13747,13749],{"class":3397,"line":3482},[3395,13738,7949],{"class":4696},[3395,13740,11996],{"class":4715},[3395,13742,6088],{"class":4708},[3395,13744,13626],{"class":4715},[3395,13746,3860],{"class":4708},[3395,13748,12163],{"class":4715},[3395,13750,6634],{"class":4708},[3395,13752,13753],{"class":3397,"line":3487},[3395,13754,13755],{"class":4690},"        \u002F\u002F ...\n",[3395,13757,13758],{"class":3397,"line":3493},[3395,13759,6396],{"class":4708},[3395,13761,13762],{"class":3397,"line":3499},[3395,13763,3479],{"class":4708},[3704,13765,13767],{"id":13766},"стратегія-2-вибір-оптимального-обсягу-памяті","Стратегія 2: вибір оптимального обсягу пам'яті",[3353,13769,13770,13771,13774,13775,13778],{},"Ця стратегія є одним із найпоширеніших нерозуміних аспектів оптимізації Lambda. ",[3359,13772,13773],{},"Більше пам'яті = більше CPU",". Збільшення пам'яті часто ",[3359,13776,13777],{},"знижує загальну вартість",", оскільки функція виконується швидше і загальна сума GB-секунд зменшується попри вищу ставку за GB.",[3382,13780,13781],{},[3385,13782,13784],{"className":3387,"code":13783,"language":3389,"meta":3390,"style":3390},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\ntitle \"Залежність між пам'яттю, часом виконання та вартістю\"\n\nrectangle \"128 MB\\n(мінімум)\" as M128 #fca5a5 {\n    rectangle \"CPU: 1\u002F14 vCPU\\nЧас: 3200ms\\nGB-сек: 0.41\\nВартість: $0.0000068\" as V128\n}\n\nrectangle \"512 MB\" as M512 #fde68a {\n    rectangle \"CPU: 1\u002F3.5 vCPU\\nЧас: 1200ms\\nGB-сек: 0.61\\nВартість: $0.0000102\" as V512\n}\n\nrectangle \"1769 MB\\n(1 повний vCPU)\" as M1769 #bbf7d0 {\n    rectangle \"CPU: 1 vCPU\\nЧас: 500ms\\nGB-сек: 0.88\\nВартість: $0.0000147\" as V1769\n}\n\nrectangle \"3008 MB\" as M3008 #dbeafe {\n    rectangle \"CPU: ~1.7 vCPU\\nЧас: 280ms\\nGB-sek: 0.84\\nВартість: $0.0000139\" as V3008\n}\n\nnote bottom of M128 : Найдешевша ставка,\\nАЛЕ найвища загальна вартість!\\nCold Start: ~3s\nnote bottom of M512 : Баланс для легких функцій\nnote bottom of M1769 : Оптимум для більшості .NET функцій\\nCold Start: \u003C1s\nnote bottom of M3008 : Для CPU-інтенсивних задач\n\n@enduml\n",[3392,13785,13786,13790,13794,13798,13802,13807,13811,13816,13821,13825,13829,13834,13839,13843,13847,13852,13857,13861,13865,13870,13875,13879,13883,13888,13893,13898,13903,13907],{"__ignoreMap":3390},[3395,13787,13788],{"class":3397,"line":3398},[3395,13789,3401],{},[3395,13791,13792],{"class":3397,"line":3404},[3395,13793,3407],{},[3395,13795,13796],{"class":3397,"line":3410},[3395,13797,3413],{},[3395,13799,13800],{"class":3397,"line":3416},[3395,13801,3420],{"emptyLinePlaceholder":3419},[3395,13803,13804],{"class":3397,"line":3423},[3395,13805,13806],{},"title \"Залежність між пам'яттю, часом виконання та вартістю\"\n",[3395,13808,13809],{"class":3397,"line":3429},[3395,13810,3420],{"emptyLinePlaceholder":3419},[3395,13812,13813],{"class":3397,"line":3434},[3395,13814,13815],{},"rectangle \"128 MB\\n(мінімум)\" as M128 #fca5a5 {\n",[3395,13817,13818],{"class":3397,"line":3440},[3395,13819,13820],{},"    rectangle \"CPU: 1\u002F14 vCPU\\nЧас: 3200ms\\nGB-сек: 0.41\\nВартість: $0.0000068\" as V128\n",[3395,13822,13823],{"class":3397,"line":3446},[3395,13824,3479],{},[3395,13826,13827],{"class":3397,"line":3452},[3395,13828,3420],{"emptyLinePlaceholder":3419},[3395,13830,13831],{"class":3397,"line":3458},[3395,13832,13833],{},"rectangle \"512 MB\" as M512 #fde68a {\n",[3395,13835,13836],{"class":3397,"line":3464},[3395,13837,13838],{},"    rectangle \"CPU: 1\u002F3.5 vCPU\\nЧас: 1200ms\\nGB-сек: 0.61\\nВартість: $0.0000102\" as V512\n",[3395,13840,13841],{"class":3397,"line":3470},[3395,13842,3479],{},[3395,13844,13845],{"class":3397,"line":3476},[3395,13846,3420],{"emptyLinePlaceholder":3419},[3395,13848,13849],{"class":3397,"line":3482},[3395,13850,13851],{},"rectangle \"1769 MB\\n(1 повний vCPU)\" as M1769 #bbf7d0 {\n",[3395,13853,13854],{"class":3397,"line":3487},[3395,13855,13856],{},"    rectangle \"CPU: 1 vCPU\\nЧас: 500ms\\nGB-сек: 0.88\\nВартість: $0.0000147\" as V1769\n",[3395,13858,13859],{"class":3397,"line":3493},[3395,13860,3479],{},[3395,13862,13863],{"class":3397,"line":3499},[3395,13864,3420],{"emptyLinePlaceholder":3419},[3395,13866,13867],{"class":3397,"line":3505},[3395,13868,13869],{},"rectangle \"3008 MB\" as M3008 #dbeafe {\n",[3395,13871,13872],{"class":3397,"line":3511},[3395,13873,13874],{},"    rectangle \"CPU: ~1.7 vCPU\\nЧас: 280ms\\nGB-sek: 0.84\\nВартість: $0.0000139\" as V3008\n",[3395,13876,13877],{"class":3397,"line":3517},[3395,13878,3479],{},[3395,13880,13881],{"class":3397,"line":3523},[3395,13882,3420],{"emptyLinePlaceholder":3419},[3395,13884,13885],{"class":3397,"line":3529},[3395,13886,13887],{},"note bottom of M128 : Найдешевша ставка,\\nАЛЕ найвища загальна вартість!\\nCold Start: ~3s\n",[3395,13889,13890],{"class":3397,"line":3534},[3395,13891,13892],{},"note bottom of M512 : Баланс для легких функцій\n",[3395,13894,13895],{"class":3397,"line":3539},[3395,13896,13897],{},"note bottom of M1769 : Оптимум для більшості .NET функцій\\nCold Start: \u003C1s\n",[3395,13899,13900],{"class":3397,"line":3545},[3395,13901,13902],{},"note bottom of M3008 : Для CPU-інтенсивних задач\n",[3395,13904,13905],{"class":3397,"line":3551},[3395,13906,3420],{"emptyLinePlaceholder":3419},[3395,13908,13909],{"class":3397,"line":3557},[3395,13910,3675],{},[3677,13912,13913,13916,13917,3860],{},[3359,13914,13915],{},"AWS Lambda Power Tuning"," — відкрита AWS Step Functions State Machine, що автоматично тестує вашу функцію з різними обсягами пам'яті та знаходить оптимальну точку між швидкістю та вартістю. Запустіть її перед виведенням функції у production: ",[4560,13918,13921],{"href":13919,"rel":13920},"https:\u002F\u002Fgithub.com\u002Falexcasalboni\u002Faws-lambda-power-tuning",[4564],"github.com\u002Falexcasalboni\u002Faws-lambda-power-tuning",[3704,13923,13925],{"id":13924},"стратегія-3-оптимізація-розміру-deployment-package","Стратегія 3: оптимізація розміру deployment package",[3353,13927,13928],{},"Розмір ZIP-архіву безпосередньо впливає на тривалість Cold Start: Lambda завантажує весь архів при ініціалізації нового Execution Environment. Для .NET проектів основний внесок у розмір вносять NuGet-залежності та нативні бінарники.",[3353,13930,13931],{},[3359,13932,13933],{},"Техніки зменшення розміру для .NET:",[3385,13935,13940],{"className":13936,"code":13937,"filename":13938,"language":13939,"meta":3390,"style":3390},"language-xml shiki shiki-themes light-plus dark-plus dark-plus","\u003CProject Sdk=\"Microsoft.NET.Sdk\">\n  \u003CPropertyGroup>\n    \u003CTargetFramework>net8.0\u003C\u002FTargetFramework>\n    \u003CNullable>enable\u003C\u002FNullable>\n    \u003CImplicitUsings>enable\u003C\u002FImplicitUsings>\n\n    \u003C!-- Публікуємо self-contained з trimming для видалення невикористаних типів -->\n    \u003CPublishReadyToRun>true\u003C\u002FPublishReadyToRun>\n\n    \u003C!-- Видаляє невикористані типи та члени при публікації -->\n    \u003C!-- Зменшує розмір на 30-60% для типових .NET Lambda -->\n    \u003CPublishTrimmed>true\u003C\u002FPublishTrimmed>\n\n    \u003C!-- Генерує нативний код заздалегідь → швидший запуск CLR -->\n    \u003CTieredPGO>true\u003C\u002FTieredPGO>\n  \u003C\u002FPropertyGroup>\n\n  \u003CItemGroup>\n    \u003CPackageReference Include=\"Amazon.Lambda.Core\" Version=\"2.2.0\" \u002F>\n    \u003CPackageReference Include=\"Amazon.Lambda.Serialization.SystemTextJson\" Version=\"2.4.1\" \u002F>\n    \u003C!-- Використовуємо System.Text.Json замість Newtonsoft.Json — менший розмір! -->\n\n    \u003C!-- Для мінімізації: включаємо лише потрібні AWSSDK пакети -->\n    \u003C!-- ❌ Не: AWSSDK.Core (тягне ВСЕ) -->\n    \u003C!-- ✅ Так: точечні пакети для конкретних сервісів -->\n    \u003CPackageReference Include=\"AWSSDK.S3\" Version=\"3.7.*\" \u002F>\n    \u003CPackageReference Include=\"AWSSDK.DynamoDBv2\" Version=\"3.7.*\" \u002F>\n  \u003C\u002FItemGroup>\n\u003C\u002FProject>\n","MyFunction.csproj","xml",[3392,13941,13942,13965,13975,13996,14014,14031,14035,14040,14057,14061,14066,14071,14088,14092,14097,14114,14123,14127,14136,14162,14184,14189,14193,14198,14203,14208,14230,14251,14259],{"__ignoreMap":3390},[3395,13943,13944,13947,13951,13955,13958,13962],{"class":3397,"line":3398},[3395,13945,6130],{"class":13946},"s0P7L",[3395,13948,13950],{"class":13949},"sKtos","Project",[3395,13952,13954],{"class":13953},"sa4r_"," Sdk",[3395,13956,13957],{"class":4708},"=",[3395,13959,13961],{"class":13960},"su9tN","\"Microsoft.NET.Sdk\"",[3395,13963,13964],{"class":13946},">\n",[3395,13966,13967,13970,13973],{"class":3397,"line":3404},[3395,13968,13969],{"class":13946},"  \u003C",[3395,13971,13972],{"class":13949},"PropertyGroup",[3395,13974,13964],{"class":13946},[3395,13976,13977,13980,13983,13986,13989,13992,13994],{"class":3397,"line":3410},[3395,13978,13979],{"class":13946},"    \u003C",[3395,13981,13982],{"class":13949},"TargetFramework",[3395,13984,13985],{"class":13946},">",[3395,13987,13988],{"class":4708},"net8.0",[3395,13990,13991],{"class":13946},"\u003C\u002F",[3395,13993,13982],{"class":13949},[3395,13995,13964],{"class":13946},[3395,13997,13998,14000,14003,14005,14008,14010,14012],{"class":3397,"line":3416},[3395,13999,13979],{"class":13946},[3395,14001,14002],{"class":13949},"Nullable",[3395,14004,13985],{"class":13946},[3395,14006,14007],{"class":4708},"enable",[3395,14009,13991],{"class":13946},[3395,14011,14002],{"class":13949},[3395,14013,13964],{"class":13946},[3395,14015,14016,14018,14021,14023,14025,14027,14029],{"class":3397,"line":3423},[3395,14017,13979],{"class":13946},[3395,14019,14020],{"class":13949},"ImplicitUsings",[3395,14022,13985],{"class":13946},[3395,14024,14007],{"class":4708},[3395,14026,13991],{"class":13946},[3395,14028,14020],{"class":13949},[3395,14030,13964],{"class":13946},[3395,14032,14033],{"class":3397,"line":3429},[3395,14034,3420],{"emptyLinePlaceholder":3419},[3395,14036,14037],{"class":3397,"line":3434},[3395,14038,14039],{"class":4690},"    \u003C!-- Публікуємо self-contained з trimming для видалення невикористаних типів -->\n",[3395,14041,14042,14044,14047,14049,14051,14053,14055],{"class":3397,"line":3440},[3395,14043,13979],{"class":13946},[3395,14045,14046],{"class":13949},"PublishReadyToRun",[3395,14048,13985],{"class":13946},[3395,14050,3946],{"class":4708},[3395,14052,13991],{"class":13946},[3395,14054,14046],{"class":13949},[3395,14056,13964],{"class":13946},[3395,14058,14059],{"class":3397,"line":3446},[3395,14060,3420],{"emptyLinePlaceholder":3419},[3395,14062,14063],{"class":3397,"line":3452},[3395,14064,14065],{"class":4690},"    \u003C!-- Видаляє невикористані типи та члени при публікації -->\n",[3395,14067,14068],{"class":3397,"line":3458},[3395,14069,14070],{"class":4690},"    \u003C!-- Зменшує розмір на 30-60% для типових .NET Lambda -->\n",[3395,14072,14073,14075,14078,14080,14082,14084,14086],{"class":3397,"line":3464},[3395,14074,13979],{"class":13946},[3395,14076,14077],{"class":13949},"PublishTrimmed",[3395,14079,13985],{"class":13946},[3395,14081,3946],{"class":4708},[3395,14083,13991],{"class":13946},[3395,14085,14077],{"class":13949},[3395,14087,13964],{"class":13946},[3395,14089,14090],{"class":3397,"line":3470},[3395,14091,3420],{"emptyLinePlaceholder":3419},[3395,14093,14094],{"class":3397,"line":3476},[3395,14095,14096],{"class":4690},"    \u003C!-- Генерує нативний код заздалегідь → швидший запуск CLR -->\n",[3395,14098,14099,14101,14104,14106,14108,14110,14112],{"class":3397,"line":3482},[3395,14100,13979],{"class":13946},[3395,14102,14103],{"class":13949},"TieredPGO",[3395,14105,13985],{"class":13946},[3395,14107,3946],{"class":4708},[3395,14109,13991],{"class":13946},[3395,14111,14103],{"class":13949},[3395,14113,13964],{"class":13946},[3395,14115,14116,14119,14121],{"class":3397,"line":3487},[3395,14117,14118],{"class":13946},"  \u003C\u002F",[3395,14120,13972],{"class":13949},[3395,14122,13964],{"class":13946},[3395,14124,14125],{"class":3397,"line":3493},[3395,14126,3420],{"emptyLinePlaceholder":3419},[3395,14128,14129,14131,14134],{"class":3397,"line":3499},[3395,14130,13969],{"class":13946},[3395,14132,14133],{"class":13949},"ItemGroup",[3395,14135,13964],{"class":13946},[3395,14137,14138,14140,14143,14146,14148,14151,14154,14156,14159],{"class":3397,"line":3505},[3395,14139,13979],{"class":13946},[3395,14141,14142],{"class":13949},"PackageReference",[3395,14144,14145],{"class":13953}," Include",[3395,14147,13957],{"class":4708},[3395,14149,14150],{"class":13960},"\"Amazon.Lambda.Core\"",[3395,14152,14153],{"class":13953}," Version",[3395,14155,13957],{"class":4708},[3395,14157,14158],{"class":13960},"\"2.2.0\"",[3395,14160,14161],{"class":13946}," \u002F>\n",[3395,14163,14164,14166,14168,14170,14172,14175,14177,14179,14182],{"class":3397,"line":3511},[3395,14165,13979],{"class":13946},[3395,14167,14142],{"class":13949},[3395,14169,14145],{"class":13953},[3395,14171,13957],{"class":4708},[3395,14173,14174],{"class":13960},"\"Amazon.Lambda.Serialization.SystemTextJson\"",[3395,14176,14153],{"class":13953},[3395,14178,13957],{"class":4708},[3395,14180,14181],{"class":13960},"\"2.4.1\"",[3395,14183,14161],{"class":13946},[3395,14185,14186],{"class":3397,"line":3517},[3395,14187,14188],{"class":4690},"    \u003C!-- Використовуємо System.Text.Json замість Newtonsoft.Json — менший розмір! -->\n",[3395,14190,14191],{"class":3397,"line":3523},[3395,14192,3420],{"emptyLinePlaceholder":3419},[3395,14194,14195],{"class":3397,"line":3529},[3395,14196,14197],{"class":4690},"    \u003C!-- Для мінімізації: включаємо лише потрібні AWSSDK пакети -->\n",[3395,14199,14200],{"class":3397,"line":3534},[3395,14201,14202],{"class":4690},"    \u003C!-- ❌ Не: AWSSDK.Core (тягне ВСЕ) -->\n",[3395,14204,14205],{"class":3397,"line":3539},[3395,14206,14207],{"class":4690},"    \u003C!-- ✅ Так: точечні пакети для конкретних сервісів -->\n",[3395,14209,14210,14212,14214,14216,14218,14221,14223,14225,14228],{"class":3397,"line":3545},[3395,14211,13979],{"class":13946},[3395,14213,14142],{"class":13949},[3395,14215,14145],{"class":13953},[3395,14217,13957],{"class":4708},[3395,14219,14220],{"class":13960},"\"AWSSDK.S3\"",[3395,14222,14153],{"class":13953},[3395,14224,13957],{"class":4708},[3395,14226,14227],{"class":13960},"\"3.7.*\"",[3395,14229,14161],{"class":13946},[3395,14231,14232,14234,14236,14238,14240,14243,14245,14247,14249],{"class":3397,"line":3551},[3395,14233,13979],{"class":13946},[3395,14235,14142],{"class":13949},[3395,14237,14145],{"class":13953},[3395,14239,13957],{"class":4708},[3395,14241,14242],{"class":13960},"\"AWSSDK.DynamoDBv2\"",[3395,14244,14153],{"class":13953},[3395,14246,13957],{"class":4708},[3395,14248,14227],{"class":13960},[3395,14250,14161],{"class":13946},[3395,14252,14253,14255,14257],{"class":3397,"line":3557},[3395,14254,14118],{"class":13946},[3395,14256,14133],{"class":13949},[3395,14258,13964],{"class":13946},[3395,14260,14261,14263,14265],{"class":3397,"line":3563},[3395,14262,13991],{"class":13946},[3395,14264,13950],{"class":13949},[3395,14266,13964],{"class":13946},[3353,14268,14269],{},[3359,14270,14271],{},"Команда публікації з оптимізацією для Lambda:",[3385,14273,14275],{"className":4876,"code":14274,"language":4878,"meta":3390,"style":3390},"# Публікація з trimming та ReadyToRun для зменшення Cold Start\ndotnet publish src\u002FMyFunction \\\n    --configuration Release \\\n    --runtime linux-x64 \\\n    --self-contained true \\\n    --output .\u002Fpublish \\\n    -p:PublishTrimmed=true \\\n    -p:PublishReadyToRun=true\n\n# Пакуємо у ZIP для завантаження у Lambda\ncd publish && zip -r ..\u002Ffunction.zip .\n\n# Розмір до та після оптимізації (типові результати):\n# До: 48 MB | Після trimming: 18 MB | Зменшення: 62%\n",[3392,14276,14277,14282,14293,14302,14312,14322,14332,14339,14344,14348,14353,14370,14374,14379],{"__ignoreMap":3390},[3395,14278,14279],{"class":3397,"line":3398},[3395,14280,14281],{"class":4690},"# Публікація з trimming та ReadyToRun для зменшення Cold Start\n",[3395,14283,14284,14286,14288,14291],{"class":3397,"line":3404},[3395,14285,4903],{"class":4704},[3395,14287,5509],{"class":4888},[3395,14289,14290],{"class":4888}," src\u002FMyFunction",[3395,14292,5584],{"class":5583},[3395,14294,14295,14298,14300],{"class":3397,"line":3410},[3395,14296,14297],{"class":4696},"    --configuration",[3395,14299,5515],{"class":4888},[3395,14301,5584],{"class":5583},[3395,14303,14304,14307,14310],{"class":3397,"line":3416},[3395,14305,14306],{"class":4696},"    --runtime",[3395,14308,14309],{"class":4888}," linux-x64",[3395,14311,5584],{"class":5583},[3395,14313,14314,14317,14320],{"class":3397,"line":3423},[3395,14315,14316],{"class":4696},"    --self-contained",[3395,14318,14319],{"class":4696}," true",[3395,14321,5584],{"class":5583},[3395,14323,14324,14327,14330],{"class":3397,"line":3429},[3395,14325,14326],{"class":4696},"    --output",[3395,14328,14329],{"class":4888}," .\u002Fpublish",[3395,14331,5584],{"class":5583},[3395,14333,14334,14337],{"class":3397,"line":3434},[3395,14335,14336],{"class":4696},"    -p:PublishTrimmed=true",[3395,14338,5584],{"class":5583},[3395,14340,14341],{"class":3397,"line":3440},[3395,14342,14343],{"class":4696},"    -p:PublishReadyToRun=true\n",[3395,14345,14346],{"class":3397,"line":3446},[3395,14347,3420],{"emptyLinePlaceholder":3419},[3395,14349,14350],{"class":3397,"line":3452},[3395,14351,14352],{"class":4690},"# Пакуємо у ZIP для завантаження у Lambda\n",[3395,14354,14355,14357,14359,14361,14363,14365,14368],{"class":3397,"line":3458},[3395,14356,4895],{"class":4704},[3395,14358,5509],{"class":4888},[3395,14360,4892],{"class":4708},[3395,14362,5552],{"class":4704},[3395,14364,5555],{"class":4696},[3395,14366,14367],{"class":4888}," ..\u002Ffunction.zip",[3395,14369,5521],{"class":4888},[3395,14371,14372],{"class":3397,"line":3464},[3395,14373,3420],{"emptyLinePlaceholder":3419},[3395,14375,14376],{"class":3397,"line":3470},[3395,14377,14378],{"class":4690},"# Розмір до та після оптимізації (типові результати):\n",[3395,14380,14381],{"class":3397,"line":3476},[3395,14382,14383],{"class":4690},"# До: 48 MB | Після trimming: 18 MB | Зменшення: 62%\n",[3684,14385],{},[3704,14387,14389],{"id":14388},"стратегія-4-net-native-aot-максимальна-мінімізація-cold-start","Стратегія 4: .NET Native AOT — максимальна мінімізація Cold Start",[3353,14391,14392,14395],{},[3359,14393,14394],{},"Native AOT"," (Ahead-of-Time) компіляція — це технологія .NET, що компілює код безпосередньо у нативний машинний код Linux заздалегідь, повністю усуваючи необхідність запуску CLR та JIT-компіляції при ініціалізації. Результатом є самодостатній бінарний файл, що запускається на порядок швидше за стандартний .NET Runtime.",[3382,14397,14398],{},[3385,14399,14401],{"className":3387,"code":14400,"language":3389,"meta":3390,"style":3390},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\ntitle \".NET стандартний Runtime vs Native AOT: Cold Start\"\n\nrectangle \"Стандартний .NET 10 Runtime\" as STD #fef3c7 {\n    rectangle \"1. Завантаження CLR\\n(Common Language Runtime)\" as CLR #fca5a5\n    rectangle \"2. Завантаження Assembly (.dll)\" as ASM #fca5a5\n    rectangle \"3. JIT-компіляція методів\\n(Just-in-Time, при першому виклику)\" as JIT #fca5a5\n    rectangle \"4. Init-код (DI, static ctor)\" as INIT #fde68a\n    rectangle \"5. Виконання Handler\" as HANDLER1 #bbf7d0\n}\n\nrectangle \"Native AOT (.NET 10)\" as AOT #d1fae5 {\n    rectangle \"1. Завантаження бінарника\\n(нативний Linux ELF, ~10-15MB)\" as BIN #bbf7d0\n    rectangle \"2. Init-код (DI, static ctor)\" as INIT2 #fde68a\n    rectangle \"3. Виконання Handler\" as HANDLER2 #bbf7d0\n}\n\nnote right of STD\n  Cold Start: ~800-3000ms\n  Розмір: 30-100MB (ZIP)\n  Сумісність: 100% NuGet\nend note\n\nnote right of AOT\n  Cold Start: ~50-150ms (10-20x швидше!)\n  Розмір: 8-20MB (ZIP)\n  Обмеження: немає рефлексії, Roslyn,\n  dynamic loading. Не всі NuGet сумісні.\nend note\n\n@enduml\n",[3392,14402,14403,14407,14411,14415,14419,14424,14428,14433,14438,14443,14448,14453,14458,14462,14466,14471,14476,14481,14486,14490,14494,14499,14504,14509,14514,14518,14522,14527,14532,14537,14542,14547,14551,14555],{"__ignoreMap":3390},[3395,14404,14405],{"class":3397,"line":3398},[3395,14406,3401],{},[3395,14408,14409],{"class":3397,"line":3404},[3395,14410,3407],{},[3395,14412,14413],{"class":3397,"line":3410},[3395,14414,3413],{},[3395,14416,14417],{"class":3397,"line":3416},[3395,14418,3420],{"emptyLinePlaceholder":3419},[3395,14420,14421],{"class":3397,"line":3423},[3395,14422,14423],{},"title \".NET стандартний Runtime vs Native AOT: Cold Start\"\n",[3395,14425,14426],{"class":3397,"line":3429},[3395,14427,3420],{"emptyLinePlaceholder":3419},[3395,14429,14430],{"class":3397,"line":3434},[3395,14431,14432],{},"rectangle \"Стандартний .NET 10 Runtime\" as STD #fef3c7 {\n",[3395,14434,14435],{"class":3397,"line":3440},[3395,14436,14437],{},"    rectangle \"1. Завантаження CLR\\n(Common Language Runtime)\" as CLR #fca5a5\n",[3395,14439,14440],{"class":3397,"line":3446},[3395,14441,14442],{},"    rectangle \"2. Завантаження Assembly (.dll)\" as ASM #fca5a5\n",[3395,14444,14445],{"class":3397,"line":3452},[3395,14446,14447],{},"    rectangle \"3. JIT-компіляція методів\\n(Just-in-Time, при першому виклику)\" as JIT #fca5a5\n",[3395,14449,14450],{"class":3397,"line":3458},[3395,14451,14452],{},"    rectangle \"4. Init-код (DI, static ctor)\" as INIT #fde68a\n",[3395,14454,14455],{"class":3397,"line":3464},[3395,14456,14457],{},"    rectangle \"5. Виконання Handler\" as HANDLER1 #bbf7d0\n",[3395,14459,14460],{"class":3397,"line":3470},[3395,14461,3479],{},[3395,14463,14464],{"class":3397,"line":3476},[3395,14465,3420],{"emptyLinePlaceholder":3419},[3395,14467,14468],{"class":3397,"line":3482},[3395,14469,14470],{},"rectangle \"Native AOT (.NET 10)\" as AOT #d1fae5 {\n",[3395,14472,14473],{"class":3397,"line":3487},[3395,14474,14475],{},"    rectangle \"1. Завантаження бінарника\\n(нативний Linux ELF, ~10-15MB)\" as BIN #bbf7d0\n",[3395,14477,14478],{"class":3397,"line":3493},[3395,14479,14480],{},"    rectangle \"2. Init-код (DI, static ctor)\" as INIT2 #fde68a\n",[3395,14482,14483],{"class":3397,"line":3499},[3395,14484,14485],{},"    rectangle \"3. Виконання Handler\" as HANDLER2 #bbf7d0\n",[3395,14487,14488],{"class":3397,"line":3505},[3395,14489,3479],{},[3395,14491,14492],{"class":3397,"line":3511},[3395,14493,3420],{"emptyLinePlaceholder":3419},[3395,14495,14496],{"class":3397,"line":3517},[3395,14497,14498],{},"note right of STD\n",[3395,14500,14501],{"class":3397,"line":3523},[3395,14502,14503],{},"  Cold Start: ~800-3000ms\n",[3395,14505,14506],{"class":3397,"line":3529},[3395,14507,14508],{},"  Розмір: 30-100MB (ZIP)\n",[3395,14510,14511],{"class":3397,"line":3534},[3395,14512,14513],{},"  Сумісність: 100% NuGet\n",[3395,14515,14516],{"class":3397,"line":3539},[3395,14517,4215],{},[3395,14519,14520],{"class":3397,"line":3545},[3395,14521,3420],{"emptyLinePlaceholder":3419},[3395,14523,14524],{"class":3397,"line":3551},[3395,14525,14526],{},"note right of AOT\n",[3395,14528,14529],{"class":3397,"line":3557},[3395,14530,14531],{},"  Cold Start: ~50-150ms (10-20x швидше!)\n",[3395,14533,14534],{"class":3397,"line":3563},[3395,14535,14536],{},"  Розмір: 8-20MB (ZIP)\n",[3395,14538,14539],{"class":3397,"line":3569},[3395,14540,14541],{},"  Обмеження: немає рефлексії, Roslyn,\n",[3395,14543,14544],{"class":3397,"line":3575},[3395,14545,14546],{},"  dynamic loading. Не всі NuGet сумісні.\n",[3395,14548,14549],{"class":3397,"line":3581},[3395,14550,4215],{},[3395,14552,14553],{"class":3397,"line":3586},[3395,14554,3420],{"emptyLinePlaceholder":3419},[3395,14556,14557],{"class":3397,"line":3591},[3395,14558,3675],{},[3353,14560,14561],{},[3359,14562,14563],{},"Налаштування проекту для Native AOT Lambda:",[3385,14565,14568],{"className":13936,"code":14566,"filename":14567,"language":13939,"meta":3390,"style":3390},"\u003CProject Sdk=\"Microsoft.NET.Sdk\">\n  \u003CPropertyGroup>\n    \u003CTargetFramework>net8.0\u003C\u002FTargetFramework>\n    \u003CNullable>enable\u003C\u002FNullable>\n    \u003CImplicitUsings>enable\u003C\u002FImplicitUsings>\n\n    \u003C!-- Увімкнення Native AOT -->\n    \u003CPublishAot>true\u003C\u002FPublishAot>\n\n    \u003C!-- Для AOT необхідна явна вказівка типів серіалізації -->\n    \u003C!-- (рефлексія недоступна в AOT для JSON серіалізації) -->\n  \u003C\u002FPropertyGroup>\n\n  \u003CItemGroup>\n    \u003C!-- Спеціальний пакет для Native AOT Lambda -->\n    \u003CPackageReference Include=\"Amazon.Lambda.RuntimeSupport\" Version=\"1.10.*\" \u002F>\n    \u003CPackageReference Include=\"Amazon.Lambda.Core\" Version=\"2.2.0\" \u002F>\n    \u003CPackageReference Include=\"Amazon.Lambda.Serialization.SystemTextJson\" Version=\"2.4.1\" \u002F>\n  \u003C\u002FItemGroup>\n\u003C\u002FProject>\n","NativeAotFunction.csproj",[3392,14569,14570,14584,14592,14608,14624,14640,14644,14649,14666,14670,14675,14680,14688,14692,14700,14705,14727,14747,14767,14775],{"__ignoreMap":3390},[3395,14571,14572,14574,14576,14578,14580,14582],{"class":3397,"line":3398},[3395,14573,6130],{"class":13946},[3395,14575,13950],{"class":13949},[3395,14577,13954],{"class":13953},[3395,14579,13957],{"class":4708},[3395,14581,13961],{"class":13960},[3395,14583,13964],{"class":13946},[3395,14585,14586,14588,14590],{"class":3397,"line":3404},[3395,14587,13969],{"class":13946},[3395,14589,13972],{"class":13949},[3395,14591,13964],{"class":13946},[3395,14593,14594,14596,14598,14600,14602,14604,14606],{"class":3397,"line":3410},[3395,14595,13979],{"class":13946},[3395,14597,13982],{"class":13949},[3395,14599,13985],{"class":13946},[3395,14601,13988],{"class":4708},[3395,14603,13991],{"class":13946},[3395,14605,13982],{"class":13949},[3395,14607,13964],{"class":13946},[3395,14609,14610,14612,14614,14616,14618,14620,14622],{"class":3397,"line":3416},[3395,14611,13979],{"class":13946},[3395,14613,14002],{"class":13949},[3395,14615,13985],{"class":13946},[3395,14617,14007],{"class":4708},[3395,14619,13991],{"class":13946},[3395,14621,14002],{"class":13949},[3395,14623,13964],{"class":13946},[3395,14625,14626,14628,14630,14632,14634,14636,14638],{"class":3397,"line":3423},[3395,14627,13979],{"class":13946},[3395,14629,14020],{"class":13949},[3395,14631,13985],{"class":13946},[3395,14633,14007],{"class":4708},[3395,14635,13991],{"class":13946},[3395,14637,14020],{"class":13949},[3395,14639,13964],{"class":13946},[3395,14641,14642],{"class":3397,"line":3429},[3395,14643,3420],{"emptyLinePlaceholder":3419},[3395,14645,14646],{"class":3397,"line":3434},[3395,14647,14648],{"class":4690},"    \u003C!-- Увімкнення Native AOT -->\n",[3395,14650,14651,14653,14656,14658,14660,14662,14664],{"class":3397,"line":3440},[3395,14652,13979],{"class":13946},[3395,14654,14655],{"class":13949},"PublishAot",[3395,14657,13985],{"class":13946},[3395,14659,3946],{"class":4708},[3395,14661,13991],{"class":13946},[3395,14663,14655],{"class":13949},[3395,14665,13964],{"class":13946},[3395,14667,14668],{"class":3397,"line":3446},[3395,14669,3420],{"emptyLinePlaceholder":3419},[3395,14671,14672],{"class":3397,"line":3452},[3395,14673,14674],{"class":4690},"    \u003C!-- Для AOT необхідна явна вказівка типів серіалізації -->\n",[3395,14676,14677],{"class":3397,"line":3458},[3395,14678,14679],{"class":4690},"    \u003C!-- (рефлексія недоступна в AOT для JSON серіалізації) -->\n",[3395,14681,14682,14684,14686],{"class":3397,"line":3464},[3395,14683,14118],{"class":13946},[3395,14685,13972],{"class":13949},[3395,14687,13964],{"class":13946},[3395,14689,14690],{"class":3397,"line":3470},[3395,14691,3420],{"emptyLinePlaceholder":3419},[3395,14693,14694,14696,14698],{"class":3397,"line":3476},[3395,14695,13969],{"class":13946},[3395,14697,14133],{"class":13949},[3395,14699,13964],{"class":13946},[3395,14701,14702],{"class":3397,"line":3482},[3395,14703,14704],{"class":4690},"    \u003C!-- Спеціальний пакет для Native AOT Lambda -->\n",[3395,14706,14707,14709,14711,14713,14715,14718,14720,14722,14725],{"class":3397,"line":3487},[3395,14708,13979],{"class":13946},[3395,14710,14142],{"class":13949},[3395,14712,14145],{"class":13953},[3395,14714,13957],{"class":4708},[3395,14716,14717],{"class":13960},"\"Amazon.Lambda.RuntimeSupport\"",[3395,14719,14153],{"class":13953},[3395,14721,13957],{"class":4708},[3395,14723,14724],{"class":13960},"\"1.10.*\"",[3395,14726,14161],{"class":13946},[3395,14728,14729,14731,14733,14735,14737,14739,14741,14743,14745],{"class":3397,"line":3493},[3395,14730,13979],{"class":13946},[3395,14732,14142],{"class":13949},[3395,14734,14145],{"class":13953},[3395,14736,13957],{"class":4708},[3395,14738,14150],{"class":13960},[3395,14740,14153],{"class":13953},[3395,14742,13957],{"class":4708},[3395,14744,14158],{"class":13960},[3395,14746,14161],{"class":13946},[3395,14748,14749,14751,14753,14755,14757,14759,14761,14763,14765],{"class":3397,"line":3499},[3395,14750,13979],{"class":13946},[3395,14752,14142],{"class":13949},[3395,14754,14145],{"class":13953},[3395,14756,13957],{"class":4708},[3395,14758,14174],{"class":13960},[3395,14760,14153],{"class":13953},[3395,14762,13957],{"class":4708},[3395,14764,14181],{"class":13960},[3395,14766,14161],{"class":13946},[3395,14768,14769,14771,14773],{"class":3397,"line":3505},[3395,14770,14118],{"class":13946},[3395,14772,14133],{"class":13949},[3395,14774,13964],{"class":13946},[3395,14776,14777,14779,14781],{"class":3397,"line":3511},[3395,14778,13991],{"class":13946},[3395,14780,13950],{"class":13949},[3395,14782,13964],{"class":13946},[3353,14784,14785],{},[3359,14786,14787],{},"Native AOT потребує явної реєстрації типів для JSON серіалізації через Source Generators:",[3385,14789,14792],{"className":4681,"code":14790,"filename":14791,"language":4683,"meta":3390,"style":3390},"using Amazon.Lambda.Core;\nusing Amazon.Lambda.RuntimeSupport;\nusing Amazon.Lambda.Serialization.SystemTextJson;\nusing System.Text.Json.Serialization;\n\n\u002F\u002F Source Generator генерує AOT-сумісний серіалізатор для вказаних типів\n[JsonSerializable(typeof(ApiRequest))]\n[JsonSerializable(typeof(ApiResponse))]\n[JsonSerializable(typeof(Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyRequest))]\n[JsonSerializable(typeof(Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse))]\npublic partial class LambdaJsonContext : JsonSerializerContext { }\n\n\u002F\u002F Точка входу для Native AOT Lambda\nstatic class Program\n{\n    static async Task Main(string[] args)\n    {\n        \u002F\u002F Зовнішнє налаштування — без DI контейнера (AOT-сумісно)\n        var handler = new OrderHandler();\n\n        \u002F\u002F Bootstrap Lambda Runtime з AOT-сумісним серіалізатором\n        var serializer = new SourceGeneratorLambdaJsonSerializer\u003CLambdaJsonContext>();\n\n        await LambdaBootstrapBuilder\n            .Create\u003CApiRequest, ApiResponse>(\n                handler.HandleAsync,\n                serializer)\n            .Build()\n            .RunAsync();\n    }\n}\n\npublic sealed class OrderHandler\n{\n    \u002F\u002F Статичні клієнти — ініціалізуються при запуску процесу\n    private static readonly IAmazonDynamoDB _dynamo = new AmazonDynamoDBClient();\n\n    public async Task\u003CApiResponse> HandleAsync(\n        ApiRequest request, ILambdaContext context)\n    {\n        context.Logger.LogInformation(\n            \"AOT Handler invoked: {RequestId}\", context.AwsRequestId);\n\n        \u002F\u002F Бізнес-логіка...\n        return new ApiResponse { StatusCode = 200, Body = \"OK\" };\n    }\n}\n\npublic record ApiRequest(string Path, string Method, string? Body);\npublic record ApiResponse(int StatusCode, string Body);\n","NativeAotFunction.cs",[3392,14793,14794,14810,14827,14847,14867,14871,14876,14894,14911,14940,14969,14989,14993,14998,15007,15011,15035,15039,15044,15060,15064,15069,15090,15094,15102,15121,15133,15140,15150,15159,15163,15167,15171,15182,15186,15191,15212,15216,15234,15249,15253,15267,15282,15286,15291,15320,15324,15328,15332,15366],{"__ignoreMap":3390},[3395,14795,14796,14798,14800,14802,14804,14806,14808],{"class":3397,"line":3398},[3395,14797,7533],{"class":6221},[3395,14799,7536],{"class":4700},[3395,14801,3860],{"class":4708},[3395,14803,5754],{"class":4700},[3395,14805,3860],{"class":4708},[3395,14807,7583],{"class":4700},[3395,14809,6634],{"class":4708},[3395,14811,14812,14814,14816,14818,14820,14822,14825],{"class":3397,"line":3404},[3395,14813,7533],{"class":6221},[3395,14815,7536],{"class":4700},[3395,14817,3860],{"class":4708},[3395,14819,5754],{"class":4700},[3395,14821,3860],{"class":4708},[3395,14823,14824],{"class":4700},"RuntimeSupport",[3395,14826,6634],{"class":4708},[3395,14828,14829,14831,14833,14835,14837,14839,14841,14843,14845],{"class":3397,"line":3410},[3395,14830,7533],{"class":6221},[3395,14832,7536],{"class":4700},[3395,14834,3860],{"class":4708},[3395,14836,5754],{"class":4700},[3395,14838,3860],{"class":4708},[3395,14840,5759],{"class":4700},[3395,14842,3860],{"class":4708},[3395,14844,5764],{"class":4700},[3395,14846,6634],{"class":4708},[3395,14848,14849,14851,14853,14855,14857,14859,14861,14863,14865],{"class":3397,"line":3416},[3395,14850,7533],{"class":6221},[3395,14852,11813],{"class":4700},[3395,14854,3860],{"class":4708},[3395,14856,10470],{"class":4700},[3395,14858,3860],{"class":4708},[3395,14860,10475],{"class":4700},[3395,14862,3860],{"class":4708},[3395,14864,5759],{"class":4700},[3395,14866,6634],{"class":4708},[3395,14868,14869],{"class":3397,"line":3423},[3395,14870,3420],{"emptyLinePlaceholder":3419},[3395,14872,14873],{"class":3397,"line":3429},[3395,14874,14875],{"class":4690},"\u002F\u002F Source Generator генерує AOT-сумісний серіалізатор для вказаних типів\n",[3395,14877,14878,14880,14883,14885,14887,14889,14892],{"class":3397,"line":3434},[3395,14879,5731],{"class":4708},[3395,14881,14882],{"class":4700},"JsonSerializable",[3395,14884,4709],{"class":4708},[3395,14886,5744],{"class":4696},[3395,14888,4709],{"class":4708},[3395,14890,14891],{"class":4700},"ApiRequest",[3395,14893,5772],{"class":4708},[3395,14895,14896,14898,14900,14902,14904,14906,14909],{"class":3397,"line":3440},[3395,14897,5731],{"class":4708},[3395,14899,14882],{"class":4700},[3395,14901,4709],{"class":4708},[3395,14903,5744],{"class":4696},[3395,14905,4709],{"class":4708},[3395,14907,14908],{"class":4700},"ApiResponse",[3395,14910,5772],{"class":4708},[3395,14912,14913,14915,14917,14919,14921,14923,14925,14927,14929,14931,14934,14936,14938],{"class":3397,"line":3446},[3395,14914,5731],{"class":4708},[3395,14916,14882],{"class":4700},[3395,14918,4709],{"class":4708},[3395,14920,5744],{"class":4696},[3395,14922,4709],{"class":4708},[3395,14924,5749],{"class":4700},[3395,14926,3860],{"class":4708},[3395,14928,5754],{"class":4700},[3395,14930,3860],{"class":4708},[3395,14932,14933],{"class":4700},"APIGatewayEvents",[3395,14935,3860],{"class":4708},[3395,14937,5818],{"class":4700},[3395,14939,5772],{"class":4708},[3395,14941,14942,14944,14946,14948,14950,14952,14954,14956,14958,14960,14962,14964,14967],{"class":3397,"line":3452},[3395,14943,5731],{"class":4708},[3395,14945,14882],{"class":4700},[3395,14947,4709],{"class":4708},[3395,14949,5744],{"class":4696},[3395,14951,4709],{"class":4708},[3395,14953,5749],{"class":4700},[3395,14955,3860],{"class":4708},[3395,14957,5754],{"class":4700},[3395,14959,3860],{"class":4708},[3395,14961,14933],{"class":4700},[3395,14963,3860],{"class":4708},[3395,14965,14966],{"class":4700},"APIGatewayHttpApiV2ProxyResponse",[3395,14968,5772],{"class":4708},[3395,14970,14971,14973,14976,14978,14981,14983,14986],{"class":3397,"line":3458},[3395,14972,4697],{"class":4696},[3395,14974,14975],{"class":4696}," partial",[3395,14977,6314],{"class":4696},[3395,14979,14980],{"class":4700}," LambdaJsonContext",[3395,14982,11862],{"class":4708},[3395,14984,14985],{"class":4700},"JsonSerializerContext",[3395,14987,14988],{"class":4708}," { }\n",[3395,14990,14991],{"class":3397,"line":3464},[3395,14992,3420],{"emptyLinePlaceholder":3419},[3395,14994,14995],{"class":3397,"line":3470},[3395,14996,14997],{"class":4690},"\u002F\u002F Точка входу для Native AOT Lambda\n",[3395,14999,15000,15002,15004],{"class":3397,"line":3476},[3395,15001,4333],{"class":4696},[3395,15003,6314],{"class":4696},[3395,15005,15006],{"class":4700}," Program\n",[3395,15008,15009],{"class":3397,"line":3482},[3395,15010,5069],{"class":4708},[3395,15012,15013,15016,15018,15020,15023,15025,15027,15030,15033],{"class":3397,"line":3487},[3395,15014,15015],{"class":4696},"    static",[3395,15017,6124],{"class":4696},[3395,15019,6127],{"class":4700},[3395,15021,15022],{"class":4704}," Main",[3395,15024,4709],{"class":4708},[3395,15026,3954],{"class":4696},[3395,15028,15029],{"class":4708},"[] ",[3395,15031,15032],{"class":4715},"args",[3395,15034,4727],{"class":4708},[3395,15036,15037],{"class":3397,"line":3493},[3395,15038,6347],{"class":4708},[3395,15040,15041],{"class":3397,"line":3499},[3395,15042,15043],{"class":4690},"        \u002F\u002F Зовнішнє налаштування — без DI контейнера (AOT-сумісно)\n",[3395,15045,15046,15048,15051,15053,15055,15058],{"class":3397,"line":3505},[3395,15047,7949],{"class":4696},[3395,15049,15050],{"class":4715}," handler",[3395,15052,6088],{"class":4708},[3395,15054,6235],{"class":4696},[3395,15056,15057],{"class":4700}," OrderHandler",[3395,15059,8224],{"class":4708},[3395,15061,15062],{"class":3397,"line":3511},[3395,15063,3420],{"emptyLinePlaceholder":3419},[3395,15065,15066],{"class":3397,"line":3517},[3395,15067,15068],{"class":4690},"        \u002F\u002F Bootstrap Lambda Runtime з AOT-сумісним серіалізатором\n",[3395,15070,15071,15073,15076,15078,15080,15083,15085,15088],{"class":3397,"line":3523},[3395,15072,7949],{"class":4696},[3395,15074,15075],{"class":4715}," serializer",[3395,15077,6088],{"class":4708},[3395,15079,6235],{"class":4696},[3395,15081,15082],{"class":4700}," SourceGeneratorLambdaJsonSerializer",[3395,15084,6130],{"class":4708},[3395,15086,15087],{"class":4700},"LambdaJsonContext",[3395,15089,6370],{"class":4708},[3395,15091,15092],{"class":3397,"line":3529},[3395,15093,3420],{"emptyLinePlaceholder":3419},[3395,15095,15096,15099],{"class":3397,"line":3534},[3395,15097,15098],{"class":4696},"        await",[3395,15100,15101],{"class":4715}," LambdaBootstrapBuilder\n",[3395,15103,15104,15107,15110,15112,15114,15116,15118],{"class":3397,"line":3539},[3395,15105,15106],{"class":4708},"            .",[3395,15108,15109],{"class":4704},"Create",[3395,15111,6130],{"class":4708},[3395,15113,14891],{"class":4700},[3395,15115,4719],{"class":4708},[3395,15117,14908],{"class":4700},[3395,15119,15120],{"class":4708},">(\n",[3395,15122,15123,15126,15128,15131],{"class":3397,"line":3545},[3395,15124,15125],{"class":4715},"                handler",[3395,15127,3860],{"class":4708},[3395,15129,15130],{"class":4715},"HandleAsync",[3395,15132,5084],{"class":4708},[3395,15134,15135,15138],{"class":3397,"line":3551},[3395,15136,15137],{"class":4715},"                serializer",[3395,15139,4727],{"class":4708},[3395,15141,15142,15144,15147],{"class":3397,"line":3557},[3395,15143,15106],{"class":4708},[3395,15145,15146],{"class":4704},"Build",[3395,15148,15149],{"class":4708},"()\n",[3395,15151,15152,15154,15157],{"class":3397,"line":3563},[3395,15153,15106],{"class":4708},[3395,15155,15156],{"class":4704},"RunAsync",[3395,15158,8224],{"class":4708},[3395,15160,15161],{"class":3397,"line":3569},[3395,15162,6396],{"class":4708},[3395,15164,15165],{"class":3397,"line":3575},[3395,15166,3479],{"class":4708},[3395,15168,15169],{"class":3397,"line":3581},[3395,15170,3420],{"emptyLinePlaceholder":3419},[3395,15172,15173,15175,15177,15179],{"class":3397,"line":3586},[3395,15174,4697],{"class":4696},[3395,15176,11328],{"class":4696},[3395,15178,6314],{"class":4696},[3395,15180,15181],{"class":4700}," OrderHandler\n",[3395,15183,15184],{"class":3397,"line":3591},[3395,15185,5069],{"class":4708},[3395,15187,15188],{"class":3397,"line":3597},[3395,15189,15190],{"class":4690},"    \u002F\u002F Статичні клієнти — ініціалізуються при запуску процесу\n",[3395,15192,15193,15195,15197,15199,15201,15204,15206,15208,15210],{"class":3397,"line":3603},[3395,15194,7714],{"class":4696},[3395,15196,9157],{"class":4696},[3395,15198,7717],{"class":4696},[3395,15200,13385],{"class":4700},[3395,15202,15203],{"class":4715}," _dynamo",[3395,15205,6088],{"class":4708},[3395,15207,6235],{"class":4696},[3395,15209,13395],{"class":4700},[3395,15211,8224],{"class":4708},[3395,15213,15214],{"class":3397,"line":3609},[3395,15215,3420],{"emptyLinePlaceholder":3419},[3395,15217,15218,15220,15222,15224,15226,15228,15230,15232],{"class":3397,"line":3615},[3395,15219,6326],{"class":4696},[3395,15221,6124],{"class":4696},[3395,15223,6127],{"class":4700},[3395,15225,6130],{"class":4708},[3395,15227,14908],{"class":4700},[3395,15229,6136],{"class":4708},[3395,15231,15130],{"class":4704},[3395,15233,6142],{"class":4708},[3395,15235,15236,15239,15241,15243,15245,15247],{"class":3397,"line":3621},[3395,15237,15238],{"class":4700},"        ApiRequest",[3395,15240,6192],{"class":4715},[3395,15242,4719],{"class":4708},[3395,15244,4667],{"class":4700},[3395,15246,4724],{"class":4715},[3395,15248,4727],{"class":4708},[3395,15250,15251],{"class":3397,"line":3627},[3395,15252,6347],{"class":4708},[3395,15254,15255,15257,15259,15261,15263,15265],{"class":3397,"line":3633},[3395,15256,10921],{"class":4715},[3395,15258,3860],{"class":4708},[3395,15260,4824],{"class":4715},[3395,15262,3860],{"class":4708},[3395,15264,4835],{"class":4704},[3395,15266,6142],{"class":4708},[3395,15268,15269,15272,15274,15276,15278,15280],{"class":3397,"line":3638},[3395,15270,15271],{"class":4888},"            \"AOT Handler invoked: {RequestId}\"",[3395,15273,4719],{"class":4708},[3395,15275,5896],{"class":4715},[3395,15277,3860],{"class":4708},[3395,15279,4804],{"class":4715},[3395,15281,6522],{"class":4708},[3395,15283,15284],{"class":3397,"line":3643},[3395,15285,3420],{"emptyLinePlaceholder":3419},[3395,15287,15288],{"class":3397,"line":3649},[3395,15289,15290],{"class":4690},"        \u002F\u002F Бізнес-логіка...\n",[3395,15292,15293,15295,15297,15300,15302,15305,15307,15309,15311,15313,15315,15318],{"class":3397,"line":3655},[3395,15294,8037],{"class":6221},[3395,15296,4906],{"class":4696},[3395,15298,15299],{"class":4700}," ApiResponse",[3395,15301,6238],{"class":4708},[3395,15303,15304],{"class":4715},"StatusCode",[3395,15306,6088],{"class":4708},[3395,15308,13042],{"class":5154},[3395,15310,4719],{"class":4708},[3395,15312,10503],{"class":4715},[3395,15314,6088],{"class":4708},[3395,15316,15317],{"class":4888},"\"OK\"",[3395,15319,10706],{"class":4708},[3395,15321,15322],{"class":3397,"line":3661},[3395,15323,6396],{"class":4708},[3395,15325,15326],{"class":3397,"line":3667},[3395,15327,3479],{"class":4708},[3395,15329,15330],{"class":3397,"line":3672},[3395,15331,3420],{"emptyLinePlaceholder":3419},[3395,15333,15334,15336,15338,15341,15343,15345,15348,15350,15352,15355,15357,15359,15362,15364],{"class":3397,"line":8082},[3395,15335,4697],{"class":4696},[3395,15337,6686],{"class":4696},[3395,15339,15340],{"class":4700}," ApiRequest",[3395,15342,4709],{"class":4708},[3395,15344,3954],{"class":4696},[3395,15346,15347],{"class":4715}," Path",[3395,15349,4719],{"class":4708},[3395,15351,3954],{"class":4696},[3395,15353,15354],{"class":4715}," Method",[3395,15356,4719],{"class":4708},[3395,15358,3954],{"class":4696},[3395,15360,15361],{"class":4708},"? ",[3395,15363,10503],{"class":4715},[3395,15365,6522],{"class":4708},[3395,15367,15368,15370,15372,15374,15376,15378,15381,15383,15385,15388],{"class":3397,"line":8104},[3395,15369,4697],{"class":4696},[3395,15371,6686],{"class":4696},[3395,15373,15299],{"class":4700},[3395,15375,4709],{"class":4708},[3395,15377,6701],{"class":4696},[3395,15379,15380],{"class":4715}," StatusCode",[3395,15382,4719],{"class":4708},[3395,15384,3954],{"class":4696},[3395,15386,15387],{"class":4715}," Body",[3395,15389,6522],{"class":4708},[15391,15392,15393,15396,15397,4719,15400,4719,15403,15406,15407,15410],"caution",{},[3359,15394,15395],{},"Обмеження Native AOT."," Native AOT несумісний з динамічними можливостями .NET: рефлексія (Reflection), ",[3392,15398,15399],{},"dynamic",[3392,15401,15402],{},"Assembly.Load",[3392,15404,15405],{},"Activator.CreateInstance"," без Source Generators. Деякі популярні бібліотеки (AutoMapper, Entity Framework Core) не сумісні з AOT або мають обмежену підтримку. ",[3359,15408,15409],{},"Перевіряйте сумісність всіх NuGet-залежностей"," перед переходом на AOT.",[3684,15412],{},[3348,15414,15416],{"id":15415},"provisioned-concurrency-усунення-cold-start-для-критичних-функцій","Provisioned Concurrency: усунення Cold Start для критичних функцій",[3353,15418,15419,15422,15423,15426,15427,3860],{},[3359,15420,15421],{},"Provisioned Concurrency"," — це механізм, що дозволяє AWS підтримувати вказану кількість ",[3359,15424,15425],{},"заздалегідь ініціалізованих"," Execution Environments у постійній готовності. На відміну від звичайних (on-demand) Execution Environments, що ініціалізуються при надходженні запиту (Cold Start), Provisioned Environments вже прогріті та готові обробляти виклики ",[3359,15428,15429],{},"негайно",[3382,15431,15432],{},[3385,15433,15435],{"className":3387,"code":15434,"language":3389,"meta":3390,"style":3390},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\ntitle \"On-Demand vs Provisioned Concurrency\"\n\nrectangle \"On-Demand Concurrency\\n(стандартна поведінка)\" as OD #fef3c7 {\n    rectangle \"Виклик 1 → Cold Start\\n(Init: ~1200ms + Handler: ~50ms)\\nЗАГАЛОМ: ~1250ms\" as OD1 #fca5a5\n    rectangle \"Виклик 2 (warm)\\n(Handler: ~50ms)\\nЗАГАЛОМ: ~50ms\" as OD2 #bbf7d0\n    rectangle \"Новий Execution Env → Cold Start\\n(Init: ~1200ms + Handler: ~50ms)\\nЗАГАЛОМ: ~1250ms\" as OD3 #fca5a5\n}\n\nrectangle \"Provisioned Concurrency = 5\\n(5 Execution Envs заздалегідь ініціалізовані)\" as PC #d1fae5 {\n    rectangle \"Виклик 1\\n(Handler: ~50ms)\\n← НЕМАЄ Cold Start!\" as PC1 #bbf7d0\n    rectangle \"Виклик 2\\n(Handler: ~50ms)\\n← НЕМАЄ Cold Start!\" as PC2 #bbf7d0\n    rectangle \"Виклик 5\\n(Handler: ~50ms)\\n← НЕМАЄ Cold Start!\" as PC3 #bbf7d0\n    rectangle \"Виклик 6+ → On-Demand\\n(Cold Start якщо PC вичерпано)\" as PC4 #fde68a\n}\n\nnote bottom of OD : Безкоштовно, але непередбачувана латентність\nnote bottom of PC : Додаткова вартість: ~$0.015\u002Fгод за 1 env\\nАЛЕ: гарантована латентність \u003C100ms\n\n@enduml\n",[3392,15436,15437,15441,15445,15449,15453,15458,15462,15467,15472,15477,15482,15486,15490,15495,15500,15505,15510,15515,15519,15523,15528,15533,15537],{"__ignoreMap":3390},[3395,15438,15439],{"class":3397,"line":3398},[3395,15440,3401],{},[3395,15442,15443],{"class":3397,"line":3404},[3395,15444,3407],{},[3395,15446,15447],{"class":3397,"line":3410},[3395,15448,3413],{},[3395,15450,15451],{"class":3397,"line":3416},[3395,15452,3420],{"emptyLinePlaceholder":3419},[3395,15454,15455],{"class":3397,"line":3423},[3395,15456,15457],{},"title \"On-Demand vs Provisioned Concurrency\"\n",[3395,15459,15460],{"class":3397,"line":3429},[3395,15461,3420],{"emptyLinePlaceholder":3419},[3395,15463,15464],{"class":3397,"line":3434},[3395,15465,15466],{},"rectangle \"On-Demand Concurrency\\n(стандартна поведінка)\" as OD #fef3c7 {\n",[3395,15468,15469],{"class":3397,"line":3440},[3395,15470,15471],{},"    rectangle \"Виклик 1 → Cold Start\\n(Init: ~1200ms + Handler: ~50ms)\\nЗАГАЛОМ: ~1250ms\" as OD1 #fca5a5\n",[3395,15473,15474],{"class":3397,"line":3446},[3395,15475,15476],{},"    rectangle \"Виклик 2 (warm)\\n(Handler: ~50ms)\\nЗАГАЛОМ: ~50ms\" as OD2 #bbf7d0\n",[3395,15478,15479],{"class":3397,"line":3452},[3395,15480,15481],{},"    rectangle \"Новий Execution Env → Cold Start\\n(Init: ~1200ms + Handler: ~50ms)\\nЗАГАЛОМ: ~1250ms\" as OD3 #fca5a5\n",[3395,15483,15484],{"class":3397,"line":3458},[3395,15485,3479],{},[3395,15487,15488],{"class":3397,"line":3464},[3395,15489,3420],{"emptyLinePlaceholder":3419},[3395,15491,15492],{"class":3397,"line":3470},[3395,15493,15494],{},"rectangle \"Provisioned Concurrency = 5\\n(5 Execution Envs заздалегідь ініціалізовані)\" as PC #d1fae5 {\n",[3395,15496,15497],{"class":3397,"line":3476},[3395,15498,15499],{},"    rectangle \"Виклик 1\\n(Handler: ~50ms)\\n← НЕМАЄ Cold Start!\" as PC1 #bbf7d0\n",[3395,15501,15502],{"class":3397,"line":3482},[3395,15503,15504],{},"    rectangle \"Виклик 2\\n(Handler: ~50ms)\\n← НЕМАЄ Cold Start!\" as PC2 #bbf7d0\n",[3395,15506,15507],{"class":3397,"line":3487},[3395,15508,15509],{},"    rectangle \"Виклик 5\\n(Handler: ~50ms)\\n← НЕМАЄ Cold Start!\" as PC3 #bbf7d0\n",[3395,15511,15512],{"class":3397,"line":3493},[3395,15513,15514],{},"    rectangle \"Виклик 6+ → On-Demand\\n(Cold Start якщо PC вичерпано)\" as PC4 #fde68a\n",[3395,15516,15517],{"class":3397,"line":3499},[3395,15518,3479],{},[3395,15520,15521],{"class":3397,"line":3505},[3395,15522,3420],{"emptyLinePlaceholder":3419},[3395,15524,15525],{"class":3397,"line":3511},[3395,15526,15527],{},"note bottom of OD : Безкоштовно, але непередбачувана латентність\n",[3395,15529,15530],{"class":3397,"line":3517},[3395,15531,15532],{},"note bottom of PC : Додаткова вартість: ~$0.015\u002Fгод за 1 env\\nАЛЕ: гарантована латентність \u003C100ms\n",[3395,15534,15535],{"class":3397,"line":3523},[3395,15536,3420],{"emptyLinePlaceholder":3419},[3395,15538,15539],{"class":3397,"line":3529},[3395,15540,3675],{},[3704,15542,15544],{"id":15543},"коли-provisioned-concurrency-є-необхідністю","Коли Provisioned Concurrency є необхідністю",[3353,15546,15547],{},"Не кожна Lambda-функція потребує Provisioned Concurrency. Цей механізм є виправданим лише в конкретних сценаріях:",[3862,15549,15550,15563,15568],{},[3865,15551,15554,15557],{"icon":15552,"title":15553},"i-heroicons-user-circle","User-facing API",[3353,15555,15556],{},"API Gateway + Lambda, де Cold Start безпосередньо впливає на користувацький досвід. P99 latency > 2 секунди є неприйнятним для інтерактивних застосунків.",[3353,15558,15559,15560],{},"Рекомендація: ",[3359,15561,15562],{},"PC = мінімальна очікувана одночасна кількість запитів у пік",[3865,15564,15567],{"icon":15565,"title":15566},"i-heroicons-shield-check","SLA-критичні функції","Функції з жорсткими SLA (\u003C500ms response time), де Cold Start є порушенням контракту. Наприклад: платіжні шлюзи, системи real-time торгів.",[3865,15569,15571],{"icon":5696,"title":15570},"Функції з дорогим Init","ML-моделі, що завантажуються у Init-фазі (100-500 MB модель), або функції зі складними DI-контейнерами (> 3 секунд ініціалізації).",[3704,15573,15575],{"id":15574},"конфігурація-provisioned-concurrency","Конфігурація Provisioned Concurrency",[3353,15577,15578],{},[3359,15579,15580],{},"Налаштування через AWS CLI:",[3385,15582,15584],{"className":4876,"code":15583,"language":4878,"meta":3390,"style":3390},"# Крок 1: опублікувати нову версію функції\n# (Provisioned Concurrency застосовується до версій, не до $LATEST)\naws lambda publish-version \\\n    --function-name dotnet-api-function \\\n    --description \"v1.0.0 — production release\" \\\n    --region eu-central-1\n\n# Крок 2: зберегти ARN версії\nFUNCTION_VERSION_ARN=$(aws lambda list-versions-by-function \\\n    --function-name dotnet-api-function \\\n    --region eu-central-1 \\\n    --query \"Versions[-1].FunctionArn\" \\\n    --output text)\n\necho \"Function version: $FUNCTION_VERSION_ARN\"\n\n# Крок 3: увімкнути Provisioned Concurrency для цієї версії\naws lambda put-provisioned-concurrency-config \\\n    --function-name dotnet-api-function \\\n    --qualifier 1 \\\n    --provisioned-concurrent-executions 5 \\\n    --region eu-central-1\n",[3392,15585,15586,15591,15596,15607,15616,15625,15633,15637,15642,15659,15667,15676,15686,15695,15699,15713,15717,15722,15733,15741,15751,15761],{"__ignoreMap":3390},[3395,15587,15588],{"class":3397,"line":3398},[3395,15589,15590],{"class":4690},"# Крок 1: опублікувати нову версію функції\n",[3395,15592,15593],{"class":3397,"line":3404},[3395,15594,15595],{"class":4690},"# (Provisioned Concurrency застосовується до версій, не до $LATEST)\n",[3395,15597,15598,15600,15602,15605],{"class":3397,"line":3410},[3395,15599,5575],{"class":4704},[3395,15601,5016],{"class":4888},[3395,15603,15604],{"class":4888}," publish-version",[3395,15606,5584],{"class":5583},[3395,15608,15609,15611,15614],{"class":3397,"line":3416},[3395,15610,5650],{"class":4696},[3395,15612,15613],{"class":4888}," dotnet-api-function",[3395,15615,5584],{"class":5583},[3395,15617,15618,15620,15623],{"class":3397,"line":3423},[3395,15619,5599],{"class":4696},[3395,15621,15622],{"class":4888}," \"v1.0.0 — production release\"",[3395,15624,5584],{"class":5583},[3395,15626,15627,15630],{"class":3397,"line":3429},[3395,15628,15629],{"class":4696},"    --region",[3395,15631,15632],{"class":4888}," eu-central-1\n",[3395,15634,15635],{"class":3397,"line":3434},[3395,15636,3420],{"emptyLinePlaceholder":3419},[3395,15638,15639],{"class":3397,"line":3440},[3395,15640,15641],{"class":4690},"# Крок 2: зберегти ARN версії\n",[3395,15643,15644,15647,15650,15652,15654,15657],{"class":3397,"line":3446},[3395,15645,15646],{"class":4715},"FUNCTION_VERSION_ARN",[3395,15648,15649],{"class":4708},"=$(",[3395,15651,5575],{"class":4704},[3395,15653,5016],{"class":4888},[3395,15655,15656],{"class":4888}," list-versions-by-function",[3395,15658,5584],{"class":5583},[3395,15660,15661,15663,15665],{"class":3397,"line":3452},[3395,15662,5650],{"class":4696},[3395,15664,15613],{"class":4888},[3395,15666,5584],{"class":5583},[3395,15668,15669,15671,15674],{"class":3397,"line":3458},[3395,15670,15629],{"class":4696},[3395,15672,15673],{"class":4888}," eu-central-1",[3395,15675,5584],{"class":5583},[3395,15677,15678,15681,15684],{"class":3397,"line":3464},[3395,15679,15680],{"class":4696},"    --query",[3395,15682,15683],{"class":4888}," \"Versions[-1].FunctionArn\"",[3395,15685,5584],{"class":5583},[3395,15687,15688,15690,15693],{"class":3397,"line":3470},[3395,15689,14326],{"class":4696},[3395,15691,15692],{"class":4888}," text",[3395,15694,4727],{"class":4708},[3395,15696,15697],{"class":3397,"line":3476},[3395,15698,3420],{"emptyLinePlaceholder":3419},[3395,15700,15701,15704,15707,15710],{"class":3397,"line":3482},[3395,15702,15703],{"class":4704},"echo",[3395,15705,15706],{"class":4888}," \"Function version: ",[3395,15708,15709],{"class":4715},"$FUNCTION_VERSION_ARN",[3395,15711,15712],{"class":4888},"\"\n",[3395,15714,15715],{"class":3397,"line":3487},[3395,15716,3420],{"emptyLinePlaceholder":3419},[3395,15718,15719],{"class":3397,"line":3493},[3395,15720,15721],{"class":4690},"# Крок 3: увімкнути Provisioned Concurrency для цієї версії\n",[3395,15723,15724,15726,15728,15731],{"class":3397,"line":3499},[3395,15725,5575],{"class":4704},[3395,15727,5016],{"class":4888},[3395,15729,15730],{"class":4888}," put-provisioned-concurrency-config",[3395,15732,5584],{"class":5583},[3395,15734,15735,15737,15739],{"class":3397,"line":3505},[3395,15736,5650],{"class":4696},[3395,15738,15613],{"class":4888},[3395,15740,5584],{"class":5583},[3395,15742,15743,15746,15749],{"class":3397,"line":3511},[3395,15744,15745],{"class":4696},"    --qualifier",[3395,15747,15748],{"class":5154}," 1",[3395,15750,5584],{"class":5583},[3395,15752,15753,15756,15759],{"class":3397,"line":3517},[3395,15754,15755],{"class":4696},"    --provisioned-concurrent-executions",[3395,15757,15758],{"class":5154}," 5",[3395,15760,5584],{"class":5583},[3395,15762,15763,15765],{"class":3397,"line":3523},[3395,15764,15629],{"class":4696},[3395,15766,15632],{"class":4888},[15768,15769,15771,15783,15786,15800,15811,15821,15833,15844,15855,15858],"terminal-preview",{"title":15770},"put-provisioned-concurrency-config",[15772,15773,15775,4577,15780],"div",{"className":15774},[3397],[3395,15776,15779],{"className":15777},[15778],"opacity-40","$",[3359,15781,15782],{},"aws lambda put-provisioned-concurrency-config --function-name dotnet-api-function --qualifier 1 --provisioned-concurrent-executions 5",[15772,15784,6507],{"className":15785},[3397],[15772,15787,15789,15790,5078,15795,15799],{"className":15788},[3397],"  ",[3395,15791,15794],{"className":15792},[15793],"text-blue-400","\"RequestedProvisionedConcurrentExecutions\"",[3395,15796,11976],{"className":15797},[15798],"text-yellow-400",",",[15772,15801,15789,15803,5078,15807,15799],{"className":15802},[3397],[3395,15804,15806],{"className":15805},[15793],"\"AvailableProvisionedConcurrentExecutions\"",[3395,15808,15810],{"className":15809},[15798],"0",[15772,15812,15789,15814,5078,15818,15799],{"className":15813},[3397],[3395,15815,15817],{"className":15816},[15793],"\"AllocatedProvisionedConcurrentExecutions\"",[3395,15819,15810],{"className":15820},[15798],[15772,15822,15789,15824,5078,15828,15799],{"className":15823},[3397],[3395,15825,15827],{"className":15826},[15793],"\"Status\"",[3395,15829,15832],{"className":15830},[15831],"text-green-400","\"IN_PROGRESS\"",[15772,15834,15789,15836,5078,15840,15799],{"className":15835},[3397],[3395,15837,15839],{"className":15838},[15793],"\"StatusReason\"",[3395,15841,15843],{"className":15842},[15831],"\"Provisioning 5 concurrent executions\"",[15772,15845,15789,15847,5078,15851],{"className":15846},[3397],[3395,15848,15850],{"className":15849},[15793],"\"LastModified\"",[3395,15852,15854],{"className":15853},[15831],"\"2024-03-15T10:30:00+0000\"",[15772,15856,6516],{"className":15857},[3397],[15772,15859,15861],{"className":15860},[3397],[3395,15862,15865],{"className":15863},[15798,15864],"opacity-60","← Статус \"IN_PROGRESS\": AWS ініціалізує 5 Execution Environments (~2-3 хвилини)",[3353,15867,15868],{},[3359,15869,15870],{},"Перевірка готовності Provisioned Concurrency:",[3385,15872,15874],{"className":4876,"code":15873,"language":4878,"meta":3390,"style":3390},"# Очікуємо переходу статусу з IN_PROGRESS на READY\naws lambda get-provisioned-concurrency-config \\\n    --function-name dotnet-api-function \\\n    --qualifier 1 \\\n    --region eu-central-1\n",[3392,15875,15876,15881,15892,15900,15908],{"__ignoreMap":3390},[3395,15877,15878],{"class":3397,"line":3398},[3395,15879,15880],{"class":4690},"# Очікуємо переходу статусу з IN_PROGRESS на READY\n",[3395,15882,15883,15885,15887,15890],{"class":3397,"line":3404},[3395,15884,5575],{"class":4704},[3395,15886,5016],{"class":4888},[3395,15888,15889],{"class":4888}," get-provisioned-concurrency-config",[3395,15891,5584],{"class":5583},[3395,15893,15894,15896,15898],{"class":3397,"line":3410},[3395,15895,5650],{"class":4696},[3395,15897,15613],{"class":4888},[3395,15899,5584],{"class":5583},[3395,15901,15902,15904,15906],{"class":3397,"line":3416},[3395,15903,15745],{"class":4696},[3395,15905,15748],{"class":5154},[3395,15907,5584],{"class":5583},[3395,15909,15910,15912],{"class":3397,"line":3423},[3395,15911,15629],{"class":4696},[3395,15913,15632],{"class":4888},[15768,15915,15917,15926,15929,15938,15947,15956,15966,15976,15979],{"title":15916},"Статус READY — Provisioned Concurrency активний",[15772,15918,15920,4577,15923],{"className":15919},[3397],[3395,15921,15779],{"className":15922},[15778],[3359,15924,15925],{},"aws lambda get-provisioned-concurrency-config --function-name dotnet-api-function --qualifier 1",[15772,15927,6507],{"className":15928},[3397],[15772,15930,15789,15932,5078,15935,15799],{"className":15931},[3397],[3395,15933,15794],{"className":15934},[15793],[3395,15936,11976],{"className":15937},[15798],[15772,15939,15789,15941,5078,15944,15799],{"className":15940},[3397],[3395,15942,15806],{"className":15943},[15793],[3395,15945,11976],{"className":15946},[15798],[15772,15948,15789,15950,5078,15953,15799],{"className":15949},[3397],[3395,15951,15817],{"className":15952},[15793],[3395,15954,11976],{"className":15955},[15798],[15772,15957,15789,15959,5078,15962,15799],{"className":15958},[3397],[3395,15960,15827],{"className":15961},[15793],[3395,15963,15965],{"className":15964},[15831],"\"READY\"",[15772,15967,15789,15969,5078,15972],{"className":15968},[3397],[3395,15970,15850],{"className":15971},[15793],[3395,15973,15975],{"className":15974},[15831],"\"2024-03-15T10:32:47+0000\"",[15772,15977,6516],{"className":15978},[3397],[15772,15980,15982],{"className":15981},[3397],[3395,15983,15985],{"className":15984},[15831,15864],"← READY: всі 5 Execution Environments ініціалізовані та чекають викликів",[3704,15987,15989],{"id":15988},"application-auto-scaling-для-provisioned-concurrency","Application Auto Scaling для Provisioned Concurrency",[3353,15991,15992,15993,15996],{},"Оскільки Provisioned Concurrency має фіксовану щогодинну вартість, утримувати максимальний рівень цілодобово є нераціональним. ",[3359,15994,15995],{},"Application Auto Scaling"," дозволяє автоматично змінювати кількість Provisioned Environments за розкладом або на основі метрик.",[3385,15998,16000],{"className":4876,"code":15999,"language":4878,"meta":3390,"style":3390},"# Реєстрація Lambda як scalable target для Application Auto Scaling\naws application-autoscaling register-scalable-target \\\n    --service-namespace lambda \\\n    --resource-id \"function:dotnet-api-function:1\" \\\n    --scalable-dimension \"lambda:function:ProvisionedConcurrency\" \\\n    --min-capacity 2 \\\n    --max-capacity 50 \\\n    --region eu-central-1\n\n# Створення Scheduled Action: збільшення PC о 07:00 UTC (ранкова активність)\naws application-autoscaling put-scheduled-action \\\n    --service-namespace lambda \\\n    --resource-id \"function:dotnet-api-function:1\" \\\n    --scalable-dimension \"lambda:function:ProvisionedConcurrency\" \\\n    --scheduled-action-name \"scale-up-morning\" \\\n    --schedule \"cron(0 7 * * ? *)\" \\\n    --scalable-target-action MinCapacity=10,MaxCapacity=50 \\\n    --region eu-central-1\n\n# Зменшення PC о 22:00 UTC (нічний мінімум)\naws application-autoscaling put-scheduled-action \\\n    --service-namespace lambda \\\n    --resource-id \"function:dotnet-api-function:1\" \\\n    --scalable-dimension \"lambda:function:ProvisionedConcurrency\" \\\n    --scheduled-action-name \"scale-down-night\" \\\n    --schedule \"cron(0 22 * * ? *)\" \\\n    --scalable-target-action MinCapacity=2,MaxCapacity=50 \\\n    --region eu-central-1\n",[3392,16001,16002,16007,16019,16028,16038,16048,16058,16068,16074,16078,16083,16094,16102,16110,16118,16128,16138,16151,16157,16161,16166,16176,16184,16192,16200,16209,16218,16229],{"__ignoreMap":3390},[3395,16003,16004],{"class":3397,"line":3398},[3395,16005,16006],{"class":4690},"# Реєстрація Lambda як scalable target для Application Auto Scaling\n",[3395,16008,16009,16011,16014,16017],{"class":3397,"line":3404},[3395,16010,5575],{"class":4704},[3395,16012,16013],{"class":4888}," application-autoscaling",[3395,16015,16016],{"class":4888}," register-scalable-target",[3395,16018,5584],{"class":5583},[3395,16020,16021,16024,16026],{"class":3397,"line":3410},[3395,16022,16023],{"class":4696},"    --service-namespace",[3395,16025,5016],{"class":4888},[3395,16027,5584],{"class":5583},[3395,16029,16030,16033,16036],{"class":3397,"line":3416},[3395,16031,16032],{"class":4696},"    --resource-id",[3395,16034,16035],{"class":4888}," \"function:dotnet-api-function:1\"",[3395,16037,5584],{"class":5583},[3395,16039,16040,16043,16046],{"class":3397,"line":3423},[3395,16041,16042],{"class":4696},"    --scalable-dimension",[3395,16044,16045],{"class":4888}," \"lambda:function:ProvisionedConcurrency\"",[3395,16047,5584],{"class":5583},[3395,16049,16050,16053,16056],{"class":3397,"line":3429},[3395,16051,16052],{"class":4696},"    --min-capacity",[3395,16054,16055],{"class":5154}," 2",[3395,16057,5584],{"class":5583},[3395,16059,16060,16063,16066],{"class":3397,"line":3434},[3395,16061,16062],{"class":4696},"    --max-capacity",[3395,16064,16065],{"class":5154}," 50",[3395,16067,5584],{"class":5583},[3395,16069,16070,16072],{"class":3397,"line":3440},[3395,16071,15629],{"class":4696},[3395,16073,15632],{"class":4888},[3395,16075,16076],{"class":3397,"line":3446},[3395,16077,3420],{"emptyLinePlaceholder":3419},[3395,16079,16080],{"class":3397,"line":3452},[3395,16081,16082],{"class":4690},"# Створення Scheduled Action: збільшення PC о 07:00 UTC (ранкова активність)\n",[3395,16084,16085,16087,16089,16092],{"class":3397,"line":3458},[3395,16086,5575],{"class":4704},[3395,16088,16013],{"class":4888},[3395,16090,16091],{"class":4888}," put-scheduled-action",[3395,16093,5584],{"class":5583},[3395,16095,16096,16098,16100],{"class":3397,"line":3464},[3395,16097,16023],{"class":4696},[3395,16099,5016],{"class":4888},[3395,16101,5584],{"class":5583},[3395,16103,16104,16106,16108],{"class":3397,"line":3470},[3395,16105,16032],{"class":4696},[3395,16107,16035],{"class":4888},[3395,16109,5584],{"class":5583},[3395,16111,16112,16114,16116],{"class":3397,"line":3476},[3395,16113,16042],{"class":4696},[3395,16115,16045],{"class":4888},[3395,16117,5584],{"class":5583},[3395,16119,16120,16123,16126],{"class":3397,"line":3482},[3395,16121,16122],{"class":4696},"    --scheduled-action-name",[3395,16124,16125],{"class":4888}," \"scale-up-morning\"",[3395,16127,5584],{"class":5583},[3395,16129,16130,16133,16136],{"class":3397,"line":3487},[3395,16131,16132],{"class":4696},"    --schedule",[3395,16134,16135],{"class":4888}," \"cron(0 7 * * ? *)\"",[3395,16137,5584],{"class":5583},[3395,16139,16140,16143,16146,16149],{"class":3397,"line":3493},[3395,16141,16142],{"class":4696},"    --scalable-target-action",[3395,16144,16145],{"class":4888}," MinCapacity=10,MaxCapacity=",[3395,16147,16148],{"class":5154},"50",[3395,16150,5584],{"class":5583},[3395,16152,16153,16155],{"class":3397,"line":3499},[3395,16154,15629],{"class":4696},[3395,16156,15632],{"class":4888},[3395,16158,16159],{"class":3397,"line":3505},[3395,16160,3420],{"emptyLinePlaceholder":3419},[3395,16162,16163],{"class":3397,"line":3511},[3395,16164,16165],{"class":4690},"# Зменшення PC о 22:00 UTC (нічний мінімум)\n",[3395,16167,16168,16170,16172,16174],{"class":3397,"line":3517},[3395,16169,5575],{"class":4704},[3395,16171,16013],{"class":4888},[3395,16173,16091],{"class":4888},[3395,16175,5584],{"class":5583},[3395,16177,16178,16180,16182],{"class":3397,"line":3523},[3395,16179,16023],{"class":4696},[3395,16181,5016],{"class":4888},[3395,16183,5584],{"class":5583},[3395,16185,16186,16188,16190],{"class":3397,"line":3529},[3395,16187,16032],{"class":4696},[3395,16189,16035],{"class":4888},[3395,16191,5584],{"class":5583},[3395,16193,16194,16196,16198],{"class":3397,"line":3534},[3395,16195,16042],{"class":4696},[3395,16197,16045],{"class":4888},[3395,16199,5584],{"class":5583},[3395,16201,16202,16204,16207],{"class":3397,"line":3539},[3395,16203,16122],{"class":4696},[3395,16205,16206],{"class":4888}," \"scale-down-night\"",[3395,16208,5584],{"class":5583},[3395,16210,16211,16213,16216],{"class":3397,"line":3545},[3395,16212,16132],{"class":4696},[3395,16214,16215],{"class":4888}," \"cron(0 22 * * ? *)\"",[3395,16217,5584],{"class":5583},[3395,16219,16220,16222,16225,16227],{"class":3397,"line":3551},[3395,16221,16142],{"class":4696},[3395,16223,16224],{"class":4888}," MinCapacity=2,MaxCapacity=",[3395,16226,16148],{"class":5154},[3395,16228,5584],{"class":5583},[3395,16230,16231,16233],{"class":3397,"line":3557},[3395,16232,15629],{"class":4696},[3395,16234,15632],{"class":4888},[3684,16236],{},[3348,16238,16240],{"id":16239},"моніторинг-lambda-через-amazon-cloudwatch","Моніторинг Lambda через Amazon CloudWatch",[3353,16242,16243],{},"Lambda автоматично публікує набір метрик у CloudWatch без будь-якого налаштування. Розуміння цих метрик є фундаментальним для операційного контролю над serverless системою.",[3862,16245,16246,16252,16263,16270,16278,16286],{},[3865,16247,16249,16251],{"icon":3867,"title":16248},"Invocations",[3359,16250,3868],{}," функції за період. Включає успішні та невдалі виклики. Базова метрика для розуміння навантаження та оцінки витрат.",[3865,16253,16256,16259,16260,3860],{"icon":16254,"title":16255},"i-heroicons-exclamation-triangle","Errors",[3359,16257,16258],{},"Кількість викликів, що завершились помилкою",": необроблені виключення, таймаути, помилки MemoryExceeded. ",[3392,16261,16262],{},"Error Rate = Errors \u002F Invocations",[3865,16264,16266,16269],{"icon":3883,"title":16265},"Duration",[3359,16267,16268],{},"Час виконання"," у мілісекундах: Average, P50, P95, P99. P99 Duration є критичним показником: він відображає найгірший досвід 1% користувачів.",[3865,16271,16274,16277],{"icon":16272,"title":16273},"i-heroicons-no-symbol","Throttles",[3359,16275,16276],{},"Кількість викликів, що відхилені"," через перевищення Concurrency Limit. Якщо Throttles > 0 — функція досягла ліміту паралелізму і деякі запити не обробляються.",[3865,16279,16282,16285],{"icon":16280,"title":16281},"i-heroicons-square-3-stack-3d","ConcurrentExecutions",[3359,16283,16284],{},"Поточна кількість"," одночасно виконуваних інстанцій. Корисна для відстеження наближення до Concurrency Limit (1,000 за замовчуванням).",[3865,16287,16290,16293],{"icon":16288,"title":16289},"i-heroicons-rocket-launch","InitDuration",[3359,16291,16292],{},"Час Cold Start Init-фази"," у мілісекундах. Відображається лише для викликів, що викликали Cold Start. Ключова метрика для відстеження ефективності оптимізацій.",[3353,16295,16296],{},[3359,16297,16298],{},"Рекомендований CloudWatch Dashboard для Lambda:",[3385,16300,16302],{"className":4876,"code":16301,"language":4878,"meta":3390,"style":3390},"# Створення CloudWatch Alarm для відстеження критичного рівня помилок\naws cloudwatch put-metric-alarm \\\n    --alarm-name \"lambda-dotnet-error-rate-critical\" \\\n    --alarm-description \"Error rate > 5% for 2 consecutive periods\" \\\n    --metric-name Errors \\\n    --namespace AWS\u002FLambda \\\n    --dimensions Name=FunctionName,Value=dotnet-api-function \\\n    --statistic Sum \\\n    --period 60 \\\n    --evaluation-periods 2 \\\n    --threshold 5 \\\n    --comparison-operator GreaterThanOrEqualToThreshold \\\n    --treat-missing-data notBreaching \\\n    --alarm-actions \"arn:aws:sns:eu-central-1:123456789012:ops-alerts\" \\\n    --region eu-central-1\n\n# Alarm для відстеження Cold Start тривалості > 3 секунд\naws cloudwatch put-metric-alarm \\\n    --alarm-name \"lambda-cold-start-too-long\" \\\n    --alarm-description \"Init duration > 3000ms — investigate optimization\" \\\n    --metric-name InitDuration \\\n    --namespace AWS\u002FLambda \\\n    --dimensions Name=FunctionName,Value=dotnet-api-function \\\n    --statistic p99 \\\n    --period 300 \\\n    --evaluation-periods 1 \\\n    --threshold 3000 \\\n    --comparison-operator GreaterThanThreshold \\\n    --alarm-actions \"arn:aws:sns:eu-central-1:123456789012:ops-alerts\" \\\n    --region eu-central-1\n",[3392,16303,16304,16309,16321,16331,16341,16351,16361,16371,16381,16391,16400,16409,16419,16429,16439,16445,16449,16454,16464,16473,16482,16491,16499,16507,16516,16525,16533,16542,16551,16559],{"__ignoreMap":3390},[3395,16305,16306],{"class":3397,"line":3398},[3395,16307,16308],{"class":4690},"# Створення CloudWatch Alarm для відстеження критичного рівня помилок\n",[3395,16310,16311,16313,16316,16319],{"class":3397,"line":3404},[3395,16312,5575],{"class":4704},[3395,16314,16315],{"class":4888}," cloudwatch",[3395,16317,16318],{"class":4888}," put-metric-alarm",[3395,16320,5584],{"class":5583},[3395,16322,16323,16326,16329],{"class":3397,"line":3410},[3395,16324,16325],{"class":4696},"    --alarm-name",[3395,16327,16328],{"class":4888}," \"lambda-dotnet-error-rate-critical\"",[3395,16330,5584],{"class":5583},[3395,16332,16333,16336,16339],{"class":3397,"line":3416},[3395,16334,16335],{"class":4696},"    --alarm-description",[3395,16337,16338],{"class":4888}," \"Error rate > 5% for 2 consecutive periods\"",[3395,16340,5584],{"class":5583},[3395,16342,16343,16346,16349],{"class":3397,"line":3423},[3395,16344,16345],{"class":4696},"    --metric-name",[3395,16347,16348],{"class":4888}," Errors",[3395,16350,5584],{"class":5583},[3395,16352,16353,16356,16359],{"class":3397,"line":3429},[3395,16354,16355],{"class":4696},"    --namespace",[3395,16357,16358],{"class":4888}," AWS\u002FLambda",[3395,16360,5584],{"class":5583},[3395,16362,16363,16366,16369],{"class":3397,"line":3434},[3395,16364,16365],{"class":4696},"    --dimensions",[3395,16367,16368],{"class":4888}," Name=FunctionName,Value=dotnet-api-function",[3395,16370,5584],{"class":5583},[3395,16372,16373,16376,16379],{"class":3397,"line":3440},[3395,16374,16375],{"class":4696},"    --statistic",[3395,16377,16378],{"class":4888}," Sum",[3395,16380,5584],{"class":5583},[3395,16382,16383,16386,16389],{"class":3397,"line":3446},[3395,16384,16385],{"class":4696},"    --period",[3395,16387,16388],{"class":5154}," 60",[3395,16390,5584],{"class":5583},[3395,16392,16393,16396,16398],{"class":3397,"line":3452},[3395,16394,16395],{"class":4696},"    --evaluation-periods",[3395,16397,16055],{"class":5154},[3395,16399,5584],{"class":5583},[3395,16401,16402,16405,16407],{"class":3397,"line":3458},[3395,16403,16404],{"class":4696},"    --threshold",[3395,16406,15758],{"class":5154},[3395,16408,5584],{"class":5583},[3395,16410,16411,16414,16417],{"class":3397,"line":3464},[3395,16412,16413],{"class":4696},"    --comparison-operator",[3395,16415,16416],{"class":4888}," GreaterThanOrEqualToThreshold",[3395,16418,5584],{"class":5583},[3395,16420,16421,16424,16427],{"class":3397,"line":3470},[3395,16422,16423],{"class":4696},"    --treat-missing-data",[3395,16425,16426],{"class":4888}," notBreaching",[3395,16428,5584],{"class":5583},[3395,16430,16431,16434,16437],{"class":3397,"line":3476},[3395,16432,16433],{"class":4696},"    --alarm-actions",[3395,16435,16436],{"class":4888}," \"arn:aws:sns:eu-central-1:123456789012:ops-alerts\"",[3395,16438,5584],{"class":5583},[3395,16440,16441,16443],{"class":3397,"line":3482},[3395,16442,15629],{"class":4696},[3395,16444,15632],{"class":4888},[3395,16446,16447],{"class":3397,"line":3487},[3395,16448,3420],{"emptyLinePlaceholder":3419},[3395,16450,16451],{"class":3397,"line":3493},[3395,16452,16453],{"class":4690},"# Alarm для відстеження Cold Start тривалості > 3 секунд\n",[3395,16455,16456,16458,16460,16462],{"class":3397,"line":3499},[3395,16457,5575],{"class":4704},[3395,16459,16315],{"class":4888},[3395,16461,16318],{"class":4888},[3395,16463,5584],{"class":5583},[3395,16465,16466,16468,16471],{"class":3397,"line":3505},[3395,16467,16325],{"class":4696},[3395,16469,16470],{"class":4888}," \"lambda-cold-start-too-long\"",[3395,16472,5584],{"class":5583},[3395,16474,16475,16477,16480],{"class":3397,"line":3511},[3395,16476,16335],{"class":4696},[3395,16478,16479],{"class":4888}," \"Init duration > 3000ms — investigate optimization\"",[3395,16481,5584],{"class":5583},[3395,16483,16484,16486,16489],{"class":3397,"line":3517},[3395,16485,16345],{"class":4696},[3395,16487,16488],{"class":4888}," InitDuration",[3395,16490,5584],{"class":5583},[3395,16492,16493,16495,16497],{"class":3397,"line":3523},[3395,16494,16355],{"class":4696},[3395,16496,16358],{"class":4888},[3395,16498,5584],{"class":5583},[3395,16500,16501,16503,16505],{"class":3397,"line":3529},[3395,16502,16365],{"class":4696},[3395,16504,16368],{"class":4888},[3395,16506,5584],{"class":5583},[3395,16508,16509,16511,16514],{"class":3397,"line":3534},[3395,16510,16375],{"class":4696},[3395,16512,16513],{"class":4888}," p99",[3395,16515,5584],{"class":5583},[3395,16517,16518,16520,16523],{"class":3397,"line":3539},[3395,16519,16385],{"class":4696},[3395,16521,16522],{"class":5154}," 300",[3395,16524,5584],{"class":5583},[3395,16526,16527,16529,16531],{"class":3397,"line":3545},[3395,16528,16395],{"class":4696},[3395,16530,15748],{"class":5154},[3395,16532,5584],{"class":5583},[3395,16534,16535,16537,16540],{"class":3397,"line":3551},[3395,16536,16404],{"class":4696},[3395,16538,16539],{"class":5154}," 3000",[3395,16541,5584],{"class":5583},[3395,16543,16544,16546,16549],{"class":3397,"line":3557},[3395,16545,16413],{"class":4696},[3395,16547,16548],{"class":4888}," GreaterThanThreshold",[3395,16550,5584],{"class":5583},[3395,16552,16553,16555,16557],{"class":3397,"line":3563},[3395,16554,16433],{"class":4696},[3395,16556,16436],{"class":4888},[3395,16558,5584],{"class":5583},[3395,16560,16561,16563],{"class":3397,"line":3569},[3395,16562,15629],{"class":4696},[3395,16564,15632],{"class":4888},[3684,16566],{},[3684,16568],{},[3348,16570,16572],{"id":16571},"mini-workshop-перший-деплой-lambda-функції","Mini-Workshop: Перший деплой Lambda-функції",[3353,16574,16575],{},"У цьому міні-воркшопі ми пройдемо шлях від встановлення інструментів до запуску вашої першої функції в хмарі. Ми розглянемо два підходи: спрощений (автоматизований) та повний (через S3 та AWS CLI).",[3704,16577,16579],{"id":16578},"_1-підготовка-інструментарію","1. Підготовка інструментарію",[3353,16581,16582,16583,3860],{},"Для роботи з .NET Lambda в AWS нам знадобиться спеціальний інструмент командного рядка, який розширює стандартний ",[3392,16584,16585],{},"dotnet cli",[3385,16587,16589],{"className":4876,"code":16588,"language":4878,"meta":3390,"style":3390},"# 0. Встановлюємо шаблони\ndotnet new install Amazon.Lambda.Templates\n\n# 1. Встановлюємо глобальний інструмент Amazon.Lambda.Tools\ndotnet tool install -g Amazon.Lambda.Tools\n\n# 2. Оновлюємо (якщо вже був встановлений)\ndotnet tool update -g Amazon.Lambda.Tools\n\n# 3. Перевіряємо готовність\ndotnet lambda --version\n",[3392,16590,16591,16596,16606,16610,16615,16630,16634,16639,16652,16656,16661],{"__ignoreMap":3390},[3395,16592,16593],{"class":3397,"line":3398},[3395,16594,16595],{"class":4690},"# 0. Встановлюємо шаблони\n",[3395,16597,16598,16600,16602,16604],{"class":3397,"line":3404},[3395,16599,4903],{"class":4704},[3395,16601,4906],{"class":4888},[3395,16603,4994],{"class":4888},[3395,16605,4997],{"class":4888},[3395,16607,16608],{"class":3397,"line":3410},[3395,16609,3420],{"emptyLinePlaceholder":3419},[3395,16611,16612],{"class":3397,"line":3416},[3395,16613,16614],{"class":4690},"# 1. Встановлюємо глобальний інструмент Amazon.Lambda.Tools\n",[3395,16616,16617,16619,16622,16624,16627],{"class":3397,"line":3423},[3395,16618,4903],{"class":4704},[3395,16620,16621],{"class":4888}," tool",[3395,16623,4994],{"class":4888},[3395,16625,16626],{"class":4696}," -g",[3395,16628,16629],{"class":4888}," Amazon.Lambda.Tools\n",[3395,16631,16632],{"class":3397,"line":3429},[3395,16633,3420],{"emptyLinePlaceholder":3419},[3395,16635,16636],{"class":3397,"line":3434},[3395,16637,16638],{"class":4690},"# 2. Оновлюємо (якщо вже був встановлений)\n",[3395,16640,16641,16643,16645,16648,16650],{"class":3397,"line":3440},[3395,16642,4903],{"class":4704},[3395,16644,16621],{"class":4888},[3395,16646,16647],{"class":4888}," update",[3395,16649,16626],{"class":4696},[3395,16651,16629],{"class":4888},[3395,16653,16654],{"class":3397,"line":3446},[3395,16655,3420],{"emptyLinePlaceholder":3419},[3395,16657,16658],{"class":3397,"line":3452},[3395,16659,16660],{"class":4690},"# 3. Перевіряємо готовність\n",[3395,16662,16663,16665,16667],{"class":3397,"line":3458},[3395,16664,4903],{"class":4704},[3395,16666,5016],{"class":4888},[3395,16668,16669],{"class":4696}," --version\n",[3704,16671,16673],{"id":16672},"_2-створення-тестового-проекту","2. Створення тестового проекту",[3353,16675,16676],{},"Створимо найпростішу функцію \"Hello World\", щоб перевірити ланцюжок деплойменту.",[16678,16679,16680,16735],"tabs",{},[16681,16682,16684],"tabs-item",{"label":16683},"CLI Commands",[3385,16685,16687],{"className":4876,"code":16686,"language":4878,"meta":3390,"style":3390},"# Створюємо проект за допомогою AWS шаблону\ndotnet new lambda.EmptyFunction -n MyFirstLambda -o src\u002FMyFirstLambda\ncd src\u002FMyFirstLambda\n\n# Додаємо залежності та перевіряємо проект\ndotnet restore\n",[3392,16688,16689,16694,16713,16719,16723,16728],{"__ignoreMap":3390},[3395,16690,16691],{"class":3397,"line":3398},[3395,16692,16693],{"class":4690},"# Створюємо проект за допомогою AWS шаблону\n",[3395,16695,16696,16698,16700,16703,16705,16708,16710],{"class":3397,"line":3404},[3395,16697,4903],{"class":4704},[3395,16699,4906],{"class":4888},[3395,16701,16702],{"class":4888}," lambda.EmptyFunction",[3395,16704,5041],{"class":4696},[3395,16706,16707],{"class":4888}," MyFirstLambda",[3395,16709,5518],{"class":4696},[3395,16711,16712],{"class":4888}," src\u002FMyFirstLambda\n",[3395,16714,16715,16717],{"class":3397,"line":3410},[3395,16716,4895],{"class":4704},[3395,16718,16712],{"class":4888},[3395,16720,16721],{"class":3397,"line":3416},[3395,16722,3420],{"emptyLinePlaceholder":3419},[3395,16724,16725],{"class":3397,"line":3423},[3395,16726,16727],{"class":4690},"# Додаємо залежності та перевіряємо проект\n",[3395,16729,16730,16732],{"class":3397,"line":3429},[3395,16731,4903],{"class":4704},[3395,16733,16734],{"class":4888}," restore\n",[16681,16736,16738],{"label":16737},"Function Code",[3385,16739,16741],{"className":4681,"code":16740,"filename":4952,"language":4683,"meta":3390,"style":3390},"using Amazon.Lambda.Core;\n\n\u002F\u002F Реєструємо серіалізатор (обов'язково для обробки JSON)\n[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]\n\nnamespace MyFirstLambda;\n\npublic class Function\n{\n    \u002F\u002F\u002F \u003Csummary>\n    \u002F\u002F\u002F Простий метод, який приймає рядок і повертає його у верхньому регістрі\n    \u002F\u002F\u002F \u003C\u002Fsummary>\n    public string FunctionHandler(string input, ILambdaContext context)\n    {\n        context.Logger.LogInformation($\"Received input: {input}\");\n        return input.ToUpper();\n    }\n}\n",[3392,16742,16743,16759,16763,16768,16804,16808,16816,16820,16829,16833,16845,16850,16860,16882,16886,16913,16926,16930],{"__ignoreMap":3390},[3395,16744,16745,16747,16749,16751,16753,16755,16757],{"class":3397,"line":3398},[3395,16746,7533],{"class":6221},[3395,16748,7536],{"class":4700},[3395,16750,3860],{"class":4708},[3395,16752,5754],{"class":4700},[3395,16754,3860],{"class":4708},[3395,16756,7583],{"class":4700},[3395,16758,6634],{"class":4708},[3395,16760,16761],{"class":3397,"line":3404},[3395,16762,3420],{"emptyLinePlaceholder":3419},[3395,16764,16765],{"class":3397,"line":3410},[3395,16766,16767],{"class":4690},"\u002F\u002F Реєструємо серіалізатор (обов'язково для обробки JSON)\n",[3395,16769,16770,16772,16774,16776,16778,16780,16782,16784,16786,16788,16790,16792,16794,16796,16798,16800,16802],{"class":3397,"line":3416},[3395,16771,5731],{"class":4708},[3395,16773,5734],{"class":4696},[3395,16775,5078],{"class":4708},[3395,16777,5739],{"class":4700},[3395,16779,4709],{"class":4708},[3395,16781,5744],{"class":4696},[3395,16783,4709],{"class":4708},[3395,16785,5749],{"class":4700},[3395,16787,3860],{"class":4708},[3395,16789,5754],{"class":4700},[3395,16791,3860],{"class":4708},[3395,16793,5759],{"class":4700},[3395,16795,3860],{"class":4708},[3395,16797,5764],{"class":4700},[3395,16799,3860],{"class":4708},[3395,16801,5769],{"class":4700},[3395,16803,5772],{"class":4708},[3395,16805,16806],{"class":3397,"line":3423},[3395,16807,3420],{"emptyLinePlaceholder":3419},[3395,16809,16810,16812,16814],{"class":3397,"line":3429},[3395,16811,7658],{"class":4696},[3395,16813,16707],{"class":4700},[3395,16815,6634],{"class":4708},[3395,16817,16818],{"class":3397,"line":3434},[3395,16819,3420],{"emptyLinePlaceholder":3419},[3395,16821,16822,16824,16826],{"class":3397,"line":3440},[3395,16823,4697],{"class":4696},[3395,16825,6314],{"class":4696},[3395,16827,16828],{"class":4700}," Function\n",[3395,16830,16831],{"class":3397,"line":3446},[3395,16832,5069],{"class":4708},[3395,16834,16835,16838,16840,16843],{"class":3397,"line":3452},[3395,16836,16837],{"class":4690},"    \u002F\u002F\u002F ",[3395,16839,6130],{"class":13946},[3395,16841,16842],{"class":13949},"summary",[3395,16844,13964],{"class":13946},[3395,16846,16847],{"class":3397,"line":3458},[3395,16848,16849],{"class":4690},"    \u002F\u002F\u002F Простий метод, який приймає рядок і повертає його у верхньому регістрі\n",[3395,16851,16852,16854,16856,16858],{"class":3397,"line":3464},[3395,16853,16837],{"class":4690},[3395,16855,13991],{"class":13946},[3395,16857,16842],{"class":13949},[3395,16859,13964],{"class":13946},[3395,16861,16862,16864,16866,16868,16870,16872,16874,16876,16878,16880],{"class":3397,"line":3470},[3395,16863,6326],{"class":4696},[3395,16865,9184],{"class":4696},[3395,16867,4705],{"class":4704},[3395,16869,4709],{"class":4708},[3395,16871,3954],{"class":4696},[3395,16873,4716],{"class":4715},[3395,16875,4719],{"class":4708},[3395,16877,4667],{"class":4700},[3395,16879,4724],{"class":4715},[3395,16881,4727],{"class":4708},[3395,16883,16884],{"class":3397,"line":3476},[3395,16885,6347],{"class":4708},[3395,16887,16888,16890,16892,16894,16896,16898,16900,16903,16905,16907,16909,16911],{"class":3397,"line":3482},[3395,16889,10921],{"class":4715},[3395,16891,3860],{"class":4708},[3395,16893,4824],{"class":4715},[3395,16895,3860],{"class":4708},[3395,16897,4835],{"class":4704},[3395,16899,4709],{"class":4708},[3395,16901,16902],{"class":4888},"$\"Received input: ",[3395,16904,6507],{"class":6506},[3395,16906,6654],{"class":4715},[3395,16908,6516],{"class":6506},[3395,16910,6519],{"class":4888},[3395,16912,6522],{"class":4708},[3395,16914,16915,16917,16919,16921,16924],{"class":3397,"line":3487},[3395,16916,8037],{"class":6221},[3395,16918,4716],{"class":4715},[3395,16920,3860],{"class":4708},[3395,16922,16923],{"class":4704},"ToUpper",[3395,16925,8224],{"class":4708},[3395,16927,16928],{"class":3397,"line":3493},[3395,16929,6396],{"class":4708},[3395,16931,16932],{"class":3397,"line":3499},[3395,16933,3479],{"class":4708},[3704,16935,16937],{"id":16936},"_3-автоматизований-деплой-dotnet-lambda","3. Автоматизований деплой (dotnet lambda)",[3353,16939,16940,16941,16944],{},"Це найшвидший спосіб для розробки та тестування. Команда ",[3392,16942,16943],{},"deploy-function"," бере на себе компіляцію, пакування, завантаження та оновлення конфігурації.",[16678,16946,16947,17018],{},[16681,16948,16950],{"label":16949},"Bash (CLI)",[3385,16951,16953],{"className":4876,"code":16952,"language":4878,"meta":3390,"style":3390},"# Деплой з автоматичним створенням\u002Fоновленням функції\ndotnet lambda deploy-function MyFirstLambda \\\n    --runtime dotnet10 \\\n    --handler MyFirstLambda::MyFirstLambda.Function::FunctionHandler \\\n    --memory-size 256 \\\n    --timeout 30 \\\n    --region eu-central-1\n",[3392,16954,16955,16960,16973,16982,16992,17002,17012],{"__ignoreMap":3390},[3395,16956,16957],{"class":3397,"line":3398},[3395,16958,16959],{"class":4690},"# Деплой з автоматичним створенням\u002Fоновленням функції\n",[3395,16961,16962,16964,16966,16969,16971],{"class":3397,"line":3404},[3395,16963,4903],{"class":4704},[3395,16965,5016],{"class":4888},[3395,16967,16968],{"class":4888}," deploy-function",[3395,16970,16707],{"class":4888},[3395,16972,5584],{"class":5583},[3395,16974,16975,16977,16980],{"class":3397,"line":3410},[3395,16976,14306],{"class":4696},[3395,16978,16979],{"class":4888}," dotnet10",[3395,16981,5584],{"class":5583},[3395,16983,16984,16987,16990],{"class":3397,"line":3416},[3395,16985,16986],{"class":4696},"    --handler",[3395,16988,16989],{"class":4888}," MyFirstLambda::MyFirstLambda.Function::FunctionHandler",[3395,16991,5584],{"class":5583},[3395,16993,16994,16997,17000],{"class":3397,"line":3423},[3395,16995,16996],{"class":4696},"    --memory-size",[3395,16998,16999],{"class":5154}," 256",[3395,17001,5584],{"class":5583},[3395,17003,17004,17007,17010],{"class":3397,"line":3429},[3395,17005,17006],{"class":4696},"    --timeout",[3395,17008,17009],{"class":5154}," 30",[3395,17011,5584],{"class":5583},[3395,17013,17014,17016],{"class":3397,"line":3434},[3395,17015,15629],{"class":4696},[3395,17017,15632],{"class":4888},[16681,17019,17021],{"label":17020},"PowerShell",[3385,17022,17026],{"className":17023,"code":17024,"language":17025,"meta":3390,"style":3390},"language-powershell shiki shiki-themes light-plus dark-plus dark-plus","# Використовуємо той самий dotnet tool\ndotnet lambda deploy-function MyFirstLambda `\n    --runtime dotnet10 `\n    --handler MyFirstLambda::MyFirstLambda.Function::FunctionHandler `\n    --memory-size 256 `\n    --timeout 30 `\n    --region eu-central-1\n","powershell",[3392,17027,17028,17033,17043,17048,17053,17063,17072],{"__ignoreMap":3390},[3395,17029,17030],{"class":3397,"line":3398},[3395,17031,17032],{"class":4690},"# Використовуємо той самий dotnet tool\n",[3395,17034,17035,17038,17040],{"class":3397,"line":3404},[3395,17036,17037],{"class":4708},"dotnet lambda ",[3395,17039,16943],{"class":4704},[3395,17041,17042],{"class":4708}," MyFirstLambda `\n",[3395,17044,17045],{"class":3397,"line":3410},[3395,17046,17047],{"class":4708},"    --runtime dotnet10 `\n",[3395,17049,17050],{"class":3397,"line":3416},[3395,17051,17052],{"class":4708},"    --handler MyFirstLambda::MyFirstLambda.Function::FunctionHandler `\n",[3395,17054,17055,17058,17060],{"class":3397,"line":3423},[3395,17056,17057],{"class":4708},"    --memory-size ",[3395,17059,5155],{"class":5154},[3395,17061,17062],{"class":4708}," `\n",[3395,17064,17065,17068,17070],{"class":3397,"line":3429},[3395,17066,17067],{"class":4708},"    --timeout ",[3395,17069,5167],{"class":5154},[3395,17071,17062],{"class":4708},[3395,17073,17074,17077],{"class":3397,"line":3434},[3395,17075,17076],{"class":4708},"    --region eu-central-",[3395,17078,12971],{"class":5154},[12741,17080,17081],{},"При першому деплої інструмент запитає вас, яку IAM Role призначити функції. Ви можете обрати існуючу або дозволити створити нову з базовими правами на логування (AWSLambdaBasicExecutionRole).",[3704,17083,17085],{"id":17084},"_4-повний-контроль-деплой-через-s3-та-aws-cli","4. Повний контроль: Деплой через S3 та AWS CLI",[3353,17087,17088],{},"У великих проектах та CI\u002FCD пайплайнах часто використовують двостадійний деплой: спочатку завантажують пакет у S3, а потім оновлюють функцію. Це надійніше для великих артефактів (> 50MB).",[5436,17090,17091,17095,17126,17130,17163,17167,17217,17221],{},[3704,17092,17094],{"id":17093},"крок-a-пакування-артефакту","Крок A: Пакування артефакту",[3385,17096,17098],{"className":4876,"code":17097,"language":4878,"meta":3390,"style":3390},"dotnet lambda package \\\n    --configuration Release \\\n    --output-package .\u002Fpublish\u002Ffunction.zip\n",[3392,17099,17100,17110,17118],{"__ignoreMap":3390},[3395,17101,17102,17104,17106,17108],{"class":3397,"line":3398},[3395,17103,4903],{"class":4704},[3395,17105,5016],{"class":4888},[3395,17107,4929],{"class":4888},[3395,17109,5584],{"class":5583},[3395,17111,17112,17114,17116],{"class":3397,"line":3404},[3395,17113,14297],{"class":4696},[3395,17115,5515],{"class":4888},[3395,17117,5584],{"class":5583},[3395,17119,17120,17123],{"class":3397,"line":3410},[3395,17121,17122],{"class":4696},"    --output-package",[3395,17124,17125],{"class":4888}," .\u002Fpublish\u002Ffunction.zip\n",[3704,17127,17129],{"id":17128},"крок-b-завантаження-в-s3","Крок B: Завантаження в S3",[3385,17131,17133],{"className":4876,"code":17132,"language":4878,"meta":3390,"style":3390},"aws s3 cp .\u002Fpublish\u002Ffunction.zip \\\n    s3:\u002F\u002Fmy-deployment-bucket\u002Fv1\u002Fmy-first-lambda.zip \\\n    --region eu-central-1\n",[3392,17134,17135,17150,17157],{"__ignoreMap":3390},[3395,17136,17137,17139,17142,17145,17148],{"class":3397,"line":3398},[3395,17138,5575],{"class":4704},[3395,17140,17141],{"class":4888}," s3",[3395,17143,17144],{"class":4888}," cp",[3395,17146,17147],{"class":4888}," .\u002Fpublish\u002Ffunction.zip",[3395,17149,5584],{"class":5583},[3395,17151,17152,17155],{"class":3397,"line":3404},[3395,17153,17154],{"class":4888},"    s3:\u002F\u002Fmy-deployment-bucket\u002Fv1\u002Fmy-first-lambda.zip",[3395,17156,5584],{"class":5583},[3395,17158,17159,17161],{"class":3397,"line":3410},[3395,17160,15629],{"class":4696},[3395,17162,15632],{"class":4888},[3704,17164,17166],{"id":17165},"крок-c-оновлення-коду-lambda","Крок C: Оновлення коду Lambda",[3385,17168,17170],{"className":4876,"code":17169,"language":4878,"meta":3390,"style":3390},"aws lambda update-function-code \\\n    --function-name MyFirstLambda \\\n    --s3-bucket my-deployment-bucket \\\n    --s3-key v1\u002Fmy-first-lambda.zip \\\n    --region eu-central-1\n",[3392,17171,17172,17183,17191,17201,17211],{"__ignoreMap":3390},[3395,17173,17174,17176,17178,17181],{"class":3397,"line":3398},[3395,17175,5575],{"class":4704},[3395,17177,5016],{"class":4888},[3395,17179,17180],{"class":4888}," update-function-code",[3395,17182,5584],{"class":5583},[3395,17184,17185,17187,17189],{"class":3397,"line":3404},[3395,17186,5650],{"class":4696},[3395,17188,16707],{"class":4888},[3395,17190,5584],{"class":5583},[3395,17192,17193,17196,17199],{"class":3397,"line":3410},[3395,17194,17195],{"class":4696},"    --s3-bucket",[3395,17197,17198],{"class":4888}," my-deployment-bucket",[3395,17200,5584],{"class":5583},[3395,17202,17203,17206,17209],{"class":3397,"line":3416},[3395,17204,17205],{"class":4696},"    --s3-key",[3395,17207,17208],{"class":4888}," v1\u002Fmy-first-lambda.zip",[3395,17210,5584],{"class":5583},[3395,17212,17213,17215],{"class":3397,"line":3423},[3395,17214,15629],{"class":4696},[3395,17216,15632],{"class":4888},[3704,17218,17220],{"id":17219},"крок-d-оновлення-конфігурації-опційно","Крок D: Оновлення конфігурації (опційно)",[3385,17222,17224],{"className":4876,"code":17223,"language":4878,"meta":3390,"style":3390},"aws lambda update-function-configuration \\\n    --function-name MyFirstLambda \\\n    --memory-size 512 \\\n    --environment \"Variables={ENV=production,DEBUG=false}\" \\\n    --region eu-central-1\n",[3392,17225,17226,17236,17244,17253,17263],{"__ignoreMap":3390},[3395,17227,17228,17230,17232,17234],{"class":3397,"line":3398},[3395,17229,5575],{"class":4704},[3395,17231,5016],{"class":4888},[3395,17233,5643],{"class":4888},[3395,17235,5584],{"class":5583},[3395,17237,17238,17240,17242],{"class":3397,"line":3404},[3395,17239,5650],{"class":4696},[3395,17241,16707],{"class":4888},[3395,17243,5584],{"class":5583},[3395,17245,17246,17248,17251],{"class":3397,"line":3410},[3395,17247,16996],{"class":4696},[3395,17249,17250],{"class":5154}," 512",[3395,17252,5584],{"class":5583},[3395,17254,17255,17258,17261],{"class":3397,"line":3416},[3395,17256,17257],{"class":4696},"    --environment",[3395,17259,17260],{"class":4888}," \"Variables={ENV=production,DEBUG=false}\"",[3395,17262,5584],{"class":5583},[3395,17264,17265,17267],{"class":3397,"line":3423},[3395,17266,15629],{"class":4696},[3395,17268,15632],{"class":4888},[3704,17270,17272],{"id":17271},"_5-виклик-функції-та-перевірка-результату","5. Виклик функції та перевірка результату",[3353,17274,17275],{},"Після успішного деплою ми можемо викликати нашу функцію і перевірити, чи вона працює коректно. Оскільки ми очікуємо рядок і повертаємо його у верхньому регістрі, передамо тестовий рядок.",[16678,17277,17278,17320],{},[16681,17279,17281],{"label":17280},"dotnet lambda",[3385,17282,17284],{"className":4876,"code":17283,"language":4878,"meta":3390,"style":3390},"# Викликаємо функцію з тестовим навантаженням (payload)\ndotnet lambda invoke-function MyFirstLambda \\\n    --payload '\"hello serverless world\"' \\\n    --region eu-central-1\n",[3392,17285,17286,17291,17304,17314],{"__ignoreMap":3390},[3395,17287,17288],{"class":3397,"line":3398},[3395,17289,17290],{"class":4690},"# Викликаємо функцію з тестовим навантаженням (payload)\n",[3395,17292,17293,17295,17297,17300,17302],{"class":3397,"line":3404},[3395,17294,4903],{"class":4704},[3395,17296,5016],{"class":4888},[3395,17298,17299],{"class":4888}," invoke-function",[3395,17301,16707],{"class":4888},[3395,17303,5584],{"class":5583},[3395,17305,17306,17309,17312],{"class":3397,"line":3410},[3395,17307,17308],{"class":4696},"    --payload",[3395,17310,17311],{"class":4888}," '\"hello serverless world\"'",[3395,17313,5584],{"class":5583},[3395,17315,17316,17318],{"class":3397,"line":3416},[3395,17317,15629],{"class":4696},[3395,17319,15632],{"class":4888},[16681,17321,17323],{"label":17322},"AWS CLI",[3385,17324,17326],{"className":4876,"code":17325,"language":4878,"meta":3390,"style":3390},"# Альтернативний спосіб виклику через стандартний AWS CLI\naws lambda invoke \\\n    --function-name MyFirstLambda \\\n    --payload '\"hello serverless world\"' \\\n    --cli-binary-format raw-in-base64-out \\\n    --region eu-central-1 \\\n    response.json\n\n# Перегляд результату\ncat response.json\n# Очікуваний вивід: \"HELLO SERVERLESS WORLD\"\n",[3392,17327,17328,17333,17344,17352,17360,17370,17378,17383,17387,17392,17400],{"__ignoreMap":3390},[3395,17329,17330],{"class":3397,"line":3398},[3395,17331,17332],{"class":4690},"# Альтернативний спосіб виклику через стандартний AWS CLI\n",[3395,17334,17335,17337,17339,17342],{"class":3397,"line":3404},[3395,17336,5575],{"class":4704},[3395,17338,5016],{"class":4888},[3395,17340,17341],{"class":4888}," invoke",[3395,17343,5584],{"class":5583},[3395,17345,17346,17348,17350],{"class":3397,"line":3410},[3395,17347,5650],{"class":4696},[3395,17349,16707],{"class":4888},[3395,17351,5584],{"class":5583},[3395,17353,17354,17356,17358],{"class":3397,"line":3416},[3395,17355,17308],{"class":4696},[3395,17357,17311],{"class":4888},[3395,17359,5584],{"class":5583},[3395,17361,17362,17365,17368],{"class":3397,"line":3423},[3395,17363,17364],{"class":4696},"    --cli-binary-format",[3395,17366,17367],{"class":4888}," raw-in-base64-out",[3395,17369,5584],{"class":5583},[3395,17371,17372,17374,17376],{"class":3397,"line":3429},[3395,17373,15629],{"class":4696},[3395,17375,15673],{"class":4888},[3395,17377,5584],{"class":5583},[3395,17379,17380],{"class":3397,"line":3434},[3395,17381,17382],{"class":4888},"    response.json\n",[3395,17384,17385],{"class":3397,"line":3440},[3395,17386,3420],{"emptyLinePlaceholder":3419},[3395,17388,17389],{"class":3397,"line":3446},[3395,17390,17391],{"class":4690},"# Перегляд результату\n",[3395,17393,17394,17397],{"class":3397,"line":3452},[3395,17395,17396],{"class":4704},"cat",[3395,17398,17399],{"class":4888}," response.json\n",[3395,17401,17402],{"class":3397,"line":3458},[3395,17403,17404],{"class":4690},"# Очікуваний вивід: \"HELLO SERVERLESS WORLD\"\n",[3704,17406,17408],{"id":17407},"_6-активація-публічного-лінка-lambda-function-url","6. Активація публічного лінка (Lambda Function URL)",[3353,17410,17411],{},"Оскільки ми розглядаємо автоматизацію та повний контроль, найшвидше це зробити через AWS CLI.",[5436,17413,17414,17418,17425,17465,17469,17476,17545,17549,17552],{},[3704,17415,17417],{"id":17416},"крок-a-створення-конфігурації-url","Крок A: Створення конфігурації URL",[3353,17419,17420,17421,17424],{},"Вмикаємо функцію URL для нашої Lambda. Прапор ",[3392,17422,17423],{},"--auth-type NONE"," означає, що лінк буде публічним і не вимагатиме підписів AWS IAM для кожного запиту.",[3385,17426,17428],{"className":4876,"code":17427,"language":4878,"meta":3390,"style":3390},"aws lambda create-function-url-config \\\n    --function-name MyFirstLambda \\\n    --auth-type NONE \\\n    --region eu-central-1\n",[3392,17429,17430,17441,17449,17459],{"__ignoreMap":3390},[3395,17431,17432,17434,17436,17439],{"class":3397,"line":3398},[3395,17433,5575],{"class":4704},[3395,17435,5016],{"class":4888},[3395,17437,17438],{"class":4888}," create-function-url-config",[3395,17440,5584],{"class":5583},[3395,17442,17443,17445,17447],{"class":3397,"line":3404},[3395,17444,5650],{"class":4696},[3395,17446,16707],{"class":4888},[3395,17448,5584],{"class":5583},[3395,17450,17451,17454,17457],{"class":3397,"line":3410},[3395,17452,17453],{"class":4696},"    --auth-type",[3395,17455,17456],{"class":4888}," NONE",[3395,17458,5584],{"class":5583},[3395,17460,17461,17463],{"class":3397,"line":3416},[3395,17462,15629],{"class":4696},[3395,17464,15632],{"class":4888},[3704,17466,17468],{"id":17467},"крок-b-дозвіл-на-публічний-доступ-cors-permissions","Крок B: Дозвіл на публічний доступ (CORS \u002F Permissions)",[3353,17470,17471,17472,17475],{},"За замовчуванням AWS заблокує будь-які анонімні запити з інтернету з міркувань безпеки. Нам потрібно явно дозволити всьому світу (",[3392,17473,17474],{},"*",") викликати цей URL:",[3385,17477,17479],{"className":4876,"code":17478,"language":4878,"meta":3390,"style":3390},"aws lambda add-permission \\\n    --function-name MyFirstLambda \\\n    --statement-id FunctionURLAllowPublicAccess \\\n    --action lambda:InvokeFunctionUrl \\\n    --principal \"*\" \\\n    --function-url-auth-type NONE \\\n    --region eu-central-1\n",[3392,17480,17481,17492,17500,17510,17520,17530,17539],{"__ignoreMap":3390},[3395,17482,17483,17485,17487,17490],{"class":3397,"line":3398},[3395,17484,5575],{"class":4704},[3395,17486,5016],{"class":4888},[3395,17488,17489],{"class":4888}," add-permission",[3395,17491,5584],{"class":5583},[3395,17493,17494,17496,17498],{"class":3397,"line":3404},[3395,17495,5650],{"class":4696},[3395,17497,16707],{"class":4888},[3395,17499,5584],{"class":5583},[3395,17501,17502,17505,17508],{"class":3397,"line":3410},[3395,17503,17504],{"class":4696},"    --statement-id",[3395,17506,17507],{"class":4888}," FunctionURLAllowPublicAccess",[3395,17509,5584],{"class":5583},[3395,17511,17512,17515,17518],{"class":3397,"line":3416},[3395,17513,17514],{"class":4696},"    --action",[3395,17516,17517],{"class":4888}," lambda:InvokeFunctionUrl",[3395,17519,5584],{"class":5583},[3395,17521,17522,17525,17528],{"class":3397,"line":3423},[3395,17523,17524],{"class":4696},"    --principal",[3395,17526,17527],{"class":4888}," \"*\"",[3395,17529,5584],{"class":5583},[3395,17531,17532,17535,17537],{"class":3397,"line":3429},[3395,17533,17534],{"class":4696},"    --function-url-auth-type",[3395,17536,17456],{"class":4888},[3395,17538,5584],{"class":5583},[3395,17540,17541,17543],{"class":3397,"line":3434},[3395,17542,15629],{"class":4696},[3395,17544,15632],{"class":4888},[3704,17546,17548],{"id":17547},"крок-c-отримання-вашого-готового-лінка","Крок C: Отримання вашого готового лінка",[3353,17550,17551],{},"Тепер дізнаємося згенеровану адресу нашої функції:",[3385,17553,17555],{"className":4876,"code":17554,"language":4878,"meta":3390,"style":3390},"aws lambda get-function-url-config \\\n    --function-name MyFirstLambda \\\n    --region eu-central-1 \\\n    --query FunctionUrl \\\n    --output text\n",[3392,17556,17557,17568,17576,17584,17593],{"__ignoreMap":3390},[3395,17558,17559,17561,17563,17566],{"class":3397,"line":3398},[3395,17560,5575],{"class":4704},[3395,17562,5016],{"class":4888},[3395,17564,17565],{"class":4888}," get-function-url-config",[3395,17567,5584],{"class":5583},[3395,17569,17570,17572,17574],{"class":3397,"line":3404},[3395,17571,5650],{"class":4696},[3395,17573,16707],{"class":4888},[3395,17575,5584],{"class":5583},[3395,17577,17578,17580,17582],{"class":3397,"line":3410},[3395,17579,15629],{"class":4696},[3395,17581,15673],{"class":4888},[3395,17583,5584],{"class":5583},[3395,17585,17586,17588,17591],{"class":3397,"line":3416},[3395,17587,15680],{"class":4696},[3395,17589,17590],{"class":4888}," FunctionUrl",[3395,17592,5584],{"class":5583},[3395,17594,17595,17597],{"class":3397,"line":3423},[3395,17596,14326],{"class":4696},[3395,17598,17599],{"class":4888}," text\n",[3353,17601,17602],{},[3359,17603,17604],{},"Як це протестувати?",[3353,17606,17607,17608,3860],{},"У результаті виконання останньої команди ви отримаєте унікальний лінк, який виглядає приблизно так: ",[3392,17609,17610],{},"https:\u002F\u002Fabcdefg1234567890.lambda-url.eu-central-1.on.aws\u002F",[3353,17612,17613,17614,17616,17617,17620],{},"Оскільки ваш метод ",[3392,17615,10328],{}," у C# приймає рядок і повертає його в UPPERCASE, ви можете протестувати його через звичайний ",[3392,17618,17619],{},"curl"," у терміналі (або через Postman), передавши текст у тілі POST-запиту:",[3385,17622,17624],{"className":4876,"code":17623,"language":4878,"meta":3390,"style":3390},"curl -X POST https:\u002F\u002Fyour-lambda-url.on.aws\u002F \\\n    -d '\"hello from internet\"' \\\n    -H \"Content-Type: application\u002Fjson\"\n",[3392,17625,17626,17641,17651],{"__ignoreMap":3390},[3395,17627,17628,17630,17633,17636,17639],{"class":3397,"line":3398},[3395,17629,17619],{"class":4704},[3395,17631,17632],{"class":4696}," -X",[3395,17634,17635],{"class":4888}," POST",[3395,17637,17638],{"class":4888}," https:\u002F\u002Fyour-lambda-url.on.aws\u002F",[3395,17640,5584],{"class":5583},[3395,17642,17643,17646,17649],{"class":3397,"line":3404},[3395,17644,17645],{"class":4696},"    -d",[3395,17647,17648],{"class":4888}," '\"hello from internet\"'",[3395,17650,5584],{"class":5583},[3395,17652,17653,17656],{"class":3397,"line":3410},[3395,17654,17655],{"class":4696},"    -H",[3395,17657,17658],{"class":4888}," \"Content-Type: application\u002Fjson\"\n",[12741,17660,17661,17664,17665,17667,17668,17671,17672,17674,17675,3860],{},[3359,17662,17663],{},"Важливий нюанс для .NET",": Оскільки функція очікує чистий JSON-рядок, у утиліті ",[3392,17666,17619],{}," ми передаємо текст у подвійних лапках всередині одинарних (",[3392,17669,17670],{},"'\"hello\"'","), щоб серіалізатор ",[3392,17673,5764],{}," правильно його розпізнав.\nРезультатом у консолі буде: ",[3392,17676,17677],{},"\"HELLO FROM INTERNET\"",[3704,17679,17681],{"id":17680},"_7-інтеграція-з-amazon-api-gateway-альтернатива-function-url","7. Інтеграція з Amazon API Gateway (Альтернатива Function URL)",[3353,17683,17684,17685,17688,17689,3860],{},"Якщо вам потрібен більший контроль над маршрутизацією, авторизацією (наприклад, інтеграція з Cognito), лімітами (Rate Limiting) або ви хочете побудувати повноцінний REST API, замість ",[5187,17686,17687],{},"Function URL"," краще використовувати ",[3359,17690,7165],{},[3353,17692,17693],{},"Найпростіший спосіб створити HTTP API та підключити його до нашої Lambda-функції через AWS CLI:",[5436,17695,17696,17700,17753,17762,17766,17769,17825,17829,17836],{},[3704,17697,17699],{"id":17698},"крок-a-створення-http-api","Крок A: Створення HTTP API",[3385,17701,17703],{"className":4876,"code":17702,"language":4878,"meta":3390,"style":3390},"aws apigatewayv2 create-api \\\n    --name MyFirstLambdaAPI \\\n    --protocol-type HTTP \\\n    --target arn:aws:lambda:eu-central-1:ACCOUNT_ID:function:MyFirstLambda \\\n    --region eu-central-1\n",[3392,17704,17705,17717,17727,17737,17747],{"__ignoreMap":3390},[3395,17706,17707,17709,17712,17715],{"class":3397,"line":3398},[3395,17708,5575],{"class":4704},[3395,17710,17711],{"class":4888}," apigatewayv2",[3395,17713,17714],{"class":4888}," create-api",[3395,17716,5584],{"class":5583},[3395,17718,17719,17722,17725],{"class":3397,"line":3404},[3395,17720,17721],{"class":4696},"    --name",[3395,17723,17724],{"class":4888}," MyFirstLambdaAPI",[3395,17726,5584],{"class":5583},[3395,17728,17729,17732,17735],{"class":3397,"line":3410},[3395,17730,17731],{"class":4696},"    --protocol-type",[3395,17733,17734],{"class":4888}," HTTP",[3395,17736,5584],{"class":5583},[3395,17738,17739,17742,17745],{"class":3397,"line":3416},[3395,17740,17741],{"class":4696},"    --target",[3395,17743,17744],{"class":4888}," arn:aws:lambda:eu-central-1:ACCOUNT_ID:function:MyFirstLambda",[3395,17746,5584],{"class":5583},[3395,17748,17749,17751],{"class":3397,"line":3423},[3395,17750,15629],{"class":4696},[3395,17752,15632],{"class":4888},[3353,17754,17755],{},[5187,17756,17757,17758,17761],{},"Зверніть увагу: замініть ",[3392,17759,17760],{},"ACCOUNT_ID"," на ваш реальний ідентифікатор аккаунта.",[3704,17763,17765],{"id":17764},"крок-b-надання-дозволу-api-gateway-на-виклик-функції","Крок B: Надання дозволу API Gateway на виклик функції",[3353,17767,17768],{},"Як і у випадку з Function URL, Lambda повинна явно дозволити API Gateway викликати себе:",[3385,17770,17772],{"className":4876,"code":17771,"language":4878,"meta":3390,"style":3390},"aws lambda add-permission \\\n    --function-name MyFirstLambda \\\n    --statement-id ApiGatewayInvokeAccess \\\n    --action lambda:InvokeFunction \\\n    --principal apigateway.amazonaws.com \\\n    --region eu-central-1\n",[3392,17773,17774,17784,17792,17801,17810,17819],{"__ignoreMap":3390},[3395,17775,17776,17778,17780,17782],{"class":3397,"line":3398},[3395,17777,5575],{"class":4704},[3395,17779,5016],{"class":4888},[3395,17781,17489],{"class":4888},[3395,17783,5584],{"class":5583},[3395,17785,17786,17788,17790],{"class":3397,"line":3404},[3395,17787,5650],{"class":4696},[3395,17789,16707],{"class":4888},[3395,17791,5584],{"class":5583},[3395,17793,17794,17796,17799],{"class":3397,"line":3410},[3395,17795,17504],{"class":4696},[3395,17797,17798],{"class":4888}," ApiGatewayInvokeAccess",[3395,17800,5584],{"class":5583},[3395,17802,17803,17805,17808],{"class":3397,"line":3416},[3395,17804,17514],{"class":4696},[3395,17806,17807],{"class":4888}," lambda:InvokeFunction",[3395,17809,5584],{"class":5583},[3395,17811,17812,17814,17817],{"class":3397,"line":3423},[3395,17813,17524],{"class":4696},[3395,17815,17816],{"class":4888}," apigateway.amazonaws.com",[3395,17818,5584],{"class":5583},[3395,17820,17821,17823],{"class":3397,"line":3429},[3395,17822,15629],{"class":4696},[3395,17824,15632],{"class":4888},[3704,17826,17828],{"id":17827},"крок-c-отримання-endpoint-url","Крок C: Отримання Endpoint URL",[3353,17830,17831,17832,17835],{},"Після створення API (Крок A) у відповіді ви отримаєте поле ",[3392,17833,17834],{},"ApiEndpoint",". Ви також можете дізнатись його такою командою:",[3385,17837,17839],{"className":4876,"code":17838,"language":4878,"meta":3390,"style":3390},"aws apigatewayv2 get-apis \\\n    --query \"Items[?Name=='MyFirstLambdaAPI'].ApiEndpoint\" \\\n    --output text \\\n    --region eu-central-1\n",[3392,17840,17841,17852,17861,17869],{"__ignoreMap":3390},[3395,17842,17843,17845,17847,17850],{"class":3397,"line":3398},[3395,17844,5575],{"class":4704},[3395,17846,17711],{"class":4888},[3395,17848,17849],{"class":4888}," get-apis",[3395,17851,5584],{"class":5583},[3395,17853,17854,17856,17859],{"class":3397,"line":3404},[3395,17855,15680],{"class":4696},[3395,17857,17858],{"class":4888}," \"Items[?Name=='MyFirstLambdaAPI'].ApiEndpoint\"",[3395,17860,5584],{"class":5583},[3395,17862,17863,17865,17867],{"class":3397,"line":3410},[3395,17864,14326],{"class":4696},[3395,17866,15692],{"class":4888},[3395,17868,5584],{"class":5583},[3395,17870,17871,17873],{"class":3397,"line":3416},[3395,17872,15629],{"class":4696},[3395,17874,15632],{"class":4888},[3353,17876,17877],{},[3359,17878,17604],{},[3353,17880,17881,17882,17884,17885,17888],{},"Використовуйте отриманий ",[3392,17883,17834],{}," (наприклад, ",[3392,17886,17887],{},"https:\u002F\u002Fxyz123.execute-api.eu-central-1.amazonaws.com",") аналогічно до Function URL:",[3385,17890,17892],{"className":4876,"code":17891,"language":4878,"meta":3390,"style":3390},"curl -X POST https:\u002F\u002Fyour-api-gateway-url.amazonaws.com\u002F \\\n    -d '\"hello via api gateway\"' \\\n    -H \"Content-Type: application\u002Fjson\"\n",[3392,17893,17894,17907,17916],{"__ignoreMap":3390},[3395,17895,17896,17898,17900,17902,17905],{"class":3397,"line":3398},[3395,17897,17619],{"class":4704},[3395,17899,17632],{"class":4696},[3395,17901,17635],{"class":4888},[3395,17903,17904],{"class":4888}," https:\u002F\u002Fyour-api-gateway-url.amazonaws.com\u002F",[3395,17906,5584],{"class":5583},[3395,17908,17909,17911,17914],{"class":3397,"line":3404},[3395,17910,17645],{"class":4696},[3395,17912,17913],{"class":4888}," '\"hello via api gateway\"'",[3395,17915,5584],{"class":5583},[3395,17917,17918,17920],{"class":3397,"line":3410},[3395,17919,17655],{"class":4696},[3395,17921,17658],{"class":4888},[3704,17923,17925],{"id":17924},"_8-використання-aws-toolkit-ide","8. Використання AWS Toolkit (IDE)",[3353,17927,17928],{},"Якщо ви віддаєте перевагу роботі в IDE, AWS надає потужні розширення (Toolkit) для Visual Studio, JetBrains Rider та VS Code.",[4032,17930,17931,17937,17943],{},[4035,17932,17933,17936],{},[3359,17934,17935],{},"Visual Studio:"," Дозволяє створювати проекти з шаблонів, запускати локальне тестування (Mock Lambda Test Tool) та деплоїти правою кнопкою миші.",[4035,17938,17939,17942],{},[3359,17940,17941],{},"VS Code:"," Надає інтерфейс для перегляду логів CloudWatch прямо в редакторі, керування Lambda-функціями та локального дебагу через SAM CLI.",[4035,17944,17945,17948],{},[3359,17946,17947],{},"Rider:"," Найкраща підтримка для macOS\u002FLinux розробників з глибокою інтеграцією AWS-ресурсів та шаблонів проектів.",[3677,17950,17951,17952,17955],{},"Для локальної розробки та дебагу .NET Lambda без завантаження в хмару використовуйте ",[3359,17953,17954],{},"Amazon.Lambda.TestTool",". Це дозволяє імітувати вхідні події (JSON) та зупинятися на breakpoints у вашому коді.",[3684,17957],{},[3348,17959,17961],{"id":17960},"підсумок-коли-використовувати-lambda-а-коли-ec2ecs","Підсумок: коли використовувати Lambda, а коли — EC2\u002FECS",[3353,17963,17964],{},"Вибір між Lambda та традиційними обчислювальними сервісами є архітектурним рішенням, що залежить від конкретних характеристик навантаження, вимог до латентності та операційної складності.",[4273,17966,17967,17979],{},[4276,17968,17969],{},[4279,17970,17971,17974,17976],{},[4282,17972,17973],{},"Критерій",[4282,17975,5754],{},[4282,17977,17978],{},"EC2 \u002F ECS",[4292,17980,17981,17994,18007,18020,18033,18046,18059,18072],{},[4279,17982,17983,17988,17991],{},[4297,17984,17985],{},[3359,17986,17987],{},"Час запуску",[4297,17989,17990],{},"Cold Start 100ms – 3s",[4297,17992,17993],{},"Постійно запущений (0ms latency)",[4279,17995,17996,18001,18004],{},[4297,17997,17998],{},[3359,17999,18000],{},"Максимальний час виконання",[4297,18002,18003],{},"15 хвилин",[4297,18005,18006],{},"Необмежено",[4279,18008,18009,18014,18017],{},[4297,18010,18011],{},[3359,18012,18013],{},"Стан між запитами",[4297,18015,18016],{},"Stateless (ephemeral)",[4297,18018,18019],{},"Stateful (можливо)",[4279,18021,18022,18027,18030],{},[4297,18023,18024],{},[3359,18025,18026],{},"Масштабування",[4297,18028,18029],{},"Автоматичне, миттєве",[4297,18031,18032],{},"ASG (хвилини)",[4279,18034,18035,18040,18043],{},[4297,18036,18037],{},[3359,18038,18039],{},"Вартість при низькому навантаженні",[4297,18041,18042],{},"Майже нульова",[4297,18044,18045],{},"Фіксована",[4279,18047,18048,18053,18056],{},[4297,18049,18050],{},[3359,18051,18052],{},"Вартість при високому навантаженні",[4297,18054,18055],{},"Лінійна (може бути вищою)",[4297,18057,18058],{},"Фіксована + резерви",[4279,18060,18061,18066,18069],{},[4297,18062,18063],{},[3359,18064,18065],{},"Операційна складність",[4297,18067,18068],{},"Мінімальна",[4297,18070,18071],{},"Середня — висока",[4279,18073,18074,18079,18082],{},[4297,18075,18076],{},[3359,18077,18078],{},"Контроль над середовищем",[4297,18080,18081],{},"Обмежений",[4297,18083,18084],{},"Повний",[3353,18086,18087],{},[3359,18088,18089],{},"Lambda є оптимальним вибором для:",[4032,18091,18092,18095,18098,18101,18104],{},[4035,18093,18094],{},"Event-driven обробки: S3 файлів, SQS повідомлень, DynamoDB Streams",[4035,18096,18097],{},"Нерегулярного трафіку з піками та тривалими паузами",[4035,18099,18100],{},"Простих HTTP API з низьким та середнім навантаженням",[4035,18102,18103],{},"Задач за розкладом (cron jobs)",[4035,18105,18106],{},"Glue-коду між AWS-сервісами",[3353,18108,18109],{},[3359,18110,18111],{},"EC2 або ECS є кращим вибором для:",[4032,18113,18114,18117,18120,18123,18126],{},[4035,18115,18116],{},"Довготривалих задач (> 15 хвилин)",[4035,18118,18119],{},"Систем з постійно-стабільним навантаженням (Lambda буде дорожчою)",[4035,18121,18122],{},"Застосунків з жорсткими вимогами до Cold Start без бажання платити за Provisioned Concurrency",[4035,18124,18125],{},"Систем, що потребують специфічного апаратного забезпечення (GPU, великий обсяг RAM)",[4035,18127,18128],{},"Stateful додатків з WebSocket з'єднаннями тривалістю > 15 хвилин",[3684,18130],{},[3348,18132,18134],{"id":18133},"практичний-воркшоп-побудова-системи-обробки-зображень-a-z","Практичний воркшоп: Побудова системи обробки зображень (A-Z)",[3353,18136,18137],{},"У цьому розділі ми побудуємо повноцінну serverless-систему «від А до Я». Наш сценарій: автоматичне створення мініатюр (thumbnails) для зображень, що завантажуються користувачами в S3.",[3704,18139,18141],{"id":18140},"архітектура-рішення","Архітектура рішення",[3353,18143,18144],{},"Система працює за подієво-орієнтованою моделлю:",[4867,18146,18147,18153,18159,18165],{},[4035,18148,18149,18150,3860],{},"Користувач завантажує оригінальне зображення у ",[3392,18151,18152],{},"source-images-bucket",[4035,18154,18155,18156,18158],{},"S3 генерує подію ",[3392,18157,8649],{}," та викликає Lambda-функцію.",[4035,18160,18161,18162,3860],{},"Lambda-функція (.NET 10) завантажує оригінал, змінює розмір та зберігає результат у ",[3392,18163,18164],{},"processed-images-bucket",[4035,18166,18167],{},"Всі дії логуються у CloudWatch для моніторингу.",[3382,18169,18170],{},[3385,18171,18173],{"className":3387,"code":18172,"language":3389,"meta":3390,"style":3390},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\nactor \"Користувач\" as USR\nrectangle \"S3: source-bucket\" as S3_SRC #fef3c7\nrectangle \"AWS Lambda\\n(ImageProcessor)\" as LAM #d1fae5\nrectangle \"S3: processed-bucket\" as S3_DST #dbeafe\n\nUSR -> S3_SRC : 1. Upload image.jpg\nS3_SRC -> LAM : 2. Trigger Event\nLAM -> S3_SRC : 3. GetObject\nLAM -> LAM : 4. Resize Image\nLAM -> S3_DST : 5. PutObject (thumbnail.jpg)\nLAM -> \"CloudWatch Logs\" : 6. Logging\n@enduml\n",[3392,18174,18175,18179,18183,18187,18191,18196,18201,18206,18211,18215,18220,18225,18230,18235,18240,18245],{"__ignoreMap":3390},[3395,18176,18177],{"class":3397,"line":3398},[3395,18178,3401],{},[3395,18180,18181],{"class":3397,"line":3404},[3395,18182,3407],{},[3395,18184,18185],{"class":3397,"line":3410},[3395,18186,3413],{},[3395,18188,18189],{"class":3397,"line":3416},[3395,18190,3420],{"emptyLinePlaceholder":3419},[3395,18192,18193],{"class":3397,"line":3423},[3395,18194,18195],{},"actor \"Користувач\" as USR\n",[3395,18197,18198],{"class":3397,"line":3429},[3395,18199,18200],{},"rectangle \"S3: source-bucket\" as S3_SRC #fef3c7\n",[3395,18202,18203],{"class":3397,"line":3434},[3395,18204,18205],{},"rectangle \"AWS Lambda\\n(ImageProcessor)\" as LAM #d1fae5\n",[3395,18207,18208],{"class":3397,"line":3440},[3395,18209,18210],{},"rectangle \"S3: processed-bucket\" as S3_DST #dbeafe\n",[3395,18212,18213],{"class":3397,"line":3446},[3395,18214,3420],{"emptyLinePlaceholder":3419},[3395,18216,18217],{"class":3397,"line":3452},[3395,18218,18219],{},"USR -> S3_SRC : 1. Upload image.jpg\n",[3395,18221,18222],{"class":3397,"line":3458},[3395,18223,18224],{},"S3_SRC -> LAM : 2. Trigger Event\n",[3395,18226,18227],{"class":3397,"line":3464},[3395,18228,18229],{},"LAM -> S3_SRC : 3. GetObject\n",[3395,18231,18232],{"class":3397,"line":3470},[3395,18233,18234],{},"LAM -> LAM : 4. Resize Image\n",[3395,18236,18237],{"class":3397,"line":3476},[3395,18238,18239],{},"LAM -> S3_DST : 5. PutObject (thumbnail.jpg)\n",[3395,18241,18242],{"class":3397,"line":3482},[3395,18243,18244],{},"LAM -> \"CloudWatch Logs\" : 6. Logging\n",[3395,18246,18247],{"class":3397,"line":3487},[3395,18248,3675],{},[3704,18250,18252],{"id":18251},"крок-1-підготовка-інфраструктури-s3-buckets","Крок 1: Підготовка інфраструктури (S3 Buckets)",[3353,18254,18255],{},"Перш за все, нам потрібно створити два S3-кошики: один для оригіналів, інший для мініатюр.",[16678,18257,18258,18297,18357],{},[16681,18259,18261],{"label":18260},"AWS Console",[4867,18262,18263,18268,18274,18280,18286,18291],{},[4035,18264,18265,18266,3860],{},"Перейдіть у сервіс ",[3359,18267,9044],{},[4035,18269,18270,18271,3860],{},"Натисніть ",[3359,18272,18273],{},"Create bucket",[4035,18275,18276,18277,3860],{},"Bucket name: ",[3392,18278,18279],{},"kostyl-dev-source-images-[unique-id]",[4035,18281,18282,18283,3860],{},"Region: ",[3392,18284,18285],{},"eu-central-1",[4035,18287,18288,18289,3860],{},"Залиште інші налаштування за замовчуванням та натисніть ",[3359,18290,18273],{},[4035,18292,18293,18294,3860],{},"Повторіть кроки для створення другого кошика з іменем ",[3392,18295,18296],{},"kostyl-dev-processed-images-[unique-id]",[16681,18298,18299],{"label":16949},[3385,18300,18302],{"className":4876,"code":18301,"language":4878,"meta":3390,"style":3390},"# Створюємо кошик для оригіналів\naws s3 mb s3:\u002F\u002Fkostyl-dev-source-images \\\n    --region eu-central-1\n\n# Створюємо кошик для оброблених мініатюр\naws s3 mb s3:\u002F\u002Fkostyl-dev-processed-images \\\n    --region eu-central-1\n",[3392,18303,18304,18309,18323,18329,18333,18338,18351],{"__ignoreMap":3390},[3395,18305,18306],{"class":3397,"line":3398},[3395,18307,18308],{"class":4690},"# Створюємо кошик для оригіналів\n",[3395,18310,18311,18313,18315,18318,18321],{"class":3397,"line":3404},[3395,18312,5575],{"class":4704},[3395,18314,17141],{"class":4888},[3395,18316,18317],{"class":4888}," mb",[3395,18319,18320],{"class":4888}," s3:\u002F\u002Fkostyl-dev-source-images",[3395,18322,5584],{"class":5583},[3395,18324,18325,18327],{"class":3397,"line":3410},[3395,18326,15629],{"class":4696},[3395,18328,15632],{"class":4888},[3395,18330,18331],{"class":3397,"line":3416},[3395,18332,3420],{"emptyLinePlaceholder":3419},[3395,18334,18335],{"class":3397,"line":3423},[3395,18336,18337],{"class":4690},"# Створюємо кошик для оброблених мініатюр\n",[3395,18339,18340,18342,18344,18346,18349],{"class":3397,"line":3429},[3395,18341,5575],{"class":4704},[3395,18343,17141],{"class":4888},[3395,18345,18317],{"class":4888},[3395,18347,18348],{"class":4888}," s3:\u002F\u002Fkostyl-dev-processed-images",[3395,18350,5584],{"class":5583},[3395,18352,18353,18355],{"class":3397,"line":3434},[3395,18354,15629],{"class":4696},[3395,18356,15632],{"class":4888},[16681,18358,18359],{"label":17020},[3385,18360,18362],{"className":17023,"code":18361,"language":17025,"meta":3390,"style":3390},"# Створюємо кошик для оригіналів\nNew-S3Bucket -BucketName kostyl-dev-source-images -Region eu-central-1\n\n# Створюємо кошик для оброблених мініатюр\nNew-S3Bucket -BucketName kostyl-dev-processed-images -Region eu-central-1\n",[3392,18363,18364,18368,18378,18382,18386],{"__ignoreMap":3390},[3395,18365,18366],{"class":3397,"line":3398},[3395,18367,18308],{"class":4690},[3395,18369,18370,18373,18376],{"class":3397,"line":3404},[3395,18371,18372],{"class":4704},"New-S3Bucket",[3395,18374,18375],{"class":4708}," -BucketName kostyl-dev-source-images -Region eu-central-",[3395,18377,12971],{"class":5154},[3395,18379,18380],{"class":3397,"line":3410},[3395,18381,3420],{"emptyLinePlaceholder":3419},[3395,18383,18384],{"class":3397,"line":3416},[3395,18385,18337],{"class":4690},[3395,18387,18388,18390,18393],{"class":3397,"line":3423},[3395,18389,18372],{"class":4704},[3395,18391,18392],{"class":4708}," -BucketName kostyl-dev-processed-images -Region eu-central-",[3395,18394,12971],{"class":5154},[3704,18396,18398],{"id":18397},"крок-2-налаштування-безпеки-iam-role","Крок 2: Налаштування безпеки (IAM Role)",[3353,18400,18401],{},"Lambda-функція повинна мати права на читання з одного кошика та запис у інший.",[16678,18403,18404,18629,18808],{},[16681,18405,18406],{"label":18260},[4867,18407,18408,18419,18431,18437,18610,18617,18620],{},[4035,18409,18265,18410,18413,18414,18413,18416,3860],{},[3359,18411,18412],{},"IAM"," → ",[3359,18415,6718],{},[3359,18417,18418],{},"Create role",[4035,18420,18421,18422,18413,18425,18427,18428,3860],{},"Trusted entity: ",[3359,18423,18424],{},"AWS service",[3359,18426,5754],{},". Натисніть ",[3359,18429,18430],{},"Next",[4035,18432,18270,18433,18436],{},[3359,18434,18435],{},"Create policy"," (відкриється нова вкладка).",[4035,18438,18439,18440,18443,18444],{},"Оберіть вкладку ",[3359,18441,18442],{},"JSON"," та вставте наступний код (замініть імена bucket на ваші):\n",[3385,18445,18447],{"className":5060,"code":18446,"language":5062,"meta":3390,"style":3390},"{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\"s3:GetObject\"],\n            \"Resource\": \"arn:aws:s3:::kostyl-dev-source-images\u002F*\"\n        },\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\"s3:PutObject\"],\n            \"Resource\": \"arn:aws:s3:::kostyl-dev-processed-images\u002F*\"\n        },\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\"logs:CreateLogGroup\", \"logs:CreateLogStream\", \"logs:PutLogEvents\"],\n            \"Resource\": \"arn:aws:logs:*:*:*\"\n        }\n    ]\n}\n",[3392,18448,18449,18453,18465,18472,18476,18488,18502,18512,18516,18520,18530,18541,18550,18554,18558,18568,18589,18598,18602,18606],{"__ignoreMap":3390},[3395,18450,18451],{"class":3397,"line":3398},[3395,18452,5069],{"class":4708},[3395,18454,18455,18458,18460,18463],{"class":3397,"line":3404},[3395,18456,18457],{"class":5074},"    \"Version\"",[3395,18459,5078],{"class":4708},[3395,18461,18462],{"class":4888},"\"2012-10-17\"",[3395,18464,5084],{"class":4708},[3395,18466,18467,18470],{"class":3397,"line":3410},[3395,18468,18469],{"class":5074},"    \"Statement\"",[3395,18471,8799],{"class":4708},[3395,18473,18474],{"class":3397,"line":3416},[3395,18475,8192],{"class":4708},[3395,18477,18478,18481,18483,18486],{"class":3397,"line":3423},[3395,18479,18480],{"class":5074},"            \"Effect\"",[3395,18482,5078],{"class":4708},[3395,18484,18485],{"class":4888},"\"Allow\"",[3395,18487,5084],{"class":4708},[3395,18489,18490,18493,18496,18499],{"class":3397,"line":3429},[3395,18491,18492],{"class":5074},"            \"Action\"",[3395,18494,18495],{"class":4708},": [",[3395,18497,18498],{"class":4888},"\"s3:GetObject\"",[3395,18500,18501],{"class":4708},"],\n",[3395,18503,18504,18507,18509],{"class":3397,"line":3434},[3395,18505,18506],{"class":5074},"            \"Resource\"",[3395,18508,5078],{"class":4708},[3395,18510,18511],{"class":4888},"\"arn:aws:s3:::kostyl-dev-source-images\u002F*\"\n",[3395,18513,18514],{"class":3397,"line":3440},[3395,18515,7462],{"class":4708},[3395,18517,18518],{"class":3397,"line":3446},[3395,18519,8192],{"class":4708},[3395,18521,18522,18524,18526,18528],{"class":3397,"line":3452},[3395,18523,18480],{"class":5074},[3395,18525,5078],{"class":4708},[3395,18527,18485],{"class":4888},[3395,18529,5084],{"class":4708},[3395,18531,18532,18534,18536,18539],{"class":3397,"line":3458},[3395,18533,18492],{"class":5074},[3395,18535,18495],{"class":4708},[3395,18537,18538],{"class":4888},"\"s3:PutObject\"",[3395,18540,18501],{"class":4708},[3395,18542,18543,18545,18547],{"class":3397,"line":3464},[3395,18544,18506],{"class":5074},[3395,18546,5078],{"class":4708},[3395,18548,18549],{"class":4888},"\"arn:aws:s3:::kostyl-dev-processed-images\u002F*\"\n",[3395,18551,18552],{"class":3397,"line":3470},[3395,18553,7462],{"class":4708},[3395,18555,18556],{"class":3397,"line":3476},[3395,18557,8192],{"class":4708},[3395,18559,18560,18562,18564,18566],{"class":3397,"line":3482},[3395,18561,18480],{"class":5074},[3395,18563,5078],{"class":4708},[3395,18565,18485],{"class":4888},[3395,18567,5084],{"class":4708},[3395,18569,18570,18572,18574,18577,18579,18582,18584,18587],{"class":3397,"line":3487},[3395,18571,18492],{"class":5074},[3395,18573,18495],{"class":4708},[3395,18575,18576],{"class":4888},"\"logs:CreateLogGroup\"",[3395,18578,4719],{"class":4708},[3395,18580,18581],{"class":4888},"\"logs:CreateLogStream\"",[3395,18583,4719],{"class":4708},[3395,18585,18586],{"class":4888},"\"logs:PutLogEvents\"",[3395,18588,18501],{"class":4708},[3395,18590,18591,18593,18595],{"class":3397,"line":3493},[3395,18592,18506],{"class":5074},[3395,18594,5078],{"class":4708},[3395,18596,18597],{"class":4888},"\"arn:aws:logs:*:*:*\"\n",[3395,18599,18600],{"class":3397,"line":3499},[3395,18601,8230],{"class":4708},[3395,18603,18604],{"class":3397,"line":3505},[3395,18605,8975],{"class":4708},[3395,18607,18608],{"class":3397,"line":3511},[3395,18609,3479],{"class":4708},[4035,18611,18612,18613,18616],{},"Назвіть політику ",[3392,18614,18615],{},"ImageProcessorPolicy"," та збережіть.",[4035,18618,18619],{},"Поверніться до вкладки створення ролі, оновіть список та оберіть вашу нову політику.",[4035,18621,18622,18623,18626,18627,3860],{},"Назвіть роль ",[3392,18624,18625],{},"ImageProcessorRole"," та натисніть ",[3359,18628,18418],{},[16681,18630,18631],{"label":16949},[3385,18632,18634],{"className":4876,"code":18633,"language":4878,"meta":3390,"style":3390},"# 1. Створюємо Trust Policy файл\necho '{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [{\n    \"Effect\": \"Allow\",\n    \"Principal\": { \"Service\": \"lambda.amazonaws.com\" },\n    \"Action\": \"sts:AssumeRole\"\n  }]\n}' > trust-policy.json\n\n# 2. Створюємо роль\naws iam create-role \\\n    --role-name ImageProcessorRole \\\n    --assume-role-policy-document file:\u002F\u002Ftrust-policy.json\n\n# 3. Додаємо права (inline policy)\naws iam put-role-policy \\\n    --role-name ImageProcessorRole \\\n    --policy-name S3Access \\\n    --policy-document '{\n      \"Version\": \"2012-10-17\",\n      \"Statement\": [\n        { \"Effect\": \"Allow\", \"Action\": \"s3:GetObject\", \"Resource\": \"arn:aws:s3:::kostyl-dev-source-images\u002F*\" },\n        { \"Effect\": \"Allow\", \"Action\": \"s3:PutObject\", \"Resource\": \"arn:aws:s3:::kostyl-dev-processed-images\u002F*\" },\n        { \"Effect\": \"Allow\", \"Action\": [\"logs:*\"], \"Resource\": \"arn:aws:logs:*:*:*\" }\n      ]\n    }'\n",[3392,18635,18636,18641,18648,18653,18658,18663,18668,18673,18678,18689,18693,18698,18710,18720,18728,18732,18737,18748,18756,18766,18773,18778,18783,18788,18793,18798,18803],{"__ignoreMap":3390},[3395,18637,18638],{"class":3397,"line":3398},[3395,18639,18640],{"class":4690},"# 1. Створюємо Trust Policy файл\n",[3395,18642,18643,18645],{"class":3397,"line":3404},[3395,18644,15703],{"class":4704},[3395,18646,18647],{"class":4888}," '{\n",[3395,18649,18650],{"class":3397,"line":3410},[3395,18651,18652],{"class":4888},"  \"Version\": \"2012-10-17\",\n",[3395,18654,18655],{"class":3397,"line":3416},[3395,18656,18657],{"class":4888},"  \"Statement\": [{\n",[3395,18659,18660],{"class":3397,"line":3423},[3395,18661,18662],{"class":4888},"    \"Effect\": \"Allow\",\n",[3395,18664,18665],{"class":3397,"line":3429},[3395,18666,18667],{"class":4888},"    \"Principal\": { \"Service\": \"lambda.amazonaws.com\" },\n",[3395,18669,18670],{"class":3397,"line":3434},[3395,18671,18672],{"class":4888},"    \"Action\": \"sts:AssumeRole\"\n",[3395,18674,18675],{"class":3397,"line":3440},[3395,18676,18677],{"class":4888},"  }]\n",[3395,18679,18680,18683,18686],{"class":3397,"line":3446},[3395,18681,18682],{"class":4888},"}'",[3395,18684,18685],{"class":4708}," > ",[3395,18687,18688],{"class":4888},"trust-policy.json\n",[3395,18690,18691],{"class":3397,"line":3452},[3395,18692,3420],{"emptyLinePlaceholder":3419},[3395,18694,18695],{"class":3397,"line":3458},[3395,18696,18697],{"class":4690},"# 2. Створюємо роль\n",[3395,18699,18700,18702,18705,18708],{"class":3397,"line":3464},[3395,18701,5575],{"class":4704},[3395,18703,18704],{"class":4888}," iam",[3395,18706,18707],{"class":4888}," create-role",[3395,18709,5584],{"class":5583},[3395,18711,18712,18715,18718],{"class":3397,"line":3470},[3395,18713,18714],{"class":4696},"    --role-name",[3395,18716,18717],{"class":4888}," ImageProcessorRole",[3395,18719,5584],{"class":5583},[3395,18721,18722,18725],{"class":3397,"line":3476},[3395,18723,18724],{"class":4696},"    --assume-role-policy-document",[3395,18726,18727],{"class":4888}," file:\u002F\u002Ftrust-policy.json\n",[3395,18729,18730],{"class":3397,"line":3482},[3395,18731,3420],{"emptyLinePlaceholder":3419},[3395,18733,18734],{"class":3397,"line":3487},[3395,18735,18736],{"class":4690},"# 3. Додаємо права (inline policy)\n",[3395,18738,18739,18741,18743,18746],{"class":3397,"line":3493},[3395,18740,5575],{"class":4704},[3395,18742,18704],{"class":4888},[3395,18744,18745],{"class":4888}," put-role-policy",[3395,18747,5584],{"class":5583},[3395,18749,18750,18752,18754],{"class":3397,"line":3499},[3395,18751,18714],{"class":4696},[3395,18753,18717],{"class":4888},[3395,18755,5584],{"class":5583},[3395,18757,18758,18761,18764],{"class":3397,"line":3505},[3395,18759,18760],{"class":4696},"    --policy-name",[3395,18762,18763],{"class":4888}," S3Access",[3395,18765,5584],{"class":5583},[3395,18767,18768,18771],{"class":3397,"line":3511},[3395,18769,18770],{"class":4696},"    --policy-document",[3395,18772,18647],{"class":4888},[3395,18774,18775],{"class":3397,"line":3517},[3395,18776,18777],{"class":4888},"      \"Version\": \"2012-10-17\",\n",[3395,18779,18780],{"class":3397,"line":3523},[3395,18781,18782],{"class":4888},"      \"Statement\": [\n",[3395,18784,18785],{"class":3397,"line":3529},[3395,18786,18787],{"class":4888},"        { \"Effect\": \"Allow\", \"Action\": \"s3:GetObject\", \"Resource\": \"arn:aws:s3:::kostyl-dev-source-images\u002F*\" },\n",[3395,18789,18790],{"class":3397,"line":3534},[3395,18791,18792],{"class":4888},"        { \"Effect\": \"Allow\", \"Action\": \"s3:PutObject\", \"Resource\": \"arn:aws:s3:::kostyl-dev-processed-images\u002F*\" },\n",[3395,18794,18795],{"class":3397,"line":3539},[3395,18796,18797],{"class":4888},"        { \"Effect\": \"Allow\", \"Action\": [\"logs:*\"], \"Resource\": \"arn:aws:logs:*:*:*\" }\n",[3395,18799,18800],{"class":3397,"line":3545},[3395,18801,18802],{"class":4888},"      ]\n",[3395,18804,18805],{"class":3397,"line":3551},[3395,18806,18807],{"class":4888},"    }'\n",[16681,18809,18810],{"label":17020},[3385,18811,18813],{"className":17023,"code":18812,"language":17025,"meta":3390,"style":3390},"# 1. Створюємо Trust Policy\n$trustPolicy = '{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [{\n    \"Effect\": \"Allow\",\n    \"Principal\": { \"Service\": \"lambda.amazonaws.com\" },\n    \"Action\": \"sts:AssumeRole\"\n  }]\n}'\n\n# 2. Створюємо роль\nNew-IAMRole -RoleName ImageProcessorRole -AssumeRolePolicyDocument $trustPolicy\n\n# 3. Додаємо права\n$permissions = '{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    { \"Effect\": \"Allow\", \"Action\": \"s3:GetObject\", \"Resource\": \"arn:aws:s3:::kostyl-dev-source-images\u002F*\" },\n    { \"Effect\": \"Allow\", \"Action\": \"s3:PutObject\", \"Resource\": \"arn:aws:s3:::kostyl-dev-processed-images\u002F*\" },\n    { \"Effect\": \"Allow\", \"Action\": [\"logs:*\"], \"Resource\": \"arn:aws:logs:*:*:*\" }\n  ]\n}'\nWrite-IAMRolePolicy -RoleName ImageProcessorRole -PolicyName S3Access -PolicyDocument $permissions\n",[3392,18814,18815,18820,18830,18834,18838,18842,18846,18850,18854,18859,18863,18867,18878,18882,18887,18896,18900,18905,18910,18915,18920,18925,18929],{"__ignoreMap":3390},[3395,18816,18817],{"class":3397,"line":3398},[3395,18818,18819],{"class":4690},"# 1. Створюємо Trust Policy\n",[3395,18821,18822,18825,18827],{"class":3397,"line":3404},[3395,18823,18824],{"class":4715},"$trustPolicy",[3395,18826,6088],{"class":4708},[3395,18828,18829],{"class":4888},"'{\n",[3395,18831,18832],{"class":3397,"line":3410},[3395,18833,18652],{"class":4888},[3395,18835,18836],{"class":3397,"line":3416},[3395,18837,18657],{"class":4888},[3395,18839,18840],{"class":3397,"line":3423},[3395,18841,18662],{"class":4888},[3395,18843,18844],{"class":3397,"line":3429},[3395,18845,18667],{"class":4888},[3395,18847,18848],{"class":3397,"line":3434},[3395,18849,18672],{"class":4888},[3395,18851,18852],{"class":3397,"line":3440},[3395,18853,18677],{"class":4888},[3395,18855,18856],{"class":3397,"line":3446},[3395,18857,18858],{"class":4888},"}'\n",[3395,18860,18861],{"class":3397,"line":3452},[3395,18862,3420],{"emptyLinePlaceholder":3419},[3395,18864,18865],{"class":3397,"line":3458},[3395,18866,18697],{"class":4690},[3395,18868,18869,18872,18875],{"class":3397,"line":3464},[3395,18870,18871],{"class":4704},"New-IAMRole",[3395,18873,18874],{"class":4708}," -RoleName ImageProcessorRole -AssumeRolePolicyDocument ",[3395,18876,18877],{"class":4715},"$trustPolicy\n",[3395,18879,18880],{"class":3397,"line":3470},[3395,18881,3420],{"emptyLinePlaceholder":3419},[3395,18883,18884],{"class":3397,"line":3476},[3395,18885,18886],{"class":4690},"# 3. Додаємо права\n",[3395,18888,18889,18892,18894],{"class":3397,"line":3482},[3395,18890,18891],{"class":4715},"$permissions",[3395,18893,6088],{"class":4708},[3395,18895,18829],{"class":4888},[3395,18897,18898],{"class":3397,"line":3487},[3395,18899,18652],{"class":4888},[3395,18901,18902],{"class":3397,"line":3493},[3395,18903,18904],{"class":4888},"  \"Statement\": [\n",[3395,18906,18907],{"class":3397,"line":3499},[3395,18908,18909],{"class":4888},"    { \"Effect\": \"Allow\", \"Action\": \"s3:GetObject\", \"Resource\": \"arn:aws:s3:::kostyl-dev-source-images\u002F*\" },\n",[3395,18911,18912],{"class":3397,"line":3505},[3395,18913,18914],{"class":4888},"    { \"Effect\": \"Allow\", \"Action\": \"s3:PutObject\", \"Resource\": \"arn:aws:s3:::kostyl-dev-processed-images\u002F*\" },\n",[3395,18916,18917],{"class":3397,"line":3511},[3395,18918,18919],{"class":4888},"    { \"Effect\": \"Allow\", \"Action\": [\"logs:*\"], \"Resource\": \"arn:aws:logs:*:*:*\" }\n",[3395,18921,18922],{"class":3397,"line":3517},[3395,18923,18924],{"class":4888},"  ]\n",[3395,18926,18927],{"class":3397,"line":3523},[3395,18928,18858],{"class":4888},[3395,18930,18931,18934,18937],{"class":3397,"line":3529},[3395,18932,18933],{"class":4704},"Write-IAMRolePolicy",[3395,18935,18936],{"class":4708}," -RoleName ImageProcessorRole -PolicyName S3Access -PolicyDocument ",[3395,18938,18939],{"class":4715},"$permissions\n",[3704,18941,18943],{"id":18942},"крок-3-розробка-net-10-коду","Крок 3: Розробка .NET 10 коду",[3353,18945,18946,18947,18950],{},"Ми використаємо бібліотеку ",[3392,18948,18949],{},"SixLabors.ImageSharp"," для обробки зображень та офіційний AWS SDK.",[16678,18952,18953,19046,19304],{},[16681,18954,18955],{"label":16683},[3385,18956,18958],{"className":4876,"code":18957,"language":4878,"meta":3390,"style":3390},"# 1. Створюємо проект (класична бібліотека)\ndotnet new classlib -n ImageProcessor.Lambda\ncd ImageProcessor.Lambda\n\n# 2. Додаємо необхідні NuGet-пакети\ndotnet add package Amazon.Lambda.Core\ndotnet add package Amazon.Lambda.Serialization.SystemTextJson\ndotnet add package Amazon.Lambda.S3Events\ndotnet add package AWSSDK.S3\ndotnet add package SixLabors.ImageSharp\n",[3392,18959,18960,18965,18978,18984,18988,18993,19003,19013,19024,19035],{"__ignoreMap":3390},[3395,18961,18962],{"class":3397,"line":3398},[3395,18963,18964],{"class":4690},"# 1. Створюємо проект (класична бібліотека)\n",[3395,18966,18967,18969,18971,18973,18975],{"class":3397,"line":3404},[3395,18968,4903],{"class":4704},[3395,18970,4906],{"class":4888},[3395,18972,5486],{"class":4888},[3395,18974,5041],{"class":4696},[3395,18976,18977],{"class":4888}," ImageProcessor.Lambda\n",[3395,18979,18980,18982],{"class":3397,"line":3410},[3395,18981,4895],{"class":4704},[3395,18983,18977],{"class":4888},[3395,18985,18986],{"class":3397,"line":3416},[3395,18987,3420],{"emptyLinePlaceholder":3419},[3395,18989,18990],{"class":3397,"line":3423},[3395,18991,18992],{"class":4690},"# 2. Додаємо необхідні NuGet-пакети\n",[3395,18994,18995,18997,18999,19001],{"class":3397,"line":3429},[3395,18996,4903],{"class":4704},[3395,18998,4926],{"class":4888},[3395,19000,4929],{"class":4888},[3395,19002,4932],{"class":4888},[3395,19004,19005,19007,19009,19011],{"class":3397,"line":3434},[3395,19006,4903],{"class":4704},[3395,19008,4926],{"class":4888},[3395,19010,4929],{"class":4888},[3395,19012,4943],{"class":4888},[3395,19014,19015,19017,19019,19021],{"class":3397,"line":3440},[3395,19016,4903],{"class":4704},[3395,19018,4926],{"class":4888},[3395,19020,4929],{"class":4888},[3395,19022,19023],{"class":4888}," Amazon.Lambda.S3Events\n",[3395,19025,19026,19028,19030,19032],{"class":3397,"line":3446},[3395,19027,4903],{"class":4704},[3395,19029,4926],{"class":4888},[3395,19031,4929],{"class":4888},[3395,19033,19034],{"class":4888}," AWSSDK.S3\n",[3395,19036,19037,19039,19041,19043],{"class":3397,"line":3452},[3395,19038,4903],{"class":4704},[3395,19040,4926],{"class":4888},[3395,19042,4929],{"class":4888},[3395,19044,19045],{"class":4888}," SixLabors.ImageSharp\n",[16681,19047,19049],{"label":19048},"Project File",[3385,19050,19053],{"className":13936,"code":19051,"filename":19052,"language":13939,"meta":3390,"style":3390},"\u003CProject Sdk=\"Microsoft.NET.Sdk\">\n  \u003CPropertyGroup>\n    \u003CTargetFramework>net10.0\u003C\u002FTargetFramework>\n    \u003CImplicitUsings>enable\u003C\u002FImplicitUsings>\n    \u003CNullable>enable\u003C\u002FNullable>\n    \u003C!-- Оптимізації для Lambda -->\n    \u003CPublishReadyToRun>true\u003C\u002FPublishReadyToRun>\n    \u003CPublishTrimmed>true\u003C\u002FPublishTrimmed>\n  \u003C\u002FPropertyGroup>\n\n  \u003CItemGroup>\n    \u003CPackageReference Include=\"Amazon.Lambda.Core\" Version=\"2.5.*\" \u002F>\n    \u003CPackageReference Include=\"Amazon.Lambda.Serialization.SystemTextJson\" Version=\"2.4.*\" \u002F>\n    \u003CPackageReference Include=\"Amazon.Lambda.S3Events\" Version=\"3.1.*\" \u002F>\n    \u003CPackageReference Include=\"AWSSDK.S3\" Version=\"3.7.*\" \u002F>\n    \u003CPackageReference Include=\"SixLabors.ImageSharp\" Version=\"3.1.*\" \u002F>\n  \u003C\u002FItemGroup>\n\u003C\u002FProject>\n","ImageProcessor.csproj",[3392,19054,19055,19069,19077,19094,19110,19126,19131,19147,19163,19171,19175,19183,19204,19225,19247,19267,19288,19296],{"__ignoreMap":3390},[3395,19056,19057,19059,19061,19063,19065,19067],{"class":3397,"line":3398},[3395,19058,6130],{"class":13946},[3395,19060,13950],{"class":13949},[3395,19062,13954],{"class":13953},[3395,19064,13957],{"class":4708},[3395,19066,13961],{"class":13960},[3395,19068,13964],{"class":13946},[3395,19070,19071,19073,19075],{"class":3397,"line":3404},[3395,19072,13969],{"class":13946},[3395,19074,13972],{"class":13949},[3395,19076,13964],{"class":13946},[3395,19078,19079,19081,19083,19085,19088,19090,19092],{"class":3397,"line":3410},[3395,19080,13979],{"class":13946},[3395,19082,13982],{"class":13949},[3395,19084,13985],{"class":13946},[3395,19086,19087],{"class":4708},"net10.0",[3395,19089,13991],{"class":13946},[3395,19091,13982],{"class":13949},[3395,19093,13964],{"class":13946},[3395,19095,19096,19098,19100,19102,19104,19106,19108],{"class":3397,"line":3416},[3395,19097,13979],{"class":13946},[3395,19099,14020],{"class":13949},[3395,19101,13985],{"class":13946},[3395,19103,14007],{"class":4708},[3395,19105,13991],{"class":13946},[3395,19107,14020],{"class":13949},[3395,19109,13964],{"class":13946},[3395,19111,19112,19114,19116,19118,19120,19122,19124],{"class":3397,"line":3423},[3395,19113,13979],{"class":13946},[3395,19115,14002],{"class":13949},[3395,19117,13985],{"class":13946},[3395,19119,14007],{"class":4708},[3395,19121,13991],{"class":13946},[3395,19123,14002],{"class":13949},[3395,19125,13964],{"class":13946},[3395,19127,19128],{"class":3397,"line":3429},[3395,19129,19130],{"class":4690},"    \u003C!-- Оптимізації для Lambda -->\n",[3395,19132,19133,19135,19137,19139,19141,19143,19145],{"class":3397,"line":3434},[3395,19134,13979],{"class":13946},[3395,19136,14046],{"class":13949},[3395,19138,13985],{"class":13946},[3395,19140,3946],{"class":4708},[3395,19142,13991],{"class":13946},[3395,19144,14046],{"class":13949},[3395,19146,13964],{"class":13946},[3395,19148,19149,19151,19153,19155,19157,19159,19161],{"class":3397,"line":3440},[3395,19150,13979],{"class":13946},[3395,19152,14077],{"class":13949},[3395,19154,13985],{"class":13946},[3395,19156,3946],{"class":4708},[3395,19158,13991],{"class":13946},[3395,19160,14077],{"class":13949},[3395,19162,13964],{"class":13946},[3395,19164,19165,19167,19169],{"class":3397,"line":3446},[3395,19166,14118],{"class":13946},[3395,19168,13972],{"class":13949},[3395,19170,13964],{"class":13946},[3395,19172,19173],{"class":3397,"line":3452},[3395,19174,3420],{"emptyLinePlaceholder":3419},[3395,19176,19177,19179,19181],{"class":3397,"line":3458},[3395,19178,13969],{"class":13946},[3395,19180,14133],{"class":13949},[3395,19182,13964],{"class":13946},[3395,19184,19185,19187,19189,19191,19193,19195,19197,19199,19202],{"class":3397,"line":3464},[3395,19186,13979],{"class":13946},[3395,19188,14142],{"class":13949},[3395,19190,14145],{"class":13953},[3395,19192,13957],{"class":4708},[3395,19194,14150],{"class":13960},[3395,19196,14153],{"class":13953},[3395,19198,13957],{"class":4708},[3395,19200,19201],{"class":13960},"\"2.5.*\"",[3395,19203,14161],{"class":13946},[3395,19205,19206,19208,19210,19212,19214,19216,19218,19220,19223],{"class":3397,"line":3470},[3395,19207,13979],{"class":13946},[3395,19209,14142],{"class":13949},[3395,19211,14145],{"class":13953},[3395,19213,13957],{"class":4708},[3395,19215,14174],{"class":13960},[3395,19217,14153],{"class":13953},[3395,19219,13957],{"class":4708},[3395,19221,19222],{"class":13960},"\"2.4.*\"",[3395,19224,14161],{"class":13946},[3395,19226,19227,19229,19231,19233,19235,19238,19240,19242,19245],{"class":3397,"line":3476},[3395,19228,13979],{"class":13946},[3395,19230,14142],{"class":13949},[3395,19232,14145],{"class":13953},[3395,19234,13957],{"class":4708},[3395,19236,19237],{"class":13960},"\"Amazon.Lambda.S3Events\"",[3395,19239,14153],{"class":13953},[3395,19241,13957],{"class":4708},[3395,19243,19244],{"class":13960},"\"3.1.*\"",[3395,19246,14161],{"class":13946},[3395,19248,19249,19251,19253,19255,19257,19259,19261,19263,19265],{"class":3397,"line":3482},[3395,19250,13979],{"class":13946},[3395,19252,14142],{"class":13949},[3395,19254,14145],{"class":13953},[3395,19256,13957],{"class":4708},[3395,19258,14220],{"class":13960},[3395,19260,14153],{"class":13953},[3395,19262,13957],{"class":4708},[3395,19264,14227],{"class":13960},[3395,19266,14161],{"class":13946},[3395,19268,19269,19271,19273,19275,19277,19280,19282,19284,19286],{"class":3397,"line":3487},[3395,19270,13979],{"class":13946},[3395,19272,14142],{"class":13949},[3395,19274,14145],{"class":13953},[3395,19276,13957],{"class":4708},[3395,19278,19279],{"class":13960},"\"SixLabors.ImageSharp\"",[3395,19281,14153],{"class":13953},[3395,19283,13957],{"class":4708},[3395,19285,19244],{"class":13960},[3395,19287,14161],{"class":13946},[3395,19289,19290,19292,19294],{"class":3397,"line":3493},[3395,19291,14118],{"class":13946},[3395,19293,14133],{"class":13949},[3395,19295,13964],{"class":13946},[3395,19297,19298,19300,19302],{"class":3397,"line":3499},[3395,19299,13991],{"class":13946},[3395,19301,13950],{"class":13949},[3395,19303,13964],{"class":13946},[16681,19305,19306],{"label":16737},[3385,19307,19309],{"className":4681,"code":19308,"filename":4952,"language":4683,"meta":3390,"style":3390},"using Amazon.Lambda.Core;\nusing Amazon.Lambda.S3Events;\nusing Amazon.S3;\nusing Amazon.S3.Model;\nusing SixLabors.ImageSharp;\nusing SixLabors.ImageSharp.Processing;\n\n[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]\n\nnamespace ImageProcessor.Lambda;\n\npublic class Function\n{\n    private readonly IAmazonS3 _s3Client;\n    private const string DestinationBucket = \"kostyl-dev-processed-images\";\n\n    public Function() : this(new AmazonS3Client()) { }\n\n    public Function(IAmazonS3 s3Client) => _s3Client = s3Client;\n\n    public async Task FunctionHandler(S3Event evnt, ILambdaContext context)\n    {\n        foreach (var record in evnt.Records)\n        {\n            var srcBucket = record.S3.Bucket.Name;\n            var srcKey = Uri.UnescapeDataString(record.S3.Object.Key.Replace(\"+\", \" \"));\n\n            context.Logger.LogInformation($\"Processing {srcBucket}\u002F{srcKey}\");\n\n            using var response = await _s3Client.GetObjectAsync(srcBucket, srcKey);\n            using var inputStream = response.ResponseStream;\n\n            \u002F\u002F Обробка зображення через ImageSharp\n            using var image = await Image.LoadAsync(inputStream);\n\n            \u002F\u002F Змінюємо розмір до ширини 300px, зберігаючи пропорції\n            image.Mutate(x => x.Resize(new ResizeOptions {\n                Mode = ResizeMode.Max,\n                Size = new Size(300, 0)\n            }));\n\n            using var outputStream = new MemoryStream();\n            await image.SaveAsJpegAsync(outputStream);\n            outputStream.Position = 0;\n\n            \u002F\u002F Зберігаємо мініатюру\n            var dstKey = $\"thumbnails\u002F{srcKey}\";\n            await _s3Client.PutObjectAsync(new PutObjectRequest\n            {\n                BucketName = DestinationBucket,\n                Key = dstKey,\n                InputStream = outputStream,\n                ContentType = \"image\u002Fjpeg\"\n            });\n\n            context.Logger.LogInformation($\"Thumbnail saved to {DestinationBucket}\u002F{dstKey}\");\n        }\n    }\n}\n",[3392,19310,19311,19327,19343,19355,19371,19385,19402,19406,19442,19446,19458,19462,19470,19474,19487,19504,19508,19530,19534,19560,19564,19588,19592,19612,19616,19640,19684,19688,19724,19728,19757,19775,19779,19784,19811,19815,19820,19855,19872,19895,19900,19904,19922,19941,19957,19961,19966,19987,20003,20007,20018,20029,20040,20050,20055,20059,20094,20098,20102],{"__ignoreMap":3390},[3395,19312,19313,19315,19317,19319,19321,19323,19325],{"class":3397,"line":3398},[3395,19314,7533],{"class":6221},[3395,19316,7536],{"class":4700},[3395,19318,3860],{"class":4708},[3395,19320,5754],{"class":4700},[3395,19322,3860],{"class":4708},[3395,19324,7583],{"class":4700},[3395,19326,6634],{"class":4708},[3395,19328,19329,19331,19333,19335,19337,19339,19341],{"class":3397,"line":3404},[3395,19330,7533],{"class":6221},[3395,19332,7536],{"class":4700},[3395,19334,3860],{"class":4708},[3395,19336,5754],{"class":4700},[3395,19338,3860],{"class":4708},[3395,19340,9031],{"class":4700},[3395,19342,6634],{"class":4708},[3395,19344,19345,19347,19349,19351,19353],{"class":3397,"line":3410},[3395,19346,7533],{"class":6221},[3395,19348,7536],{"class":4700},[3395,19350,3860],{"class":4708},[3395,19352,9044],{"class":4700},[3395,19354,6634],{"class":4708},[3395,19356,19357,19359,19361,19363,19365,19367,19369],{"class":3397,"line":3416},[3395,19358,7533],{"class":6221},[3395,19360,7536],{"class":4700},[3395,19362,3860],{"class":4708},[3395,19364,9044],{"class":4700},[3395,19366,3860],{"class":4708},[3395,19368,9061],{"class":4700},[3395,19370,6634],{"class":4708},[3395,19372,19373,19375,19378,19380,19383],{"class":3397,"line":3423},[3395,19374,7533],{"class":6221},[3395,19376,19377],{"class":4700}," SixLabors",[3395,19379,3860],{"class":4708},[3395,19381,19382],{"class":4700},"ImageSharp",[3395,19384,6634],{"class":4708},[3395,19386,19387,19389,19391,19393,19395,19397,19400],{"class":3397,"line":3429},[3395,19388,7533],{"class":6221},[3395,19390,19377],{"class":4700},[3395,19392,3860],{"class":4708},[3395,19394,19382],{"class":4700},[3395,19396,3860],{"class":4708},[3395,19398,19399],{"class":4700},"Processing",[3395,19401,6634],{"class":4708},[3395,19403,19404],{"class":3397,"line":3434},[3395,19405,3420],{"emptyLinePlaceholder":3419},[3395,19407,19408,19410,19412,19414,19416,19418,19420,19422,19424,19426,19428,19430,19432,19434,19436,19438,19440],{"class":3397,"line":3440},[3395,19409,5731],{"class":4708},[3395,19411,5734],{"class":4696},[3395,19413,5078],{"class":4708},[3395,19415,5739],{"class":4700},[3395,19417,4709],{"class":4708},[3395,19419,5744],{"class":4696},[3395,19421,4709],{"class":4708},[3395,19423,5749],{"class":4700},[3395,19425,3860],{"class":4708},[3395,19427,5754],{"class":4700},[3395,19429,3860],{"class":4708},[3395,19431,5759],{"class":4700},[3395,19433,3860],{"class":4708},[3395,19435,5764],{"class":4700},[3395,19437,3860],{"class":4708},[3395,19439,5769],{"class":4700},[3395,19441,5772],{"class":4708},[3395,19443,19444],{"class":3397,"line":3446},[3395,19445,3420],{"emptyLinePlaceholder":3419},[3395,19447,19448,19450,19452,19454,19456],{"class":3397,"line":3452},[3395,19449,7658],{"class":4696},[3395,19451,9117],{"class":4700},[3395,19453,3860],{"class":4708},[3395,19455,5754],{"class":4700},[3395,19457,6634],{"class":4708},[3395,19459,19460],{"class":3397,"line":3458},[3395,19461,3420],{"emptyLinePlaceholder":3419},[3395,19463,19464,19466,19468],{"class":3397,"line":3464},[3395,19465,4697],{"class":4696},[3395,19467,6314],{"class":4696},[3395,19469,16828],{"class":4700},[3395,19471,19472],{"class":3397,"line":3470},[3395,19473,5069],{"class":4708},[3395,19475,19476,19478,19480,19482,19485],{"class":3397,"line":3476},[3395,19477,7714],{"class":4696},[3395,19479,7717],{"class":4696},[3395,19481,9162],{"class":4700},[3395,19483,19484],{"class":4715}," _s3Client",[3395,19486,6634],{"class":4708},[3395,19488,19489,19491,19493,19495,19497,19499,19502],{"class":3397,"line":3482},[3395,19490,7714],{"class":4696},[3395,19492,9181],{"class":4696},[3395,19494,9184],{"class":4696},[3395,19496,9187],{"class":4715},[3395,19498,6088],{"class":4708},[3395,19500,19501],{"class":4888},"\"kostyl-dev-processed-images\"",[3395,19503,6634],{"class":4708},[3395,19505,19506],{"class":3397,"line":3487},[3395,19507,3420],{"emptyLinePlaceholder":3419},[3395,19509,19510,19512,19515,19518,19521,19523,19525,19527],{"class":3397,"line":3493},[3395,19511,6326],{"class":4696},[3395,19513,19514],{"class":4704}," Function",[3395,19516,19517],{"class":4708},"() : ",[3395,19519,19520],{"class":4696},"this",[3395,19522,4709],{"class":4708},[3395,19524,6235],{"class":4696},[3395,19526,9172],{"class":4700},[3395,19528,19529],{"class":4708},"()) { }\n",[3395,19531,19532],{"class":3397,"line":3499},[3395,19533,3420],{"emptyLinePlaceholder":3419},[3395,19535,19536,19538,19540,19542,19545,19547,19550,19553,19555,19558],{"class":3397,"line":3505},[3395,19537,6326],{"class":4696},[3395,19539,19514],{"class":4704},[3395,19541,4709],{"class":4708},[3395,19543,19544],{"class":4700},"IAmazonS3",[3395,19546,13283],{"class":4715},[3395,19548,19549],{"class":4708},") => ",[3395,19551,19552],{"class":4715},"_s3Client",[3395,19554,6088],{"class":4708},[3395,19556,19557],{"class":4715},"s3Client",[3395,19559,6634],{"class":4708},[3395,19561,19562],{"class":3397,"line":3511},[3395,19563,3420],{"emptyLinePlaceholder":3419},[3395,19565,19566,19568,19570,19572,19574,19576,19578,19580,19582,19584,19586],{"class":3397,"line":3517},[3395,19567,6326],{"class":4696},[3395,19569,6124],{"class":4696},[3395,19571,6127],{"class":4700},[3395,19573,4705],{"class":4704},[3395,19575,4709],{"class":4708},[3395,19577,5835],{"class":4700},[3395,19579,9215],{"class":4715},[3395,19581,4719],{"class":4708},[3395,19583,4667],{"class":4700},[3395,19585,4724],{"class":4715},[3395,19587,4727],{"class":4708},[3395,19589,19590],{"class":3397,"line":3523},[3395,19591,6347],{"class":4708},[3395,19593,19594,19596,19598,19600,19602,19604,19606,19608,19610],{"class":3397,"line":3529},[3395,19595,9237],{"class":6221},[3395,19597,5956],{"class":4708},[3395,19599,9242],{"class":4696},[3395,19601,6686],{"class":4715},[3395,19603,9247],{"class":6221},[3395,19605,9215],{"class":4715},[3395,19607,3860],{"class":4708},[3395,19609,8988],{"class":4715},[3395,19611,4727],{"class":4708},[3395,19613,19614],{"class":3397,"line":3534},[3395,19615,8192],{"class":4708},[3395,19617,19618,19620,19622,19624,19626,19628,19630,19632,19634,19636,19638],{"class":3397,"line":3539},[3395,19619,9264],{"class":4696},[3395,19621,9267],{"class":4715},[3395,19623,6088],{"class":4708},[3395,19625,9272],{"class":4715},[3395,19627,3860],{"class":4708},[3395,19629,9044],{"class":4715},[3395,19631,3860],{"class":4708},[3395,19633,9281],{"class":4715},[3395,19635,3860],{"class":4708},[3395,19637,6803],{"class":4715},[3395,19639,6634],{"class":4708},[3395,19641,19642,19644,19646,19648,19650,19652,19654,19656,19658,19660,19662,19664,19666,19668,19670,19672,19674,19676,19678,19680,19682],{"class":3397,"line":3545},[3395,19643,9264],{"class":4696},[3395,19645,9294],{"class":4715},[3395,19647,6088],{"class":4708},[3395,19649,9299],{"class":4715},[3395,19651,3860],{"class":4708},[3395,19653,9304],{"class":4704},[3395,19655,4709],{"class":4708},[3395,19657,9272],{"class":4715},[3395,19659,3860],{"class":4708},[3395,19661,9044],{"class":4715},[3395,19663,3860],{"class":4708},[3395,19665,9317],{"class":4715},[3395,19667,3860],{"class":4708},[3395,19669,9322],{"class":4715},[3395,19671,3860],{"class":4708},[3395,19673,9327],{"class":4704},[3395,19675,4709],{"class":4708},[3395,19677,9332],{"class":4888},[3395,19679,4719],{"class":4708},[3395,19681,9337],{"class":4888},[3395,19683,9340],{"class":4708},[3395,19685,19686],{"class":3397,"line":3551},[3395,19687,3420],{"emptyLinePlaceholder":3419},[3395,19689,19690,19692,19694,19696,19698,19700,19702,19705,19707,19709,19711,19714,19716,19718,19720,19722],{"class":3397,"line":3557},[3395,19691,7929],{"class":4715},[3395,19693,3860],{"class":4708},[3395,19695,4824],{"class":4715},[3395,19697,3860],{"class":4708},[3395,19699,4835],{"class":4704},[3395,19701,4709],{"class":4708},[3395,19703,19704],{"class":4888},"$\"Processing ",[3395,19706,6507],{"class":6506},[3395,19708,9443],{"class":4715},[3395,19710,6516],{"class":6506},[3395,19712,19713],{"class":4888},"\u002F",[3395,19715,6507],{"class":6506},[3395,19717,9375],{"class":4715},[3395,19719,6516],{"class":6506},[3395,19721,6519],{"class":4888},[3395,19723,6522],{"class":4708},[3395,19725,19726],{"class":3397,"line":3563},[3395,19727,3420],{"emptyLinePlaceholder":3419},[3395,19729,19730,19733,19735,19737,19739,19741,19743,19745,19747,19749,19751,19753,19755],{"class":3397,"line":3569},[3395,19731,19732],{"class":6221},"            using",[3395,19734,9472],{"class":4696},[3395,19736,9475],{"class":4715},[3395,19738,6088],{"class":4708},[3395,19740,7957],{"class":4696},[3395,19742,19484],{"class":4715},[3395,19744,3860],{"class":4708},[3395,19746,9486],{"class":4704},[3395,19748,4709],{"class":4708},[3395,19750,9443],{"class":4715},[3395,19752,4719],{"class":4708},[3395,19754,9375],{"class":4715},[3395,19756,6522],{"class":4708},[3395,19758,19759,19761,19763,19765,19767,19769,19771,19773],{"class":3397,"line":3575},[3395,19760,19732],{"class":6221},[3395,19762,9472],{"class":4696},[3395,19764,9502],{"class":4715},[3395,19766,6088],{"class":4708},[3395,19768,9507],{"class":4715},[3395,19770,3860],{"class":4708},[3395,19772,9512],{"class":4715},[3395,19774,6634],{"class":4708},[3395,19776,19777],{"class":3397,"line":3581},[3395,19778,3420],{"emptyLinePlaceholder":3419},[3395,19780,19781],{"class":3397,"line":3586},[3395,19782,19783],{"class":4690},"            \u002F\u002F Обробка зображення через ImageSharp\n",[3395,19785,19786,19788,19790,19793,19795,19797,19800,19802,19805,19807,19809],{"class":3397,"line":3591},[3395,19787,19732],{"class":6221},[3395,19789,9472],{"class":4696},[3395,19791,19792],{"class":4715}," image",[3395,19794,6088],{"class":4708},[3395,19796,7957],{"class":4696},[3395,19798,19799],{"class":4715}," Image",[3395,19801,3860],{"class":4708},[3395,19803,19804],{"class":4704},"LoadAsync",[3395,19806,4709],{"class":4708},[3395,19808,9544],{"class":4715},[3395,19810,6522],{"class":4708},[3395,19812,19813],{"class":3397,"line":3597},[3395,19814,3420],{"emptyLinePlaceholder":3419},[3395,19816,19817],{"class":3397,"line":3603},[3395,19818,19819],{"class":4690},"            \u002F\u002F Змінюємо розмір до ширини 300px, зберігаючи пропорції\n",[3395,19821,19822,19825,19827,19830,19832,19835,19838,19840,19842,19845,19847,19849,19852],{"class":3397,"line":3609},[3395,19823,19824],{"class":4715},"            image",[3395,19826,3860],{"class":4708},[3395,19828,19829],{"class":4704},"Mutate",[3395,19831,4709],{"class":4708},[3395,19833,19834],{"class":4715},"x",[3395,19836,19837],{"class":4708}," => ",[3395,19839,19834],{"class":4715},[3395,19841,3860],{"class":4708},[3395,19843,19844],{"class":4704},"Resize",[3395,19846,4709],{"class":4708},[3395,19848,6235],{"class":4696},[3395,19850,19851],{"class":4700}," ResizeOptions",[3395,19853,19854],{"class":4708}," {\n",[3395,19856,19857,19860,19862,19865,19867,19870],{"class":3397,"line":3615},[3395,19858,19859],{"class":4715},"                Mode",[3395,19861,6088],{"class":4708},[3395,19863,19864],{"class":4715},"ResizeMode",[3395,19866,3860],{"class":4708},[3395,19868,19869],{"class":4715},"Max",[3395,19871,5084],{"class":4708},[3395,19873,19874,19877,19879,19881,19884,19886,19889,19891,19893],{"class":3397,"line":3621},[3395,19875,19876],{"class":4715},"                Size",[3395,19878,6088],{"class":4708},[3395,19880,6235],{"class":4696},[3395,19882,19883],{"class":4700}," Size",[3395,19885,4709],{"class":4708},[3395,19887,19888],{"class":5154},"300",[3395,19890,4719],{"class":4708},[3395,19892,15810],{"class":5154},[3395,19894,4727],{"class":4708},[3395,19896,19897],{"class":3397,"line":3627},[3395,19898,19899],{"class":4708},"            }));\n",[3395,19901,19902],{"class":3397,"line":3633},[3395,19903,3420],{"emptyLinePlaceholder":3419},[3395,19905,19906,19908,19910,19913,19915,19917,19920],{"class":3397,"line":3638},[3395,19907,19732],{"class":6221},[3395,19909,9472],{"class":4696},[3395,19911,19912],{"class":4715}," outputStream",[3395,19914,6088],{"class":4708},[3395,19916,6235],{"class":4696},[3395,19918,19919],{"class":4700}," MemoryStream",[3395,19921,8224],{"class":4708},[3395,19923,19924,19927,19929,19931,19934,19936,19939],{"class":3397,"line":3643},[3395,19925,19926],{"class":4696},"            await",[3395,19928,19792],{"class":4715},[3395,19930,3860],{"class":4708},[3395,19932,19933],{"class":4704},"SaveAsJpegAsync",[3395,19935,4709],{"class":4708},[3395,19937,19938],{"class":4715},"outputStream",[3395,19940,6522],{"class":4708},[3395,19942,19943,19946,19948,19951,19953,19955],{"class":3397,"line":3649},[3395,19944,19945],{"class":4715},"            outputStream",[3395,19947,3860],{"class":4708},[3395,19949,19950],{"class":4715},"Position",[3395,19952,6088],{"class":4708},[3395,19954,15810],{"class":5154},[3395,19956,6634],{"class":4708},[3395,19958,19959],{"class":3397,"line":3655},[3395,19960,3420],{"emptyLinePlaceholder":3419},[3395,19962,19963],{"class":3397,"line":3661},[3395,19964,19965],{"class":4690},"            \u002F\u002F Зберігаємо мініатюру\n",[3395,19967,19968,19970,19972,19974,19977,19979,19981,19983,19985],{"class":3397,"line":3667},[3395,19969,9264],{"class":4696},[3395,19971,9566],{"class":4715},[3395,19973,6088],{"class":4708},[3395,19975,19976],{"class":4888},"$\"thumbnails\u002F",[3395,19978,6507],{"class":6506},[3395,19980,9375],{"class":4715},[3395,19982,6516],{"class":6506},[3395,19984,6519],{"class":4888},[3395,19986,6634],{"class":4708},[3395,19988,19989,19991,19993,19995,19997,19999,20001],{"class":3397,"line":3672},[3395,19990,19926],{"class":4696},[3395,19992,19484],{"class":4715},[3395,19994,3860],{"class":4708},[3395,19996,9685],{"class":4704},[3395,19998,4709],{"class":4708},[3395,20000,6235],{"class":4696},[3395,20002,9595],{"class":4700},[3395,20004,20005],{"class":3397,"line":8082},[3395,20006,9408],{"class":4708},[3395,20008,20009,20012,20014,20016],{"class":3397,"line":8104},[3395,20010,20011],{"class":4715},"                BucketName",[3395,20013,6088],{"class":4708},[3395,20015,9608],{"class":4715},[3395,20017,5084],{"class":4708},[3395,20019,20020,20023,20025,20027],{"class":3397,"line":8124},[3395,20021,20022],{"class":4715},"                Key",[3395,20024,6088],{"class":4708},[3395,20026,9619],{"class":4715},[3395,20028,5084],{"class":4708},[3395,20030,20031,20034,20036,20038],{"class":3397,"line":8141},[3395,20032,20033],{"class":4715},"                InputStream",[3395,20035,6088],{"class":4708},[3395,20037,19938],{"class":4715},[3395,20039,5084],{"class":4708},[3395,20041,20042,20045,20047],{"class":3397,"line":8150},[3395,20043,20044],{"class":4715},"                ContentType",[3395,20046,6088],{"class":4708},[3395,20048,20049],{"class":4888},"\"image\u002Fjpeg\"\n",[3395,20051,20052],{"class":3397,"line":8155},[3395,20053,20054],{"class":4708},"            });\n",[3395,20056,20057],{"class":3397,"line":8161},[3395,20058,3420],{"emptyLinePlaceholder":3419},[3395,20060,20061,20063,20065,20067,20069,20071,20073,20076,20078,20080,20082,20084,20086,20088,20090,20092],{"class":3397,"line":8189},[3395,20062,7929],{"class":4715},[3395,20064,3860],{"class":4708},[3395,20066,4824],{"class":4715},[3395,20068,3860],{"class":4708},[3395,20070,4835],{"class":4704},[3395,20072,4709],{"class":4708},[3395,20074,20075],{"class":4888},"$\"Thumbnail saved to ",[3395,20077,6507],{"class":6506},[3395,20079,9608],{"class":4715},[3395,20081,6516],{"class":6506},[3395,20083,19713],{"class":4888},[3395,20085,6507],{"class":6506},[3395,20087,9619],{"class":4715},[3395,20089,6516],{"class":6506},[3395,20091,6519],{"class":4888},[3395,20093,6522],{"class":4708},[3395,20095,20096],{"class":3397,"line":8195},[3395,20097,8230],{"class":4708},[3395,20099,20100],{"class":3397,"line":8212},[3395,20101,6396],{"class":4708},[3395,20103,20104],{"class":3397,"line":8227},[3395,20105,3479],{"class":4708},[3704,20107,20109],{"id":20108},"крок-4-деплой-та-конфігурація-тригера","Крок 4: Деплой та конфігурація тригера",[3353,20111,20112],{},"Тепер ми скомпілюємо код та налаштуємо автоматичний виклик Lambda при завантаженні файлу в S3.",[16678,20114,20115,20219,20442],{},[16681,20116,20117],{"label":18260},[4867,20118,20119,20186],{},[4035,20120,20121,20124],{},[3359,20122,20123],{},"Деплой коду:",[4032,20125,20126,20136,20145,20154,20163,20176],{},[4035,20127,20128,20129,20132,20133,3860],{},"Виконайте ",[3392,20130,20131],{},"dotnet lambda package"," локально, щоб отримати ",[3392,20134,20135],{},"function.zip",[4035,20137,20138,20139,20141,20142,3860],{},"В консолі ",[3359,20140,5754],{}," натисніть ",[3359,20143,20144],{},"Create function",[4035,20146,20147,20148,20151,20152,3860],{},"Назва: ",[3392,20149,20150],{},"ImageProcessor",", Runtime: ",[3392,20153,4571],{},[4035,20155,20156,20157,20160,20161,3860],{},"Permissions: оберіть ",[3359,20158,20159],{},"Use an existing role"," та вкажіть ",[3392,20162,18625],{},[4035,20164,20165,20166,20141,20169,18413,20172,20175],{},"Після створення у вкладці ",[3359,20167,20168],{},"Code",[3359,20170,20171],{},"Upload from",[3359,20173,20174],{},".zip file"," та оберіть ваш архів.",[4035,20177,20178,20179,20182,20183,3860],{},"У ",[3359,20180,20181],{},"Runtime settings"," змініть Handler на: ",[3392,20184,20185],{},"ImageProcessor::ImageProcessor.Lambda.Function::FunctionHandler",[4035,20187,20188,20191],{},[3359,20189,20190],{},"Налаштування тригера:",[4032,20192,20193,20199,20208,20214],{},[4035,20194,20195,20196,3860],{},"На сторінці функції натисніть ",[3359,20197,20198],{},"+ Add trigger",[4035,20200,20201,20202,20204,20205,3860],{},"Оберіть ",[3359,20203,9044],{},". Bucket: ",[3392,20206,20207],{},"kostyl-dev-source-images",[4035,20209,20210,20211,3860],{},"Event type: ",[3359,20212,20213],{},"All object create events",[4035,20215,20216,20217,3860],{},"Підтвердіть згоду (Recursive invocation warning) та натисніть ",[3359,20218,10639],{},[16681,20220,20221],{"label":16949},[3385,20222,20224],{"className":4876,"code":20223,"language":4878,"meta":3390,"style":3390},"# 1. Компіляція\ndotnet lambda package \\\n    --output-package function.zip\n\n# 2. Деплой (використовуйте ARN вашої ролі)\naws lambda create-function \\\n    --function-name ImageProcessor \\\n    --runtime dotnet10 \\\n    --handler ImageProcessor::ImageProcessor.Lambda.Function::FunctionHandler \\\n    --role arn:aws:iam::ACCOUNT_ID:role\u002FImageProcessorRole \\\n    --zip-file fileb:\u002F\u002Ffunction.zip \\\n    --region eu-central-1\n\n# 3. Дозвіл для S3\naws lambda add-permission \\\n    --function-name ImageProcessor \\\n    --statement-id s3-trigger \\\n    --action \"lambda:InvokeFunction\" \\\n    --principal s3.amazonaws.com \\\n    --source-arn \"arn:aws:s3:::kostyl-dev-source-images\"\n\n# 4. Реєстрація тригера\naws s3api put-bucket-notification-configuration \\\n    --bucket kostyl-dev-source-images \\\n    --notification-configuration '{\n      \"LambdaFunctionConfigurations\": [{\n        \"LambdaFunctionArn\": \"arn:aws:lambda:eu-central-1:ACCOUNT_ID:function:ImageProcessor\",\n        \"Events\": [\"s3:ObjectCreated:*\"]\n      }]\n    }'\n",[3392,20225,20226,20231,20241,20248,20252,20257,20268,20276,20284,20293,20303,20312,20318,20322,20327,20337,20345,20354,20363,20372,20380,20384,20389,20401,20411,20418,20423,20428,20433,20438],{"__ignoreMap":3390},[3395,20227,20228],{"class":3397,"line":3398},[3395,20229,20230],{"class":4690},"# 1. Компіляція\n",[3395,20232,20233,20235,20237,20239],{"class":3397,"line":3404},[3395,20234,4903],{"class":4704},[3395,20236,5016],{"class":4888},[3395,20238,4929],{"class":4888},[3395,20240,5584],{"class":5583},[3395,20242,20243,20245],{"class":3397,"line":3410},[3395,20244,17122],{"class":4696},[3395,20246,20247],{"class":4888}," function.zip\n",[3395,20249,20250],{"class":3397,"line":3416},[3395,20251,3420],{"emptyLinePlaceholder":3419},[3395,20253,20254],{"class":3397,"line":3423},[3395,20255,20256],{"class":4690},"# 2. Деплой (використовуйте ARN вашої ролі)\n",[3395,20258,20259,20261,20263,20266],{"class":3397,"line":3429},[3395,20260,5575],{"class":4704},[3395,20262,5016],{"class":4888},[3395,20264,20265],{"class":4888}," create-function",[3395,20267,5584],{"class":5583},[3395,20269,20270,20272,20274],{"class":3397,"line":3434},[3395,20271,5650],{"class":4696},[3395,20273,9117],{"class":4888},[3395,20275,5584],{"class":5583},[3395,20277,20278,20280,20282],{"class":3397,"line":3440},[3395,20279,14306],{"class":4696},[3395,20281,16979],{"class":4888},[3395,20283,5584],{"class":5583},[3395,20285,20286,20288,20291],{"class":3397,"line":3446},[3395,20287,16986],{"class":4696},[3395,20289,20290],{"class":4888}," ImageProcessor::ImageProcessor.Lambda.Function::FunctionHandler",[3395,20292,5584],{"class":5583},[3395,20294,20295,20298,20301],{"class":3397,"line":3452},[3395,20296,20297],{"class":4696},"    --role",[3395,20299,20300],{"class":4888}," arn:aws:iam::ACCOUNT_ID:role\u002FImageProcessorRole",[3395,20302,5584],{"class":5583},[3395,20304,20305,20307,20310],{"class":3397,"line":3458},[3395,20306,5609],{"class":4696},[3395,20308,20309],{"class":4888}," fileb:\u002F\u002Ffunction.zip",[3395,20311,5584],{"class":5583},[3395,20313,20314,20316],{"class":3397,"line":3464},[3395,20315,15629],{"class":4696},[3395,20317,15632],{"class":4888},[3395,20319,20320],{"class":3397,"line":3470},[3395,20321,3420],{"emptyLinePlaceholder":3419},[3395,20323,20324],{"class":3397,"line":3476},[3395,20325,20326],{"class":4690},"# 3. Дозвіл для S3\n",[3395,20328,20329,20331,20333,20335],{"class":3397,"line":3482},[3395,20330,5575],{"class":4704},[3395,20332,5016],{"class":4888},[3395,20334,17489],{"class":4888},[3395,20336,5584],{"class":5583},[3395,20338,20339,20341,20343],{"class":3397,"line":3487},[3395,20340,5650],{"class":4696},[3395,20342,9117],{"class":4888},[3395,20344,5584],{"class":5583},[3395,20346,20347,20349,20352],{"class":3397,"line":3493},[3395,20348,17504],{"class":4696},[3395,20350,20351],{"class":4888}," s3-trigger",[3395,20353,5584],{"class":5583},[3395,20355,20356,20358,20361],{"class":3397,"line":3499},[3395,20357,17514],{"class":4696},[3395,20359,20360],{"class":4888}," \"lambda:InvokeFunction\"",[3395,20362,5584],{"class":5583},[3395,20364,20365,20367,20370],{"class":3397,"line":3505},[3395,20366,17524],{"class":4696},[3395,20368,20369],{"class":4888}," s3.amazonaws.com",[3395,20371,5584],{"class":5583},[3395,20373,20374,20377],{"class":3397,"line":3511},[3395,20375,20376],{"class":4696},"    --source-arn",[3395,20378,20379],{"class":4888}," \"arn:aws:s3:::kostyl-dev-source-images\"\n",[3395,20381,20382],{"class":3397,"line":3517},[3395,20383,3420],{"emptyLinePlaceholder":3419},[3395,20385,20386],{"class":3397,"line":3523},[3395,20387,20388],{"class":4690},"# 4. Реєстрація тригера\n",[3395,20390,20391,20393,20396,20399],{"class":3397,"line":3529},[3395,20392,5575],{"class":4704},[3395,20394,20395],{"class":4888}," s3api",[3395,20397,20398],{"class":4888}," put-bucket-notification-configuration",[3395,20400,5584],{"class":5583},[3395,20402,20403,20406,20409],{"class":3397,"line":3534},[3395,20404,20405],{"class":4696},"    --bucket",[3395,20407,20408],{"class":4888}," kostyl-dev-source-images",[3395,20410,5584],{"class":5583},[3395,20412,20413,20416],{"class":3397,"line":3539},[3395,20414,20415],{"class":4696},"    --notification-configuration",[3395,20417,18647],{"class":4888},[3395,20419,20420],{"class":3397,"line":3545},[3395,20421,20422],{"class":4888},"      \"LambdaFunctionConfigurations\": [{\n",[3395,20424,20425],{"class":3397,"line":3551},[3395,20426,20427],{"class":4888},"        \"LambdaFunctionArn\": \"arn:aws:lambda:eu-central-1:ACCOUNT_ID:function:ImageProcessor\",\n",[3395,20429,20430],{"class":3397,"line":3557},[3395,20431,20432],{"class":4888},"        \"Events\": [\"s3:ObjectCreated:*\"]\n",[3395,20434,20435],{"class":3397,"line":3563},[3395,20436,20437],{"class":4888},"      }]\n",[3395,20439,20440],{"class":3397,"line":3569},[3395,20441,18807],{"class":4888},[16681,20443,20444],{"label":17020},[3385,20445,20447],{"className":17023,"code":20446,"language":17025,"meta":3390,"style":3390},"# 1. Деплой\nPublish-LMFunction -FunctionName ImageProcessor `\n    -Runtime dotnet10 `\n    -Handler \"ImageProcessor::ImageProcessor.Lambda.Function::FunctionHandler\" `\n    -Role \"arn:aws:iam::ACCOUNT_ID:role\u002FImageProcessorRole\" `\n    -ZipFile \"function.zip\" `\n    -Region eu-central-1\n\n# 2. Дозвіл\nAdd-LMPermission -FunctionName ImageProcessor `\n    -StatementId s3-trigger `\n    -Action \"lambda:InvokeFunction\" `\n    -Principal s3.amazonaws.com `\n    -SourceArn \"arn:aws:s3:::kostyl-dev-source-images\"\n\n# 3. Тригер\n$config = @{\n    LambdaFunctionConfigurations = @(@{\n        LambdaFunctionArn = \"arn:aws:lambda:eu-central-1:ACCOUNT_ID:function:ImageProcessor\"\n        Events = @(\"s3:ObjectCreated:*\")\n    })\n}\nWrite-S3BucketNotification -BucketName kostyl-dev-source-images -Configuration $config\n",[3392,20448,20449,20454,20462,20467,20477,20487,20497,20504,20508,20513,20520,20525,20535,20545,20553,20557,20562,20574,20589,20599,20615,20620,20624],{"__ignoreMap":3390},[3395,20450,20451],{"class":3397,"line":3398},[3395,20452,20453],{"class":4690},"# 1. Деплой\n",[3395,20455,20456,20459],{"class":3397,"line":3404},[3395,20457,20458],{"class":4704},"Publish-LMFunction",[3395,20460,20461],{"class":4708}," -FunctionName ImageProcessor `\n",[3395,20463,20464],{"class":3397,"line":3410},[3395,20465,20466],{"class":4708},"    -Runtime dotnet10 `\n",[3395,20468,20469,20472,20475],{"class":3397,"line":3416},[3395,20470,20471],{"class":4708},"    -Handler ",[3395,20473,20474],{"class":4888},"\"ImageProcessor::ImageProcessor.Lambda.Function::FunctionHandler\"",[3395,20476,17062],{"class":4708},[3395,20478,20479,20482,20485],{"class":3397,"line":3423},[3395,20480,20481],{"class":4708},"    -Role ",[3395,20483,20484],{"class":4888},"\"arn:aws:iam::ACCOUNT_ID:role\u002FImageProcessorRole\"",[3395,20486,17062],{"class":4708},[3395,20488,20489,20492,20495],{"class":3397,"line":3429},[3395,20490,20491],{"class":4708},"    -ZipFile ",[3395,20493,20494],{"class":4888},"\"function.zip\"",[3395,20496,17062],{"class":4708},[3395,20498,20499,20502],{"class":3397,"line":3434},[3395,20500,20501],{"class":4708},"    -Region eu-central-",[3395,20503,12971],{"class":5154},[3395,20505,20506],{"class":3397,"line":3440},[3395,20507,3420],{"emptyLinePlaceholder":3419},[3395,20509,20510],{"class":3397,"line":3446},[3395,20511,20512],{"class":4690},"# 2. Дозвіл\n",[3395,20514,20515,20518],{"class":3397,"line":3452},[3395,20516,20517],{"class":4704},"Add-LMPermission",[3395,20519,20461],{"class":4708},[3395,20521,20522],{"class":3397,"line":3458},[3395,20523,20524],{"class":4708},"    -StatementId s3-trigger `\n",[3395,20526,20527,20530,20533],{"class":3397,"line":3464},[3395,20528,20529],{"class":4708},"    -Action ",[3395,20531,20532],{"class":4888},"\"lambda:InvokeFunction\"",[3395,20534,17062],{"class":4708},[3395,20536,20537,20540,20543],{"class":3397,"line":3470},[3395,20538,20539],{"class":4708},"    -Principal ",[3395,20541,20542],{"class":4704},"s3.amazonaws.com",[3395,20544,17062],{"class":4708},[3395,20546,20547,20550],{"class":3397,"line":3476},[3395,20548,20549],{"class":4708},"    -SourceArn ",[3395,20551,20552],{"class":4888},"\"arn:aws:s3:::kostyl-dev-source-images\"\n",[3395,20554,20555],{"class":3397,"line":3482},[3395,20556,3420],{"emptyLinePlaceholder":3419},[3395,20558,20559],{"class":3397,"line":3487},[3395,20560,20561],{"class":4690},"# 3. Тригер\n",[3395,20563,20564,20567,20569,20572],{"class":3397,"line":3493},[3395,20565,20566],{"class":4715},"$config",[3395,20568,6088],{"class":4708},[3395,20570,20571],{"class":4696},"@",[3395,20573,5069],{"class":4708},[3395,20575,20576,20579,20581,20583,20585,20587],{"class":3397,"line":3499},[3395,20577,20578],{"class":4715},"    LambdaFunctionConfigurations",[3395,20580,6088],{"class":4708},[3395,20582,20571],{"class":4696},[3395,20584,4709],{"class":4708},[3395,20586,20571],{"class":4696},[3395,20588,5069],{"class":4708},[3395,20590,20591,20594,20596],{"class":3397,"line":3505},[3395,20592,20593],{"class":4715},"        LambdaFunctionArn",[3395,20595,6088],{"class":4708},[3395,20597,20598],{"class":4888},"\"arn:aws:lambda:eu-central-1:ACCOUNT_ID:function:ImageProcessor\"\n",[3395,20600,20601,20604,20606,20608,20610,20613],{"class":3397,"line":3511},[3395,20602,20603],{"class":4715},"        Events",[3395,20605,6088],{"class":4708},[3395,20607,20571],{"class":4696},[3395,20609,4709],{"class":4708},[3395,20611,20612],{"class":4888},"\"s3:ObjectCreated:*\"",[3395,20614,4727],{"class":4708},[3395,20616,20617],{"class":3397,"line":3517},[3395,20618,20619],{"class":4708},"    })\n",[3395,20621,20622],{"class":3397,"line":3523},[3395,20623,3479],{"class":4708},[3395,20625,20626,20629,20632],{"class":3397,"line":3529},[3395,20627,20628],{"class":4704},"Write-S3BucketNotification",[3395,20630,20631],{"class":4708}," -BucketName kostyl-dev-source-images -Configuration ",[3395,20633,20634],{"class":4715},"$config\n",[3704,20636,20638],{"id":20637},"крок-5-тестування-та-моніторинг","Крок 5: Тестування та моніторинг",[5436,20640,20641,20645,20669,20673,20695,20699],{},[3704,20642,20644],{"id":20643},"завантаження-тестового-файлу","Завантаження тестового файлу",[3385,20646,20648],{"className":4876,"code":20647,"language":4878,"meta":3390,"style":3390},"# Завантажуємо будь-яке зображення у source bucket\naws s3 cp my-photo.jpg s3:\u002F\u002Fkostyl-dev-source-images\u002Fphoto-1.jpg\n",[3392,20649,20650,20655],{"__ignoreMap":3390},[3395,20651,20652],{"class":3397,"line":3398},[3395,20653,20654],{"class":4690},"# Завантажуємо будь-яке зображення у source bucket\n",[3395,20656,20657,20659,20661,20663,20666],{"class":3397,"line":3404},[3395,20658,5575],{"class":4704},[3395,20660,17141],{"class":4888},[3395,20662,17144],{"class":4888},[3395,20664,20665],{"class":4888}," my-photo.jpg",[3395,20667,20668],{"class":4888}," s3:\u002F\u002Fkostyl-dev-source-images\u002Fphoto-1.jpg\n",[3704,20670,20672],{"id":20671},"перевірка-результату","Перевірка результату",[3385,20674,20676],{"className":4876,"code":20675,"language":4878,"meta":3390,"style":3390},"# Перевіряємо, чи з'явилася мініатюра у другому кошику\naws s3 ls s3:\u002F\u002Fkostyl-dev-processed-images\u002Fthumbnails\u002F\n",[3392,20677,20678,20683],{"__ignoreMap":3390},[3395,20679,20680],{"class":3397,"line":3398},[3395,20681,20682],{"class":4690},"# Перевіряємо, чи з'явилася мініатюра у другому кошику\n",[3395,20684,20685,20687,20689,20692],{"class":3397,"line":3404},[3395,20686,5575],{"class":4704},[3395,20688,17141],{"class":4888},[3395,20690,20691],{"class":4888}," ls",[3395,20693,20694],{"class":4888}," s3:\u002F\u002Fkostyl-dev-processed-images\u002Fthumbnails\u002F\n",[3704,20696,20698],{"id":20697},"моніторинг-логів","Моніторинг логів",[3385,20700,20702],{"className":4876,"code":20701,"language":4878,"meta":3390,"style":3390},"# Дивимось логи виконання у реальному часі\naws logs tail \u002Faws\u002Flambda\u002FImageProcessor \\\n    --follow\n",[3392,20703,20704,20709,20724],{"__ignoreMap":3390},[3395,20705,20706],{"class":3397,"line":3398},[3395,20707,20708],{"class":4690},"# Дивимось логи виконання у реальному часі\n",[3395,20710,20711,20713,20716,20719,20722],{"class":3397,"line":3404},[3395,20712,5575],{"class":4704},[3395,20714,20715],{"class":4888}," logs",[3395,20717,20718],{"class":4888}," tail",[3395,20720,20721],{"class":4888}," \u002Faws\u002Flambda\u002FImageProcessor",[3395,20723,5584],{"class":5583},[3395,20725,20726],{"class":3397,"line":3410},[3395,20727,20728],{"class":4696},"    --follow\n",[3677,20730,20731,20732,20735,20736,20739],{},"У реальних проектах рекомендується використовувати ",[3359,20733,20734],{},"AWS SAM"," або ",[3359,20737,20738],{},"Terraform"," для опису цієї інфраструктури як коду (IaC), щоб уникнути ручного введення команд CLI.",[3684,20741],{},[3348,20743,20745],{"id":20744},"практичний-воркшоп-проектування-serverless-url-shortener-api-dynamodb","Практичний воркшоп: Проектування Serverless URL Shortener (API + DynamoDB)",[3353,20747,20748],{},"Цей розділ присвячений побудові високонавантаженої системи скорочення посилань. Проект демонструє синергію синхронного HTTP API та персистентного сховища NoSQL, реалізуючи патерн «Compute-as-a-Service» з мінімальною латентністю.",[3704,20750,20752],{"id":20751},"архітектурна-парадигма-та-потік-даних","Архітектурна парадигма та потік даних",[3353,20754,20755],{},"Система базується на трирівневій serverless-архітектурі:",[4867,20757,20758,20764,20770],{},[4035,20759,20760,20763],{},[3359,20761,20762],{},"Інтерфейсний рівень (API Gateway):"," забезпечує HTTP-ендпоінти та автоматичну десеріалізацію запитів.",[4035,20765,20766,20769],{},[3359,20767,20768],{},"Логічний рівень (Lambda .NET 10):"," виконує бізнес-логіку (генерація кодів, валідація URL) та взаємодію з базою даних.",[4035,20771,20772,20775],{},[3359,20773,20774],{},"Рівень зберігання (DynamoDB):"," забезпечує атомарне збереження пар «Код — Оригінальний URL» з гарантованим часом доступу \u003C 10ms.",[3382,20777,20778],{},[3385,20779,20781],{"className":3387,"code":20780,"language":3389,"meta":3390,"style":3390},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\n\ntitle \"Архітектура Serverless URL Shortener\"\n\nactor \"Клієнт\" as CL\nrectangle \"API Gateway (HTTP API)\" as AGW #dbeafe\nrectangle \"AWS Lambda (.NET 10)\\nUrlShortenerFunction\" as LAM #d1fae5\ndatabase \"Amazon DynamoDB\\nUrlMappingTable\" as DDB #f3e8ff\n\nCL -> AGW : 1. POST \u002Fshorten {url: \"...\"}\nAGW -> LAM : 2. Invoke (Event JSON)\nLAM -> DDB : 3. PutItem (ID, LongUrl)\nLAM --> AGW : 4. Return {shortUrl: \"...\"}\nAGW --> CL : 5. HTTP 201 Created\n\nCL -> AGW : 6. GET \u002F{shortCode}\nAGW -> LAM : 7. Invoke (Path Parameter)\nLAM -> DDB : 8. GetItem (ID)\nLAM --> AGW : 9. HTTP 302 Redirect (Location)\nAGW --> CL : 10. Redirect to Target\n@enduml\n",[3392,20782,20783,20787,20791,20795,20799,20804,20808,20812,20817,20822,20827,20831,20836,20841,20846,20851,20856,20860,20865,20870,20875,20880,20885],{"__ignoreMap":3390},[3395,20784,20785],{"class":3397,"line":3398},[3395,20786,3401],{},[3395,20788,20789],{"class":3397,"line":3404},[3395,20790,3407],{},[3395,20792,20793],{"class":3397,"line":3410},[3395,20794,3413],{},[3395,20796,20797],{"class":3397,"line":3416},[3395,20798,3420],{"emptyLinePlaceholder":3419},[3395,20800,20801],{"class":3397,"line":3423},[3395,20802,20803],{},"title \"Архітектура Serverless URL Shortener\"\n",[3395,20805,20806],{"class":3397,"line":3429},[3395,20807,3420],{"emptyLinePlaceholder":3419},[3395,20809,20810],{"class":3397,"line":3434},[3395,20811,8691],{},[3395,20813,20814],{"class":3397,"line":3440},[3395,20815,20816],{},"rectangle \"API Gateway (HTTP API)\" as AGW #dbeafe\n",[3395,20818,20819],{"class":3397,"line":3446},[3395,20820,20821],{},"rectangle \"AWS Lambda (.NET 10)\\nUrlShortenerFunction\" as LAM #d1fae5\n",[3395,20823,20824],{"class":3397,"line":3452},[3395,20825,20826],{},"database \"Amazon DynamoDB\\nUrlMappingTable\" as DDB #f3e8ff\n",[3395,20828,20829],{"class":3397,"line":3458},[3395,20830,3420],{"emptyLinePlaceholder":3419},[3395,20832,20833],{"class":3397,"line":3464},[3395,20834,20835],{},"CL -> AGW : 1. POST \u002Fshorten {url: \"...\"}\n",[3395,20837,20838],{"class":3397,"line":3470},[3395,20839,20840],{},"AGW -> LAM : 2. Invoke (Event JSON)\n",[3395,20842,20843],{"class":3397,"line":3476},[3395,20844,20845],{},"LAM -> DDB : 3. PutItem (ID, LongUrl)\n",[3395,20847,20848],{"class":3397,"line":3482},[3395,20849,20850],{},"LAM --> AGW : 4. Return {shortUrl: \"...\"}\n",[3395,20852,20853],{"class":3397,"line":3487},[3395,20854,20855],{},"AGW --> CL : 5. HTTP 201 Created\n",[3395,20857,20858],{"class":3397,"line":3493},[3395,20859,3420],{"emptyLinePlaceholder":3419},[3395,20861,20862],{"class":3397,"line":3499},[3395,20863,20864],{},"CL -> AGW : 6. GET \u002F{shortCode}\n",[3395,20866,20867],{"class":3397,"line":3505},[3395,20868,20869],{},"AGW -> LAM : 7. Invoke (Path Parameter)\n",[3395,20871,20872],{"class":3397,"line":3511},[3395,20873,20874],{},"LAM -> DDB : 8. GetItem (ID)\n",[3395,20876,20877],{"class":3397,"line":3517},[3395,20878,20879],{},"LAM --> AGW : 9. HTTP 302 Redirect (Location)\n",[3395,20881,20882],{"class":3397,"line":3523},[3395,20883,20884],{},"AGW --> CL : 10. Redirect to Target\n",[3395,20886,20887],{"class":3397,"line":3529},[3395,20888,3675],{},[3704,20890,20892],{"id":20891},"крок-1-проектування-схеми-даних-dynamodb","Крок 1: Проектування схеми даних (DynamoDB)",[3353,20894,20895],{},"Нам потрібна таблиця з високою пропускною здатністю для ключ-значення запитів.",[16678,20897,20898,20938,21003],{},[16681,20899,20900],{"label":18260},[4867,20901,20902,20914,20920,20927,20934],{},[4035,20903,20904,20905,18413,20908,18413,20911,3860],{},"Перейдіть до ",[3359,20906,20907],{},"DynamoDB",[3359,20909,20910],{},"Tables",[3359,20912,20913],{},"Create table",[4035,20915,20916,20917,3860],{},"Table name: ",[3392,20918,20919],{},"UrlMappingTable",[4035,20921,20922,20923,20926],{},"Partition key: ",[3392,20924,20925],{},"ShortCode"," (String).",[4035,20928,20929,20930,20933],{},"Table settings: ",[3359,20931,20932],{},"Default settings"," (On-Demand capacity).",[4035,20935,18270,20936,3860],{},[3359,20937,20913],{},[16681,20939,20940],{"label":16949},[3385,20941,20943],{"className":4876,"code":20942,"language":4878,"meta":3390,"style":3390},"aws dynamodb create-table \\\n    --table-name UrlMappingTable \\\n    --attribute-definitions AttributeName=ShortCode,AttributeType=S \\\n    --key-schema AttributeName=ShortCode,KeyType=HASH \\\n    --billing-mode PAY_PER_REQUEST \\\n    --region eu-central-1\n",[3392,20944,20945,20957,20967,20977,20987,20997],{"__ignoreMap":3390},[3395,20946,20947,20949,20952,20955],{"class":3397,"line":3398},[3395,20948,5575],{"class":4704},[3395,20950,20951],{"class":4888}," dynamodb",[3395,20953,20954],{"class":4888}," create-table",[3395,20956,5584],{"class":5583},[3395,20958,20959,20962,20965],{"class":3397,"line":3404},[3395,20960,20961],{"class":4696},"    --table-name",[3395,20963,20964],{"class":4888}," UrlMappingTable",[3395,20966,5584],{"class":5583},[3395,20968,20969,20972,20975],{"class":3397,"line":3410},[3395,20970,20971],{"class":4696},"    --attribute-definitions",[3395,20973,20974],{"class":4888}," AttributeName=ShortCode,AttributeType=S",[3395,20976,5584],{"class":5583},[3395,20978,20979,20982,20985],{"class":3397,"line":3416},[3395,20980,20981],{"class":4696},"    --key-schema",[3395,20983,20984],{"class":4888}," AttributeName=ShortCode,KeyType=HASH",[3395,20986,5584],{"class":5583},[3395,20988,20989,20992,20995],{"class":3397,"line":3423},[3395,20990,20991],{"class":4696},"    --billing-mode",[3395,20993,20994],{"class":4888}," PAY_PER_REQUEST",[3395,20996,5584],{"class":5583},[3395,20998,20999,21001],{"class":3397,"line":3429},[3395,21000,15629],{"class":4696},[3395,21002,15632],{"class":4888},[16681,21004,21005],{"label":17020},[3385,21006,21008],{"className":17023,"code":21007,"language":17025,"meta":3390,"style":3390},"New-DDBTable -TableName \"UrlMappingTable\" `\n    -AttributeDefinition @{AttributeName=\"ShortCode\";AttributeType=\"S\"} `\n    -KeySchema @{AttributeName=\"ShortCode\";KeyType=\"HASH\"} `\n    -BillingMode PAY_PER_REQUEST `\n    -Region eu-central-1\n",[3392,21009,21010,21023,21054,21081,21086],{"__ignoreMap":3390},[3395,21011,21012,21015,21018,21021],{"class":3397,"line":3398},[3395,21013,21014],{"class":4704},"New-DDBTable",[3395,21016,21017],{"class":4708}," -TableName ",[3395,21019,21020],{"class":4888},"\"UrlMappingTable\"",[3395,21022,17062],{"class":4708},[3395,21024,21025,21028,21030,21032,21035,21037,21040,21043,21046,21048,21051],{"class":3397,"line":3404},[3395,21026,21027],{"class":4708},"    -AttributeDefinition ",[3395,21029,20571],{"class":4696},[3395,21031,6507],{"class":4708},[3395,21033,21034],{"class":4715},"AttributeName",[3395,21036,13957],{"class":4708},[3395,21038,21039],{"class":4888},"\"ShortCode\"",[3395,21041,21042],{"class":4708},";",[3395,21044,21045],{"class":4715},"AttributeType",[3395,21047,13957],{"class":4708},[3395,21049,21050],{"class":4888},"\"S\"",[3395,21052,21053],{"class":4708},"} `\n",[3395,21055,21056,21059,21061,21063,21065,21067,21069,21071,21074,21076,21079],{"class":3397,"line":3410},[3395,21057,21058],{"class":4708},"    -KeySchema ",[3395,21060,20571],{"class":4696},[3395,21062,6507],{"class":4708},[3395,21064,21034],{"class":4715},[3395,21066,13957],{"class":4708},[3395,21068,21039],{"class":4888},[3395,21070,21042],{"class":4708},[3395,21072,21073],{"class":4715},"KeyType",[3395,21075,13957],{"class":4708},[3395,21077,21078],{"class":4888},"\"HASH\"",[3395,21080,21053],{"class":4708},[3395,21082,21083],{"class":3397,"line":3416},[3395,21084,21085],{"class":4708},"    -BillingMode PAY_PER_REQUEST `\n",[3395,21087,21088,21090],{"class":3397,"line":3423},[3395,21089,20501],{"class":4708},[3395,21091,12971],{"class":5154},[3704,21093,21095],{"id":21094},"крок-2-дефініція-політик-доступу-iam","Крок 2: Дефініція політик доступу (IAM)",[3353,21097,21098,21099,5930,21102,21105],{},"Lambda потребує гранулярних прав на виконання операцій ",[3392,21100,21101],{},"GetItem",[3392,21103,21104],{},"PutItem"," над створеною таблицею.",[16678,21107,21108,21239],{},[16681,21109,21110],{"label":18260},[4867,21111,21112,21119],{},[4035,21113,21114,21115,21118],{},"Створіть роль ",[3359,21116,21117],{},"UrlShortenerRole"," для сервісу Lambda.",[4035,21120,21121,21122,21125,21126],{},"Додайте ",[3359,21123,21124],{},"Inline Policy"," з наступним JSON:\n",[3385,21127,21129],{"className":5060,"code":21128,"language":5062,"meta":3390,"style":3390},"{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\"dynamodb:GetItem\", \"dynamodb:PutItem\"],\n            \"Resource\": \"arn:aws:dynamodb:eu-central-1:*:table\u002FUrlMappingTable\"\n        },\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\"logs:*\"],\n            \"Resource\": \"arn:aws:logs:*:*:*\"\n        }\n    ]\n}\n",[3392,21130,21131,21135,21145,21151,21155,21165,21181,21190,21194,21198,21208,21219,21227,21231,21235],{"__ignoreMap":3390},[3395,21132,21133],{"class":3397,"line":3398},[3395,21134,5069],{"class":4708},[3395,21136,21137,21139,21141,21143],{"class":3397,"line":3404},[3395,21138,18457],{"class":5074},[3395,21140,5078],{"class":4708},[3395,21142,18462],{"class":4888},[3395,21144,5084],{"class":4708},[3395,21146,21147,21149],{"class":3397,"line":3410},[3395,21148,18469],{"class":5074},[3395,21150,8799],{"class":4708},[3395,21152,21153],{"class":3397,"line":3416},[3395,21154,8192],{"class":4708},[3395,21156,21157,21159,21161,21163],{"class":3397,"line":3423},[3395,21158,18480],{"class":5074},[3395,21160,5078],{"class":4708},[3395,21162,18485],{"class":4888},[3395,21164,5084],{"class":4708},[3395,21166,21167,21169,21171,21174,21176,21179],{"class":3397,"line":3429},[3395,21168,18492],{"class":5074},[3395,21170,18495],{"class":4708},[3395,21172,21173],{"class":4888},"\"dynamodb:GetItem\"",[3395,21175,4719],{"class":4708},[3395,21177,21178],{"class":4888},"\"dynamodb:PutItem\"",[3395,21180,18501],{"class":4708},[3395,21182,21183,21185,21187],{"class":3397,"line":3434},[3395,21184,18506],{"class":5074},[3395,21186,5078],{"class":4708},[3395,21188,21189],{"class":4888},"\"arn:aws:dynamodb:eu-central-1:*:table\u002FUrlMappingTable\"\n",[3395,21191,21192],{"class":3397,"line":3440},[3395,21193,7462],{"class":4708},[3395,21195,21196],{"class":3397,"line":3446},[3395,21197,8192],{"class":4708},[3395,21199,21200,21202,21204,21206],{"class":3397,"line":3452},[3395,21201,18480],{"class":5074},[3395,21203,5078],{"class":4708},[3395,21205,18485],{"class":4888},[3395,21207,5084],{"class":4708},[3395,21209,21210,21212,21214,21217],{"class":3397,"line":3458},[3395,21211,18492],{"class":5074},[3395,21213,18495],{"class":4708},[3395,21215,21216],{"class":4888},"\"logs:*\"",[3395,21218,18501],{"class":4708},[3395,21220,21221,21223,21225],{"class":3397,"line":3464},[3395,21222,18506],{"class":5074},[3395,21224,5078],{"class":4708},[3395,21226,18597],{"class":4888},[3395,21228,21229],{"class":3397,"line":3470},[3395,21230,8230],{"class":4708},[3395,21232,21233],{"class":3397,"line":3476},[3395,21234,8975],{"class":4708},[3395,21236,21237],{"class":3397,"line":3482},[3395,21238,3479],{"class":4708},[16681,21240,21241],{"label":16949},[3385,21242,21244],{"className":4876,"code":21243,"language":4878,"meta":3390,"style":3390},"# 1. Створення ролі\naws iam create-role --role-name UrlShortenerRole \\\n    --assume-role-policy-document '{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"lambda.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}'\n\n# 2. Прикріплення прав\naws iam put-role-policy --role-name UrlShortenerRole \\\n    --policy-name DynamoDBAccess \\\n    --policy-document '{\n      \"Version\": \"2012-10-17\",\n      \"Statement\": [\n        { \"Effect\": \"Allow\", \"Action\": [\"dynamodb:PutItem\", \"dynamodb:GetItem\"], \"Resource\": \"arn:aws:dynamodb:eu-central-1:*:table\u002FUrlMappingTable\" },\n        { \"Effect\": \"Allow\", \"Action\": [\"logs:*\"], \"Resource\": \"arn:aws:logs:*:*:*\" }\n      ]\n    }'\n",[3392,21245,21246,21251,21267,21274,21278,21283,21297,21306,21312,21316,21320,21325,21329,21333],{"__ignoreMap":3390},[3395,21247,21248],{"class":3397,"line":3398},[3395,21249,21250],{"class":4690},"# 1. Створення ролі\n",[3395,21252,21253,21255,21257,21259,21262,21265],{"class":3397,"line":3404},[3395,21254,5575],{"class":4704},[3395,21256,18704],{"class":4888},[3395,21258,18707],{"class":4888},[3395,21260,21261],{"class":4696}," --role-name",[3395,21263,21264],{"class":4888}," UrlShortenerRole",[3395,21266,5584],{"class":5583},[3395,21268,21269,21271],{"class":3397,"line":3410},[3395,21270,18724],{"class":4696},[3395,21272,21273],{"class":4888}," '{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"lambda.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}'\n",[3395,21275,21276],{"class":3397,"line":3416},[3395,21277,3420],{"emptyLinePlaceholder":3419},[3395,21279,21280],{"class":3397,"line":3423},[3395,21281,21282],{"class":4690},"# 2. Прикріплення прав\n",[3395,21284,21285,21287,21289,21291,21293,21295],{"class":3397,"line":3429},[3395,21286,5575],{"class":4704},[3395,21288,18704],{"class":4888},[3395,21290,18745],{"class":4888},[3395,21292,21261],{"class":4696},[3395,21294,21264],{"class":4888},[3395,21296,5584],{"class":5583},[3395,21298,21299,21301,21304],{"class":3397,"line":3434},[3395,21300,18760],{"class":4696},[3395,21302,21303],{"class":4888}," DynamoDBAccess",[3395,21305,5584],{"class":5583},[3395,21307,21308,21310],{"class":3397,"line":3440},[3395,21309,18770],{"class":4696},[3395,21311,18647],{"class":4888},[3395,21313,21314],{"class":3397,"line":3446},[3395,21315,18777],{"class":4888},[3395,21317,21318],{"class":3397,"line":3452},[3395,21319,18782],{"class":4888},[3395,21321,21322],{"class":3397,"line":3458},[3395,21323,21324],{"class":4888},"        { \"Effect\": \"Allow\", \"Action\": [\"dynamodb:PutItem\", \"dynamodb:GetItem\"], \"Resource\": \"arn:aws:dynamodb:eu-central-1:*:table\u002FUrlMappingTable\" },\n",[3395,21326,21327],{"class":3397,"line":3464},[3395,21328,18797],{"class":4888},[3395,21330,21331],{"class":3397,"line":3470},[3395,21332,18802],{"class":4888},[3395,21334,21335],{"class":3397,"line":3476},[3395,21336,18807],{"class":4888},[3704,21338,21340],{"id":21339},"крок-3-реалізація-бізнес-логіки-net-10","Крок 3: Реалізація бізнес-логіки (.NET 10)",[3353,21342,21343,21344,21347],{},"Для чистоти коду ми використаємо ",[3359,21345,21346],{},"Lambda Annotations",", що дозволяє будувати API у декларативному стилі.",[16678,21349,21350,21402,21614,22312],{},[16681,21351,21352],{"label":16683},[3385,21353,21355],{"className":4876,"code":21354,"language":4878,"meta":3390,"style":3390},"# Створюємо проект\ndotnet new lambda.Annotations -n UrlShortener.Lambda\ncd UrlShortener.Lambda\n\n# Додаємо SDK для DynamoDB\ndotnet add package AWSSDK.DynamoDBv2\n",[3392,21356,21357,21362,21376,21382,21386,21391],{"__ignoreMap":3390},[3395,21358,21359],{"class":3397,"line":3398},[3395,21360,21361],{"class":4690},"# Створюємо проект\n",[3395,21363,21364,21366,21368,21371,21373],{"class":3397,"line":3404},[3395,21365,4903],{"class":4704},[3395,21367,4906],{"class":4888},[3395,21369,21370],{"class":4888}," lambda.Annotations",[3395,21372,5041],{"class":4696},[3395,21374,21375],{"class":4888}," UrlShortener.Lambda\n",[3395,21377,21378,21380],{"class":3397,"line":3410},[3395,21379,4895],{"class":4704},[3395,21381,21375],{"class":4888},[3395,21383,21384],{"class":3397,"line":3416},[3395,21385,3420],{"emptyLinePlaceholder":3419},[3395,21387,21388],{"class":3397,"line":3423},[3395,21389,21390],{"class":4690},"# Додаємо SDK для DynamoDB\n",[3395,21392,21393,21395,21397,21399],{"class":3397,"line":3429},[3395,21394,4903],{"class":4704},[3395,21396,4926],{"class":4888},[3395,21398,4929],{"class":4888},[3395,21400,21401],{"class":4888}," AWSSDK.DynamoDBv2\n",[16681,21403,21404],{"label":19048},[3385,21405,21408],{"className":13936,"code":21406,"filename":21407,"language":13939,"meta":3390,"style":3390},"\u003CProject Sdk=\"Microsoft.NET.Sdk\">\n  \u003CPropertyGroup>\n    \u003CTargetFramework>net10.0\u003C\u002FTargetFramework>\n    \u003CImplicitUsings>enable\u003C\u002FImplicitUsings>\n    \u003CNullable>enable\u003C\u002FNullable>\n    \u003CPublishReadyToRun>true\u003C\u002FPublishReadyToRun>\n  \u003C\u002FPropertyGroup>\n\n  \u003CItemGroup>\n    \u003CPackageReference Include=\"Amazon.Lambda.Annotations\" Version=\"1.6.0\" \u002F>\n    \u003CPackageReference Include=\"Amazon.Lambda.Core\" Version=\"2.5.*\" \u002F>\n    \u003CPackageReference Include=\"Amazon.Lambda.Serialization.SystemTextJson\" Version=\"2.4.*\" \u002F>\n    \u003CPackageReference Include=\"AWSSDK.DynamoDBv2\" Version=\"3.7.*\" \u002F>\n  \u003C\u002FItemGroup>\n\u003C\u002FProject>\n","UrlShortener.csproj",[3392,21409,21410,21424,21432,21448,21464,21480,21496,21504,21508,21516,21538,21558,21578,21598,21606],{"__ignoreMap":3390},[3395,21411,21412,21414,21416,21418,21420,21422],{"class":3397,"line":3398},[3395,21413,6130],{"class":13946},[3395,21415,13950],{"class":13949},[3395,21417,13954],{"class":13953},[3395,21419,13957],{"class":4708},[3395,21421,13961],{"class":13960},[3395,21423,13964],{"class":13946},[3395,21425,21426,21428,21430],{"class":3397,"line":3404},[3395,21427,13969],{"class":13946},[3395,21429,13972],{"class":13949},[3395,21431,13964],{"class":13946},[3395,21433,21434,21436,21438,21440,21442,21444,21446],{"class":3397,"line":3410},[3395,21435,13979],{"class":13946},[3395,21437,13982],{"class":13949},[3395,21439,13985],{"class":13946},[3395,21441,19087],{"class":4708},[3395,21443,13991],{"class":13946},[3395,21445,13982],{"class":13949},[3395,21447,13964],{"class":13946},[3395,21449,21450,21452,21454,21456,21458,21460,21462],{"class":3397,"line":3416},[3395,21451,13979],{"class":13946},[3395,21453,14020],{"class":13949},[3395,21455,13985],{"class":13946},[3395,21457,14007],{"class":4708},[3395,21459,13991],{"class":13946},[3395,21461,14020],{"class":13949},[3395,21463,13964],{"class":13946},[3395,21465,21466,21468,21470,21472,21474,21476,21478],{"class":3397,"line":3423},[3395,21467,13979],{"class":13946},[3395,21469,14002],{"class":13949},[3395,21471,13985],{"class":13946},[3395,21473,14007],{"class":4708},[3395,21475,13991],{"class":13946},[3395,21477,14002],{"class":13949},[3395,21479,13964],{"class":13946},[3395,21481,21482,21484,21486,21488,21490,21492,21494],{"class":3397,"line":3429},[3395,21483,13979],{"class":13946},[3395,21485,14046],{"class":13949},[3395,21487,13985],{"class":13946},[3395,21489,3946],{"class":4708},[3395,21491,13991],{"class":13946},[3395,21493,14046],{"class":13949},[3395,21495,13964],{"class":13946},[3395,21497,21498,21500,21502],{"class":3397,"line":3434},[3395,21499,14118],{"class":13946},[3395,21501,13972],{"class":13949},[3395,21503,13964],{"class":13946},[3395,21505,21506],{"class":3397,"line":3440},[3395,21507,3420],{"emptyLinePlaceholder":3419},[3395,21509,21510,21512,21514],{"class":3397,"line":3446},[3395,21511,13969],{"class":13946},[3395,21513,14133],{"class":13949},[3395,21515,13964],{"class":13946},[3395,21517,21518,21520,21522,21524,21526,21529,21531,21533,21536],{"class":3397,"line":3452},[3395,21519,13979],{"class":13946},[3395,21521,14142],{"class":13949},[3395,21523,14145],{"class":13953},[3395,21525,13957],{"class":4708},[3395,21527,21528],{"class":13960},"\"Amazon.Lambda.Annotations\"",[3395,21530,14153],{"class":13953},[3395,21532,13957],{"class":4708},[3395,21534,21535],{"class":13960},"\"1.6.0\"",[3395,21537,14161],{"class":13946},[3395,21539,21540,21542,21544,21546,21548,21550,21552,21554,21556],{"class":3397,"line":3458},[3395,21541,13979],{"class":13946},[3395,21543,14142],{"class":13949},[3395,21545,14145],{"class":13953},[3395,21547,13957],{"class":4708},[3395,21549,14150],{"class":13960},[3395,21551,14153],{"class":13953},[3395,21553,13957],{"class":4708},[3395,21555,19201],{"class":13960},[3395,21557,14161],{"class":13946},[3395,21559,21560,21562,21564,21566,21568,21570,21572,21574,21576],{"class":3397,"line":3464},[3395,21561,13979],{"class":13946},[3395,21563,14142],{"class":13949},[3395,21565,14145],{"class":13953},[3395,21567,13957],{"class":4708},[3395,21569,14174],{"class":13960},[3395,21571,14153],{"class":13953},[3395,21573,13957],{"class":4708},[3395,21575,19222],{"class":13960},[3395,21577,14161],{"class":13946},[3395,21579,21580,21582,21584,21586,21588,21590,21592,21594,21596],{"class":3397,"line":3470},[3395,21581,13979],{"class":13946},[3395,21583,14142],{"class":13949},[3395,21585,14145],{"class":13953},[3395,21587,13957],{"class":4708},[3395,21589,14242],{"class":13960},[3395,21591,14153],{"class":13953},[3395,21593,13957],{"class":4708},[3395,21595,14227],{"class":13960},[3395,21597,14161],{"class":13946},[3395,21599,21600,21602,21604],{"class":3397,"line":3476},[3395,21601,14118],{"class":13946},[3395,21603,14133],{"class":13949},[3395,21605,13964],{"class":13946},[3395,21607,21608,21610,21612],{"class":3397,"line":3482},[3395,21609,13991],{"class":13946},[3395,21611,13950],{"class":13949},[3395,21613,13964],{"class":13946},[16681,21615,21616],{"label":7526},[3385,21617,21619],{"className":4681,"code":21618,"filename":7526,"language":4683,"meta":3390,"style":3390},"using Amazon.Lambda.Annotations;\nusing Amazon.Lambda.Annotations.APIGateway;\nusing Amazon.Lambda.Core;\nusing Amazon.DynamoDBv2;\nusing Amazon.DynamoDBv2.Model;\n\n[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]\n\nnamespace UrlShortener.Lambda;\n\npublic class Functions\n{\n    private readonly IAmazonDynamoDB _dynamoDb;\n    private const string TableName = \"UrlMappingTable\";\n\n    public Functions(IAmazonDynamoDB dynamoDb) => _dynamoDb = dynamoDb;\n\n    [LambdaFunction]\n    [HttpApi(LambdaHttpMethod.Post, \"\u002Fshorten\")]\n    public async Task\u003CIHttpResult> ShortenUrl([FromBody] ShortenRequest request)\n    {\n        var shortCode = Guid.NewGuid().ToString()[..8]; \u002F\u002F Спрощена генерація\n\n        await _dynamoDb.PutItemAsync(TableName, new Dictionary\u003Cstring, AttributeValue>\n        {\n            [\"ShortCode\"] = new AttributeValue { S = shortCode },\n            [\"LongUrl\"] = new AttributeValue { S = request.Url }\n        });\n\n        return HttpResults.Created($\"\u002F{{shortCode}}\", new { shortCode });\n    }\n\n    [LambdaFunction]\n    [HttpApi(LambdaHttpMethod.Get, \"\u002F{shortCode}\")]\n    public async Task\u003CIHttpResult> Redirect(string shortCode)\n    {\n        var response = await _dynamoDb.GetItemAsync(TableName, new Dictionary\u003Cstring, AttributeValue>\n        {\n            [\"ShortCode\"] = new AttributeValue { S = shortCode }\n        });\n\n        if (!response.IsItemSet) return HttpResults.NotFound();\n\n        var longUrl = response.Item[\"LongUrl\"].S;\n        return HttpResults.Redirect(longUrl);\n    }\n}\n\npublic record ShortenRequest(string Url);\n",[3392,21620,21621,21637,21657,21673,21686,21702,21706,21742,21746,21759,21763,21772,21776,21789,21806,21810,21836,21840,21848,21869,21900,21904,21938,21942,21976,21980,22008,22037,22041,22045,22070,22074,22078,22086,22107,22132,22136,22173,22177,22199,22203,22207,22234,22238,22265,22282,22286,22290,22294],{"__ignoreMap":3390},[3395,21622,21623,21625,21627,21629,21631,21633,21635],{"class":3397,"line":3398},[3395,21624,7533],{"class":6221},[3395,21626,7536],{"class":4700},[3395,21628,3860],{"class":4708},[3395,21630,5754],{"class":4700},[3395,21632,3860],{"class":4708},[3395,21634,7545],{"class":4700},[3395,21636,6634],{"class":4708},[3395,21638,21639,21641,21643,21645,21647,21649,21651,21653,21655],{"class":3397,"line":3404},[3395,21640,7533],{"class":6221},[3395,21642,7536],{"class":4700},[3395,21644,3860],{"class":4708},[3395,21646,5754],{"class":4700},[3395,21648,3860],{"class":4708},[3395,21650,7545],{"class":4700},[3395,21652,3860],{"class":4708},[3395,21654,7566],{"class":4700},[3395,21656,6634],{"class":4708},[3395,21658,21659,21661,21663,21665,21667,21669,21671],{"class":3397,"line":3410},[3395,21660,7533],{"class":6221},[3395,21662,7536],{"class":4700},[3395,21664,3860],{"class":4708},[3395,21666,5754],{"class":4700},[3395,21668,3860],{"class":4708},[3395,21670,7583],{"class":4700},[3395,21672,6634],{"class":4708},[3395,21674,21675,21677,21679,21681,21684],{"class":3397,"line":3416},[3395,21676,7533],{"class":6221},[3395,21678,7536],{"class":4700},[3395,21680,3860],{"class":4708},[3395,21682,21683],{"class":4700},"DynamoDBv2",[3395,21685,6634],{"class":4708},[3395,21687,21688,21690,21692,21694,21696,21698,21700],{"class":3397,"line":3423},[3395,21689,7533],{"class":6221},[3395,21691,7536],{"class":4700},[3395,21693,3860],{"class":4708},[3395,21695,21683],{"class":4700},[3395,21697,3860],{"class":4708},[3395,21699,9061],{"class":4700},[3395,21701,6634],{"class":4708},[3395,21703,21704],{"class":3397,"line":3429},[3395,21705,3420],{"emptyLinePlaceholder":3419},[3395,21707,21708,21710,21712,21714,21716,21718,21720,21722,21724,21726,21728,21730,21732,21734,21736,21738,21740],{"class":3397,"line":3434},[3395,21709,5731],{"class":4708},[3395,21711,5734],{"class":4696},[3395,21713,5078],{"class":4708},[3395,21715,5739],{"class":4700},[3395,21717,4709],{"class":4708},[3395,21719,5744],{"class":4696},[3395,21721,4709],{"class":4708},[3395,21723,5749],{"class":4700},[3395,21725,3860],{"class":4708},[3395,21727,5754],{"class":4700},[3395,21729,3860],{"class":4708},[3395,21731,5759],{"class":4700},[3395,21733,3860],{"class":4708},[3395,21735,5764],{"class":4700},[3395,21737,3860],{"class":4708},[3395,21739,5769],{"class":4700},[3395,21741,5772],{"class":4708},[3395,21743,21744],{"class":3397,"line":3440},[3395,21745,3420],{"emptyLinePlaceholder":3419},[3395,21747,21748,21750,21753,21755,21757],{"class":3397,"line":3446},[3395,21749,7658],{"class":4696},[3395,21751,21752],{"class":4700}," UrlShortener",[3395,21754,3860],{"class":4708},[3395,21756,5754],{"class":4700},[3395,21758,6634],{"class":4708},[3395,21760,21761],{"class":3397,"line":3452},[3395,21762,3420],{"emptyLinePlaceholder":3419},[3395,21764,21765,21767,21769],{"class":3397,"line":3458},[3395,21766,4697],{"class":4696},[3395,21768,6314],{"class":4696},[3395,21770,21771],{"class":4700}," Functions\n",[3395,21773,21774],{"class":3397,"line":3464},[3395,21775,5069],{"class":4708},[3395,21777,21778,21780,21782,21784,21787],{"class":3397,"line":3470},[3395,21779,7714],{"class":4696},[3395,21781,7717],{"class":4696},[3395,21783,13385],{"class":4700},[3395,21785,21786],{"class":4715}," _dynamoDb",[3395,21788,6634],{"class":4708},[3395,21790,21791,21793,21795,21797,21800,21802,21804],{"class":3397,"line":3476},[3395,21792,7714],{"class":4696},[3395,21794,9181],{"class":4696},[3395,21796,9184],{"class":4696},[3395,21798,21799],{"class":4715}," TableName",[3395,21801,6088],{"class":4708},[3395,21803,21020],{"class":4888},[3395,21805,6634],{"class":4708},[3395,21807,21808],{"class":3397,"line":3482},[3395,21809,3420],{"emptyLinePlaceholder":3419},[3395,21811,21812,21814,21817,21819,21821,21824,21826,21829,21831,21834],{"class":3397,"line":3487},[3395,21813,6326],{"class":4696},[3395,21815,21816],{"class":4704}," Functions",[3395,21818,4709],{"class":4708},[3395,21820,6367],{"class":4700},[3395,21822,21823],{"class":4715}," dynamoDb",[3395,21825,19549],{"class":4708},[3395,21827,21828],{"class":4715},"_dynamoDb",[3395,21830,6088],{"class":4708},[3395,21832,21833],{"class":4715},"dynamoDb",[3395,21835,6634],{"class":4708},[3395,21837,21838],{"class":3397,"line":3493},[3395,21839,3420],{"emptyLinePlaceholder":3419},[3395,21841,21842,21844,21846],{"class":3397,"line":3499},[3395,21843,6147],{"class":4708},[3395,21845,6080],{"class":4700},[3395,21847,6307],{"class":4708},[3395,21849,21850,21852,21854,21856,21858,21860,21862,21864,21867],{"class":3397,"line":3505},[3395,21851,6147],{"class":4708},[3395,21853,6100],{"class":4700},[3395,21855,4709],{"class":4708},[3395,21857,6105],{"class":4715},[3395,21859,3860],{"class":4708},[3395,21861,6110],{"class":4715},[3395,21863,4719],{"class":4708},[3395,21865,21866],{"class":4888},"\"\u002Fshorten\"",[3395,21868,6093],{"class":4708},[3395,21870,21871,21873,21875,21877,21879,21881,21883,21886,21889,21891,21893,21896,21898],{"class":3397,"line":3511},[3395,21872,6326],{"class":4696},[3395,21874,6124],{"class":4696},[3395,21876,6127],{"class":4700},[3395,21878,6130],{"class":4708},[3395,21880,6133],{"class":4700},[3395,21882,6136],{"class":4708},[3395,21884,21885],{"class":4704},"ShortenUrl",[3395,21887,21888],{"class":4708},"([",[3395,21890,6184],{"class":4700},[3395,21892,6153],{"class":4708},[3395,21894,21895],{"class":4700},"ShortenRequest",[3395,21897,6192],{"class":4715},[3395,21899,4727],{"class":4708},[3395,21901,21902],{"class":3397,"line":3517},[3395,21903,6347],{"class":4708},[3395,21905,21906,21908,21911,21913,21916,21918,21921,21923,21926,21929,21932,21935],{"class":3397,"line":3523},[3395,21907,7949],{"class":4696},[3395,21909,21910],{"class":4715}," shortCode",[3395,21912,6088],{"class":4708},[3395,21914,21915],{"class":4715},"Guid",[3395,21917,3860],{"class":4708},[3395,21919,21920],{"class":4704},"NewGuid",[3395,21922,12680],{"class":4708},[3395,21924,21925],{"class":4704},"ToString",[3395,21927,21928],{"class":4708},"()[..",[3395,21930,21931],{"class":5154},"8",[3395,21933,21934],{"class":4708},"]; ",[3395,21936,21937],{"class":4690},"\u002F\u002F Спрощена генерація\n",[3395,21939,21940],{"class":3397,"line":3529},[3395,21941,3420],{"emptyLinePlaceholder":3419},[3395,21943,21944,21946,21948,21950,21953,21955,21958,21960,21962,21965,21967,21969,21971,21974],{"class":3397,"line":3534},[3395,21945,15098],{"class":4696},[3395,21947,21786],{"class":4715},[3395,21949,3860],{"class":4708},[3395,21951,21952],{"class":4704},"PutItemAsync",[3395,21954,4709],{"class":4708},[3395,21956,21957],{"class":4715},"TableName",[3395,21959,4719],{"class":4708},[3395,21961,6235],{"class":4696},[3395,21963,21964],{"class":4700}," Dictionary",[3395,21966,6130],{"class":4708},[3395,21968,3954],{"class":4696},[3395,21970,4719],{"class":4708},[3395,21972,21973],{"class":4700},"AttributeValue",[3395,21975,13964],{"class":4708},[3395,21977,21978],{"class":3397,"line":3539},[3395,21979,8192],{"class":4708},[3395,21981,21982,21985,21987,21990,21992,21995,21997,22000,22002,22005],{"class":3397,"line":3545},[3395,21983,21984],{"class":4708},"            [",[3395,21986,21039],{"class":4888},[3395,21988,21989],{"class":4708},"] = ",[3395,21991,6235],{"class":4696},[3395,21993,21994],{"class":4700}," AttributeValue",[3395,21996,6238],{"class":4708},[3395,21998,21999],{"class":4715},"S",[3395,22001,6088],{"class":4708},[3395,22003,22004],{"class":4715},"shortCode",[3395,22006,22007],{"class":4708}," },\n",[3395,22009,22010,22012,22015,22017,22019,22021,22023,22025,22027,22029,22031,22034],{"class":3397,"line":3551},[3395,22011,21984],{"class":4708},[3395,22013,22014],{"class":4888},"\"LongUrl\"",[3395,22016,21989],{"class":4708},[3395,22018,6235],{"class":4696},[3395,22020,21994],{"class":4700},[3395,22022,6238],{"class":4708},[3395,22024,21999],{"class":4715},[3395,22026,6088],{"class":4708},[3395,22028,6265],{"class":4715},[3395,22030,3860],{"class":4708},[3395,22032,22033],{"class":4715},"Url",[3395,22035,22036],{"class":4708}," }\n",[3395,22038,22039],{"class":3397,"line":3557},[3395,22040,8555],{"class":4708},[3395,22042,22043],{"class":3397,"line":3563},[3395,22044,3420],{"emptyLinePlaceholder":3419},[3395,22046,22047,22049,22051,22053,22055,22057,22060,22062,22064,22066,22068],{"class":3397,"line":3569},[3395,22048,8037],{"class":6221},[3395,22050,6225],{"class":4715},[3395,22052,3860],{"class":4708},[3395,22054,8271],{"class":4704},[3395,22056,4709],{"class":4708},[3395,22058,22059],{"class":4888},"$\"\u002F{{shortCode}}\"",[3395,22061,4719],{"class":4708},[3395,22063,6235],{"class":4696},[3395,22065,6238],{"class":4708},[3395,22067,22004],{"class":4715},[3395,22069,6273],{"class":4708},[3395,22071,22072],{"class":3397,"line":3575},[3395,22073,6396],{"class":4708},[3395,22075,22076],{"class":3397,"line":3581},[3395,22077,3420],{"emptyLinePlaceholder":3419},[3395,22079,22080,22082,22084],{"class":3397,"line":3586},[3395,22081,6147],{"class":4708},[3395,22083,6080],{"class":4700},[3395,22085,6307],{"class":4708},[3395,22087,22088,22090,22092,22094,22096,22098,22100,22102,22105],{"class":3397,"line":3591},[3395,22089,6147],{"class":4708},[3395,22091,6100],{"class":4700},[3395,22093,4709],{"class":4708},[3395,22095,6105],{"class":4715},[3395,22097,3860],{"class":4708},[3395,22099,7858],{"class":4715},[3395,22101,4719],{"class":4708},[3395,22103,22104],{"class":4888},"\"\u002F{shortCode}\"",[3395,22106,6093],{"class":4708},[3395,22108,22109,22111,22113,22115,22117,22119,22121,22124,22126,22128,22130],{"class":3397,"line":3597},[3395,22110,6326],{"class":4696},[3395,22112,6124],{"class":4696},[3395,22114,6127],{"class":4700},[3395,22116,6130],{"class":4708},[3395,22118,6133],{"class":4700},[3395,22120,6136],{"class":4708},[3395,22122,22123],{"class":4704},"Redirect",[3395,22125,4709],{"class":4708},[3395,22127,3954],{"class":4696},[3395,22129,21910],{"class":4715},[3395,22131,4727],{"class":4708},[3395,22133,22134],{"class":3397,"line":3603},[3395,22135,6347],{"class":4708},[3395,22137,22138,22140,22142,22144,22146,22148,22150,22153,22155,22157,22159,22161,22163,22165,22167,22169,22171],{"class":3397,"line":3609},[3395,22139,7949],{"class":4696},[3395,22141,9475],{"class":4715},[3395,22143,6088],{"class":4708},[3395,22145,7957],{"class":4696},[3395,22147,21786],{"class":4715},[3395,22149,3860],{"class":4708},[3395,22151,22152],{"class":4704},"GetItemAsync",[3395,22154,4709],{"class":4708},[3395,22156,21957],{"class":4715},[3395,22158,4719],{"class":4708},[3395,22160,6235],{"class":4696},[3395,22162,21964],{"class":4700},[3395,22164,6130],{"class":4708},[3395,22166,3954],{"class":4696},[3395,22168,4719],{"class":4708},[3395,22170,21973],{"class":4700},[3395,22172,13964],{"class":4708},[3395,22174,22175],{"class":3397,"line":3615},[3395,22176,8192],{"class":4708},[3395,22178,22179,22181,22183,22185,22187,22189,22191,22193,22195,22197],{"class":3397,"line":3621},[3395,22180,21984],{"class":4708},[3395,22182,21039],{"class":4888},[3395,22184,21989],{"class":4708},[3395,22186,6235],{"class":4696},[3395,22188,21994],{"class":4700},[3395,22190,6238],{"class":4708},[3395,22192,21999],{"class":4715},[3395,22194,6088],{"class":4708},[3395,22196,22004],{"class":4715},[3395,22198,22036],{"class":4708},[3395,22200,22201],{"class":3397,"line":3627},[3395,22202,8555],{"class":4708},[3395,22204,22205],{"class":3397,"line":3633},[3395,22206,3420],{"emptyLinePlaceholder":3419},[3395,22208,22209,22211,22214,22216,22218,22221,22223,22226,22228,22230,22232],{"class":3397,"line":3638},[3395,22210,7979],{"class":6221},[3395,22212,22213],{"class":4708}," (!",[3395,22215,9507],{"class":4715},[3395,22217,3860],{"class":4708},[3395,22219,22220],{"class":4715},"IsItemSet",[3395,22222,6204],{"class":4708},[3395,22224,22225],{"class":6221},"return",[3395,22227,6225],{"class":4715},[3395,22229,3860],{"class":4708},[3395,22231,8003],{"class":4704},[3395,22233,8224],{"class":4708},[3395,22235,22236],{"class":3397,"line":3643},[3395,22237,3420],{"emptyLinePlaceholder":3419},[3395,22239,22240,22242,22245,22247,22249,22251,22254,22256,22258,22261,22263],{"class":3397,"line":3649},[3395,22241,7949],{"class":4696},[3395,22243,22244],{"class":4715}," longUrl",[3395,22246,6088],{"class":4708},[3395,22248,9507],{"class":4715},[3395,22250,3860],{"class":4708},[3395,22252,22253],{"class":4715},"Item",[3395,22255,5731],{"class":4708},[3395,22257,22014],{"class":4888},[3395,22259,22260],{"class":4708},"].",[3395,22262,21999],{"class":4715},[3395,22264,6634],{"class":4708},[3395,22266,22267,22269,22271,22273,22275,22277,22280],{"class":3397,"line":3655},[3395,22268,8037],{"class":6221},[3395,22270,6225],{"class":4715},[3395,22272,3860],{"class":4708},[3395,22274,22123],{"class":4704},[3395,22276,4709],{"class":4708},[3395,22278,22279],{"class":4715},"longUrl",[3395,22281,6522],{"class":4708},[3395,22283,22284],{"class":3397,"line":3661},[3395,22285,6396],{"class":4708},[3395,22287,22288],{"class":3397,"line":3667},[3395,22289,3479],{"class":4708},[3395,22291,22292],{"class":3397,"line":3672},[3395,22293,3420],{"emptyLinePlaceholder":3419},[3395,22295,22296,22298,22300,22303,22305,22307,22310],{"class":3397,"line":8082},[3395,22297,4697],{"class":4696},[3395,22299,6686],{"class":4696},[3395,22301,22302],{"class":4700}," ShortenRequest",[3395,22304,4709],{"class":4708},[3395,22306,3954],{"class":4696},[3395,22308,22309],{"class":4715}," Url",[3395,22311,6522],{"class":4708},[16681,22313,22314],{"label":6291},[3385,22315,22317],{"className":4681,"code":22316,"filename":6291,"language":4683,"meta":3390,"style":3390},"using Amazon.Lambda.Annotations;\nusing Microsoft.Extensions.DependencyInjection;\nusing Amazon.DynamoDBv2;\n\n[LambdaStartup]\npublic class Startup\n{\n    public void ConfigureServices(IServiceCollection services)\n    {\n        services.AddAWSService\u003CIAmazonDynamoDB>();\n    }\n}\n",[3392,22318,22319,22335,22351,22363,22367,22375,22383,22387,22403,22407,22421,22425],{"__ignoreMap":3390},[3395,22320,22321,22323,22325,22327,22329,22331,22333],{"class":3397,"line":3398},[3395,22322,7533],{"class":6221},[3395,22324,7536],{"class":4700},[3395,22326,3860],{"class":4708},[3395,22328,5754],{"class":4700},[3395,22330,3860],{"class":4708},[3395,22332,7545],{"class":4700},[3395,22334,6634],{"class":4708},[3395,22336,22337,22339,22341,22343,22345,22347,22349],{"class":3397,"line":3404},[3395,22338,7533],{"class":6221},[3395,22340,7592],{"class":4700},[3395,22342,3860],{"class":4708},[3395,22344,7597],{"class":4700},[3395,22346,3860],{"class":4708},[3395,22348,8346],{"class":4700},[3395,22350,6634],{"class":4708},[3395,22352,22353,22355,22357,22359,22361],{"class":3397,"line":3410},[3395,22354,7533],{"class":6221},[3395,22356,7536],{"class":4700},[3395,22358,3860],{"class":4708},[3395,22360,21683],{"class":4700},[3395,22362,6634],{"class":4708},[3395,22364,22365],{"class":3397,"line":3416},[3395,22366,3420],{"emptyLinePlaceholder":3419},[3395,22368,22369,22371,22373],{"class":3397,"line":3423},[3395,22370,5731],{"class":4708},[3395,22372,6304],{"class":4700},[3395,22374,6307],{"class":4708},[3395,22376,22377,22379,22381],{"class":3397,"line":3429},[3395,22378,4697],{"class":4696},[3395,22380,6314],{"class":4696},[3395,22382,6317],{"class":4700},[3395,22384,22385],{"class":3397,"line":3434},[3395,22386,5069],{"class":4708},[3395,22388,22389,22391,22393,22395,22397,22399,22401],{"class":3397,"line":3440},[3395,22390,6326],{"class":4696},[3395,22392,6329],{"class":4696},[3395,22394,6332],{"class":4704},[3395,22396,4709],{"class":4708},[3395,22398,6337],{"class":4700},[3395,22400,6340],{"class":4715},[3395,22402,4727],{"class":4708},[3395,22404,22405],{"class":3397,"line":3446},[3395,22406,6347],{"class":4708},[3395,22408,22409,22411,22413,22415,22417,22419],{"class":3397,"line":3452},[3395,22410,6357],{"class":4715},[3395,22412,3860],{"class":4708},[3395,22414,6362],{"class":4704},[3395,22416,6130],{"class":4708},[3395,22418,6367],{"class":4700},[3395,22420,6370],{"class":4708},[3395,22422,22423],{"class":3397,"line":3458},[3395,22424,6396],{"class":4708},[3395,22426,22427],{"class":3397,"line":3464},[3395,22428,3479],{"class":4708},[3704,22430,22432],{"id":22431},"крок-4-деплоймент-та-інтеграція-з-api-gateway","Крок 4: Деплоймент та інтеграція з API Gateway",[16678,22434,22435,22478,22504,22508,22515],{},[16681,22436,22437],{"label":16949},[3385,22438,22440],{"className":4876,"code":22439,"language":4878,"meta":3390,"style":3390},"# 1. Деплой функції (Amazon.Lambda.Tools автоматично налаштує API Gateway на основі анотацій)\ndotnet lambda deploy-serverless --stack-name url-shortener-stack \\\n    --s3-bucket my-deployment-bucket \\\n    --region eu-central-1\n",[3392,22441,22442,22447,22464,22472],{"__ignoreMap":3390},[3395,22443,22444],{"class":3397,"line":3398},[3395,22445,22446],{"class":4690},"# 1. Деплой функції (Amazon.Lambda.Tools автоматично налаштує API Gateway на основі анотацій)\n",[3395,22448,22449,22451,22453,22456,22459,22462],{"class":3397,"line":3404},[3395,22450,4903],{"class":4704},[3395,22452,5016],{"class":4888},[3395,22454,22455],{"class":4888}," deploy-serverless",[3395,22457,22458],{"class":4696}," --stack-name",[3395,22460,22461],{"class":4888}," url-shortener-stack",[3395,22463,5584],{"class":5583},[3395,22465,22466,22468,22470],{"class":3397,"line":3410},[3395,22467,17195],{"class":4696},[3395,22469,17198],{"class":4888},[3395,22471,5584],{"class":5583},[3395,22473,22474,22476],{"class":3397,"line":3416},[3395,22475,15629],{"class":4696},[3395,22477,15632],{"class":4888},[16681,22479,22481,22490],{"label":22480},"Опис процесу",[3353,22482,6437,22483,22486,22487,22489],{},[3392,22484,22485],{},"deploy-serverless"," замість ",[3392,22488,16943],{}," є критичним при використанні Lambda Annotations. Ця команда генерує CloudFormation шаблон, який автоматично створює:",[4032,22491,22492,22495,22498,22501],{},[4035,22493,22494],{},"Lambda функції.",[4035,22496,22497],{},"API Gateway (HTTP API).",[4035,22499,22500],{},"Схеми маршрутизації (Routes).",[4035,22502,22503],{},"IAM ролі та дозволи.\n::",[3704,22505,22507],{"id":22506},"крок-5-верифікація-та-тестування","Крок 5: Верифікація та тестування",[3353,22509,22510,22511,22514],{},"Після успішного деплою ви отримаєте ",[3359,22512,22513],{},"Base URL"," вашого API.",[5436,22516,22517,22521,22557,22561],{},[3704,22518,22520],{"id":22519},"скорочення-посилання","Скорочення посилання",[3385,22522,22524],{"className":4876,"code":22523,"language":4878,"meta":3390,"style":3390},"curl -X POST https:\u002F\u002Fapi-id.execute-api.eu-central-1.amazonaws.com\u002Fshorten \\\n     -H \"Content-Type: application\u002Fjson\" \\\n     -d '{\"url\": \"https:\u002F\u002Fkostyl.dev\u002Faws\u002Flambda\"}'\n",[3392,22525,22526,22539,22549],{"__ignoreMap":3390},[3395,22527,22528,22530,22532,22534,22537],{"class":3397,"line":3398},[3395,22529,17619],{"class":4704},[3395,22531,17632],{"class":4696},[3395,22533,17635],{"class":4888},[3395,22535,22536],{"class":4888}," https:\u002F\u002Fapi-id.execute-api.eu-central-1.amazonaws.com\u002Fshorten",[3395,22538,5584],{"class":5583},[3395,22540,22541,22544,22547],{"class":3397,"line":3404},[3395,22542,22543],{"class":4696},"     -H",[3395,22545,22546],{"class":4888}," \"Content-Type: application\u002Fjson\"",[3395,22548,5584],{"class":5583},[3395,22550,22551,22554],{"class":3397,"line":3410},[3395,22552,22553],{"class":4696},"     -d",[3395,22555,22556],{"class":4888}," '{\"url\": \"https:\u002F\u002Fkostyl.dev\u002Faws\u002Flambda\"}'\n",[3704,22558,22560],{"id":22559},"відповідь-системи","Відповідь системи",[15768,22562,22564],{"title":22563},"Response 201 Created",[3385,22565,22567],{"className":5060,"code":22566,"language":5062,"meta":3390,"style":3390},"{\n    \"shortCode\": \"a1b2c3d4\"\n}\n",[3392,22568,22569,22573,22583],{"__ignoreMap":3390},[3395,22570,22571],{"class":3397,"line":3398},[3395,22572,5069],{"class":4708},[3395,22574,22575,22578,22580],{"class":3397,"line":3404},[3395,22576,22577],{"class":5074},"    \"shortCode\"",[3395,22579,5078],{"class":4708},[3395,22581,22582],{"class":4888},"\"a1b2c3d4\"\n",[3395,22584,22585],{"class":3397,"line":3410},[3395,22586,3479],{"class":4708},[3704,22588,22590],{"id":22589},"перевірка-редиректу","Перевірка редиректу",[3385,22592,22594],{"className":4876,"code":22593,"language":4878,"meta":3390,"style":3390},"# Відкрийте у браузері або через curl -I\ncurl -I https:\u002F\u002Fapi-id.execute-api.eu-central-1.amazonaws.com\u002Fa1b2c3d4\n",[3392,22595,22596,22601],{"__ignoreMap":3390},[3395,22597,22598],{"class":3397,"line":3398},[3395,22599,22600],{"class":4690},"# Відкрийте у браузері або через curl -I\n",[3395,22602,22603,22605,22608],{"class":3397,"line":3404},[3395,22604,17619],{"class":4704},[3395,22606,22607],{"class":4696}," -I",[3395,22609,22610],{"class":4888}," https:\u002F\u002Fapi-id.execute-api.eu-central-1.amazonaws.com\u002Fa1b2c3d4\n",[3353,22612,5945],{},[3865,22614,22617,22618,22621,22622,22625],{"icon":22615,"title":22616},"i-heroicons-academic-cap","Академічний висновок","Даний воркшоп демонструє реалізацію ",[3359,22619,22620],{},"Stateless Backend"," з використанням зовнішнього ",[3359,22623,22624],{},"State Store"," (DynamoDB). Завдяки використанню .NET 10 та Native AOT (опційно), система забезпечує передбачувану продуктивність при нульових витратах у стані простою, що є еталоном сучасної хмарної архітектури.",[3704,22627,22629],{"id":22628},"крок-6-очистка-ресурсів","Крок 6: Очистка ресурсів",[15391,22631,22632],{},"Не забудьте видалити всі створені ресурси після завершення роботи з воркшопом, щоб уникнути небажаних витрат на AWS-рахунку.",[16678,22634,22635,22747],{},[16681,22636,22637],{"label":16949},[3385,22638,22640],{"className":4876,"code":22639,"language":4878,"meta":3390,"style":3390},"# 1. Видаляємо CloudFormation стек (видаляє Lambda + API Gateway + IAM ролі автоматично)\naws cloudformation delete-stack \\\n    --stack-name url-shortener-stack \\\n    --region eu-central-1\n\n# 2. Видаляємо DynamoDB таблицю\naws dynamodb delete-table \\\n    --table-name UrlMappingTable \\\n    --region eu-central-1\n\n# 3. Перевіряємо, що стек видалено\naws cloudformation describe-stacks \\\n    --stack-name url-shortener-stack \\\n    --region eu-central-1\n# Очікуємо: \"An error occurred (ValidationError): Stack with id url-shortener-stack does not exist\"\n",[3392,22641,22642,22647,22659,22668,22674,22678,22683,22694,22702,22708,22712,22717,22728,22736,22742],{"__ignoreMap":3390},[3395,22643,22644],{"class":3397,"line":3398},[3395,22645,22646],{"class":4690},"# 1. Видаляємо CloudFormation стек (видаляє Lambda + API Gateway + IAM ролі автоматично)\n",[3395,22648,22649,22651,22654,22657],{"class":3397,"line":3404},[3395,22650,5575],{"class":4704},[3395,22652,22653],{"class":4888}," cloudformation",[3395,22655,22656],{"class":4888}," delete-stack",[3395,22658,5584],{"class":5583},[3395,22660,22661,22664,22666],{"class":3397,"line":3410},[3395,22662,22663],{"class":4696},"    --stack-name",[3395,22665,22461],{"class":4888},[3395,22667,5584],{"class":5583},[3395,22669,22670,22672],{"class":3397,"line":3416},[3395,22671,15629],{"class":4696},[3395,22673,15632],{"class":4888},[3395,22675,22676],{"class":3397,"line":3423},[3395,22677,3420],{"emptyLinePlaceholder":3419},[3395,22679,22680],{"class":3397,"line":3429},[3395,22681,22682],{"class":4690},"# 2. Видаляємо DynamoDB таблицю\n",[3395,22684,22685,22687,22689,22692],{"class":3397,"line":3434},[3395,22686,5575],{"class":4704},[3395,22688,20951],{"class":4888},[3395,22690,22691],{"class":4888}," delete-table",[3395,22693,5584],{"class":5583},[3395,22695,22696,22698,22700],{"class":3397,"line":3440},[3395,22697,20961],{"class":4696},[3395,22699,20964],{"class":4888},[3395,22701,5584],{"class":5583},[3395,22703,22704,22706],{"class":3397,"line":3446},[3395,22705,15629],{"class":4696},[3395,22707,15632],{"class":4888},[3395,22709,22710],{"class":3397,"line":3452},[3395,22711,3420],{"emptyLinePlaceholder":3419},[3395,22713,22714],{"class":3397,"line":3458},[3395,22715,22716],{"class":4690},"# 3. Перевіряємо, що стек видалено\n",[3395,22718,22719,22721,22723,22726],{"class":3397,"line":3464},[3395,22720,5575],{"class":4704},[3395,22722,22653],{"class":4888},[3395,22724,22725],{"class":4888}," describe-stacks",[3395,22727,5584],{"class":5583},[3395,22729,22730,22732,22734],{"class":3397,"line":3470},[3395,22731,22663],{"class":4696},[3395,22733,22461],{"class":4888},[3395,22735,5584],{"class":5583},[3395,22737,22738,22740],{"class":3397,"line":3476},[3395,22739,15629],{"class":4696},[3395,22741,15632],{"class":4888},[3395,22743,22744],{"class":3397,"line":3482},[3395,22745,22746],{"class":4690},"# Очікуємо: \"An error occurred (ValidationError): Stack with id url-shortener-stack does not exist\"\n",[16681,22748,22749],{"label":18260},[4867,22750,22751,22759,22767,22770],{},[4035,22752,20904,22753,18413,22756,3860],{},[3359,22754,22755],{},"CloudFormation",[3359,22757,22758],{},"Stacks",[4035,22760,20201,22761,18626,22764,3860],{},[3392,22762,22763],{},"url-shortener-stack",[3359,22765,22766],{},"Delete",[4035,22768,22769],{},"Підтвердіть видалення — AWS автоматично видалить Lambda, API Gateway та IAM ролі, що були створені стеком.",[4035,22771,22772,22773,18413,22775,22777,22778,18626,22780,3860],{},"Окремо перейдіть до ",[3359,22774,20907],{},[3359,22776,20910],{},", оберіть ",[3392,22779,20919],{},[3359,22781,22782],{},"Delete table",[3684,22784],{},[3348,22786,22788],{"id":22787},"фінальний-висновок","Фінальний висновок",[3353,22790,22791],{},"AWS Lambda — це не просто «функція в хмарі». Це архітектурний підхід, що кардинально змінює спосіб мислення про серверну інфраструктуру. Від простого Hello World до розподілених систем обробки зображень та URL-шортенерів — ми пройшли повний шлях.",[3704,22793,22795],{"id":22794},"ключові-принципи-які-варто-запамятати","Ключові принципи, які варто запам'ятати",[3862,22797,22798,22803,22807,22815,22820,22825],{},[3865,22799,22802],{"icon":22800,"title":22801},"i-heroicons-arrow-path","Stateless за замовчуванням","Lambda функції не мають стану між викликами. Execution Environment може бути перероблено у будь-який момент. Весь стан зберігайте зовні: DynamoDB, S3, ElastiCache.",[3865,22804,22806],{"icon":3883,"title":22805},"Cold Start — це компроміс","Cold Start є невід'ємною частиною serverless-моделі. Для більшості застосунків він не є проблемою. Для SLA-критичних систем використовуйте Provisioned Concurrency або Function URL + SnapStart.",[3865,22808,22810,22811,22814],{"icon":15565,"title":22809},"IAM — найменші привілеї","Кожна Lambda функція повинна мати лише ті дозволи, які їй необхідні. Це принцип ",[3359,22812,22813],{},"Least Privilege"," — основа безпеки хмарних систем.",[3865,22816,22819],{"icon":22817,"title":22818},"i-heroicons-chart-bar","Observability з CloudWatch","Без метрик і логів Lambda — це «чорна скринька». Завжди налаштовуйте CloudWatch Alarms для Errors, Throttles та Duration. Використовуйте Structured Logging для зручного пошуку.",[3865,22821,22824],{"icon":22822,"title":22823},"i-heroicons-currency-dollar","Вартість = час × пам'ять","Оптимізація Lambda — це завжди баланс між часом виконання та обсягом пам'яті. Профілюйте реальне навантаження за допомогою AWS Lambda Power Tuning перед вибором параметрів у Production.",[3865,22826,22828],{"icon":4644,"title":22827},"IaC для всього","Ніколи не створюйте Lambda-ресурси вручну в Production. AWS SAM, Terraform або CDK дозволяють версіонувати інфраструктуру, відтворювати середовища та уникати «snowflake servers».",[3704,22830,22832],{"id":22831},"що-далі","Що далі?",[3353,22834,22835],{},"Після освоєння основ Lambda, наступні кроки у вивченні serverless на AWS:",[4273,22837,22838,22848],{},[4276,22839,22840],{},[4279,22841,22842,22845],{},[4282,22843,22844],{},"Технологія",[4282,22846,22847],{},"Що вивчити",[4292,22849,22850,22859,22869,22878,22888],{},[4279,22851,22852,22856],{},[4297,22853,22854],{},[3359,22855,20734],{},[4297,22857,22858],{},"Infrastructure as Code для serverless: шаблони, локальне тестування",[4279,22860,22861,22866],{},[4297,22862,22863],{},[3359,22864,22865],{},"AWS Step Functions",[4297,22867,22868],{},"Оркестрація складних multi-step бізнес-процесів",[4279,22870,22871,22875],{},[4297,22872,22873],{},[3359,22874,10725],{},[4297,22876,22877],{},"Event-driven архітектура між сервісами та SaaS-інтеграції",[4279,22879,22880,22885],{},[4297,22881,22882],{},[3359,22883,22884],{},"AWS App Runner",[4297,22886,22887],{},"Serverless контейнери для довготривалих HTTP-сервісів",[4279,22889,22890,22895],{},[4297,22891,22892],{},[3359,22893,22894],{},"Amazon Bedrock + Lambda",[4297,22896,22897],{},"Інтеграція AI\u002FML моделей у serverless пайплайни",[3677,22899,22900],{},"Найкращий спосіб закріпити знання — побудувати власний реальний проект. Оберіть будь-яку задачу автоматизації (обробка файлів, webhook-handler, scheduled job) та реалізуйте її на AWS Lambda з .NET. Практика швидко розставить усе на свої місця.",[22902,22903,22904],"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 .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 .sN1BT, html code.shiki .sN1BT{--shiki-light:#267F99;--shiki-default:#4EC9B0;--shiki-dark:#4EC9B0}html pre.shiki code .s8Opu, html code.shiki .s8Opu{--shiki-light:#795E26;--shiki-default:#DCDCAA;--shiki-dark:#DCDCAA}html pre.shiki code .sHH4Y, html code.shiki .sHH4Y{--shiki-light:#000000;--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .siwwj, html code.shiki .siwwj{--shiki-light:#001080;--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}html pre.shiki code .sbdoH, html code.shiki .sbdoH{--shiki-light:#A31515;--shiki-default:#CE9178;--shiki-dark:#CE9178}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 .sjcCO, html code.shiki .sjcCO{--shiki-light:#EE0000;--shiki-default:#D7BA7D;--shiki-dark:#D7BA7D}html pre.shiki code .s8xlr, html code.shiki .s8xlr{--shiki-light:#AF00DB;--shiki-default:#C586C0;--shiki-dark:#C586C0}html pre.shiki code .sD7JJ, html code.shiki .sD7JJ{--shiki-light:#000000FF;--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}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":3390,"searchDepth":3404,"depth":3404,"links":22906},[22907,22908,22913,22916,22919,22925,22934,22941,22950,22954,22955,22961,22966,22967,22987,22988,22999,23009],{"id":3350,"depth":3404,"text":3351},{"id":3688,"depth":3404,"text":3689,"children":22909},[22910,22911,22912],{"id":3706,"depth":3410,"text":3707},{"id":3848,"depth":3410,"text":3849},{"id":3933,"depth":3410,"text":3934},{"id":4015,"depth":3404,"text":4016,"children":22914},[22915],{"id":4264,"depth":3410,"text":4265},{"id":4540,"depth":3404,"text":4541,"children":22917},[22918],{"id":4657,"depth":3410,"text":4658},{"id":4854,"depth":3404,"text":4855,"children":22920},[22921,22922,22923],{"id":4861,"depth":3410,"text":4862},{"id":4969,"depth":3410,"text":4970},{"id":5047,"depth":3410,"text":22924},"Структура проекту: Файл aws-lambda-tools-defaults.json",{"id":5194,"depth":3404,"text":5195,"children":22926},[22927,22928,22929,22930,22931,22932,22933],{"id":5380,"depth":3410,"text":5381},{"id":5405,"depth":3410,"text":5406},{"id":5426,"depth":3410,"text":5427},{"id":5440,"depth":3410,"text":5441},{"id":5468,"depth":3410,"text":5469},{"id":5529,"depth":3410,"text":5530},{"id":5625,"depth":3410,"text":5626},{"id":5680,"depth":3404,"text":5681,"children":22935},[22936,22937,22938,22939,22940],{"id":5687,"depth":3410,"text":5688},{"id":5775,"depth":3410,"text":5776},{"id":5889,"depth":3410,"text":5890},{"id":5948,"depth":3410,"text":5949},{"id":6426,"depth":3410,"text":6427},{"id":6882,"depth":3404,"text":6883,"children":22942},[22943,22944,22945,22946,22947,22948,22949],{"id":6907,"depth":3410,"text":6908},{"id":6940,"depth":3410,"text":6941},{"id":6968,"depth":3410,"text":6969},{"id":7158,"depth":3410,"text":7159},{"id":8638,"depth":3410,"text":8639},{"id":9928,"depth":3410,"text":9929},{"id":10719,"depth":3410,"text":10720},{"id":11244,"depth":3404,"text":11245,"children":22951},[22952,22953],{"id":11248,"depth":3410,"text":11249},{"id":11584,"depth":3410,"text":11585},{"id":12728,"depth":3404,"text":12729},{"id":13192,"depth":3404,"text":13193,"children":22956},[22957,22958,22959,22960],{"id":13199,"depth":3410,"text":13200},{"id":13766,"depth":3410,"text":13767},{"id":13924,"depth":3410,"text":13925},{"id":14388,"depth":3410,"text":14389},{"id":15415,"depth":3404,"text":15416,"children":22962},[22963,22964,22965],{"id":15543,"depth":3410,"text":15544},{"id":15574,"depth":3410,"text":15575},{"id":15988,"depth":3410,"text":15989},{"id":16239,"depth":3404,"text":16240},{"id":16571,"depth":3404,"text":16572,"children":22968},[22969,22970,22971,22972,22973,22974,22975,22976,22977,22978,22979,22980,22981,22982,22983,22984,22985,22986],{"id":16578,"depth":3410,"text":16579},{"id":16672,"depth":3410,"text":16673},{"id":16936,"depth":3410,"text":16937},{"id":17084,"depth":3410,"text":17085},{"id":17093,"depth":3410,"text":17094},{"id":17128,"depth":3410,"text":17129},{"id":17165,"depth":3410,"text":17166},{"id":17219,"depth":3410,"text":17220},{"id":17271,"depth":3410,"text":17272},{"id":17407,"depth":3410,"text":17408},{"id":17416,"depth":3410,"text":17417},{"id":17467,"depth":3410,"text":17468},{"id":17547,"depth":3410,"text":17548},{"id":17680,"depth":3410,"text":17681},{"id":17698,"depth":3410,"text":17699},{"id":17764,"depth":3410,"text":17765},{"id":17827,"depth":3410,"text":17828},{"id":17924,"depth":3410,"text":17925},{"id":17960,"depth":3404,"text":17961},{"id":18133,"depth":3404,"text":18134,"children":22989},[22990,22991,22992,22993,22994,22995,22996,22997,22998],{"id":18140,"depth":3410,"text":18141},{"id":18251,"depth":3410,"text":18252},{"id":18397,"depth":3410,"text":18398},{"id":18942,"depth":3410,"text":18943},{"id":20108,"depth":3410,"text":20109},{"id":20637,"depth":3410,"text":20638},{"id":20643,"depth":3410,"text":20644},{"id":20671,"depth":3410,"text":20672},{"id":20697,"depth":3410,"text":20698},{"id":20744,"depth":3404,"text":20745,"children":23000},[23001,23002,23003,23004,23005,23006,23007,23008],{"id":20751,"depth":3410,"text":20752},{"id":20891,"depth":3410,"text":20892},{"id":21094,"depth":3410,"text":21095},{"id":21339,"depth":3410,"text":21340},{"id":22431,"depth":3410,"text":22432},{"id":22506,"depth":3410,"text":22507},{"id":22589,"depth":3410,"text":22590},{"id":22628,"depth":3410,"text":22629},{"id":22787,"depth":3404,"text":22788,"children":23010},[23011,23012],{"id":22794,"depth":3410,"text":22795},{"id":22831,"depth":3410,"text":22832},"Глибоке дослідження AWS Lambda — від фундаментальних принципів serverless архітектури до продакшн-оптимізації .NET функцій. Runtimes, Layers, Triggers, Cold Start, Provisioned Concurrency, Lambda Destinations та повна інтеграція з екосистемою AWS для .NET 10 розробників.","md",null,{},{"title":3262,"description":23013},"rMa5N0SEVGRRqV053tScn-BtmwlzHAyuFI9FqEdcfB8",[23020,23022],{"title":3258,"path":3259,"stem":3260,"description":23021,"children":-1},"Фундаментальний посібник з Amazon DynamoDB для .NET розробників. Від моделі даних та первинних ключів до вторинних індексів, транзакцій, Streams, TTL, Global Tables та інтеграції через AWS SDK for .NET — з акцентом на проектування схем для реальних production-сценаріїв.",{"title":3266,"path":3267,"stem":3268,"description":23023,"children":-1},"Глибоке занурення в Amazon Bedrock. Практична інтеграція великих мовних моделей Claude, Llama та Titan з .NET 8 та React. Реалізація Streaming, побудова Knowledge Bases для RAG, налаштування Guardrails безпеки та розробка автономних AI Agents.",1782371306787]