[{"data":1,"prerenderedAt":22894},["ShallowReactive",2],{"navigation_docs":3,"-python-advanced-dunder-methods":5492,"-python-advanced-dunder-methods-surround":22889},[4,1707,2220,2692,2873,3041,3248,3370,3420,3477,3511,3637,3714,3728,3867,4245,4322,5055,5230,5323,5376,5488],{"title":5,"icon":6,"path":7,"stem":8,"children":9},"C#","i-devicon-csharp","\u002Fcsharp","01.csharp",[10,13,60,90,120,202,219,253,379,404,457,650,1364,1654,1703],{"title":11,"path":7,"stem":12},"C# та .NET","01.csharp\u002Findex",{"title":14,"icon":15,"path":16,"stem":17,"children":18,"page":59},"Fundamentals","i-lucide-book-open","\u002Fcsharp\u002Ffundamentals","01.csharp\u002F01.fundamentals",[19,23,27,31,35,39,43,47,51,55],{"title":20,"path":21,"stem":22},"Вступ до екосистеми .NET","\u002Fcsharp\u002Ffundamentals\u002Fintroduction-to-ecosystem","01.csharp\u002F01.fundamentals\u002F01.introduction-to-ecosystem",{"title":24,"path":25,"stem":26},"Структура програми на C#","\u002Fcsharp\u002Ffundamentals\u002Fprogram-structure","01.csharp\u002F01.fundamentals\u002F02.program-structure",{"title":28,"path":29,"stem":30},"Змінні та Типи Даних","\u002Fcsharp\u002Ffundamentals\u002Fvariables-data-types","01.csharp\u002F01.fundamentals\u002F03.variables-data-types",{"title":32,"path":33,"stem":34},"Масиви","\u002Fcsharp\u002Ffundamentals\u002Farrays","01.csharp\u002F01.fundamentals\u002F04.arrays",{"title":36,"path":37,"stem":38},"Strings & Text Handling","\u002Fcsharp\u002Ffundamentals\u002Fstrings-text-handling","01.csharp\u002F01.fundamentals\u002F05.strings-text-handling",{"title":40,"path":41,"stem":42},"Дати і Час","\u002Fcsharp\u002Ffundamentals\u002Fdates-time-handling","01.csharp\u002F01.fundamentals\u002F06.dates-time-handling",{"title":44,"path":45,"stem":46},"Потік Керування","\u002Fcsharp\u002Ffundamentals\u002Fcontrol-flow","01.csharp\u002F01.fundamentals\u002F07.control-flow",{"title":48,"path":49,"stem":50},"Методи","\u002Fcsharp\u002Ffundamentals\u002Fmethods","01.csharp\u002F01.fundamentals\u002F08.methods",{"title":52,"path":53,"stem":54},"Основи Відлагодження","\u002Fcsharp\u002Ffundamentals\u002Fdebugging-basics","01.csharp\u002F01.fundamentals\u002F09.debugging-basics",{"title":56,"path":57,"stem":58},"Інтерактивна Консоль (Classic)","\u002Fcsharp\u002Ffundamentals\u002Finteractive-console","01.csharp\u002F01.fundamentals\u002F10.interactive-console",false,{"title":61,"icon":62,"path":63,"stem":64,"children":65,"page":59},"OOP","i-lucide-box","\u002Fcsharp\u002Foop","01.csharp\u002F02.oop",[66,70,74,78,82,86],{"title":67,"path":68,"stem":69},"Package Management (Управління Пакетами)","\u002Fcsharp\u002Foop\u002Fpackage-management","01.csharp\u002F02.oop\u002F01.package-management",{"title":71,"path":72,"stem":73},"Класи та Об'єкти","\u002Fcsharp\u002Foop\u002Fclasses-objects","01.csharp\u002F02.oop\u002F02.classes-objects",{"title":75,"path":76,"stem":77},"Властивості та Поля","\u002Fcsharp\u002Foop\u002Fproperties-fields","01.csharp\u002F02.oop\u002F03.properties-fields",{"title":79,"path":80,"stem":81},"Стовпи ООП","\u002Fcsharp\u002Foop\u002Foop-pillars","01.csharp\u002F02.oop\u002F04.oop-pillars",{"title":83,"path":84,"stem":85},"Advanced Types","\u002Fcsharp\u002Foop\u002Fadvanced-types","01.csharp\u002F02.oop\u002F05.advanced-types",{"title":87,"path":88,"stem":89},"Namespaces (Простори Імен)","\u002Fcsharp\u002Foop\u002Fnamespaces","01.csharp\u002F02.oop\u002F06.namespaces",{"title":91,"icon":92,"path":93,"stem":94,"children":95,"page":59},"Advanced Core","i-lucide-zap","\u002Fcsharp\u002Fadvanced-core","01.csharp\u002F03.advanced-core",[96,100,104,108,112,116],{"title":97,"path":98,"stem":99},"Generics (Узагальнення)","\u002Fcsharp\u002Fadvanced-core\u002Fgenerics","01.csharp\u002F03.advanced-core\u002F01.generics",{"title":101,"path":102,"stem":103},"Делегати, Події та Лямбда-вирази","\u002Fcsharp\u002Fadvanced-core\u002Fdelegates-events-lambdas","01.csharp\u002F03.advanced-core\u002F02.delegates-events-lambdas",{"title":105,"path":106,"stem":107},"Interfaces Deep Dive (Інтерфейси: Поглиблений Розгляд)","\u002Fcsharp\u002Fadvanced-core\u002Finterfaces-deep-dive","01.csharp\u002F03.advanced-core\u002F03.interfaces-deep-dive",{"title":109,"path":110,"stem":111},"Обробка Винятків","\u002Fcsharp\u002Fadvanced-core\u002Fexception-handling","01.csharp\u002F03.advanced-core\u002F04.exception-handling",{"title":113,"path":114,"stem":115},"Pattern Matching","\u002Fcsharp\u002Fadvanced-core\u002Fpattern-matching","01.csharp\u002F03.advanced-core\u002F05.pattern-matching",{"title":117,"path":118,"stem":119},"Додаткові Можливості C#","\u002Fcsharp\u002Fadvanced-core\u002Fadditional-features","01.csharp\u002F03.advanced-core\u002F06.additional-features",{"title":121,"icon":122,"path":123,"stem":124,"children":125,"page":59},"Architecture Best Practices","i-lucide-building-2","\u002Fcsharp\u002Farchitecture-best-practices","01.csharp\u002F04.architecture-best-practices",[126,130,149,153,157,161,165,169],{"title":127,"path":128,"stem":129},"Software Design Principles (Частина 1)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fsoftware-design-principles","01.csharp\u002F04.architecture-best-practices\u002F01.software-design-principles",{"title":131,"icon":132,"path":133,"stem":134,"children":135,"page":59},"Design Patterns","i-lucide-folder","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns",[136],{"title":137,"icon":132,"path":138,"stem":139,"children":140,"page":59},"Creational","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational",[141,145],{"title":142,"path":143,"stem":144},"Singleton (Одинак)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational\u002Fsingleton","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational\u002F01.singleton",{"title":146,"path":147,"stem":148},"Builder (Будівельник)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational\u002Fbuilder","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational\u002F02.builder",{"title":150,"path":151,"stem":152},"Building Professional CLIs","\u002Fcsharp\u002Farchitecture-best-practices\u002Fbuilding-professional-clis","01.csharp\u002F04.architecture-best-practices\u002F03.building-professional-clis",{"title":154,"path":155,"stem":156},"Validation & Flow Control","\u002Fcsharp\u002Farchitecture-best-practices\u002Fvalidation-flow-control","01.csharp\u002F04.architecture-best-practices\u002F04.validation-flow-control",{"title":158,"path":159,"stem":160},"The Modern .NET Host (Microsoft.Extensions)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fmodern-dotnet-host","01.csharp\u002F04.architecture-best-practices\u002F05.modern-dotnet-host",{"title":162,"path":163,"stem":164},"Data Mapper: Repository та DAO патерни (Частина 1)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdata-mapper-part1","01.csharp\u002F04.architecture-best-practices\u002F06.data-mapper-part1",{"title":166,"path":167,"stem":168},"Data Mapper: Repository та DAO патерни (Частина 2)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdata-mapper-part2","01.csharp\u002F04.architecture-best-practices\u002F07.data-mapper-part2",{"title":170,"icon":132,"path":171,"stem":172,"children":173,"page":59},"Di Ioc","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc",[174,178,182,186,190,194,198],{"title":175,"path":176,"stem":177},"Проблема залежностей та Інверсія Контролю","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fthe-dependency-problem","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F01.the-dependency-problem",{"title":179,"path":180,"stem":181},"Будуємо власний Service Container","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fbuild-your-own-container","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F02.build-your-own-container",{"title":183,"path":184,"stem":185},"Service Locator: Паттерн та Анти-паттерн","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fservice-locator-pattern","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F03.service-locator-pattern",{"title":187,"path":188,"stem":189},"Паттерни Dependency Injection","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fdependency-injection-patterns","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F04.dependency-injection-patterns",{"title":191,"path":192,"stem":193},"Microsoft DI: IServiceCollection та IServiceProvider","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fmicrosoft-di-deep-dive","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F05.microsoft-di-deep-dive",{"title":195,"path":196,"stem":197},"Service Lifetimes та Scopes","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fservice-lifetimes-and-scopes","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F06.service-lifetimes-and-scopes",{"title":199,"path":200,"stem":201},"DI Анти-паттерни та Найкращі Практики","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fdi-anti-patterns-and-best-practices","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F07.di-anti-patterns-and-best-practices",{"title":203,"icon":132,"path":204,"stem":205,"children":206,"page":59},"Standard Library","\u002Fcsharp\u002Fstandard-library","01.csharp\u002F05.standard-library",[207,211,215],{"title":208,"path":209,"stem":210},"Collections (Колекції)","\u002Fcsharp\u002Fstandard-library\u002Fcollections","01.csharp\u002F05.standard-library\u002F01.collections",{"title":212,"path":213,"stem":214},"High Performance Types (Високопродуктивні Типи)","\u002Fcsharp\u002Fstandard-library\u002Fhigh-performance-types","01.csharp\u002F05.standard-library\u002F02.high-performance-types",{"title":216,"path":217,"stem":218},"LINQ (Language Integrated Query)","\u002Fcsharp\u002Fstandard-library\u002Flinq","01.csharp\u002F05.standard-library\u002F03.linq",{"title":220,"icon":221,"path":222,"stem":223,"children":224,"page":59},"System Internals Concurrency","i-lucide-server","\u002Fcsharp\u002Fsystem-internals-concurrency","01.csharp\u002F06.system-internals-concurrency",[225,229,233,237,241,245,249],{"title":226,"path":227,"stem":228},"Memory Management","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fmemory-management","01.csharp\u002F06.system-internals-concurrency\u002F01.memory-management",{"title":230,"path":231,"stem":232},"Reflection API: System.Type та Метадані","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Freflection-fundamentals","01.csharp\u002F06.system-internals-concurrency\u002F02.reflection-fundamentals",{"title":234,"path":235,"stem":236},"Attributes та Dynamic Language Runtime","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fattributes-dynamic","01.csharp\u002F06.system-internals-concurrency\u002F03.attributes-dynamic",{"title":238,"path":239,"stem":240},"Expression Trees: Швидка Альтернатива Рефлексії","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fexpression-trees-compiled","01.csharp\u002F06.system-internals-concurrency\u002F04.expression-trees-compiled",{"title":242,"path":243,"stem":244},"Source Generators: Compile-Time Code Generation","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fsource-generators","01.csharp\u002F06.system-internals-concurrency\u002F05.source-generators",{"title":246,"path":247,"stem":248},"Multithreading Fundamentals","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fmultithreading-fundamentals","01.csharp\u002F06.system-internals-concurrency\u002F06.multithreading-fundamentals",{"title":250,"path":251,"stem":252},"Synchronization Primitives","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fsynchronization-primitives","01.csharp\u002F06.system-internals-concurrency\u002F07.synchronization-primitives",{"title":254,"icon":255,"path":256,"stem":257,"children":258,"page":59},"System Programming Windows","i-lucide-cpu","\u002Fcsharp\u002Fsystem-programming-windows","01.csharp\u002F07.system-programming-windows",[259,263,267,271,275,279,283,287,291,295,299,303,307,311,315,319,323,327,331,335,339,343,347,351,355,359,363,367,371,375],{"title":260,"path":261,"stem":262},"Як Працює Операційна Система","\u002Fcsharp\u002Fsystem-programming-windows\u002Fhow-os-works","01.csharp\u002F07.system-programming-windows\u002F01.how-os-works",{"title":264,"path":265,"stem":266},"Процеси в .NET — API та Запуск","\u002Fcsharp\u002Fsystem-programming-windows\u002Fprocesses-in-dotnet","01.csharp\u002F07.system-programming-windows\u002F02.processes-in-dotnet",{"title":268,"path":269,"stem":270},"Процеси в .NET — IPC та Міжпроцесна Комунікація","\u002Fcsharp\u002Fsystem-programming-windows\u002F02a.processes-ipc","01.csharp\u002F07.system-programming-windows\u002F02a.processes-ipc",{"title":272,"path":273,"stem":274},"Application Domains та Збірки — AppDomain і AssemblyLoadContext","\u002Fcsharp\u002Fsystem-programming-windows\u002Fappdomains-assemblies","01.csharp\u002F07.system-programming-windows\u002F03.appdomains-assemblies",{"title":276,"path":277,"stem":278},"Application Domains та Збірки — Plug-in Система з Hot-Reload","\u002Fcsharp\u002Fsystem-programming-windows\u002F03a.appdomains-plugin-system","01.csharp\u002F07.system-programming-windows\u002F03a.appdomains-plugin-system",{"title":280,"path":281,"stem":282},"Потоки — Основи та API Thread","\u002Fcsharp\u002Fsystem-programming-windows\u002Fthread-fundamentals","01.csharp\u002F07.system-programming-windows\u002F04.thread-fundamentals",{"title":284,"path":285,"stem":286},"Потоки — Lifecycle, Пріоритети та Безпечне Завершення","\u002Fcsharp\u002Fsystem-programming-windows\u002F04a.thread-lifecycle-priorities","01.csharp\u002F07.system-programming-windows\u002F04a.thread-lifecycle-priorities",{"title":288,"path":289,"stem":290},"Проблеми Спільного Стану — Race Condition та Data Race","\u002Fcsharp\u002Fsystem-programming-windows\u002Fshared-state-problems","01.csharp\u002F07.system-programming-windows\u002F05.shared-state-problems",{"title":292,"path":293,"stem":294},"Проблеми Спільного Стану — Memory Model та volatile","\u002Fcsharp\u002Fsystem-programming-windows\u002F05a.shared-state-memory-model","01.csharp\u002F07.system-programming-windows\u002F05a.shared-state-memory-model",{"title":296,"path":297,"stem":298},"Синхронізація — Monitor, lock та еволюція примітивів","\u002Fcsharp\u002Fsystem-programming-windows\u002Fsynchronization-fundamentals","01.csharp\u002F07.system-programming-windows\u002F06.synchronization-fundamentals",{"title":300,"path":301,"stem":302},"Синхронізація — Наскрізний Приклад та Deadlock Detection","\u002Fcsharp\u002Fsystem-programming-windows\u002F06a.synchronization-walkthrough","01.csharp\u002F07.system-programming-windows\u002F06a.synchronization-walkthrough",{"title":304,"path":305,"stem":306},"Синхронізація — Mutex, Semaphore та Event-Based Primitives","\u002Fcsharp\u002Fsystem-programming-windows\u002Fsynchronization-advanced","01.csharp\u002F07.system-programming-windows\u002F07.synchronization-advanced",{"title":308,"path":309,"stem":310},"Синхронізація — Interlocked, Volatile та Lock-Free Структури","\u002Fcsharp\u002Fsystem-programming-windows\u002F07a.synchronization-advanced-walkthrough","01.csharp\u002F07.system-programming-windows\u002F07a.synchronization-advanced-walkthrough",{"title":312,"path":313,"stem":314},"Interlocked, CAS та Lock-Free Структури","\u002Fcsharp\u002Fsystem-programming-windows\u002Finterlocked-cas-lockfree","01.csharp\u002F07.system-programming-windows\u002F08.interlocked-cas-lockfree",{"title":316,"path":317,"stem":318},"Volatile, Memory Model та Spinning","\u002Fcsharp\u002Fsystem-programming-windows\u002F08a.volatile-memory-model","01.csharp\u002F07.system-programming-windows\u002F08a.volatile-memory-model",{"title":320,"path":321,"stem":322},"ThreadPool — Пул Потоків для Ефективного Виконання","\u002Fcsharp\u002Fsystem-programming-windows\u002Fthread-pool","01.csharp\u002F07.system-programming-windows\u002F09.thread-pool",{"title":324,"path":325,"stem":326},"ThreadPool — Просунуті Сценарії та Внутрішня Будова","\u002Fcsharp\u002Fsystem-programming-windows\u002F09a.thread-pool-advanced","01.csharp\u002F07.system-programming-windows\u002F09a.thread-pool-advanced",{"title":328,"path":329,"stem":330},"Concurrent та Immutable Collections","\u002Fcsharp\u002Fsystem-programming-windows\u002Fconcurrent-collections","01.csharp\u002F07.system-programming-windows\u002F10.concurrent-collections",{"title":332,"path":333,"stem":334},"TPL, Task та Композиція — Від Thread до Task","\u002Fcsharp\u002Fsystem-programming-windows\u002Ftpl-parallel-plinq","01.csharp\u002F07.system-programming-windows\u002F11.tpl-parallel-plinq",{"title":336,"path":337,"stem":338},"Parallel Class та PLINQ — Data Parallelism","\u002Fcsharp\u002Fsystem-programming-windows\u002F11a.tpl-parallel-plinq-advanced","01.csharp\u002F07.system-programming-windows\u002F11a.tpl-parallel-plinq-advanced",{"title":340,"path":341,"stem":342},"Async\u002FAwait — Фундамент Асинхронного Програмування","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-fundamentals","01.csharp\u002F07.system-programming-windows\u002F12.async-fundamentals",{"title":344,"path":345,"stem":346},"SynchronizationContext та ConfigureAwait — Контекст Виконання","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-context-configureawait","01.csharp\u002F07.system-programming-windows\u002F13.async-context-configureawait",{"title":348,"path":349,"stem":350},"Async — Просунуті Паттерни","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-advanced","01.csharp\u002F07.system-programming-windows\u002F14.async-advanced",{"title":352,"path":353,"stem":354},"System.Threading.Channels — Async Producer-Consumer","\u002Fcsharp\u002Fsystem-programming-windows\u002Fchannels","01.csharp\u002F07.system-programming-windows\u002F15.channels",{"title":356,"path":357,"stem":358},"Асинхронна Синхронізація","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-synchronization","01.csharp\u002F07.system-programming-windows\u002F16.async-synchronization",{"title":360,"path":361,"stem":362},"Unsafe Code та Вказівники","\u002Fcsharp\u002Fsystem-programming-windows\u002Funsafe-code","01.csharp\u002F07.system-programming-windows\u002F17.unsafe-code",{"title":364,"path":365,"stem":366},"P\u002FInvoke та Windows API — Міст між .NET та Native Code","\u002Fcsharp\u002Fsystem-programming-windows\u002Fpinvoke-winapi","01.csharp\u002F07.system-programming-windows\u002F18.pinvoke-winapi",{"title":368,"path":369,"stem":370},"Реєстр Windows — Центральна База Конфігурації Системи","\u002Fcsharp\u002Fsystem-programming-windows\u002Fwindows-registry","01.csharp\u002F07.system-programming-windows\u002F19.windows-registry",{"title":372,"path":373,"stem":374},"Windows Hooks, Hotkeys та Services — Глибока Інтеграція з ОС","\u002Fcsharp\u002Fsystem-programming-windows\u002Fwindows-hooks-services","01.csharp\u002F07.system-programming-windows\u002F20.windows-hooks-services",{"title":376,"path":377,"stem":378},"Системне Програмування C# (Windows) — 07.system-programming-windows","\u002Fcsharp\u002Fsystem-programming-windows\u002Fimplementation_plan","01.csharp\u002F07.system-programming-windows\u002Fimplementation_plan",{"title":380,"icon":132,"path":381,"stem":382,"children":383,"page":59},"Io","\u002Fcsharp\u002Fio","01.csharp\u002F08.io",[384,388,392,396,400],{"title":385,"path":386,"stem":387},"8.1.1. Основи роботи з файловою системою","\u002Fcsharp\u002Fio\u002Ffile-system-basics","01.csharp\u002F08.io\u002F01.file-system-basics",{"title":389,"path":390,"stem":391},"8.1.2. Потоки (Streams) та Серіалізація Даних","\u002Fcsharp\u002Fio\u002Fstreams-serialization","01.csharp\u002F08.io\u002F02.streams-serialization",{"title":393,"path":394,"stem":395},"8.2.1. JSON Serialization з System.Text.Json","\u002Fcsharp\u002Fio\u002Fjson-serialization","01.csharp\u002F08.io\u002F03.json-serialization",{"title":397,"path":398,"stem":399},"8.2.2. XML Serialization та LINQ to XML","\u002Fcsharp\u002Fio\u002Fxml-serialization","01.csharp\u002F08.io\u002F04.xml-serialization",{"title":401,"path":402,"stem":403},"8.2.3. Binary Serialization: MessagePack та Protocol Buffers","\u002Fcsharp\u002Fio\u002Fbinary-serialization","01.csharp\u002F08.io\u002F05.binary-serialization",{"title":405,"icon":132,"path":406,"stem":407,"children":408,"page":59},"Ado Net","\u002Fcsharp\u002Fado-net","01.csharp\u002F09.ado-net",[409,413,417,421,425,429,433,437,441,445,449,453],{"title":410,"path":411,"stem":412},"9.1. Введення в ADO.NET","\u002Fcsharp\u002Fado-net\u002Fintroduction-to-adonet","01.csharp\u002F09.ado-net\u002F01.introduction-to-adonet",{"title":414,"path":415,"stem":416},"9.2. Клас DbConnection — з'єднання з базою даних","\u002Fcsharp\u002Fado-net\u002Fconnection","01.csharp\u002F09.ado-net\u002F02.connection",{"title":418,"path":419,"stem":420},"9.3. Клас DbCommand — виконання SQL-запитів","\u002Fcsharp\u002Fado-net\u002Fcommand-and-queries","01.csharp\u002F09.ado-net\u002F03.command-and-queries",{"title":422,"path":423,"stem":424},"9.4. Клас DbDataReader — ефективне читання даних","\u002Fcsharp\u002Fado-net\u002Fdatareader","01.csharp\u002F09.ado-net\u002F04.datareader",{"title":426,"path":427,"stem":428},"9.5. Параметризовані запити та захист від SQL Injection","\u002Fcsharp\u002Fado-net\u002Fparameters-and-sql-injection","01.csharp\u002F09.ado-net\u002F05.parameters-and-sql-injection",{"title":430,"path":431,"stem":432},"9.6. Транзакції в ADO.NET","\u002Fcsharp\u002Fado-net\u002Ftransactions","01.csharp\u002F09.ado-net\u002F06.transactions",{"title":434,"path":435,"stem":436},"9.7. DbProviderFactory — провайдер-незалежний код","\u002Fcsharp\u002Fado-net\u002Fprovider-factory","01.csharp\u002F09.ado-net\u002F07.provider-factory",{"title":438,"path":439,"stem":440},"9.8. Асинхронний доступ до даних","\u002Fcsharp\u002Fado-net\u002Fasync-data-access","01.csharp\u002F09.ado-net\u002F08.async-data-access",{"title":442,"path":443,"stem":444},"9.9. Від'єднаний режим: DataSet, DataTable, DataRow","\u002Fcsharp\u002Fado-net\u002Fdisconnected-mode-dataset","01.csharp\u002F09.ado-net\u002F09.disconnected-mode-dataset",{"title":446,"path":447,"stem":448},"9.10. DataAdapter — міст між DataSet та базою даних","\u002Fcsharp\u002Fado-net\u002Fdata-adapter","01.csharp\u002F09.ado-net\u002F10.data-adapter",{"title":450,"path":451,"stem":452},"9.11. Data Mapper та Repository: Архітектура доступу до даних","\u002Fcsharp\u002Fado-net\u002Fdata-mapper-repository","01.csharp\u002F09.ado-net\u002F11.data-mapper-repository",{"title":454,"path":455,"stem":456},"9.12. Identity Map, Unit of Work та Specification Pattern","\u002Fcsharp\u002Fado-net\u002Fadvanced-patterns","01.csharp\u002F09.ado-net\u002F12.advanced-patterns",{"title":458,"icon":255,"path":459,"stem":460,"children":461,"page":59},"Ef Core","\u002Fcsharp\u002Fef-core","01.csharp\u002F10.ef-core",[462,466,470,474,478,482,486,490,494,498,502,506,510,514,518,522,526,532,538,542,546,550,554,558,562,566,570,574,578,582,586,590,594,598,602,606,610,614,618,622,626,630,634,638,642,646],{"title":463,"path":464,"stem":465},"Що таке ORM? Від SQL до об'єктів","\u002Fcsharp\u002Fef-core\u002Fwhat-is-orm","01.csharp\u002F10.ef-core\u002F01.what-is-orm",{"title":467,"path":468,"stem":469},"Перший проєкт — від нуля до CRUD","\u002Fcsharp\u002Fef-core\u002Ffirst-project","01.csharp\u002F10.ef-core\u002F02.first-project",{"title":471,"path":472,"stem":473},"DbContext — Серце EF Core","\u002Fcsharp\u002Fef-core\u002Fdbcontext-deep-dive","01.csharp\u002F10.ef-core\u002F03.dbcontext-deep-dive",{"title":475,"path":476,"stem":477},"Провайдери баз даних — Архітектура та Вибір СУБД","\u002Fcsharp\u002Fef-core\u002Fdatabase-providers","01.csharp\u002F10.ef-core\u002F04.database-providers",{"title":479,"path":480,"stem":481},"Конвенції EF Core — Магія без конфігурації","\u002Fcsharp\u002Fef-core\u002Fconventions","01.csharp\u002F10.ef-core\u002F05.conventions",{"title":483,"path":484,"stem":485},"Fluent API та Data Annotations — Явна конфігурація моделі","\u002Fcsharp\u002Fef-core\u002Ffluent-api-vs-annotations","01.csharp\u002F10.ef-core\u002F06.fluent-api-vs-annotations",{"title":487,"path":488,"stem":489},"Зв'язки — One-to-One та One-to-Many","\u002Fcsharp\u002Fef-core\u002Frelationships-basics","01.csharp\u002F10.ef-core\u002F07.relationships-basics",{"title":491,"path":492,"stem":493},"Зв'язки Advanced — Many-to-Many та Складні Сценарії","\u002Fcsharp\u002Fef-core\u002Frelationships-advanced","01.csharp\u002F10.ef-core\u002F08.relationships-advanced",{"title":495,"path":496,"stem":497},"Властивості — Типи, Конвертери, Компаратори (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fproperty-configuration-part1","01.csharp\u002F10.ef-core\u002F09.property-configuration-part1",{"title":499,"path":500,"stem":501},"Властивості — Value Comparers, Generators, Shadow Properties (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fproperty-configuration-part2","01.csharp\u002F10.ef-core\u002F09.property-configuration-part2",{"title":503,"path":504,"stem":505},"Складні типи — Owned Types та Complex Types (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fcomplex-types-owned-part1","01.csharp\u002F10.ef-core\u002F10.complex-types-owned-part1",{"title":507,"path":508,"stem":509},"Складні типи — Complex Types, Keyless Entities, Порівняння (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fcomplex-types-owned-part2","01.csharp\u002F10.ef-core\u002F10.complex-types-owned-part2",{"title":511,"path":512,"stem":513},"JSON Columns — Складні дані у JSON (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fjson-columns-part1","01.csharp\u002F10.ef-core\u002F11.json-columns-part1",{"title":515,"path":516,"stem":517},"JSON Columns — Value Comparers, Індекси, Провайдери (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fjson-columns-part2","01.csharp\u002F10.ef-core\u002F11.json-columns-part2",{"title":519,"path":520,"stem":521},"Успадкування — Абстрактні класи та TPH (Частина 1)","\u002Fcsharp\u002Fef-core\u002Finheritance-part1","01.csharp\u002F10.ef-core\u002F12.inheritance-part1",{"title":523,"path":524,"stem":525},"Успадкування — TPT, TPC та Порівняння Стратегій (Частина 2)","\u002Fcsharp\u002Fef-core\u002Finheritance-part2","01.csharp\u002F10.ef-core\u002F12.inheritance-part2",{"title":527,"path":528,"stem":529,"children":530},"Індекси, Обмеження та Схема (Частина 1)","\u002Fcsharp\u002Fef-core\u002Findexes-constraints-part1","01.csharp\u002F10.ef-core\u002F13.indexes-constraints-part1",[531],{"title":527,"path":528,"stem":529},{"title":533,"path":534,"stem":535,"children":536},"Індекси, Обмеження та Схема (Частина 2)","\u002Fcsharp\u002Fef-core\u002Findexes-constraints-part2","01.csharp\u002F10.ef-core\u002F13.indexes-constraints-part2",[537],{"title":533,"path":534,"stem":535},{"title":539,"path":540,"stem":541},"Seed Data — Початкові Дані (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fseeding-part1","01.csharp\u002F10.ef-core\u002F14.seeding-part1",{"title":543,"path":544,"stem":545},"Seed Data — SQL-скрипти, Bogus та Стратегії (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fseeding-part2","01.csharp\u002F10.ef-core\u002F14.seeding-part2",{"title":547,"path":548,"stem":549},"Global Query Filters — Глобальні Фільтри (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fglobal-query-filters-part1","01.csharp\u002F10.ef-core\u002F15.global-query-filters-part1",{"title":551,"path":552,"stem":553},"Global Query Filters — Підводні камені та Інтеграція (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fglobal-query-filters-part2","01.csharp\u002F10.ef-core\u002F15.global-query-filters-part2",{"title":555,"path":556,"stem":557},"LINQ-запити в EF Core (Частина 1)","\u002Fcsharp\u002Fef-core\u002Flinq-queries-part1","01.csharp\u002F10.ef-core\u002F16.linq-queries-part1",{"title":559,"path":560,"stem":561},"LINQ-запити в EF Core (Частина 2)","\u002Fcsharp\u002Fef-core\u002Flinq-queries-part2","01.csharp\u002F10.ef-core\u002F16.linq-queries-part2",{"title":563,"path":564,"stem":565},"Завантаження Пов'язаних Даних (Частина 1)","\u002Fcsharp\u002Fef-core\u002Floading-related-data-part1","01.csharp\u002F10.ef-core\u002F17.loading-related-data-part1",{"title":567,"path":568,"stem":569},"Завантаження Пов'язаних Даних (Частина 2)","\u002Fcsharp\u002Fef-core\u002Floading-related-data-part2","01.csharp\u002F10.ef-core\u002F17.loading-related-data-part2",{"title":571,"path":572,"stem":573},"Raw SQL, Views та Stored Procedures (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fraw-sql-part1","01.csharp\u002F10.ef-core\u002F18.raw-sql-part1",{"title":575,"path":576,"stem":577},"Raw SQL — Stored Procedures, DbFunction та Bulk Operations (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fraw-sql-part2","01.csharp\u002F10.ef-core\u002F18.raw-sql-part2",{"title":579,"path":580,"stem":581},"Продвинуті Запити — Compiled Queries, Bulk та Оптимізація (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fadvanced-queries-part1","01.csharp\u002F10.ef-core\u002F19.advanced-queries-part1",{"title":583,"path":584,"stem":585},"Продвинуті Запити — Query Tags, Bulk та Interceptors (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fadvanced-queries-part2","01.csharp\u002F10.ef-core\u002F19.advanced-queries-part2",{"title":587,"path":588,"stem":589},"Change Tracker — Відстеження Змін (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fchange-tracking-part1","01.csharp\u002F10.ef-core\u002F20.change-tracking-part1",{"title":591,"path":592,"stem":593},"Change Tracker — Графи Об'єктів та Disconnected (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fchange-tracking-part2","01.csharp\u002F10.ef-core\u002F20.change-tracking-part2",{"title":595,"path":596,"stem":597},"Збереження Даних та Транзакції (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fsaving-data-part1","01.csharp\u002F10.ef-core\u002F21.saving-data-part1",{"title":599,"path":600,"stem":601},"Збереження Даних — Concurrency та Outbox (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fsaving-data-part2","01.csharp\u002F10.ef-core\u002F21.saving-data-part2",{"title":603,"path":604,"stem":605},"Конкурентність та Блокування (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fconcurrency-part1","01.csharp\u002F10.ef-core\u002F22.concurrency-part1",{"title":607,"path":608,"stem":609},"Конкурентність — Дедлоки та Queue Processing (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fconcurrency-part2","01.csharp\u002F10.ef-core\u002F22.concurrency-part2",{"title":611,"path":612,"stem":613},"Міграції в EF Core — Основи (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fmigrations-basics-part1","01.csharp\u002F10.ef-core\u002F23.migrations-basics-part1",{"title":615,"path":616,"stem":617},"Міграції в EF Core — Основи (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fmigrations-basics-part2","01.csharp\u002F10.ef-core\u002F23.migrations-basics-part2",{"title":619,"path":620,"stem":621},"Міграції — Просунуті Сценарії (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fmigrations-advanced-part1","01.csharp\u002F10.ef-core\u002F24.migrations-advanced-part1",{"title":623,"path":624,"stem":625},"Міграції — Просунуті Сценарії (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fmigrations-advanced-part2","01.csharp\u002F10.ef-core\u002F24.migrations-advanced-part2",{"title":627,"path":628,"stem":629},"Управління Схемою та Database-First (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fschema-management-part1","01.csharp\u002F10.ef-core\u002F25.schema-management-part1",{"title":631,"path":632,"stem":633},"Управління Схемою та Database-First (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fschema-management-part2","01.csharp\u002F10.ef-core\u002F25.schema-management-part2",{"title":635,"path":636,"stem":637},"Продуктивність EF Core — Основи (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fperformance-fundamentals-part1","01.csharp\u002F10.ef-core\u002F26.performance-fundamentals-part1",{"title":639,"path":640,"stem":641},"Interceptors в EF Core (Частина 1)","\u002Fcsharp\u002Fef-core\u002Finterceptors-part1","01.csharp\u002F10.ef-core\u002F29.interceptors-part1",{"title":643,"path":644,"stem":645},"Interceptors в EF Core — Connection, Transaction та Materialization (Частина 2)","\u002Fcsharp\u002Fef-core\u002Finterceptors-part2","01.csharp\u002F10.ef-core\u002F29.interceptors-part2",{"title":647,"path":648,"stem":649},"План вивчення Entity Framework Core — Повний курс","\u002Fcsharp\u002Fef-core\u002Fimplementation_plan","01.csharp\u002F10.ef-core\u002Fimplementation_plan",{"title":651,"icon":652,"path":653,"stem":654,"children":655,"page":59},"ASP.NET","i-devicon-dotnetcore","\u002Fcsharp\u002Faspnet","01.csharp\u002F11.aspnet",[656,730,791,869,927,941,967,1057,1111,1182,1212,1289,1346],{"title":657,"icon":658,"path":659,"stem":660,"children":661,"page":59},"Minimal API","i-lucide-network","\u002Fcsharp\u002Faspnet\u002Fminimal-api","01.csharp\u002F11.aspnet\u002F01.minimal-api",[662,666,670,674,678,682,686,690,694,698,702,706,710,714,718,722,726],{"title":663,"path":664,"stem":665},"Вступ до ASP.NET та еволюція фреймворку","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fintroduction","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F01.introduction",{"title":667,"path":668,"stem":669},"Перший додаток на ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Ffirst-application","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F02.first-application",{"title":671,"path":672,"stem":673},"WebApplication, Builder та Dependency Injection","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fwebapplication-builder","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F03.webapplication-builder",{"title":675,"path":676,"stem":677},"Конвеєр запитів та Middleware","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frequest-pipeline-middleware","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F04.request-pipeline-middleware",{"title":679,"path":680,"stem":681},"Маршрутизація в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frouting-basics","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F05.routing-basics",{"title":683,"path":684,"stem":685},"Маршрутизація в ASP.NET Core: Розширені можливості","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frouting-advanced","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F06.routing-advanced",{"title":687,"path":688,"stem":689},"Статичні файли в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstatic-files","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F07.static-files",{"title":691,"path":692,"stem":693},"Статичні Активи: MapStaticAssets (ASP.NET Core 9.0)","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstatic-assets","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F08.static-assets",{"title":695,"path":696,"stem":697},"Конфігурація в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fconfiguration-fundamentals","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F09.configuration-fundamentals",{"title":699,"path":700,"stem":701},"Конфігурація: Паттерн Options","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fconfiguration-options","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F10.configuration-options",{"title":703,"path":704,"stem":705},"Логування в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Flogging-basics","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F11.logging-basics",{"title":707,"path":708,"stem":709},"Логування: Serilog та Middleware","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Flogging-advanced","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F12.logging-advanced",{"title":711,"path":712,"stem":713},"Управління станом: HttpContext.Items та Cookies","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstate-management","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F13.state-management",{"title":715,"path":716,"stem":717},"Стан сесії: Sessions","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fsession-state","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F14.session-state",{"title":719,"path":720,"stem":721},"Структура проєкту: від хаосу до архітектури","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fproject-structure","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F15.project-structure",{"title":723,"path":724,"stem":725},"Scalar у Minimal API: повний проєкт і Fluent OpenAPI","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fscalar-openapi-fluent","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F16.scalar-openapi-fluent",{"title":727,"path":728,"stem":729},"Swagger \u002F Swashbuckle у Minimal API: окремий класичний шлях","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fswagger-swashbuckle","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F17.swagger-swashbuckle",{"title":731,"icon":658,"path":732,"stem":733,"children":734,"page":59},"API","\u002Fcsharp\u002Faspnet\u002Fapi","01.csharp\u002F11.aspnet\u002F02.api",[735,739,743,747,751,755,759,763,767,771,775,779,783,787],{"title":736,"path":737,"stem":738},"Що таке API. Клієнт-серверна архітектура","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fwhat-is-api","01.csharp\u002F11.aspnet\u002F02.api\u002F01.what-is-api",{"title":740,"path":741,"stem":742},"Формати даних: JSON, XML, TOML та бінарні формати","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fdata-formats","01.csharp\u002F11.aspnet\u002F02.api\u002F02.data-formats",{"title":744,"path":745,"stem":746},"Парадигми API та концепція REST","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-paradigms-rest","01.csharp\u002F11.aspnet\u002F02.api\u002F03.api-paradigms-rest",{"title":748,"path":749,"stem":750},"HTTP-методи, статус-коди та заголовки","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fhttp-methods-status-codes","01.csharp\u002F11.aspnet\u002F02.api\u002F04.http-methods-status-codes",{"title":752,"path":753,"stem":754},"Організація HTTP API за принципами REST","\u002Fcsharp\u002Faspnet\u002Fapi\u002Frest-organizing","01.csharp\u002F11.aspnet\u002F02.api\u002F05.rest-organizing",{"title":756,"path":757,"stem":758},"Номенклатура URL та CRUD-операції","\u002Fcsharp\u002Faspnet\u002Fapi\u002Furl-nomenclature-crud","01.csharp\u002F11.aspnet\u002F02.api\u002F06.url-nomenclature-crud",{"title":760,"path":761,"stem":762},"Правила дизайну: іменування та стандарти","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-naming","01.csharp\u002F11.aspnet\u002F02.api\u002F07.api-design-naming",{"title":764,"path":765,"stem":766},"Валідація, ліміти та обробка помилок","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-validation","01.csharp\u002F11.aspnet\u002F02.api\u002F08.api-design-validation",{"title":768,"path":769,"stem":770},"Обробка помилок у Minimal API","\u002Fcsharp\u002Faspnet\u002Fapi\u002Ferror-handling-http","01.csharp\u002F11.aspnet\u002F02.api\u002F09.error-handling-http",{"title":772,"path":773,"stem":774},"Ідемпотентність та синхронізація стану","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fidempotency-sync","01.csharp\u002F11.aspnet\u002F02.api\u002F10.idempotency-sync",{"title":776,"path":777,"stem":778},"Пагінація та організація списків","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fpagination-lists","01.csharp\u002F11.aspnet\u002F02.api\u002F11.pagination-lists",{"title":780,"path":781,"stem":782},"Безпека API, кешування та інтернаціоналізація","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fsecurity-auth","01.csharp\u002F11.aspnet\u002F02.api\u002F12.security-auth",{"title":784,"path":785,"stem":786},"Процес проєктування API та документування","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-process","01.csharp\u002F11.aspnet\u002F02.api\u002F13.api-design-process",{"title":788,"path":789,"stem":790},"OpenAPI: контракт, специфікація та документація API","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fopenapi","01.csharp\u002F11.aspnet\u002F02.api\u002F14.openapi",{"title":792,"icon":793,"path":794,"stem":795,"children":796,"page":59},"Auth","i-lucide-shield-check","\u002Fcsharp\u002Faspnet\u002Fauth","01.csharp\u002F11.aspnet\u002F03.auth",[797,801,805,809,813,817,821,825,829,833,837,841,845,849,853,857,861,865],{"title":798,"path":799,"stem":800},"Основи аутентифікації та авторизації","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fauth-fundamentals","01.csharp\u002F11.aspnet\u002F03.auth\u002F01.auth-fundamentals",{"title":802,"path":803,"stem":804},"JWT-аутентифікація","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fjwt-authentication","01.csharp\u002F11.aspnet\u002F03.auth\u002F02.jwt-authentication",{"title":806,"path":807,"stem":808},"Авторизація: ролі, політики та resource-based доступ","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fauthorization-policies","01.csharp\u002F11.aspnet\u002F03.auth\u002F03.authorization-policies",{"title":810,"path":811,"stem":812},"Cookie-аутентифікація та ASP.NET Core Identity","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fcookie-auth-identity","01.csharp\u002F11.aspnet\u002F03.auth\u002F04.cookie-auth-identity",{"title":814,"path":815,"stem":816},"JWT + Refresh Tokens (HttpOnly Cookie)","\u002Fcsharp\u002Faspnet\u002Fauth\u002F04b.identity-auth-jwt","01.csharp\u002F11.aspnet\u002F03.auth\u002F04b.identity-auth-jwt",{"title":818,"path":819,"stem":820},"Identity: Підтвердження Email та Скидання Пароля","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-email-confirmation","01.csharp\u002F11.aspnet\u002F03.auth\u002F05.identity-email-confirmation",{"title":822,"path":823,"stem":824},"Identity: Двофакторна Аутентифікація (2FA)","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-two-factor","01.csharp\u002F11.aspnet\u002F03.auth\u002F06.identity-two-factor",{"title":826,"path":827,"stem":828},"Identity: Внутрішня Архітектура та Кастомізація","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-internals","01.csharp\u002F11.aspnet\u002F03.auth\u002F07.identity-internals",{"title":830,"path":831,"stem":832},"OAuth 2.0 та зовнішні провайдери","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foauth-external-providers","01.csharp\u002F11.aspnet\u002F03.auth\u002F08.oauth-external-providers",{"title":834,"path":835,"stem":836},"Безпека на практиці: CORS, HTTPS та захист від атак","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fsecurity-hardening","01.csharp\u002F11.aspnet\u002F03.auth\u002F09.security-hardening",{"title":838,"path":839,"stem":840},"Теорія OAuth 2.0: Поняття, Аналогії та Флоу","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foauth-theory","01.csharp\u002F11.aspnet\u002F03.auth\u002F10.oauth-theory",{"title":842,"path":843,"stem":844},"OIDC, OAuth 2.0 та Keycloak в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foidc-keycloak","01.csharp\u002F11.aspnet\u002F03.auth\u002F10.oidc-keycloak",{"title":846,"path":847,"stem":848},"API Keys аутентифікація в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fapi-keys","01.csharp\u002F11.aspnet\u002F03.auth\u002F11.api-keys",{"title":850,"path":851,"stem":852},"Rate Limiting та Throttling в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frate-limiting","01.csharp\u002F11.aspnet\u002F03.auth\u002F12.rate-limiting",{"title":854,"path":855,"stem":856},"Refresh Token Rotation в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frefresh-token-rotation","01.csharp\u002F11.aspnet\u002F03.auth\u002F13.refresh-token-rotation",{"title":858,"path":859,"stem":860},"Certificate Authentication та mTLS в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fcertificate-auth","01.csharp\u002F11.aspnet\u002F03.auth\u002F14.certificate-auth",{"title":862,"path":863,"stem":864},"RBAC, ABAC та ReBAC в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frbac-abac-rebac","01.csharp\u002F11.aspnet\u002F03.auth\u002F15.rbac-abac-rebac",{"title":866,"path":867,"stem":868},"Multi-tenancy та ізоляція даних в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fmulti-tenancy","01.csharp\u002F11.aspnet\u002F03.auth\u002F16.multi-tenancy",{"title":870,"icon":871,"path":872,"stem":873,"children":874,"page":59},"Нотифікації","i-lucide-bell","\u002Fcsharp\u002Faspnet\u002Fnotifications","01.csharp\u002F11.aspnet\u002F04.notifications",[875,879,883,887,891,895,899,903,907,911,915,919,923],{"title":876,"path":877,"stem":878},"In-App нотифікації через базу даних","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fin-app-database-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F01.in-app-database-notifications",{"title":880,"path":881,"stem":882},"Polling: Регулярний запит оновлень","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fpolling","01.csharp\u002F11.aspnet\u002F04.notifications\u002F02.polling",{"title":884,"path":885,"stem":886},"Server-Sent Events: Однострімовий push від сервера","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fserver-sent-events","01.csharp\u002F11.aspnet\u002F04.notifications\u002F03.server-sent-events",{"title":888,"path":889,"stem":890},"WebSockets: Двостороннє з'єднання в реальному часі","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fwebsockets","01.csharp\u002F11.aspnet\u002F04.notifications\u002F04.websockets",{"title":892,"path":893,"stem":894},"SignalR: Абстракція над транспортами реального часу","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fsignalr","01.csharp\u002F11.aspnet\u002F04.notifications\u002F05.signalr",{"title":896,"path":897,"stem":898},"Background Services: Фонові задачі в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fbackground-services","01.csharp\u002F11.aspnet\u002F04.notifications\u002F06.background-services",{"title":900,"path":901,"stem":902},"Web Push нотифікації","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fweb-push","01.csharp\u002F11.aspnet\u002F04.notifications\u002F07.web-push",{"title":904,"path":905,"stem":906},"Email нотифікації","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Femail-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F08.email-notifications",{"title":908,"path":909,"stem":910},"Порівняння підходів: Як вибрати правильну технологію нотифікацій","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fchoosing-the-right-approach","01.csharp\u002F11.aspnet\u002F04.notifications\u002F09.choosing-the-right-approach",{"title":912,"path":913,"stem":914},"Hangfire: Надійне планування фонових задач","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire","01.csharp\u002F11.aspnet\u002F04.notifications\u002F10.hangfire",{"title":916,"path":917,"stem":918},"Практика: Конвертація зображень у WebP через Hangfire","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire-image-webp","01.csharp\u002F11.aspnet\u002F04.notifications\u002F11.hangfire-image-webp",{"title":920,"path":921,"stem":922},"Практика: Підготовка відео до HLS-стрімінгу через Hangfire","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire-video-hls","01.csharp\u002F11.aspnet\u002F04.notifications\u002F12.hangfire-video-hls",{"title":924,"path":925,"stem":926},"Telegram-нотифікації: від одного повідомлення до масових розсилок і мульти-канального підходу","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Ftelegram-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F13.telegram-notifications",{"title":928,"icon":929,"path":930,"stem":931,"children":932,"page":59},"Інтернаціоналізація","i-lucide-languages","\u002Fcsharp\u002Faspnet\u002Fi18n","01.csharp\u002F11.aspnet\u002F05.i18n",[933,937],{"title":934,"path":935,"stem":936},"Інтернаціоналізація (i18n) у Minimal API: від A до Я","\u002Fcsharp\u002Faspnet\u002Fi18n\u002Finternationalization","01.csharp\u002F11.aspnet\u002F05.i18n\u002F01.internationalization",{"title":938,"path":939,"stem":940},"Humanizer: людиномовні рядки у .NET","\u002Fcsharp\u002Faspnet\u002Fi18n\u002Fhumanizer","01.csharp\u002F11.aspnet\u002F05.i18n\u002F02.humanizer",{"title":942,"icon":943,"path":944,"stem":945,"children":946,"page":59},"Кешування","i-lucide-layers","\u002Fcsharp\u002Faspnet\u002Fcaching","01.csharp\u002F11.aspnet\u002F06.caching",[947,951,955,959,963],{"title":948,"path":949,"stem":950},"Огляд кешування: чотири рівні і коли що обирати","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fcaching","01.csharp\u002F11.aspnet\u002F06.caching\u002F01.caching",{"title":952,"path":953,"stem":954},"IMemoryCache: кеш в оперативній пам'яті","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fmemory-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F02.memory-cache",{"title":956,"path":957,"stem":958},"IDistributedCache і Redis: розподілений кеш","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fdistributed-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F03.distributed-cache",{"title":960,"path":961,"stem":962},"Response Cache: HTTP-кешування через Cache-Control","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fresponse-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F04.response-cache",{"title":964,"path":965,"stem":966},"Output Cache: серверний кеш HTTP-відповідей (.NET 7+)","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Foutput-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F05.output-cache",{"title":968,"icon":969,"path":970,"stem":971,"children":972,"page":59},"Тестування","i-lucide-test-tube","\u002Fcsharp\u002Faspnet\u002Ftesting","01.csharp\u002F11.aspnet\u002F07.testing",[973,977,981,985,989,993,997,1001,1005,1009,1013,1017,1021,1025,1029,1033,1037,1041,1045,1049,1053],{"title":974,"path":975,"stem":976},"Що таке тестування? Від інтуїції до науки","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwhat-is-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F01.what-is-testing",{"title":978,"path":979,"stem":980},"Піраміда тестування — Стратегія, а не Догма","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-pyramid","01.csharp\u002F11.aspnet\u002F07.testing\u002F02.testing-pyramid",{"title":982,"path":983,"stem":984},"Дві Школи Тестування — Лондон проти Детройту","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-schools","01.csharp\u002F11.aspnet\u002F07.testing\u002F03.testing-schools",{"title":986,"path":987,"stem":988},"TDD та BDD — Тести як Дизайн-інструмент","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftdd-and-bdd","01.csharp\u002F11.aspnet\u002F07.testing\u002F04.tdd-and-bdd",{"title":990,"path":991,"stem":992},"Що саме тестувати — Техніки аналізу та Циклomatична складність","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwhat-to-test","01.csharp\u002F11.aspnet\u002F07.testing\u002F05.what-to-test",{"title":994,"path":995,"stem":996},"Тестові Фреймворки — Навіщо вони і що всередині","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftest-frameworks","01.csharp\u002F11.aspnet\u002F07.testing\u002F06.test-frameworks",{"title":998,"path":999,"stem":1000},"xUnit — Факти, Теорії та Lifecycle тестів","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fxunit-basics","01.csharp\u002F11.aspnet\u002F07.testing\u002F07.xunit-basics",{"title":1002,"path":1003,"stem":1004},"xUnit Advanced — Fixtures, Кастомізація та Розширення","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fxunit-advanced","01.csharp\u002F11.aspnet\u002F07.testing\u002F08.xunit-advanced",{"title":1006,"path":1007,"stem":1008},"Moq — Глибоке занурення в мокування","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fmocking-with-moq","01.csharp\u002F11.aspnet\u002F07.testing\u002F09.mocking-with-moq",{"title":1010,"path":1011,"stem":1012},"Тестування Баз Даних — EF Core, SQLite та Testcontainers","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fdatabase-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F10.database-testing",{"title":1014,"path":1015,"stem":1016},"Integration Testing — Частина 1 [Теорія та WebApplicationFactory]","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fintegration-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F11.integration-testing",{"title":1018,"path":1019,"stem":1020},"Інтеграційне тестування — Практика","\u002Fcsharp\u002Faspnet\u002Ftesting\u002F11a.integration-testing-practice","01.csharp\u002F11.aspnet\u002F07.testing\u002F11a.integration-testing-practice",{"title":1022,"path":1023,"stem":1024},"Integration Testing — Частина 2 [Просунуті Сценарії та Testcontainers]","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fintegration-testing-advanced","01.csharp\u002F11.aspnet\u002F07.testing\u002F12.integration-testing-advanced",{"title":1026,"path":1027,"stem":1028},"Професійний Postman: Колекції, Змінні та GitHub Інтеграція","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fpostman-professional","01.csharp\u002F11.aspnet\u002F07.testing\u002F13.postman-professional",{"title":1030,"path":1031,"stem":1032},"HttpClient у Тестах Частина 1: Архітектура та MockHttpMessageHandler","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fhttpclient-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F14.httpclient-testing",{"title":1034,"path":1035,"stem":1036},"HttpClient у Тестах Частина 2: WireMock.Net та Resilience","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwiremock-net","01.csharp\u002F11.aspnet\u002F07.testing\u002F15.wiremock-net",{"title":1038,"path":1039,"stem":1040},"Патерни та Анти-патерни Тестування: Test Smells","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-patterns","01.csharp\u002F11.aspnet\u002F07.testing\u002F16.testing-patterns",{"title":1042,"path":1043,"stem":1044},"Просунуті інструменти: Time, Snapshots та Властивості","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fadvanced-testing-tools","01.csharp\u002F11.aspnet\u002F07.testing\u002F17.advanced-testing-tools",{"title":1046,"path":1047,"stem":1048},"Тестування Архітектури з NetArchTest","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Farchitecture-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F18.architecture-testing",{"title":1050,"path":1051,"stem":1052},"Тестування Продуктивності: BenchmarkDotNet, NBomber та k6","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fperformance-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F19.performance-testing",{"title":1054,"path":1055,"stem":1056},"Залишок плану для курсу \"Тестування ASP.NET Minimal API\"","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fremaining_plan","01.csharp\u002F11.aspnet\u002F07.testing\u002Fremaining_plan",{"title":1058,"icon":1059,"path":1060,"stem":1061,"children":1062,"page":59},"Платежі","i-lucide-credit-card","\u002Fcsharp\u002Faspnet\u002Fpayments","01.csharp\u002F11.aspnet\u002F08.payments",[1063,1067,1071,1075,1079,1083,1087,1091,1095,1099,1103,1107],{"title":1064,"path":1065,"stem":1066},"Основи платіжної інфраструктури","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-fundamentals","01.csharp\u002F11.aspnet\u002F08.payments\u002F01.payment-fundamentals",{"title":1068,"path":1069,"stem":1070},"Методи оплати в Україні","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-methods-ukraine","01.csharp\u002F11.aspnet\u002F08.payments\u002F02.payment-methods-ukraine",{"title":1072,"path":1073,"stem":1074},"PCI DSS та безпека платежів","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpci-dss-security","01.csharp\u002F11.aspnet\u002F08.payments\u002F03.pci-dss-security",{"title":1076,"path":1077,"stem":1078},"Архітектура платіжної підсистеми","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-architecture","01.csharp\u002F11.aspnet\u002F08.payments\u002F04.payment-architecture",{"title":1080,"path":1081,"stem":1082},"Інтеграція LiqPay (ПриватБанк)","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fliqpay-integration","01.csharp\u002F11.aspnet\u002F08.payments\u002F05.liqpay-integration",{"title":1084,"path":1085,"stem":1086},"Інтеграція Monobank Acquiring API","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fmonobank-acquiring","01.csharp\u002F11.aspnet\u002F08.payments\u002F06.monobank-acquiring",{"title":1088,"path":1089,"stem":1090},"Інтеграція Stripe","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fstripe-integration","01.csharp\u002F11.aspnet\u002F08.payments\u002F07.stripe-integration",{"title":1092,"path":1093,"stem":1094},"Webhooks — глибоке занурення","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fwebhooks-deep-dive","01.csharp\u002F11.aspnet\u002F08.payments\u002F08.webhooks-deep-dive",{"title":1096,"path":1097,"stem":1098},"Підписки та рекурентні платежі","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fsubscriptions-recurring","01.csharp\u002F11.aspnet\u002F08.payments\u002F09.subscriptions-recurring",{"title":1100,"path":1101,"stem":1102},"Повернення коштів та диспути","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Frefunds-disputes","01.csharp\u002F11.aspnet\u002F08.payments\u002F10.refunds-disputes",{"title":1104,"path":1105,"stem":1106},"Тестування платіжних інтеграцій","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Ftesting-payments","01.csharp\u002F11.aspnet\u002F08.payments\u002F11.testing-payments",{"title":1108,"path":1109,"stem":1110},"Чекліст виходу в Production","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fproduction-checklist","01.csharp\u002F11.aspnet\u002F08.payments\u002F12.production-checklist",{"title":1112,"icon":1113,"items":1114,"path":1127,"stem":1128,"children":1129,"page":59},"Популярні бібліотеки","lucide:box",[1115,1116,1117,1118,1119,1120,1121,1122,1123,1124,1125,1126],"01.fluent-validation","02.mapster","03.erroror-result-pattern","04.serilog","05.mediatr","06.polly","07.health-checks","08.feature-management","09.fluent-email","10.quest-pdf","11.bogus","12.humanizer-guard","\u002Fcsharp\u002Faspnet\u002Flibraries","01.csharp\u002F11.aspnet\u002F09.libraries",[1130,1134,1138,1142,1146,1150,1154,1158,1162,1166,1170,1174,1178],{"title":1131,"path":1132,"stem":1133},"Валідація з FluentValidation в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffluent-validation","01.csharp\u002F11.aspnet\u002F09.libraries\u002F01.fluent-validation",{"title":1135,"path":1136,"stem":1137},"Маппінг об","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fmapster","01.csharp\u002F11.aspnet\u002F09.libraries\u002F02.mapster",{"title":1139,"path":1140,"stem":1141},"Обробка помилок з ErrorOr та Result Pattern в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ferroror-result-pattern","01.csharp\u002F11.aspnet\u002F09.libraries\u002F03.erroror-result-pattern",{"title":1143,"path":1144,"stem":1145},"Структуроване логування з Serilog в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fserilog","01.csharp\u002F11.aspnet\u002F09.libraries\u002F04.serilog",{"title":1147,"path":1148,"stem":1149},"CQRS та Mediator з MediatR в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fmediatr","01.csharp\u002F11.aspnet\u002F09.libraries\u002F05.mediatr",{"title":1151,"path":1152,"stem":1153},"Відмовостійкість з Polly в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fpolly","01.csharp\u002F11.aspnet\u002F09.libraries\u002F06.polly",{"title":1155,"path":1156,"stem":1157},"Health Checks в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fhealth-checks","01.csharp\u002F11.aspnet\u002F09.libraries\u002F07.health-checks",{"title":1159,"path":1160,"stem":1161},"Feature Management та Feature Flags в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffeature-management","01.csharp\u002F11.aspnet\u002F09.libraries\u002F08.feature-management",{"title":1163,"path":1164,"stem":1165},"Відправка Email з FluentEmail в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffluent-email","01.csharp\u002F11.aspnet\u002F09.libraries\u002F09.fluent-email",{"title":1167,"path":1168,"stem":1169},"Генерація PDF з QuestPDF в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fquest-pdf","01.csharp\u002F11.aspnet\u002F09.libraries\u002F10.quest-pdf",{"title":1171,"path":1172,"stem":1173},"Генерація тестових даних з Bogus в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fbogus","01.csharp\u002F11.aspnet\u002F09.libraries\u002F11.bogus",{"title":1175,"path":1176,"stem":1177},"Humanizer та Guard Clauses в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fhumanizer-guard","01.csharp\u002F11.aspnet\u002F09.libraries\u002F12.humanizer-guard",{"title":1179,"path":1180,"stem":1181},"План модуля 10.libraries — Популярні бібліотеки ASP.NET","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fplan","01.csharp\u002F11.aspnet\u002F09.libraries\u002Fplan",{"title":1183,"icon":1184,"path":1185,"stem":1186,"children":1187,"page":59},"Razor Pages","i-lucide-layout-template","\u002Fcsharp\u002Faspnet\u002Frazor-pages","01.csharp\u002F11.aspnet\u002F10.razor-pages",[1188,1192,1196,1200,1204,1208],{"title":1189,"path":1190,"stem":1191},"Від Minimal API до Razor Pages: концептуальний перехід","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Ffrom-minimal-api","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F01.from-minimal-api",{"title":1193,"path":1194,"stem":1195},"PageModel: логіка сторінки Razor Pages","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fpage-model","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F02.page-model",{"title":1197,"path":1198,"stem":1199},"Razor синтаксис: шаблонізатор у .cshtml","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Frazor-syntax","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F03.razor-syntax",{"title":1201,"path":1202,"stem":1203},"Tag Helpers: типізований HTML","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Ftag-helpers","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F04.tag-helpers",{"title":1205,"path":1206,"stem":1207},"Форми і валідація: повний цикл обробки даних","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fforms-validation","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F05.forms-validation",{"title":1209,"path":1210,"stem":1211},"Практичний проєкт: TaskManager на Razor Pages","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fproject-task-manager","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F06.project-task-manager",{"title":1213,"path":1214,"stem":1215,"children":1216,"page":59},"ASP.NET Core MVC","\u002Fcsharp\u002Faspnet\u002Fmvc","01.csharp\u002F11.aspnet\u002F11.mvc",[1217,1221,1225,1229,1233,1237,1241,1245,1249,1253,1257,1261,1265,1269,1273,1277,1281,1285],{"title":1218,"path":1219,"stem":1220},"Патерн MVC: архітектура, що змінила веб","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmvc-pattern","01.csharp\u002F11.aspnet\u002F11.mvc\u002F01.mvc-pattern",{"title":1222,"path":1223,"stem":1224},"Від Razor Pages до MVC: концептуальний перехід","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffrom-razor-pages","01.csharp\u002F11.aspnet\u002F11.mvc\u002F02.from-razor-pages",{"title":1226,"path":1227,"stem":1228},"Controllers та Actions: серце MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fcontrollers-actions","01.csharp\u002F11.aspnet\u002F11.mvc\u002F03.controllers-actions",{"title":1230,"path":1231,"stem":1232},"Маршрутизація в MVC: Convention vs Attribute Routing","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Frouting-mvc","01.csharp\u002F11.aspnet\u002F11.mvc\u002F04.routing-mvc",{"title":1234,"path":1235,"stem":1236},"Model Binding: від HTTP до C#","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmodel-binding","01.csharp\u002F11.aspnet\u002F11.mvc\u002F05.model-binding",{"title":1238,"path":1239,"stem":1240},"Views, ViewData, ViewBag, TempData і ViewModel","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fviews-viewdata-tempdata","01.csharp\u002F11.aspnet\u002F11.mvc\u002F06.views-viewdata-tempdata",{"title":1242,"path":1243,"stem":1244},"Filters: аспектно-орієнтоване програмування в MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffilters","01.csharp\u002F11.aspnet\u002F11.mvc\u002F07.filters",{"title":1246,"path":1247,"stem":1248},"Areas: структурування великих застосунків","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fareas","01.csharp\u002F11.aspnet\u002F11.mvc\u002F08.areas",{"title":1250,"path":1251,"stem":1252},"View Components: повторювані незалежні блоки UI","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fview-components","01.csharp\u002F11.aspnet\u002F11.mvc\u002F09.view-components",{"title":1254,"path":1255,"stem":1256},"Display та Editor Templates","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fdisplay-editor-templates","01.csharp\u002F11.aspnet\u002F11.mvc\u002F10.display-editor-templates",{"title":1258,"path":1259,"stem":1260},"Валідація: IValidatableObject та FluentValidation","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fvalidation-advanced","01.csharp\u002F11.aspnet\u002F11.mvc\u002F11.validation-advanced",{"title":1262,"path":1263,"stem":1264},"HTMX: інтерактивність через HTML-атрибути","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fhtmx","01.csharp\u002F11.aspnet\u002F11.mvc\u002F12.htmx",{"title":1266,"path":1267,"stem":1268},"HTMX у ASP.NET Core MVC: серверна інтеграція","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fajax-htmx-mvc","01.csharp\u002F11.aspnet\u002F11.mvc\u002F13.ajax-htmx-mvc",{"title":1270,"path":1271,"stem":1272},"Практичний проєкт: Каталог товарів з HTMX","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fhtmx-project","01.csharp\u002F11.aspnet\u002F11.mvc\u002F14.htmx-project",{"title":1274,"path":1275,"stem":1276},"Завантаження та обробка файлів","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffile-upload","01.csharp\u002F11.aspnet\u002F11.mvc\u002F15.file-upload",{"title":1278,"path":1279,"stem":1280},"Глобалізація та Локалізація MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fglobalization-localization","01.csharp\u002F11.aspnet\u002F11.mvc\u002F16.globalization-localization",{"title":1282,"path":1283,"stem":1284},"Підсумковий проєкт: Блог-платформа","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmvc-project","01.csharp\u002F11.aspnet\u002F11.mvc\u002F17.mvc-project",{"title":1286,"path":1287,"stem":1288},"План курсу: ASP.NET Core MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fplan","01.csharp\u002F11.aspnet\u002F11.mvc\u002Fplan",{"title":1290,"path":1291,"stem":1292,"children":1293,"page":59},"Web Api","\u002Fcsharp\u002Faspnet\u002Fweb-api","01.csharp\u002F11.aspnet\u002F12.web-api",[1294,1298,1302,1306,1310,1314,1318,1322,1326,1330,1334,1338,1342],{"title":1295,"path":1296,"stem":1297},"Від Minimal API до Controller-based API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Ffrom-minimal-api-to-controllers","01.csharp\u002F11.aspnet\u002F12.web-api\u002F01.from-minimal-api-to-controllers",{"title":1299,"path":1300,"stem":1301},"ControllerBase, ActionResult\u003CT> та Response Types","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fcontroller-base-actionresult","01.csharp\u002F11.aspnet\u002F12.web-api\u002F02.controller-base-actionresult",{"title":1303,"path":1304,"stem":1305},"Content Negotiation - JSON, XML та власні форматери","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fcontent-negotiation","01.csharp\u002F11.aspnet\u002F12.web-api\u002F03.content-negotiation",{"title":1307,"path":1308,"stem":1309},"Версіонування API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fapi-versioning","01.csharp\u002F11.aspnet\u002F12.web-api\u002F04.api-versioning",{"title":1311,"path":1312,"stem":1313},"ProblemDetails та структурована обробка помилок","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fproblemdetails-error-handling","01.csharp\u002F11.aspnet\u002F12.web-api\u002F05.problemdetails-error-handling",{"title":1315,"path":1316,"stem":1317},"Фільтри у Web API контексті","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Ffilters-for-api","01.csharp\u002F11.aspnet\u002F12.web-api\u002F06.filters-for-api",{"title":1319,"path":1320,"stem":1321},"Пагінація, фільтрація та сортування","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fpagination-filtering-sorting","01.csharp\u002F11.aspnet\u002F12.web-api\u002F07.pagination-filtering-sorting",{"title":1323,"path":1324,"stem":1325},"HATEOAS та Resource Expansion","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fhateoas-resource-expansion","01.csharp\u002F11.aspnet\u002F12.web-api\u002F08.hateoas-resource-expansion",{"title":1327,"path":1328,"stem":1329},"Гібридна архітектура - Minimal API + Controllers","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fminimal-api-vs-controllers-hybrid","01.csharp\u002F11.aspnet\u002F12.web-api\u002F09.minimal-api-vs-controllers-hybrid",{"title":1331,"path":1332,"stem":1333},"Документація API - Swashbuckle, NSwag та генерація клієнтів","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fapi-documentation-generation","01.csharp\u002F11.aspnet\u002F12.web-api\u002F10.api-documentation-generation",{"title":1335,"path":1336,"stem":1337},"Health Checks та моніторинг API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fhealth-checks-monitoring","01.csharp\u002F11.aspnet\u002F12.web-api\u002F11.health-checks-monitoring",{"title":1339,"path":1340,"stem":1341},"Підсумковий проєкт - Production-Ready REST API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fweb-api-project","01.csharp\u002F11.aspnet\u002F12.web-api\u002F12.web-api-project",{"title":1343,"path":1344,"stem":1345},"План курсу: ASP.NET Core Web API (Controllers)","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fplan","01.csharp\u002F11.aspnet\u002F12.web-api\u002Fplan",{"title":1347,"icon":1348,"path":1349,"stem":1350,"children":1351,"page":59},"Моніторинг","i-lucide-activity","\u002Fcsharp\u002Faspnet\u002Fmonitoring","01.csharp\u002F11.aspnet\u002F13.monitoring",[1352,1356,1360],{"title":1353,"path":1354,"stem":1355},"Спостережуваність: від console.log до production-систем","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fobservability-intro","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F01.observability-intro",{"title":1357,"path":1358,"stem":1359},"Health Checks: перший рівень observability","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fhealth-checks","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F02.health-checks",{"title":1361,"path":1362,"stem":1363},"Вбудовані метрики .NET 10 та System.Diagnostics.Metrics","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fdotnet-metrics","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F03.dotnet-metrics",{"title":1365,"icon":1366,"path":1367,"stem":1368,"children":1369,"page":59},"Desktop UI","i-lucide-app-window","\u002Fcsharp\u002Fdesktop-ui","01.csharp\u002F12.desktop-ui",[1370,1374,1378,1382,1386,1390,1394,1398,1402,1406,1410,1414,1418,1422,1426,1430,1434,1438,1442,1446,1450,1454,1458,1462,1466,1470,1474,1478,1482,1486,1490,1494,1498,1502,1506,1510,1514,1518,1522,1526,1530,1534,1538,1542,1546,1550,1554,1558,1562,1566,1570,1574,1578,1582,1586,1590,1594,1598,1602,1606,1610,1614,1618,1622,1626,1630,1634,1638,1642,1646,1650],{"title":1371,"path":1372,"stem":1373},"Що таке десктопна розробка?","\u002Fcsharp\u002Fdesktop-ui\u002Fwhat-is-desktop-dev","01.csharp\u002F12.desktop-ui\u002F01.what-is-desktop-dev",{"title":1375,"path":1376,"stem":1377},"Архітектура WPF — як влаштований графічний інтерфейс","\u002Fcsharp\u002Fdesktop-ui\u002Fwpf-architecture","01.csharp\u002F12.desktop-ui\u002F02.wpf-architecture",{"title":1379,"path":1380,"stem":1381},"Перший WPF-проєкт — від нуля до вікна","\u002Fcsharp\u002Fdesktop-ui\u002Ffirst-wpf-app","01.csharp\u002F12.desktop-ui\u002F03.first-wpf-app",{"title":1383,"path":1384,"stem":1385},"Перший Avalonia-проєкт: WPF для всіх платформ","\u002Fcsharp\u002Fdesktop-ui\u002F03a.first-avalonia-app","01.csharp\u002F12.desktop-ui\u002F03a.first-avalonia-app",{"title":1387,"path":1388,"stem":1389},"XAML: декларативний інтерфейс","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-basics","01.csharp\u002F12.desktop-ui\u002F04.xaml-basics",{"title":1391,"path":1392,"stem":1393},"Fluent UI у WPF — сучасний дизайн Windows 11","\u002Fcsharp\u002Fdesktop-ui\u002F04a.wpf-fluent-ui","01.csharp\u002F12.desktop-ui\u002F04a.wpf-fluent-ui",{"title":1395,"path":1396,"stem":1397},"WPF UI — сучасна бібліотека Fluent контролів","\u002Fcsharp\u002Fdesktop-ui\u002F04b.wpf-ui-library","01.csharp\u002F12.desktop-ui\u002F04b.wpf-ui-library",{"title":1399,"path":1400,"stem":1401},"HandyControl — велика бібліотека UI контролів для WPF","\u002Fcsharp\u002Fdesktop-ui\u002F04c.handycontrol-library","01.csharp\u002F12.desktop-ui\u002F04c.handycontrol-library",{"title":1403,"path":1404,"stem":1405},"Простори імен та ресурси XAML","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-namespaces-resources","01.csharp\u002F12.desktop-ui\u002F05.xaml-namespaces-resources",{"title":1407,"path":1408,"stem":1409},"XAML в Avalonia: ключові відмінності від WPF","\u002Fcsharp\u002Fdesktop-ui\u002F05a.avalonia-xaml-differences","01.csharp\u002F12.desktop-ui\u002F05a.avalonia-xaml-differences",{"title":1411,"path":1412,"stem":1413},"Розширення розмітки XAML (Markup Extensions)","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-markup-extensions","01.csharp\u002F12.desktop-ui\u002F06.xaml-markup-extensions",{"title":1415,"path":1416,"stem":1417},"Панелі Layout: StackPanel, WrapPanel, DockPanel","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-panels-part1","01.csharp\u002F12.desktop-ui\u002F07.layout-panels-part1",{"title":1419,"path":1420,"stem":1421},"Grid, Canvas, UniformGrid","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-panels-part2","01.csharp\u002F12.desktop-ui\u002F07.layout-panels-part2",{"title":1423,"path":1424,"stem":1425},"Просунуті техніки Layout","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-advanced","01.csharp\u002F12.desktop-ui\u002F08.layout-advanced",{"title":1427,"path":1428,"stem":1429},"Адаптивний Layout та найкращі практики","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-responsive","01.csharp\u002F12.desktop-ui\u002F09.layout-responsive",{"title":1431,"path":1432,"stem":1433},"Layout в Avalonia: відмінності та нові можливості","\u002Fcsharp\u002Fdesktop-ui\u002F09a.layout-avalonia","01.csharp\u002F12.desktop-ui\u002F09a.layout-avalonia",{"title":1435,"path":1436,"stem":1437},"Button, Image, ProgressBar та інші базові контроли","\u002Fcsharp\u002Fdesktop-ui\u002Fbasic-controls","01.csharp\u002F12.desktop-ui\u002F10.basic-controls",{"title":1439,"path":1440,"stem":1441},"Контроли в Avalonia: відмінності від WPF","\u002Fcsharp\u002Fdesktop-ui\u002F10a.controls-avalonia","01.csharp\u002F12.desktop-ui\u002F10a.controls-avalonia",{"title":1443,"path":1444,"stem":1445},"Текстові контроли — TextBlock, TextBox, RichTextBox","\u002Fcsharp\u002Fdesktop-ui\u002Ftext-controls","01.csharp\u002F12.desktop-ui\u002F11.text-controls",{"title":1447,"path":1448,"stem":1449},"Контроли вибору — CheckBox, RadioButton, ComboBox, ListBox, DatePicker","\u002Fcsharp\u002Fdesktop-ui\u002Fselection-controls","01.csharp\u002F12.desktop-ui\u002F12.selection-controls",{"title":1451,"path":1452,"stem":1453},"Content Model — GroupBox, Expander, TabControl, StatusBar","\u002Fcsharp\u002Fdesktop-ui\u002Fcontent-controls","01.csharp\u002F12.desktop-ui\u002F13.content-controls",{"title":1455,"path":1456,"stem":1457},"UI\u002FUX принципи десктопних застосунків","\u002Fcsharp\u002Fdesktop-ui\u002F13a.ui-ux-principles","01.csharp\u002F12.desktop-ui\u002F13a.ui-ux-principles",{"title":1459,"path":1460,"stem":1461},"Dependency Properties — Концепція та Value Resolution","\u002Fcsharp\u002Fdesktop-ui\u002Fdependency-properties-part1","01.csharp\u002F12.desktop-ui\u002F14.dependency-properties-part1",{"title":1463,"path":1464,"stem":1465},"Avalonia Property System — StyledProperty та DirectProperty","\u002Fcsharp\u002Fdesktop-ui\u002F14a.avalonia-property-system","01.csharp\u002F12.desktop-ui\u002F14a.avalonia-property-system",{"title":1467,"path":1468,"stem":1469},"Attached Properties — Властивості без меж","\u002Fcsharp\u002Fdesktop-ui\u002Fattached-properties","01.csharp\u002F12.desktop-ui\u002F15.attached-properties",{"title":1471,"path":1472,"stem":1473},"Routed Events — Маршрутизація подій у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Frouted-events","01.csharp\u002F12.desktop-ui\u002F16.routed-events",{"title":1475,"path":1476,"stem":1477},"Data Binding — Від Code-Behind до Декларативності","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-basics-part1","01.csharp\u002F12.desktop-ui\u002F17.data-binding-basics-part1",{"title":1479,"path":1480,"stem":1481},"INotifyPropertyChanged — Живе оновлення UI","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-basics-part2","01.csharp\u002F12.desktop-ui\u002F17.data-binding-basics-part2",{"title":1483,"path":1484,"stem":1485},"Compiled Bindings в Avalonia — Безпека на етапі компіляції","\u002Fcsharp\u002Fdesktop-ui\u002F17a.avalonia-compiled-bindings","01.csharp\u002F12.desktop-ui\u002F17a.avalonia-compiled-bindings",{"title":1487,"path":1488,"stem":1489},"Просунутий Data Binding — ElementName, RelativeSource, MultiBinding","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-advanced","01.csharp\u002F12.desktop-ui\u002F18.data-binding-advanced",{"title":1491,"path":1492,"stem":1493},"Value Converters — Перетворення типів даних у Data Binding","\u002Fcsharp\u002Fdesktop-ui\u002Fvalue-converters","01.csharp\u002F12.desktop-ui\u002F19.value-converters",{"title":1495,"path":1496,"stem":1497},"Data Templates — Візуалізація об'єктів у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-templates","01.csharp\u002F12.desktop-ui\u002F20.data-templates",{"title":1499,"path":1500,"stem":1501},"Collections Binding Part 1 — ObservableCollection та ItemsControl","\u002Fcsharp\u002Fdesktop-ui\u002Fcollections-binding-part1","01.csharp\u002F12.desktop-ui\u002F21.collections-binding-part1",{"title":1503,"path":1504,"stem":1505},"Collections Binding Part 2 — ICollectionView, Filtering, Sorting та Virtualization","\u002Fcsharp\u002Fdesktop-ui\u002Fcollections-binding-part2","01.csharp\u002F12.desktop-ui\u002F21.collections-binding-part2",{"title":1507,"path":1508,"stem":1509},"MVVM Pattern — Від Spaghetti Code до архітектури","\u002Fcsharp\u002Fdesktop-ui\u002Fmvvm-pattern","01.csharp\u002F12.desktop-ui\u002F22.mvvm-pattern",{"title":1511,"path":1512,"stem":1513},"ViewModel Implementation — Від BaseViewModel до валідації","\u002Fcsharp\u002Fdesktop-ui\u002Fviewmodel-implementation","01.csharp\u002F12.desktop-ui\u002F23.viewmodel-implementation",{"title":1515,"path":1516,"stem":1517},"Commands — Від event handlers до декларативних команд","\u002Fcsharp\u002Fdesktop-ui\u002Fcommands","01.csharp\u002F12.desktop-ui\u002F24.commands",{"title":1519,"path":1520,"stem":1521},"MVVM Toolkit — MVVM без boilerplate через Source Generators","\u002Fcsharp\u002Fdesktop-ui\u002Fmvvm-toolkit","01.csharp\u002F12.desktop-ui\u002F25.mvvm-toolkit",{"title":1523,"path":1524,"stem":1525},"Messenger Pattern — Комунікація між ViewModel без прямих посилань","\u002Fcsharp\u002Fdesktop-ui\u002Fmessenger-pattern","01.csharp\u002F12.desktop-ui\u002F26.messenger-pattern",{"title":1527,"path":1528,"stem":1529},"Стилі WPF — CSS для десктопу","\u002Fcsharp\u002Fdesktop-ui\u002Fstyles-basics","01.csharp\u002F12.desktop-ui\u002F27.styles-basics",{"title":1531,"path":1532,"stem":1533},"CSS-like стилі Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002F27a.avalonia-css-styling","01.csharp\u002F12.desktop-ui\u002F27a.avalonia-css-styling",{"title":1535,"path":1536,"stem":1537},"Control Templates — Частина 1. Концепція та TemplateBinding","\u002Fcsharp\u002Fdesktop-ui\u002Fcontrol-templates-part1","01.csharp\u002F12.desktop-ui\u002F28.control-templates-part1",{"title":1539,"path":1540,"stem":1541},"Control Templates — Частина 2. Named Parts та ContentPresenter","\u002Fcsharp\u002Fdesktop-ui\u002Fcontrol-templates-part2","01.csharp\u002F12.desktop-ui\u002F28.control-templates-part2",{"title":1543,"path":1544,"stem":1545},"Control Themes в Avalonia — нова ера стилізації","\u002Fcsharp\u002Fdesktop-ui\u002F28a.avalonia-control-themes","01.csharp\u002F12.desktop-ui\u002F28a.avalonia-control-themes",{"title":1547,"path":1548,"stem":1549},"Triggers та Visual State Manager у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Ftriggers-visual-states","01.csharp\u002F12.desktop-ui\u002F29.triggers-visual-states",{"title":1551,"path":1552,"stem":1553},"Pseudo-classes в Avalonia — замість WPF Triggers","\u002Fcsharp\u002Fdesktop-ui\u002F29a.avalonia-pseudo-classes","01.csharp\u002F12.desktop-ui\u002F29a.avalonia-pseudo-classes",{"title":1555,"path":1556,"stem":1557},"Теми та ресурсні словники у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fresources-themes","01.csharp\u002F12.desktop-ui\u002F30.resources-themes",{"title":1559,"path":1560,"stem":1561},"Avalonia Themes — Fluent Design та система тематизації","\u002Fcsharp\u002Fdesktop-ui\u002F30a.avalonia-themes-fluent","01.csharp\u002F12.desktop-ui\u002F30a.avalonia-themes-fluent",{"title":1563,"path":1564,"stem":1565},"Контроли колекцій — глибоке занурення","\u002Fcsharp\u002Fdesktop-ui\u002Fcollection-controls","01.csharp\u002F12.desktop-ui\u002F31.collection-controls",{"title":1567,"path":1568,"stem":1569},"DataGrid — колонки та базове відображення","\u002Fcsharp\u002Fdesktop-ui\u002Fdatagrid-part1","01.csharp\u002F12.desktop-ui\u002F32.datagrid-part1",{"title":1571,"path":1572,"stem":1573},"DataGrid — сортування, фільтрація, редагування","\u002Fcsharp\u002Fdesktop-ui\u002Fdatagrid-part2","01.csharp\u002F12.desktop-ui\u002F32.datagrid-part2",{"title":1575,"path":1576,"stem":1577},"TreeView та GridView","\u002Fcsharp\u002Fdesktop-ui\u002Ftreeview-listview","01.csharp\u002F12.desktop-ui\u002F33.treeview-listview",{"title":1579,"path":1580,"stem":1581},"Меню, Toolbar, ContextMenu, StatusBar","\u002Fcsharp\u002Fdesktop-ui\u002Fmenus-toolbars","01.csharp\u002F12.desktop-ui\u002F34.menus-toolbars",{"title":1583,"path":1584,"stem":1585},"Навігація та керування вікнами. Частина 1: вікна та сторінки","\u002Fcsharp\u002Fdesktop-ui\u002Fnavigation-windows-part1","01.csharp\u002F12.desktop-ui\u002F35.navigation-windows-part1",{"title":1587,"path":1588,"stem":1589},"Навігація та керування вікнами. Частина 2: MVVM-навігація","\u002Fcsharp\u002Fdesktop-ui\u002Fnavigation-windows-part2","01.csharp\u002F12.desktop-ui\u002F35.navigation-windows-part2",{"title":1591,"path":1592,"stem":1593},"Avalonia — Навігація та діалоги","\u002Fcsharp\u002Fdesktop-ui\u002F35a.avalonia-navigation-dialogs","01.csharp\u002F12.desktop-ui\u002F35a.avalonia-navigation-dialogs",{"title":1595,"path":1596,"stem":1597},"Діалоги та File Pickers у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fdialogs-file-pickers","01.csharp\u002F12.desktop-ui\u002F36.dialogs-file-pickers",{"title":1599,"path":1600,"stem":1601},"UserControl: компонентний підхід у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fuser-controls","01.csharp\u002F12.desktop-ui\u002F37.user-controls",{"title":1603,"path":1604,"stem":1605},"Custom Controls: Lookless Controls у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fcustom-controls","01.csharp\u002F12.desktop-ui\u002F38.custom-controls",{"title":1607,"path":1608,"stem":1609},"Avalonia TemplatedControl — Lookless Controls","\u002Fcsharp\u002Fdesktop-ui\u002F38a.avalonia-templated-controls","01.csharp\u002F12.desktop-ui\u002F38a.avalonia-templated-controls",{"title":1611,"path":1612,"stem":1613},"Анімації у WPF: Storyboard та Easing Functions","\u002Fcsharp\u002Fdesktop-ui\u002Fanimations-transitions","01.csharp\u002F12.desktop-ui\u002F39.animations-transitions",{"title":1615,"path":1616,"stem":1617},"Анімації в Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002F39a.avalonia-animations","01.csharp\u002F12.desktop-ui\u002F39a.avalonia-animations",{"title":1619,"path":1620,"stem":1621},"2D Графіка та Мультимедіа у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fmedia-graphics","01.csharp\u002F12.desktop-ui\u002F40.media-graphics",{"title":1623,"path":1624,"stem":1625},"Dependency Injection у WPF та Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002Fdi-integration","01.csharp\u002F12.desktop-ui\u002F41.di-integration",{"title":1627,"path":1628,"stem":1629},"SQLite та EF Core у десктопних додатках","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-persistence-part1","01.csharp\u002F12.desktop-ui\u002F42.data-persistence-part1",{"title":1631,"path":1632,"stem":1633},"Repository Pattern та Unit of Work","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-persistence-part2","01.csharp\u002F12.desktop-ui\u002F43.data-persistence-part2",{"title":1635,"path":1636,"stem":1637},"Тестування ViewModels","\u002Fcsharp\u002Fdesktop-ui\u002Fviewmodel-testing","01.csharp\u002F12.desktop-ui\u002F44.viewmodel-testing",{"title":1639,"path":1640,"stem":1641},"Avalonia Headless Testing — тестування UI без вікон","\u002Fcsharp\u002Fdesktop-ui\u002F44a.avalonia-headless-testing","01.csharp\u002F12.desktop-ui\u002F44a.avalonia-headless-testing",{"title":1643,"path":1644,"stem":1645},"Кросплатформна розробка з Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002Favalonia-cross-platform","01.csharp\u002F12.desktop-ui\u002F45.avalonia-cross-platform",{"title":1647,"path":1648,"stem":1649},"Пакування та розгортання Avalonia додатків","\u002Fcsharp\u002Fdesktop-ui\u002Favalonia-packaging-deployment","01.csharp\u002F12.desktop-ui\u002F46.avalonia-packaging-deployment",{"title":1651,"path":1652,"stem":1653},"Розгортання WPF застосунків","\u002Fcsharp\u002Fdesktop-ui\u002Fwpf-packaging-deployment","01.csharp\u002F12.desktop-ui\u002F47.wpf-packaging-deployment",{"title":1655,"icon":658,"path":1656,"stem":1657,"children":1658,"page":59},"Network Programming","\u002Fcsharp\u002Fnetwork-programming","01.csharp\u002F13.network-programming",[1659,1663,1667,1671,1675,1679,1683,1687,1691,1695,1699],{"title":1660,"path":1661,"stem":1662},"Основи комп'ютерних мереж","\u002Fcsharp\u002Fnetwork-programming\u002Ffoundations","01.csharp\u002F13.network-programming\u002F01.foundations",{"title":1664,"path":1665,"stem":1666},"Модель OSI та стек TCP\u002FIP","\u002Fcsharp\u002Fnetwork-programming\u002Fosi-model","01.csharp\u002F13.network-programming\u002F02.osi-model",{"title":1668,"path":1669,"stem":1670},"IP-протокол та адресація","\u002Fcsharp\u002Fnetwork-programming\u002Fip-addressing","01.csharp\u002F13.network-programming\u002F03.ip-addressing",{"title":1672,"path":1673,"stem":1674},"UDP — протокол без з'єднання","\u002Fcsharp\u002Fnetwork-programming\u002Fudp","01.csharp\u002F13.network-programming\u002F05.udp",{"title":1676,"path":1677,"stem":1678},"UDP Broadcast та Multicast","\u002Fcsharp\u002Fnetwork-programming\u002Fudp-broadcast-multicast","01.csharp\u002F13.network-programming\u002F06.udp-broadcast-multicast",{"title":1680,"path":1681,"stem":1682},"HTTP — протокол вебу","\u002Fcsharp\u002Fnetwork-programming\u002Fhttp-fundamentals","01.csharp\u002F13.network-programming\u002F07.http-fundamentals",{"title":1684,"path":1685,"stem":1686},"HttpListener — вбудований HTTP-сервер .NET","\u002Fcsharp\u002Fnetwork-programming\u002F07a.http-listener","01.csharp\u002F13.network-programming\u002F07a.http-listener",{"title":1688,"path":1689,"stem":1690},"HTTP Advanced — cookies, аутентифікація та HTTPS","\u002Fcsharp\u002Fnetwork-programming\u002Fhttp-advanced","01.csharp\u002F13.network-programming\u002F08.http-advanced",{"title":1692,"path":1693,"stem":1694},"SMTP та протоколи електронної пошти","\u002Fcsharp\u002Fnetwork-programming\u002Fsmtp","01.csharp\u002F13.network-programming\u002F09.smtp",{"title":1696,"path":1697,"stem":1698},"WebSocket — повнодуплексний протокол реального часу","\u002Fcsharp\u002Fnetwork-programming\u002Fwebsockets","01.csharp\u002F13.network-programming\u002F10.websockets",{"title":1700,"path":1701,"stem":1702},"TLS\u002FSSL — криптографічний захист мережевих з'єднань","\u002Fcsharp\u002Fnetwork-programming\u002Ftls-ssl","01.csharp\u002F13.network-programming\u002F11.tls-ssl",{"title":1704,"path":1705,"stem":1706},"C# & .NET: The Ultimate Roadmap","\u002Fcsharp\u002Froadmap","01.csharp\u002Froadmap",{"title":1708,"icon":1709,"path":1710,"stem":1711,"children":1712,"page":59},"C++","i-devicon-cplusplus","\u002Fcpp","02.cpp",[1713,1717,1721,1725,1729,1733,1737,1741,1745,1748,1752,1756,1760,1764,1768,1772,1776,1780,1784,1788,1792,1796,1800,1804,1808,1812,1816,1820,1824,1828,1832,1836,1840,1844,1848,1852,1856,1860,1864,1868,1872,1876,1880,1884,1888,1892,1896,1900,1904,1908,1912,1916,1920,1924,1928,1932,1936,1940,1944,1948,1952,1956,1960,1964,1968,1972,1976,1980,1984,1988,1992,1996,2000,2004,2008,2012,2016,2020,2024,2028,2032,2036,2040,2044,2048,2052,2056,2060,2064,2068,2072,2076,2080,2084,2088,2092,2096,2100,2104,2108,2112,2116,2194],{"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},"Революція C++20: Ranges та Views","\u002Fcpp\u002Franges-views","02.cpp\u002F100.ranges-views",{"title":1757,"path":1758,"stem":1759},"Алгоритми пошуку","\u002Fcpp\u002Fsearching","02.cpp\u002F11.searching",{"title":1761,"path":1762,"stem":1763},"Функції: основи","\u002Fcpp\u002Ffunctions-basics","02.cpp\u002F12.functions-basics",{"title":1765,"path":1766,"stem":1767},"Функції: прототипи, область видимості та додаткові можливості","\u002Fcpp\u002Ffunctions-scope","02.cpp\u002F13.functions-scope",{"title":1769,"path":1770,"stem":1771},"Функції: перевантаження та шаблони","\u002Fcpp\u002Ffunctions-overloading-templates","02.cpp\u002F14.functions-overloading-templates",{"title":1773,"path":1774,"stem":1775},"Вказівники: основи","\u002Fcpp\u002Fpointers-basics","02.cpp\u002F15.pointers-basics",{"title":1777,"path":1778,"stem":1779},"Посилання (References)","\u002Fcpp\u002Freferences","02.cpp\u002F16.references",{"title":1781,"path":1782,"stem":1783},"Вказівники, const і масиви","\u002Fcpp\u002Fpointers-const-arrays","02.cpp\u002F17.pointers-const-arrays",{"title":1785,"path":1786,"stem":1787},"Адресна арифметика","\u002Fcpp\u002Fpointer-arithmetic","02.cpp\u002F18.pointer-arithmetic",{"title":1789,"path":1790,"stem":1791},"Динамічна пам'ять","\u002Fcpp\u002Fdynamic-memory","02.cpp\u002F19.dynamic-memory",{"title":1793,"path":1794,"stem":1795},"Вказівники типу void","\u002Fcpp\u002Fvoid-pointers","02.cpp\u002F20.void-pointers",{"title":1797,"path":1798,"stem":1799},"Вказівники на вказівники","\u002Fcpp\u002Fpointers-to-pointers","02.cpp\u002F21.pointers-to-pointers",{"title":1801,"path":1802,"stem":1803},"Оператор доступу до членів через вказівник (->)","\u002Fcpp\u002Fmember-access-operator","02.cpp\u002F22.member-access-operator",{"title":1805,"path":1806,"stem":1807},"Цикл for-each (Range-based for)","\u002Fcpp\u002Fforeach-loop","02.cpp\u002F23.foreach-loop",{"title":1809,"path":1810,"stem":1811},"Вказівники на функції","\u002Fcpp\u002Ffunction-pointers","02.cpp\u002F24.function-pointers",{"title":1813,"path":1814,"stem":1815},"Лямбда-вирази","\u002Fcpp\u002Flambdas","02.cpp\u002F25.lambdas",{"title":1817,"path":1818,"stem":1819},"Лямбда-захоплення","\u002Fcpp\u002Flambda-captures","02.cpp\u002F26.lambda-captures",{"title":1821,"path":1822,"stem":1823},"Еліпсис","\u002Fcpp\u002Fellipsis","02.cpp\u002F27.ellipsis",{"title":1825,"path":1826,"stem":1827},"Безпечні альтернативи еліпсису","\u002Fcpp\u002F27a.ellipsis","02.cpp\u002F27a.ellipsis",{"title":1829,"path":1830,"stem":1831},"Аргументи командного рядка","\u002Fcpp\u002Fcommand-line-arguments","02.cpp\u002F28.command-line-arguments",{"title":1833,"path":1834,"stem":1835},"Перерахування (enum)","\u002Fcpp\u002Fenum","02.cpp\u002F29.enum",{"title":1837,"path":1838,"stem":1839},"Класи-перерахування (enum class)","\u002Fcpp\u002Fenum-class","02.cpp\u002F30.enum-class",{"title":1841,"path":1842,"stem":1843},"Псевдоніми типів (typedef і using)","\u002Fcpp\u002Ftype-aliases","02.cpp\u002F31.type-aliases",{"title":1845,"path":1846,"stem":1847},"Системи числення та двійкова арифметика","\u002Fcpp\u002Fnumber-systems","02.cpp\u002F32.number-systems",{"title":1849,"path":1850,"stem":1851},"Структури (struct): агрегування даних","\u002Fcpp\u002Fstruct","02.cpp\u002F33.struct",{"title":1853,"path":1854,"stem":1855},"Структури у функціях","\u002Fcpp\u002Fstruct-functions","02.cpp\u002F34.struct-functions",{"title":1857,"path":1858,"stem":1859},"Масиви структур і вкладені структури","\u002Fcpp\u002Fstruct-arrays","02.cpp\u002F35.struct-arrays",{"title":1861,"path":1862,"stem":1863},"Патерни struct та межі застосування","\u002Fcpp\u002Fstruct-patterns","02.cpp\u002F36.struct-patterns",{"title":1865,"path":1866,"stem":1867},"Символи та таблиця ASCII","\u002Fcpp\u002Fascii-characters","02.cpp\u002F37.ascii-characters",{"title":1869,"path":1870,"stem":1871},"Unicode та кодування UTF","\u002Fcpp\u002Funicode-utf","02.cpp\u002F38.unicode-utf",{"title":1873,"path":1874,"stem":1875},"C-style рядки","\u002Fcpp\u002Fc-strings","02.cpp\u002F39.c-strings",{"title":1877,"path":1878,"stem":1879},"Вступ до std::string","\u002Fcpp\u002Fstd-string-intro","02.cpp\u002F40.std-string-intro",{"title":1881,"path":1882,"stem":1883},"Довжина, ємність та доступ до символів std::string","\u002Fcpp\u002Fstd-string-capacity-access","02.cpp\u002F41.std-string-capacity-access",{"title":1885,"path":1886,"stem":1887},"Модифікація std::string: присвоювання, додавання, вставка, видалення та заміна","\u002Fcpp\u002Fstd-string-modification","02.cpp\u002F42.std-string-modification",{"title":1889,"path":1890,"stem":1891},"Пошук у std::string: find, npos та практичні патерни","\u002Fcpp\u002Fstd-string-search","02.cpp\u002F43.std-string-search",{"title":1893,"path":1894,"stem":1895},"std::string_view: невласницький погляд на рядок без копіювання","\u002Fcpp\u002Fstd-string-view","02.cpp\u002F44.std-string-view",{"title":1897,"path":1898,"stem":1899},"Об'єднання (union): один блок пам'яті, кілька інтерпретацій","\u002Fcpp\u002Funion","02.cpp\u002F45.union",{"title":1901,"path":1902,"stem":1903},"Організація коду: файли, препроцесор, простори імен","\u002Fcpp\u002Fmultifile-programs","02.cpp\u002F46.multifile-programs",{"title":1905,"path":1906,"stem":1907},"Робота з файлами: C-стиль (stdio.h)","\u002Fcpp\u002Fc-style-files","02.cpp\u002F47.c-style-files",{"title":1909,"path":1910,"stem":1911},"Робота з файлами: C++-стиль (fstream)","\u002Fcpp\u002Fcpp-style-files","02.cpp\u002F48.cpp-style-files",{"title":1913,"path":1914,"stem":1915},"Введення в ООП: від процедур до об'єктів","\u002Fcpp\u002Foop-intro","02.cpp\u002F49.oop-intro",{"title":1917,"path":1918,"stem":1919},"Класи, об'єкти та методи","\u002Fcpp\u002Fclasses-objects-methods","02.cpp\u002F50.classes-objects-methods",{"title":1921,"path":1922,"stem":1923},"Специфікатори доступу та інкапсуляція","\u002Fcpp\u002Faccess-specifiers-encapsulation","02.cpp\u002F51.access-specifiers-encapsulation",{"title":1925,"path":1926,"stem":1927},"Конструктори: гарантована ініціалізація об'єктів","\u002Fcpp\u002Fconstructors","02.cpp\u002F52.constructors",{"title":1929,"path":1930,"stem":1931},"Списки ініціалізації та делегуючі конструктори","\u002Fcpp\u002Finit-lists-delegating","02.cpp\u002F53.init-lists-delegating",{"title":1933,"path":1934,"stem":1935},"Деструктори та ідіома RAII","\u002Fcpp\u002Fdestructors-raii","02.cpp\u002F54.destructors-raii",{"title":1937,"path":1938,"stem":1939},"Прихований покажчик this","\u002Fcpp\u002Fthis-pointer","02.cpp\u002F55.this-pointer",{"title":1941,"path":1942,"stem":1943},"Розподіл класу на заголовковий файл та файл реалізації","\u002Fcpp\u002Fclass-header-source","02.cpp\u002F56.class-header-source",{"title":1945,"path":1946,"stem":1947},"Класи та const","\u002Fcpp\u002Fconst-classes","02.cpp\u002F57.const-classes",{"title":1949,"path":1950,"stem":1951},"Статичні члени класу","\u002Fcpp\u002Fstatic-members","02.cpp\u002F58.static-members",{"title":1953,"path":1954,"stem":1955},"Конструктор копіювання та запобігання копіюванню","\u002Fcpp\u002Fcopy-constructor","02.cpp\u002F59.copy-constructor",{"title":1957,"path":1958,"stem":1959},"Дружні функції та класи","\u002Fcpp\u002Ffriend-functions-classes","02.cpp\u002F60.friend-functions-classes",{"title":1961,"path":1962,"stem":1963},"Анонімні об'єкти та вкладені типи","\u002Fcpp\u002Fanonymous-objects-nested-types","02.cpp\u002F61.anonymous-objects-nested-types",{"title":1965,"path":1966,"stem":1967},"Вимірювання часу виконання: RAII-таймер","\u002Fcpp\u002Ftiming-raii-timer","02.cpp\u002F62.timing-raii-timer",{"title":1969,"path":1970,"stem":1971},"Перевантаження операторів: основи та арифметика","\u002Fcpp\u002Foperator-overloading-basics","02.cpp\u002F63.operator-overloading-basics",{"title":1973,"path":1974,"stem":1975},"Перевантаження операторів: методи класу та спеціальні оператори","\u002Fcpp\u002Foperator-overloading-methods","02.cpp\u002F64.operator-overloading-methods",{"title":1977,"path":1978,"stem":1979},"Приведення типів, explicit та delete","\u002Fcpp\u002Ftypecast-explicit-delete","02.cpp\u002F65.typecast-explicit-delete",{"title":1981,"path":1982,"stem":1983},"Глибоке копіювання та оператор присвоювання","\u002Fcpp\u002Fdeep-copy-assignment","02.cpp\u002F66.deep-copy-assignment",{"title":1985,"path":1986,"stem":1987},"Зв'язки між об'єктами: композиція та агрегація","\u002Fcpp\u002Fcomposition-aggregation","02.cpp\u002F67.composition-aggregation",{"title":1989,"path":1990,"stem":1991},"Асоціація та залежність між об","\u002Fcpp\u002Fassociation-dependency","02.cpp\u002F68.association-dependency",{"title":1993,"path":1994,"stem":1995},"Контейнерні класи та `std::initializer_list`","\u002Fcpp\u002Fcontainer-classes-initializer-list","02.cpp\u002F69.container-classes-initializer-list",{"title":1997,"path":1998,"stem":1999},"Вступ до наслідування: базові поняття та відношення «is-a»","\u002Fcpp\u002Finheritance-intro","02.cpp\u002F70.inheritance-intro",{"title":2001,"path":2002,"stem":2003},"Конструктори, деструктори та порядок ініціалізації в ієрархіях","\u002Fcpp\u002Finheritance-constructors-destructors","02.cpp\u002F71.inheritance-constructors-destructors",{"title":2005,"path":2006,"stem":2007},"Специфікатор `protected` та види наслідування","\u002Fcpp\u002Finheritance-access-specifiers","02.cpp\u002F72.inheritance-access-specifiers",{"title":2009,"path":2010,"stem":2011},"Перевизначення методів та приховування імен","\u002Fcpp\u002Fmethod-overriding-hiding","02.cpp\u002F73.method-overriding-hiding",{"title":2013,"path":2014,"stem":2015},"Множинне наслідування та проблема ромба","\u002Fcpp\u002Fmultiple-inheritance-diamond","02.cpp\u002F74.multiple-inheritance-diamond",{"title":2017,"path":2018,"stem":2019},"Вказівники на базовий клас та віртуальні функції","\u002Fcpp\u002Fvirtual-functions-polymorphism","02.cpp\u002F75.virtual-functions-polymorphism",{"title":2021,"path":2022,"stem":2023},"Специфікатори override, final та віртуальні деструктори","\u002Fcpp\u002Foverride-final-virtual-destructors","02.cpp\u002F76.override-final-virtual-destructors",{"title":2025,"path":2026,"stem":2027},"Внутрішні механізми поліморфізму: vtable, vptr та зв'язування","\u002Fcpp\u002Fvirtual-table-binding","02.cpp\u002F77.virtual-table-binding",{"title":2029,"path":2030,"stem":2031},"Абстрактні класи та чисті віртуальні функції","\u002Fcpp\u002Fabstract-classes-interfaces","02.cpp\u002F78.abstract-classes-interfaces",{"title":2033,"path":2034,"stem":2035},"Зрізка об'єктів, віртуальне наслідування та поліморфний вивід","\u002Fcpp\u002Fslicing-virtual-base-io","02.cpp\u002F79.slicing-virtual-base-io",{"title":2037,"path":2038,"stem":2039},"Динамічне приведення типів (`dynamic_cast`) та RTTI","\u002Fcpp\u002Fdynamic-cast-rtti","02.cpp\u002F80.dynamic-cast-rtti",{"title":2041,"path":2042,"stem":2043},"Шаблони функцій: узагальнене програмування","\u002Fcpp\u002Ffunction-templates","02.cpp\u002F81.function-templates",{"title":2045,"path":2046,"stem":2047},"Шаблони класів та NTTP-параметри","\u002Fcpp\u002Fclass-templates-nttp","02.cpp\u002F82.class-templates-nttp",{"title":2049,"path":2050,"stem":2051},"Повна (явна) спеціалізація шаблонів","\u002Fcpp\u002Ffull-template-specialization","02.cpp\u002F83.full-template-specialization",{"title":2053,"path":2054,"stem":2055},"Часткова спеціалізація шаблонів класів","\u002Fcpp\u002Fpartial-template-specialization","02.cpp\u002F84.partial-template-specialization",{"title":2057,"path":2058,"stem":2059},"Механізм винятків: try, catch, throw та розкручування стеку","\u002Fcpp\u002Fexceptions-basics","02.cpp\u002F85.exceptions-basics",{"title":2061,"path":2062,"stem":2063},"Ієрархія std::exception та власні класи винятків","\u002Fcpp\u002Fexception-hierarchy-custom","02.cpp\u002F86.exception-hierarchy-custom",{"title":2065,"path":2066,"stem":2067},"Повторне генерування винятків та функціональний try-блок","\u002Fcpp\u002Frethrow-function-try","02.cpp\u002F87.rethrow-function-try",{"title":2069,"path":2070,"stem":2071},"Безпека винятків, noexcept та деструктори","\u002Fcpp\u002Fsafety-noexcept","02.cpp\u002F88.safety-noexcept",{"title":2073,"path":2074,"stem":2075},"Власні структури даних: стек та черга","\u002Fcpp\u002Fcustom-stack-queue","02.cpp\u002F89.custom-stack-queue",{"title":2077,"path":2078,"stem":2079},"Власні структури даних: однозв'язаний список","\u002Fcpp\u002Flinked-list","02.cpp\u002F90.linked-list",{"title":2081,"path":2082,"stem":2083},"Власні структури даних: бінарне дерево пошуку","\u002Fcpp\u002Fbinary-search-tree","02.cpp\u002F91.binary-search-tree",{"title":2085,"path":2086,"stem":2087},"Власні структури даних: хеш-таблиця","\u002Fcpp\u002Fhash-table","02.cpp\u002F92.hash-table",{"title":2089,"path":2090,"stem":2091},"Готові структури даних C++: послідовні контейнери STL","\u002Fcpp\u002Fstl-sequential-containers","02.cpp\u002F93.stl-sequential-containers",{"title":2093,"path":2094,"stem":2095},"Готові структури даних C++: асоціативні контейнери та адаптери","\u002Fcpp\u002Fstl-associative-adapters","02.cpp\u002F94.stl-associative-adapters",{"title":2097,"path":2098,"stem":2099},"Готові структури даних C++: ітератори та алгоритми STL","\u002Fcpp\u002Fstl-iterators-algorithms","02.cpp\u002F95.stl-iterators-algorithms",{"title":2101,"path":2102,"stem":2103},"R-value посилання та move-семантика","\u002Fcpp\u002Frvalue-references-move-semantics","02.cpp\u002F96.rvalue-references-move-semantics",{"title":2105,"path":2106,"stem":2107},"Move-конструктор, move-присвоювання та Правило п","\u002Fcpp\u002Fmove-constructors-rule-of-five","02.cpp\u002F97.move-constructors-rule-of-five",{"title":2109,"path":2110,"stem":2111},"Розумний покажчик std::unique_ptr","\u002Fcpp\u002Funique-ptr","02.cpp\u002F98.unique-ptr",{"title":2113,"path":2114,"stem":2115},"Спільне володіння: std::shared_ptr та std::weak_ptr","\u002Fcpp\u002Fshared-ptr-weak-ptr","02.cpp\u002F99.shared-ptr-weak-ptr",{"title":2117,"icon":2118,"path":2119,"stem":2120,"children":2121,"page":59},"CMake і vcpkg","i-devicon-cmake","\u002Fcpp\u002Fcmake","02.cpp\u002F990.cmake",[2122,2126,2130,2134,2138,2142,2146,2150,2154,2158,2162,2166,2170,2174,2178,2182,2186,2190],{"title":2123,"path":2124,"stem":2125},"CMake: навіщо він потрібен і як його встановити","\u002Fcpp\u002Fcmake\u002Fwhat-is-cmake","02.cpp\u002F990.cmake\u002F01.what-is-cmake",{"title":2127,"path":2128,"stem":2129},"Перший проєкт з CMake: конфігурація, збірка, запуск","\u002Fcpp\u002Fcmake\u002Ffirst-project","02.cpp\u002F990.cmake\u002F02.first-project",{"title":2131,"path":2132,"stem":2133},"Синтаксис CMakeLists.txt: команди, змінні, списки","\u002Fcpp\u002Fcmake\u002Fcmakelists-syntax","02.cpp\u002F990.cmake\u002F03.cmakelists-syntax",{"title":2135,"path":2136,"stem":2137},"Проєкт із кількома файлами: перелік джерел і file(GLOB)","\u002Fcpp\u002Fcmake\u002Fmultiple-files","02.cpp\u002F990.cmake\u002F04.multiple-files",{"title":2139,"path":2140,"stem":2141},"Бібліотеки в CMake: STATIC, SHARED, INTERFACE та видимість PUBLIC\u002FPRIVATE","\u002Fcpp\u002Fcmake\u002Flibraries","02.cpp\u002F990.cmake\u002F05.libraries",{"title":2143,"path":2144,"stem":2145},"Підключення зовнішніх бібліотек: find_package, add_subdirectory, FetchContent, pkg-config","\u002Fcpp\u002Fcmake\u002Fexternal-libraries","02.cpp\u002F990.cmake\u002F06.external-libraries",{"title":2147,"path":2148,"stem":2149},"Умови, опції, цикли та функції в CMake","\u002Fcpp\u002Fcmake\u002Fvariables-conditions","02.cpp\u002F990.cmake\u002F07.variables-conditions",{"title":2151,"path":2152,"stem":2153},"Конфігурації збірки: Debug, Release і вирази-генератори","\u002Fcpp\u002Fcmake\u002Fbuild-configurations","02.cpp\u002F990.cmake\u002F08.build-configurations",{"title":2155,"path":2156,"stem":2157},"Структура великого проєкту: підпапки, модулі CMake, PCH та install","\u002Fcpp\u002Fcmake\u002Fproject-structure","02.cpp\u002F990.cmake\u002F09.project-structure",{"title":2159,"path":2160,"stem":2161},"Тестування з CMake: CTest, Google Test, покриття коду","\u002Fcpp\u002Fcmake\u002Ftesting-ctest","02.cpp\u002F990.cmake\u002F10.testing-ctest",{"title":2163,"path":2164,"stem":2165},"Команди CMake, пресети, скрипти збірки та кращі практики","\u002Fcpp\u002Fcmake\u002Fcommands-best-practices","02.cpp\u002F990.cmake\u002F11.commands-best-practices",{"title":2167,"path":2168,"stem":2169},"Практичні проєкти: калькулятор, Qt-застосунок і кросплатформна збірка","\u002Fcpp\u002Fcmake\u002Freal-projects","02.cpp\u002F990.cmake\u002F12.real-projects",{"title":2171,"path":2172,"stem":2173},"Пакетні менеджери для C++: vcpkg, Conan, CPM та системні пакети","\u002Fcpp\u002Fcmake\u002Fpackage-managers","02.cpp\u002F990.cmake\u002F13.package-managers",{"title":2175,"path":2176,"stem":2177},"vcpkg: встановлення, основні команди та triplets","\u002Fcpp\u002Fcmake\u002Fvcpkg-basics","02.cpp\u002F990.cmake\u002F14.vcpkg-basics",{"title":2179,"path":2180,"stem":2181},"vcpkg і CMake: toolchain-файл, manifest vcpkg.json, IDE","\u002Fcpp\u002Fcmake\u002Fvcpkg-cmake","02.cpp\u002F990.cmake\u002F15.vcpkg-cmake",{"title":2183,"path":2184,"stem":2185},"vcpkg для досвідчених: версії, features, реєстри, власні порти, кеш і діагностика","\u002Fcpp\u002Fcmake\u002Fvcpkg-advanced","02.cpp\u002F990.cmake\u002F16.vcpkg-advanced",{"title":2187,"path":2188,"stem":2189},"Бібліотеки C++: fmt, spdlog і nlohmann\u002Fjson","\u002Fcpp\u002Fcmake\u002Flibraries-format-log-json","02.cpp\u002F990.cmake\u002F17.libraries-format-log-json",{"title":2191,"path":2192,"stem":2193},"Бібліотеки C++: cpp-httplib, cxxopts, CLI11, Google Test і Catch2","\u002Fcpp\u002Fcmake\u002Flibraries-network-cli-testing","02.cpp\u002F990.cmake\u002F18.libraries-network-cli-testing",{"title":2195,"icon":2196,"path":2197,"stem":2198,"children":2199,"page":59},"Реверс-інжиніринг і чіти","i-lucide-bug-play","\u002Fcpp\u002Freverse-engineering","02.cpp\u002F991.reverse-engineering",[2200,2204,2208,2212,2216],{"title":2201,"path":2202,"stem":2203},"Основи: пам'ять, процеси та інструменти","\u002Fcpp\u002Freverse-engineering\u002Ffoundations","02.cpp\u002F991.reverse-engineering\u002F01.foundations",{"title":2205,"path":2206,"stem":2207},"Пошук даних у пам'яті: сканування, структури, ланцюжки вказівників","\u002Fcpp\u002Freverse-engineering\u002Ffinding-data","02.cpp\u002F991.reverse-engineering\u002F02.finding-data",{"title":2209,"path":2210,"stem":2211},"Тренер і internal-модуль на C++","\u002Fcpp\u002Freverse-engineering\u002Ftrainer-and-injection","02.cpp\u002F991.reverse-engineering\u002F03.trainer-and-injection",{"title":2213,"path":2214,"stem":2215},"Аналіз коду: асемблер, налагоджувач, патчинг","\u002Fcpp\u002Freverse-engineering\u002Fcode-analysis","02.cpp\u002F991.reverse-engineering\u002F04.code-analysis",{"title":2217,"path":2218,"stem":2219},"AssaultCube і захист від чітів","\u002Fcpp\u002Freverse-engineering\u002Fassaultcube-and-defense","02.cpp\u002F991.reverse-engineering\u002F05.assaultcube-and-defense",{"title":2221,"icon":2222,"path":2223,"stem":2224,"children":2225,"page":59},"JavaScript","i-devicon-javascript","\u002Fjavascript","03.javascript",[2226,2252,2306,2328,2632,2670,2688],{"title":2227,"icon":2228,"path":2229,"stem":2230,"children":2231,"page":59},"Events","i-lucide-mouse-pointer-click","\u002Fjavascript\u002Fevents","03.javascript\u002F01.events",[2232,2236,2240,2244,2248],{"title":2233,"path":2234,"stem":2235},"Вступ до подій браузера","\u002Fjavascript\u002Fevents\u002Fintro","03.javascript\u002F01.events\u002F01.intro",{"title":2237,"path":2238,"stem":2239},"Бульбашковий механізм (Bubbling) та занурення (Capturing)","\u002Fjavascript\u002Fevents\u002Fbubbling-capturing","03.javascript\u002F01.events\u002F02.bubbling-capturing",{"title":2241,"path":2242,"stem":2243},"Делегування подій (Event Delegation)","\u002Fjavascript\u002Fevents\u002Fdelegate-events","03.javascript\u002F01.events\u002F03.delegate-events",{"title":2245,"path":2246,"stem":2247},"Типові дії браузера та preventDefault()","\u002Fjavascript\u002Fevents\u002Fprevent-default","03.javascript\u002F01.events\u002F04.prevent-default",{"title":2249,"path":2250,"stem":2251},"Запуск користувацьких подій (Custom Events)","\u002Fjavascript\u002Fevents\u002Fcustom-events","03.javascript\u002F01.events\u002F05.custom-events",{"title":2253,"icon":2254,"path":2255,"stem":2256,"children":2257,"page":59},"Network","i-lucide-globe","\u002Fjavascript\u002Fnetwork","03.javascript\u002F02.network",[2258,2262,2266,2270,2274,2278,2282,2286,2290,2294,2298,2302],{"title":2259,"path":2260,"stem":2261},"Fetch API - Сучасний підхід до HTTP-запитів","\u002Fjavascript\u002Fnetwork\u002F01-fetch-api","03.javascript\u002F02.network\u002F01-fetch-api",{"title":2263,"path":2264,"stem":2265},"FormData - Робота з формами та файлами","\u002Fjavascript\u002Fnetwork\u002F02-formdata","03.javascript\u002F02.network\u002F02-formdata",{"title":2267,"path":2268,"stem":2269},"Відстеження прогресу завантаження","\u002Fjavascript\u002Fnetwork\u002F03-download-progress","03.javascript\u002F02.network\u002F03-download-progress",{"title":2271,"path":2272,"stem":2273},"Переривання fetch-запитів","\u002Fjavascript\u002Fnetwork\u002F04-abort-requests","03.javascript\u002F02.network\u002F04-abort-requests",{"title":2275,"path":2276,"stem":2277},"CORS - Запити між різними джерелами","\u002Fjavascript\u002Fnetwork\u002F05-cors","03.javascript\u002F02.network\u002F05-cors",{"title":2279,"path":2280,"stem":2281},"Fetch API - Повний довідник опцій","\u002Fjavascript\u002Fnetwork\u002F06-fetch-options","03.javascript\u002F02.network\u002F06-fetch-options",{"title":2283,"path":2284,"stem":2285},"URL Objects - Робота з посиланнями","\u002Fjavascript\u002Fnetwork\u002F07-url-objects","03.javascript\u002F02.network\u002F07-url-objects",{"title":2287,"path":2288,"stem":2289},"XMLHttpRequest - AJAX та низькорівневі запити","\u002Fjavascript\u002Fnetwork\u002F08-xmlhttprequest","03.javascript\u002F02.network\u002F08-xmlhttprequest",{"title":2291,"path":2292,"stem":2293},"Відновлюване завантаження файлів","\u002Fjavascript\u002Fnetwork\u002F09-resumable-upload","03.javascript\u002F02.network\u002F09-resumable-upload",{"title":2295,"path":2296,"stem":2297},"Cookies, document.cookie та світ після \"Cookiepocalypse\"","\u002Fjavascript\u002Fnetwork\u002F10-cookies","03.javascript\u002F02.network\u002F10-cookies",{"title":2299,"path":2300,"stem":2301},"js-cookie: Керування Cookies без Болю","\u002Fjavascript\u002Fnetwork\u002F11-js-cookie","03.javascript\u002F02.network\u002F11-js-cookie",{"title":2303,"path":2304,"stem":2305},"Axios: Потужний HTTP-клієнт для JavaScript","\u002Fjavascript\u002Fnetwork\u002F12-axios","03.javascript\u002F02.network\u002F12-axios",{"title":2307,"icon":2308,"path":2309,"stem":2310,"children":2311,"page":59},"Bom","i-lucide-monitor","\u002Fjavascript\u002Fbom","03.javascript\u002F03.bom",[2312,2316,2320,2324],{"title":2313,"path":2314,"stem":2315},"LocalStorage, SessionStorage та patterns збереження даних","\u002Fjavascript\u002Fbom\u002F01-localstorage","03.javascript\u002F03.bom\u002F01-localstorage",{"title":2317,"path":2318,"stem":2319},"Location Object - Керування адресою сторінки","\u002Fjavascript\u002Fbom\u002F02-location-object","03.javascript\u002F03.bom\u002F02-location-object",{"title":2321,"path":2322,"stem":2323},"History API - Керування історією браузера","\u002Fjavascript\u002Fbom\u002F03-history-api","03.javascript\u002F03.bom\u002F03-history-api",{"title":2325,"path":2326,"stem":2327},"Navigator Object - Ідентифікація та Можливості Пристрою","\u002Fjavascript\u002Fbom\u002F04-navigator-object","03.javascript\u002F03.bom\u002F04-navigator-object",{"title":2329,"icon":2330,"path":2331,"stem":2332,"children":2333},"React","i-devicon-react","\u002Fjavascript\u002Freact","03.javascript\u002F04.react\u002Findex",[2334,2335,2339,2343,2347,2351,2414,2449,2601],{"title":2329,"path":2331,"stem":2332},{"title":2336,"path":2337,"stem":2338},"Робота з Формами в React","\u002Fjavascript\u002Freact\u002Freact-forms","03.javascript\u002F04.react\u002F01.react-forms",{"title":2340,"path":2341,"stem":2342},"React Hook Form: Професійна Робота з Формами","\u002Fjavascript\u002Freact\u002Freact-hook-form","03.javascript\u002F04.react\u002F02.react-hook-form",{"title":2344,"path":2345,"stem":2346},"React Hook Form: Глибоке Розуміння Архітектури та Оптимізації","\u002Fjavascript\u002Freact\u002Freact-hook-form-new","03.javascript\u002F04.react\u002F02.react-hook-form-new",{"title":2348,"path":2349,"stem":2350},"Axios та React: Професійна Архітектура Запитів","\u002Fjavascript\u002Freact\u002Fdata-fetching-axios","03.javascript\u002F04.react\u002F03.data-fetching-axios",{"title":2352,"icon":132,"path":2353,"stem":2354,"children":2355},"Tanstack Query","\u002Fjavascript\u002Freact\u002Ftanstack-query","03.javascript\u002F04.react\u002F04.tanstack-query\u002Findex",[2356,2358,2362,2366,2370,2374,2378,2382,2386,2390,2394,2398,2402,2406,2410],{"title":2357,"path":2353,"stem":2354},"TanStack Query: Майстерність Керування Станом Сервера",{"title":2359,"path":2360,"stem":2361},"Парадигма Server State: Чому useEffect недостатньо","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fserver-state-paradigm","03.javascript\u002F04.react\u002F04.tanstack-query\u002F01.server-state-paradigm",{"title":2363,"path":2364,"stem":2365},"Встановлення та Налаштування: Фундамент","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Finstallation-and-devtools","03.javascript\u002F04.react\u002F04.tanstack-query\u002F02.installation-and-devtools",{"title":2367,"path":2368,"stem":2369},"Основи Запитів та Магія Ключів","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fquery-basics-and-keys","03.javascript\u002F04.react\u002F04.tanstack-query\u002F03.query-basics-and-keys",{"title":2371,"path":2372,"stem":2373},"Синхронізація Даних: Життєвий Цикл Запиту","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fdata-synchronization","03.javascript\u002F04.react\u002F04.tanstack-query\u002F04.data-synchronization",{"title":2375,"path":2376,"stem":2377},"Мутації та Інвалідація: Зміна Даних","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fmutations-and-invalidation","03.javascript\u002F04.react\u002F04.tanstack-query\u002F05.mutations-and-invalidation",{"title":2379,"path":2380,"stem":2381},"Оптимістичні Оновлення: Швидше за Світло","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Foptimistic-updates","03.javascript\u002F04.react\u002F04.tanstack-query\u002F06.optimistic-updates",{"title":2383,"path":2384,"stem":2385},"Пагінація та Infinite Scroll","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fpagination-and-load-more","03.javascript\u002F04.react\u002F04.tanstack-query\u002F07.pagination-and-load-more",{"title":2387,"path":2388,"stem":2389},"Просунуті Патерни та Оптимізація","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fadvanced-patterns","03.javascript\u002F04.react\u002F04.tanstack-query\u002F08.advanced-patterns",{"title":2391,"path":2392,"stem":2393},"Архітектура та Best Practices","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Farchitecture-and-best-practices","03.javascript\u002F04.react\u002F04.tanstack-query\u002F09.architecture-and-best-practices",{"title":2395,"path":2396,"stem":2397},"Server-Side Rendering (SSR) та Гідратація","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fserver-side-rendering","03.javascript\u002F04.react\u002F04.tanstack-query\u002F10.server-side-rendering",{"title":2399,"path":2400,"stem":2401},"Стратегії Тестування","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Ftesting-strategies","03.javascript\u002F04.react\u002F04.tanstack-query\u002F11.testing-strategies",{"title":2403,"path":2404,"stem":2405},"Аутентифікація та Обробка Помилок","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fauthentication-and-errors","03.javascript\u002F04.react\u002F04.tanstack-query\u002F12.authentication-and-errors",{"title":2407,"path":2408,"stem":2409},"React Suspense та Майбутнє","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Freact-suspense","03.javascript\u002F04.react\u002F04.tanstack-query\u002F13.react-suspense",{"title":2411,"path":2412,"stem":2413},"Глибоке Занурення в Продуктивність","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fperformance-deep-dive","03.javascript\u002F04.react\u002F04.tanstack-query\u002F14.performance-deep-dive",{"title":2415,"icon":2330,"path":2416,"stem":2417,"children":2418},"React Router","\u002Fjavascript\u002Freact\u002Freact-router","03.javascript\u002F04.react\u002F05.react-router\u002Findex",[2419,2421,2425,2429,2433,2437,2441,2445],{"title":2420,"path":2416,"stem":2417},"React Router: Навігаційна система сучасного вебу",{"title":2422,"path":2423,"stem":2424},"Налаштування та Базовий Роутинг","\u002Fjavascript\u002Freact\u002Freact-router\u002Fsetup-and-basic-routing","03.javascript\u002F04.react\u002F05.react-router\u002F01.setup-and-basic-routing",{"title":2426,"path":2427,"stem":2428},"Динамічна Навігація","\u002Fjavascript\u002Freact\u002Freact-router\u002Fnavigation-and-links","03.javascript\u002F04.react\u002F05.react-router\u002F02.navigation-and-links",{"title":2430,"path":2431,"stem":2432},"Вкладені Маршрути та Макети","\u002Fjavascript\u002Freact\u002Freact-router\u002Fnested-routes-and-layouts","03.javascript\u002F04.react\u002F05.react-router\u002F03.nested-routes-and-layouts",{"title":2434,"path":2435,"stem":2436},"Динамічні Маршрути та Параметри","\u002Fjavascript\u002Freact\u002Freact-router\u002Fdynamic-routing","03.javascript\u002F04.react\u002F05.react-router\u002F04.dynamic-routing",{"title":2438,"path":2439,"stem":2440},"Data APIs: Loaders та Actions","\u002Fjavascript\u002Freact\u002Freact-router\u002Fdata-loading","03.javascript\u002F04.react\u002F05.react-router\u002F05.data-loading",{"title":2442,"path":2443,"stem":2444},"Просунуті Патерни","\u002Fjavascript\u002Freact\u002Freact-router\u002Fadvanced-patterns","03.javascript\u002F04.react\u002F05.react-router\u002F06.advanced-patterns",{"title":2446,"path":2447,"stem":2448},"Legacy Routing: Компонентний підхід","\u002Fjavascript\u002Freact\u002Freact-router\u002Flegacy-routing","03.javascript\u002F04.react\u002F05.react-router\u002F07.legacy-routing",{"title":2450,"icon":132,"path":2451,"stem":2452,"children":2453},"Redux","\u002Fjavascript\u002Freact\u002Fredux","03.javascript\u002F04.react\u002F06.redux\u002Findex",[2454,2456,2472,2501,2510,2531,2547,2576],{"title":2455,"path":2451,"stem":2452},"Redux: Еволюція управління станом",{"title":14,"icon":15,"path":2457,"stem":2458,"children":2459,"page":59},"\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals",[2460,2464,2468],{"title":2461,"path":2462,"stem":2463},"Вступ до State Management","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fintro-state-management","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F01.intro-state-management",{"title":2465,"path":2466,"stem":2467},"Філософія Redux та Три Принципи","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fredux-philosophy","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F02.redux-philosophy",{"title":2469,"path":2470,"stem":2471},"Чисті функції та Іммутабельність","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fpure-functions-immutability","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F03.pure-functions-immutability",{"title":2473,"icon":132,"path":2474,"stem":2475,"children":2476,"page":59},"Classic Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux",[2477,2481,2485,2489,2493,2497],{"title":2478,"path":2479,"stem":2480},"Створення Store (Classic Redux)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fstore-setup","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F01.store-setup",{"title":2482,"path":2483,"stem":2484},"Actions, Constants та Action Creators","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Factions-constants","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F02.actions-constants",{"title":2486,"path":2487,"stem":2488},"Логіка Reducers","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Freducers","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F03.reducers",{"title":2490,"path":2491,"stem":2492},"Комбінування Reducers (Root Reducer)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fdata-flow","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F04.data-flow",{"title":2494,"path":2495,"stem":2496},"Підключення до 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":2498,"path":2499,"stem":2500},"Middleware та Асинхронність (Redux Thunk)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fmiddleware-thunk","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F06.middleware-thunk",{"title":2502,"icon":132,"path":2503,"stem":2504,"children":2505,"page":59},"Transition To Rtk","\u002Fjavascript\u002Freact\u002Fredux\u002Ftransition-to-rtk","03.javascript\u002F04.react\u002F06.redux\u002F03.transition-to-rtk",[2506],{"title":2507,"path":2508,"stem":2509},"Проблеми класичного 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":2511,"icon":132,"path":2512,"stem":2513,"children":2514,"page":59},"Redux Toolkit","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit",[2515,2519,2523,2527],{"title":2516,"path":2517,"stem":2518},"Налаштування Store з configureStore","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fconfigure-store","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F01.configure-store",{"title":2520,"path":2521,"stem":2522},"createSlice: Революція в Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fcreate-slice","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F02.create-slice",{"title":2524,"path":2525,"stem":2526},"Асинхронність з createAsyncThunk","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fasync-thunks","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F03.async-thunks",{"title":2528,"path":2529,"stem":2530},"04. Entity Adapter: Керування нормалізованим станом","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fentity-adapter","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F04.entity-adapter",{"title":2532,"icon":92,"path":2533,"stem":2534,"children":2535,"page":59},"Advanced","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced",[2536,2540,2544],{"title":2537,"path":2538,"stem":2539},"Мемоізація та Селектори: Повний Гайд по Reselect","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Fselectors-reselect","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F01.selectors-reselect",{"title":2541,"path":2542,"stem":2543},"RTK Query: Архітектура Серверного Кешу","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Frtk-query-intro","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F02.rtk-query-intro",{"title":2391,"path":2545,"stem":2546},"\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Farchitecture-best-practices","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F03.architecture-best-practices",{"title":2548,"icon":132,"path":2549,"stem":2550,"children":2551,"page":59},"Project Kanban","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban",[2552,2556,2560,2564,2568,2572],{"title":2553,"path":2554,"stem":2555},"Проєкт: Kanban Board (Trello Clone)","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fproject-overview","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F01.project-overview",{"title":2557,"path":2558,"stem":2559},"Налаштування та Типізація","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fsetup-and-types","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F02.setup-and-types",{"title":2561,"path":2562,"stem":2563},"Board Slice: Серце Дошки","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fboard-slice","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F03.board-slice",{"title":2565,"path":2566,"stem":2567},"Логіка 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":2569,"path":2570,"stem":2571},"Інтеграція з RTK Query","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Frtk-query-integration","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F05.rtk-query-integration",{"title":2573,"path":2574,"stem":2575},"Optimistic Updates","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Foptimistic-updates","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F06.optimistic-updates",{"title":2577,"icon":132,"path":2578,"stem":2579,"children":2580,"page":59},"Testing","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting","03.javascript\u002F04.react\u002F06.redux\u002F07.testing",[2581,2585,2589,2593,2597],{"title":2582,"path":2583,"stem":2584},"Тестування Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Fintro-testing","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F01.intro-testing",{"title":2586,"path":2587,"stem":2588},"Тестування Reducers","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-reducers","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F02.testing-reducers",{"title":2590,"path":2591,"stem":2592},"Тестування Селекторів","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-selectors","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F03.testing-selectors",{"title":2594,"path":2595,"stem":2596},"Тестування Компонентів (Integration)","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-components","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F04.testing-components",{"title":2598,"path":2599,"stem":2600},"Тестування Async Thunks","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-thunks","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F05.testing-thunks",{"title":2602,"icon":132,"path":2603,"stem":2604,"children":2605},"Ui Libraries","\u002Fjavascript\u002Freact\u002Fui-libraries","03.javascript\u002F04.react\u002F07.ui-libraries\u002Findex",[2606,2608,2612,2616,2620,2624,2628],{"title":2607,"path":2603,"stem":2604},"UI Бібліотеки в React",{"title":2609,"path":2610,"stem":2611},"Вступ до UI Бібліотек: Навіщо Винаходити Велосипед Двічі?","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fintroduction-to-ui-libraries","03.javascript\u002F04.react\u002F07.ui-libraries\u002F01.introduction-to-ui-libraries",{"title":2613,"path":2614,"stem":2615},"Філософія shadcn\u002Fui: \"Not a Component Library\"","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-philosophy","03.javascript\u002F04.react\u002F07.ui-libraries\u002F02.shadcn-philosophy",{"title":2617,"path":2618,"stem":2619},"Установка та Налаштування shadcn\u002Fui","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-installation","03.javascript\u002F04.react\u002F07.ui-libraries\u002F03.shadcn-installation",{"title":2621,"path":2622,"stem":2623},"Базові Компоненти shadcn\u002Fui: Фундамент Інтерфейсу","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-basics","03.javascript\u002F04.react\u002F07.ui-libraries\u002F04.shadcn-components-basics",{"title":2625,"path":2626,"stem":2627},"Компоненти Форм: Побудова Інтерактивних Form","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-forms","03.javascript\u002F04.react\u002F07.ui-libraries\u002F05.shadcn-components-forms",{"title":2629,"path":2630,"stem":2631},"Складні Компоненти: Dialog, Dropdown, Table та Command","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-advanced","03.javascript\u002F04.react\u002F07.ui-libraries\u002F06.shadcn-components-advanced",{"title":2633,"icon":2634,"path":2635,"stem":2636,"children":2637,"page":59},"TypeScript","i-devicon-typescript","\u002Fjavascript\u002Ftypescript","03.javascript\u002F05.typescript",[2638,2642,2646,2650,2654,2658,2662,2666],{"title":2639,"path":2640,"stem":2641},"TypeScript: Броня для вашого коду","\u002Fjavascript\u002Ftypescript\u002Fintro-and-basic-types","03.javascript\u002F05.typescript\u002F01.intro-and-basic-types",{"title":2643,"path":2644,"stem":2645},"Майстерність Моделювання Даних: Інтерфейси та Просунуті Типи","\u002Fjavascript\u002Ftypescript\u002Finterfaces-and-advanced-types","03.javascript\u002F05.typescript\u002F02.interfaces-and-advanced-types",{"title":2647,"path":2648,"stem":2649},"Алхімія Типів: Generics та Utility Types","\u002Fjavascript\u002Ftypescript\u002Fgenerics-and-utilities","03.javascript\u002F05.typescript\u002F03.generics-and-utilities",{"title":2651,"path":2652,"stem":2653},"Архітектура та Шаблони: Класи в TypeScript","\u002Fjavascript\u002Ftypescript\u002Fclasses-and-oop","03.javascript\u002F05.typescript\u002F04.classes-and-oop",{"title":2655,"path":2656,"stem":2657},"Продакшн та Екосистема: Advanced Config & Workflow","\u002Fjavascript\u002Ftypescript\u002Fadvanced-patterns-and-config","03.javascript\u002F05.typescript\u002F05.advanced-patterns-and-config",{"title":2659,"path":2660,"stem":2661},"TypeScript у світі React","\u002Fjavascript\u002Ftypescript\u002Freact-basics","03.javascript\u002F05.typescript\u002F06.react-basics",{"title":2663,"path":2664,"stem":2665},"React + TypeScript: Продвинуті патерни","\u002Fjavascript\u002Ftypescript\u002Freact-advanced","03.javascript\u002F05.typescript\u002F07.react-advanced",{"title":2667,"path":2668,"stem":2669},"React + TypeScript: Екосистема та бібліотеки","\u002Fjavascript\u002Ftypescript\u002Freact-ecosystem","03.javascript\u002F05.typescript\u002F08.react-ecosystem",{"title":2671,"icon":2672,"path":2673,"stem":2674,"children":2675,"page":59},"Асинхронність","i-lucide-refresh-cw","\u002Fjavascript\u002Fasync-programming","03.javascript\u002F06.async-programming",[2676,2680,2684],{"title":2677,"path":2678,"stem":2679},"Event Loop: серце асинхронності в JavaScript","\u002Fjavascript\u002Fasync-programming\u002Fevent-loop-fundamentals","03.javascript\u002F06.async-programming\u002F01.event-loop-fundamentals",{"title":2681,"path":2682,"stem":2683},"Task Queue та Microtask Queue: пріоритети виконання","\u002Fjavascript\u002Fasync-programming\u002Ftask-queues","03.javascript\u002F06.async-programming\u002F02.task-queues",{"title":2685,"path":2686,"stem":2687},"Асинхронні патерни: від Callbacks до Async\u002FAwait","\u002Fjavascript\u002Fasync-programming\u002Fasync-patterns","03.javascript\u002F06.async-programming\u002F03.async-patterns",{"title":2689,"path":2690,"stem":2691},"Atomic Design","\u002Fjavascript\u002Fatomic-design","03.javascript\u002F2.atomic-design",{"title":2693,"icon":2694,"path":2695,"stem":2696,"children":2697,"page":59},"Java","i-devicon-java","\u002Fjava","04.java",[2698,2701,2704,2708,2712,2716,2720],{"title":162,"path":2699,"stem":2700},"\u002Fjava\u002Fdata-mapper-part1","04.java\u002F01.data-mapper-part1",{"title":166,"path":2702,"stem":2703},"\u002Fjava\u002Fdata-mapper-part2","04.java\u002F02.data-mapper-part2",{"title":2705,"path":2706,"stem":2707},"Service Layer: Організація бізнес-логіки","\u002Fjava\u002Fservice-layer","04.java\u002F03.service-layer",{"title":2709,"path":2710,"stem":2711},"Rich Domain Model та State Pattern","\u002Fjava\u002Frich-domain-model","04.java\u002F04.rich-domain-model",{"title":2713,"path":2714,"stem":2715},"Патерни для складної бізнес-логіки","\u002Fjava\u002Fbusiness-logic-patterns","04.java\u002F05.business-logic-patterns",{"title":2717,"path":2718,"stem":2719},"Обробка помилок та валідація","\u002Fjava\u002Ferror-handling-validation","04.java\u002F06.error-handling-validation",{"title":2721,"path":2722,"stem":2723,"children":2724,"page":59},"Проектування баз даних","\u002Fjava\u002Fpr2","04.java\u002Fpr2",[2725,2729,2733,2737,2741,2745,2749,2753,2757,2761,2765,2769,2773,2777,2781,2785,2789,2793,2797,2801,2805,2809,2813,2817,2821,2825,2829,2833,2837,2841,2845,2849,2853,2857,2861,2865,2869],{"title":2726,"path":2727,"stem":2728},"Концептуальне моделювання: Мистецтво розуміння предметної області","\u002Fjava\u002Fpr2\u002Fconceptual-modeling","04.java\u002Fpr2\u002F01.conceptual-modeling",{"title":2730,"path":2731,"stem":2732},"Логічне моделювання: Від бізнес-ідей до структур даних","\u002Fjava\u002Fpr2\u002Flogical-modeling","04.java\u002Fpr2\u002F02.logical-modeling",{"title":2734,"path":2735,"stem":2736},"Нормалізація: Гігієна даних та боротьба з аномаліями","\u002Fjava\u002Fpr2\u002Fnormalization","04.java\u002Fpr2\u002F03.normalization",{"title":2738,"path":2739,"stem":2740},"Фізична схема: Від абстракції до DDL","\u002Fjava\u002Fpr2\u002Fphysical-schema","04.java\u002Fpr2\u002F04.physical-schema",{"title":2742,"path":2743,"stem":2744},"Архітектурна класифікація таблиць","\u002Fjava\u002Fpr2\u002Ftable-classification","04.java\u002Fpr2\u002F05.table-classification",{"title":2746,"path":2747,"stem":2748},"Database Migrations: Версіонування схеми з Flyway","\u002Fjava\u002Fpr2\u002Fdatabase-migrations","04.java\u002Fpr2\u002F06.database-migrations",{"title":2750,"path":2751,"stem":2752},"А що, якби це була не реляційна БД?","\u002Fjava\u002Fpr2\u002Fbeyond-relational","04.java\u002Fpr2\u002F07.beyond-relational",{"title":2754,"path":2755,"stem":2756},"Object-Relational Impedance Mismatch: Два світи, що не хочуть дружити","\u002Fjava\u002Fpr2\u002Fimpedance-mismatch","04.java\u002Fpr2\u002F09.impedance-mismatch",{"title":2758,"path":2759,"stem":2760},"JDBC: Перший контакт із базою даних","\u002Fjava\u002Fpr2\u002Fjdbc-fundamentals","04.java\u002Fpr2\u002F10.jdbc-fundamentals",{"title":2762,"path":2763,"stem":2764},"Якість коду: Spotless, SpotBugs та SonarQube","\u002Fjava\u002Fpr2\u002F10a.code-quality","04.java\u002Fpr2\u002F10a.code-quality",{"title":2766,"path":2767,"stem":2768},"Connection Pool: Патерн Object Pool для JDBC-з'єднань","\u002Fjava\u002Fpr2\u002Fconnection-pool","04.java\u002Fpr2\u002F11.connection-pool",{"title":2770,"path":2771,"stem":2772},"Row Data Gateway: Об'єкт як обгортка рядка таблиці","\u002Fjava\u002Fpr2\u002Frow-data-gateway","04.java\u002Fpr2\u002F12.row-data-gateway",{"title":2774,"path":2775,"stem":2776},"Table Data Gateway: Фасад таблиці як архітектурний відступ","\u002Fjava\u002Fpr2\u002Ftable-data-gateway","04.java\u002Fpr2\u002F13.table-data-gateway",{"title":2778,"path":2779,"stem":2780},"Repository + Data Mapper: Правильна шарова архітектура з JDBC","\u002Fjava\u002Fpr2\u002Frepository-data-mapper","04.java\u002Fpr2\u002F14.repository-data-mapper",{"title":2782,"path":2783,"stem":2784},"Identity Map: Кешування сутностей у рамках сесії","\u002Fjava\u002Fpr2\u002Fidentity-map","04.java\u002Fpr2\u002F15.identity-map",{"title":2786,"path":2787,"stem":2788},"Unit of Work: Відстеження змін і координація JDBC-транзакцій","\u002Fjava\u002Fpr2\u002Funit-of-work","04.java\u002Fpr2\u002F16.unit-of-work",{"title":2790,"path":2791,"stem":2792},"Strategy: Замінювані SQL-стратегії для підтримки різних СУБД","\u002Fjava\u002Fpr2\u002Fstrategy-sql","04.java\u002Fpr2\u002F17.strategy-sql",{"title":2794,"path":2795,"stem":2796},"Proxy: Lazy Loading для One-To-Many колекцій","\u002Fjava\u002Fpr2\u002Fproxy-lazy-loading","04.java\u002Fpr2\u002F18.proxy-lazy-loading",{"title":2798,"path":2799,"stem":2800},"Generic Repository через Java Reflection: анотації та динамічний SQL","\u002Fjava\u002Fpr2\u002Fgeneric-repository-reflection","04.java\u002Fpr2\u002F19.generic-repository-reflection",{"title":2802,"path":2803,"stem":2804},"Specification Pattern: Композиція бізнес-правил для складних запитів","\u002Fjava\u002Fpr2\u002Fspecification-pattern","04.java\u002Fpr2\u002F20.specification-pattern",{"title":2806,"path":2807,"stem":2808},"Розширені можливості Specification Pattern: підзапити, агрегації та гібридний підхід","\u002Fjava\u002Fpr2\u002F20a.advanced-specifications","04.java\u002Fpr2\u002F20a.advanced-specifications",{"title":2810,"path":2811,"stem":2812},"Асинхронність у JDBC: Від блокуючих викликів до CompletableFuture","\u002Fjava\u002Fpr2\u002Fasynchronous-jdbc","04.java\u002Fpr2\u002F21.asynchronous-jdbc",{"title":2814,"path":2815,"stem":2816},"Інтеграційне тестування JDBC-репозиторіїв: Embedded H2 та патерн AAA","\u002Fjava\u002Fpr2\u002Fintegration-testing-h2","04.java\u002Fpr2\u002F22.integration-testing-h2",{"title":2818,"path":2819,"stem":2820},"Testcontainers: Тестування з реальною PostgreSQL у Docker-контейнерах","\u002Fjava\u002Fpr2\u002Fintegration-testing-testcontainers","04.java\u002Fpr2\u002F23.integration-testing-testcontainers",{"title":2822,"path":2823,"stem":2824},"Google Guice: Впровадження залежностей у JavaFX-проєкті","\u002Fjava\u002Fpr2\u002Fdependency-injection-guice","04.java\u002Fpr2\u002F24.dependency-injection-guice",{"title":2826,"path":2827,"stem":2828},"JavaFX: Основи побудови графічних інтерфейсів","\u002Fjava\u002Fpr2\u002Fjavafx-fundamentals","04.java\u002Fpr2\u002F25.javafx-fundamentals",{"title":2830,"path":2831,"stem":2832},"Properties та Bindings: Реактивність у JavaFX","\u002Fjava\u002Fpr2\u002Fjavafx-properties-bindings","04.java\u002Fpr2\u002F26.javafx-properties-bindings",{"title":2834,"path":2835,"stem":2836},"MVC vs MVP vs MVVM: Еволюція архітектурних патернів UI","\u002Fjava\u002Fpr2\u002Fui-architecture-patterns","04.java\u002Fpr2\u002F27.ui-architecture-patterns",{"title":2838,"path":2839,"stem":2840},"MVVM на практиці: Побудова ViewModel","\u002Fjava\u002Fpr2\u002Fmvvm-viewmodel-implementation","04.java\u002Fpr2\u002F28.mvvm-viewmodel-implementation",{"title":2842,"path":2843,"stem":2844},"View та Controller: Зв'язування з ViewModel через FXML","\u002Fjava\u002Fpr2\u002Fmvvm-view-controller","04.java\u002Fpr2\u002F29.mvvm-view-controller",{"title":2846,"path":2847,"stem":2848},"Інтеграція MVVM з Guice: Автоматична ін'єкція залежностей","\u002Fjava\u002Fpr2\u002Fmvvm-guice-integration","04.java\u002Fpr2\u002F30.mvvm-guice-integration",{"title":2850,"path":2851,"stem":2852},"Валідація та обробка помилок у MVVM","\u002Fjava\u002Fpr2\u002Fmvvm-validation-error-handling","04.java\u002Fpr2\u002F31.mvvm-validation-error-handling",{"title":2854,"path":2855,"stem":2856},"Навігація та управління екранами у JavaFX MVVM","\u002Fjava\u002Fpr2\u002Fmvvm-navigation-screen-management","04.java\u002Fpr2\u002F32.mvvm-navigation-screen-management",{"title":2858,"path":2859,"stem":2860},"Тестування JavaFX MVVM-додатків","\u002Fjava\u002Fpr2\u002Fmvvm-testing","04.java\u002Fpr2\u002F33.mvvm-testing",{"title":2862,"path":2863,"stem":2864},"Стилізація та теми у JavaFX: CSS та User Experience","\u002Fjava\u002Fpr2\u002Fjavafx-styling-themes","04.java\u002Fpr2\u002F34.javafx-styling-themes",{"title":2866,"path":2867,"stem":2868},"AtlantaFX: Сучасні теми для JavaFX додатків","\u002Fjava\u002Fpr2\u002Fatlantafx-modern-themes","04.java\u002Fpr2\u002F35.atlantafx-modern-themes",{"title":2870,"path":2871,"stem":2872},"Пакування та розповсюдження JavaFX-додатків","\u002Fjava\u002Fpr2\u002Fjar-packaging-distribution","04.java\u002Fpr2\u002F36.jar-packaging-distribution",{"title":2874,"icon":2875,"path":2876,"stem":2877,"children":2878,"page":59},"Python","i-devicon-python","\u002Fpython","05.python",[2879,2921,2980],{"title":2880,"icon":2881,"path":2882,"stem":2883,"children":2884,"page":59},"Python Core","i-lucide-code","\u002Fpython\u002Fcore","05.python\u002F01.core",[2885,2889,2893,2897,2901,2905,2909,2913,2917],{"title":2886,"path":2887,"stem":2888},"Як комп'ютер виконує програму","\u002Fpython\u002Fcore\u002Fhow-computers-run-programs","05.python\u002F01.core\u002F00.how-computers-run-programs",{"title":2890,"path":2891,"stem":2892},"Перша програма і функція print","\u002Fpython\u002Fcore\u002Ffirst-program-print","05.python\u002F01.core\u002F01.first-program-print",{"title":2894,"path":2895,"stem":2896},"Об'єкти, значення і типи","\u002Fpython\u002Fcore\u002Fobjects-values-types","05.python\u002F01.core\u002F02.objects-values-types",{"title":2898,"path":2899,"stem":2900},"Змінні — імена, посилання, ідентичність","\u002Fpython\u002Fcore\u002Fvariables-names-references","05.python\u002F01.core\u002F03.variables-names-references",{"title":2902,"path":2903,"stem":2904},"Вирази, оператори, введення і перетворення типів","\u002Fpython\u002Fcore\u002Fexpressions-input-types","05.python\u002F01.core\u002F04.expressions-input-types",{"title":2906,"path":2907,"stem":2908},"Логіка та розгалуження","\u002Fpython\u002Fcore\u002Flogic-branching","05.python\u002F01.core\u002F05.logic-branching",{"title":2910,"path":2911,"stem":2912},"Цикли та ітерація","\u002Fpython\u002Fcore\u002Floops-iteration","05.python\u002F01.core\u002F06.loops-iteration",{"title":2914,"path":2915,"stem":2916},"Налагодження (debugging)","\u002Fpython\u002Fcore\u002Fdebugging","05.python\u002F01.core\u002F07.debugging",{"title":2918,"path":2919,"stem":2920},"Рядки і текст","\u002Fpython\u002Fcore\u002Fstrings-text","05.python\u002F01.core\u002F08.strings-text",{"title":2532,"path":2922,"stem":2923,"children":2924,"page":59},"\u002Fpython\u002Fadvanced","05.python\u002F02.advanced",[2925,2929,2932,2936,2940,2944,2948,2952,2956,2960,2964,2968,2972,2976],{"title":2926,"path":2927,"stem":2928},"Модулі, Пакети та Віртуальні Середовища","\u002Fpython\u002Fadvanced\u002Fmodules-packages-venv","05.python\u002F02.advanced\u002F00.modules-packages-venv",{"title":71,"path":2930,"stem":2931},"\u002Fpython\u002Fadvanced\u002Fclasses-objects","05.python\u002F02.advanced\u002F01.classes-objects",{"title":2933,"path":2934,"stem":2935},"Інкапсуляція, Керування Доступом та Властивості","\u002Fpython\u002Fadvanced\u002Fencapsulation","05.python\u002F02.advanced\u002F02.encapsulation",{"title":2937,"path":2938,"stem":2939},"Наслідування, MRO та суперсила super()","\u002Fpython\u002Fadvanced\u002Finheritance-mro","05.python\u002F02.advanced\u002F03.inheritance-mro",{"title":2941,"path":2942,"stem":2943},"Абстракція — ABC проти Статичних Протоколів (PEP 544)","\u002Fpython\u002Fadvanced\u002Fabstraction-protocols","05.python\u002F02.advanced\u002F04.abstraction-protocols",{"title":2945,"path":2946,"stem":2947},"Магічні методи (Dunder) та Емуляція протоколів","\u002Fpython\u002Fadvanced\u002Fdunder-methods","05.python\u002F02.advanced\u002F05.dunder-methods",{"title":2949,"path":2950,"stem":2951},"Декоратори та Керування життєвим циклом методів","\u002Fpython\u002Fadvanced\u002Fdecorators-static-class","05.python\u002F02.advanced\u002F06.decorators-static-class",{"title":2953,"path":2954,"stem":2955},"Дескриптори — Магія доступу до атрибутів","\u002Fpython\u002Fadvanced\u002Fdescriptors","05.python\u002F02.advanced\u002F07.descriptors",{"title":2957,"path":2958,"stem":2959},"Метакласи — Динамічне створення класів під капотом CPython","\u002Fpython\u002Fadvanced\u002Fmetaclasses","05.python\u002F02.advanced\u002F08.metaclasses",{"title":2961,"path":2962,"stem":2963},"Dataclasses, NamedTuple та сучасні контейнери Python","\u002Fpython\u002Fadvanced\u002Fmodern-containers","05.python\u002F02.advanced\u002F09.modern-containers",{"title":2965,"path":2966,"stem":2967},"GIL та модель конкурентності CPython — фундамент перед потоками і процесами","\u002Fpython\u002Fadvanced\u002Fgil-concurrency-intro","05.python\u002F02.advanced\u002F11.gil-concurrency-intro",{"title":2969,"path":2970,"stem":2971},"Threading — конкурентність для I\u002FO-bound задач","\u002Fpython\u002Fadvanced\u002Fthreading","05.python\u002F02.advanced\u002F12.threading",{"title":2973,"path":2974,"stem":2975},"Multiprocessing — справжній паралелізм для CPU-bound задач","\u002Fpython\u002Fadvanced\u002Fmultiprocessing","05.python\u002F02.advanced\u002F13.multiprocessing",{"title":2977,"path":2978,"stem":2979},"asyncio — кооперативна конкурентність та event loop","\u002Fpython\u002Fadvanced\u002Fasyncio","05.python\u002F02.advanced\u002F14.asyncio",{"title":2981,"icon":92,"path":2982,"stem":2983,"children":2984,"page":59},"FastAPI","\u002Fpython\u002Ffastapi","05.python\u002F03.fastapi",[2985,2989,2993,2997,3001,3005,3009,3013,3017,3021,3025,3029,3033,3037],{"title":2986,"path":2987,"stem":2988},"Глибокий Typing та Pydantic v2 — від анотацій до валідації","\u002Fpython\u002Ffastapi\u002Ftyping-pydantic","05.python\u002F03.fastapi\u002F15.typing-pydantic",{"title":2990,"path":2991,"stem":2992},"WSGI, ASGI та Python Web-екосистема","\u002Fpython\u002Ffastapi\u002Fwsgi-asgi-ecosystem","05.python\u002F03.fastapi\u002F16.wsgi-asgi-ecosystem",{"title":2994,"path":2995,"stem":2996},"FastAPI: Перший додаток, Uvicorn та OpenAPI","\u002Fpython\u002Ffastapi\u002Ffastapi-intro","05.python\u002F03.fastapi\u002F17.fastapi-intro",{"title":2998,"path":2999,"stem":3000},"Маршрутизація, параметри запитів та APIRouter","\u002Fpython\u002Ffastapi\u002Ffastapi-routing-params","05.python\u002F03.fastapi\u002F18.fastapi-routing-params",{"title":3002,"path":3003,"stem":3004},"Pydantic v2 у FastAPI — схеми, валідація та серіалізація","\u002Fpython\u002Ffastapi\u002Ffastapi-pydantic-schemas","05.python\u002F03.fastapi\u002F19.fastapi-pydantic-schemas",{"title":3006,"path":3007,"stem":3008},"Dependency Injection — серце архітектури FastAPI","\u002Fpython\u002Ffastapi\u002Ffastapi-dependency-injection","05.python\u002F03.fastapi\u002F20.fastapi-dependency-injection",{"title":3010,"path":3011,"stem":3012},"Обробка помилок, Middleware та CORS у FastAPI","\u002Fpython\u002Ffastapi\u002Ffastapi-errors-middleware","05.python\u002F03.fastapi\u002F21.fastapi-errors-middleware",{"title":3014,"path":3015,"stem":3016},"SQLAlchemy 2.0 — ORM, Core та Async Engine","\u002Fpython\u002Ffastapi\u002Fsqlalchemy-orm","05.python\u002F03.fastapi\u002F22.sqlalchemy-orm",{"title":3018,"path":3019,"stem":3020},"Alembic — міграції бази даних","\u002Fpython\u002Ffastapi\u002Falembic-migrations","05.python\u002F03.fastapi\u002F23.alembic-migrations",{"title":3022,"path":3023,"stem":3024},"Repository Pattern та Clean Architecture у FastAPI","\u002Fpython\u002Ffastapi\u002Ffastapi-repository-clean-arch","05.python\u002F03.fastapi\u002F24.fastapi-repository-clean-arch",{"title":3026,"path":3027,"stem":3028},"Автентифікація та авторизація — JWT, OAuth2, RBAC","\u002Fpython\u002Ffastapi\u002Ffastapi-auth-security","05.python\u002F03.fastapi\u002F25.fastapi-auth-security",{"title":3030,"path":3031,"stem":3032},"Тестування FastAPI — pytest, httpx, fixtures","\u002Fpython\u002Ffastapi\u002Ffastapi-testing","05.python\u002F03.fastapi\u002F26.fastapi-testing",{"title":3034,"path":3035,"stem":3036},"Async на повну — Background Tasks, WebSockets, SSE та Celery","\u002Fpython\u002Ffastapi\u002Ffastapi-async-advanced","05.python\u002F03.fastapi\u002F27.fastapi-async-advanced",{"title":3038,"path":3039,"stem":3040},"Deployment — Docker, CI\u002FCD, Monitoring","\u002Fpython\u002Ffastapi\u002Ffastapi-deployment","05.python\u002F03.fastapi\u002F28.fastapi-deployment",{"title":3042,"icon":3043,"path":3044,"stem":3045,"children":3046,"page":59},"Бази даних","i-lucide-database","\u002Fdatabases","06.databases",[3047,3077,3100,3137,3166,3184,3218,3230,3239],{"title":3048,"icon":3049,"path":3050,"stem":3051,"children":3052,"page":59},"Intro","i-lucide-play","\u002Fdatabases\u002Fintro","06.databases\u002F01.intro",[3053,3057,3061,3065,3069,3073],{"title":3054,"path":3055,"stem":3056},"Введення в теорію баз даних","\u002Fdatabases\u002Fintro\u002Fintroduction-to-databases","06.databases\u002F01.intro\u002F01.introduction-to-databases",{"title":3058,"path":3059,"stem":3060},"Реляційна модель даних","\u002Fdatabases\u002Fintro\u002Frelational-model-theory","06.databases\u002F01.intro\u002F02.relational-model-theory",{"title":3062,"path":3063,"stem":3064},"ER-моделювання","\u002Fdatabases\u002Fintro\u002Fer-modeling","06.databases\u002F01.intro\u002F03.er-modeling",{"title":3066,"path":3067,"stem":3068},"Логічне проектування БД","\u002Fdatabases\u002Fintro\u002Flogical-schema","06.databases\u002F01.intro\u002F04.logical-schema",{"title":3070,"path":3071,"stem":3072},"Класифікація таблиць","\u002Fdatabases\u002Fintro\u002Ftable-classification","06.databases\u002F01.intro\u002F05.table-classification",{"title":3074,"path":3075,"stem":3076},"PlantUML для баз даних","\u002Fdatabases\u002Fintro\u002Fplantuml-diagrams","06.databases\u002F01.intro\u002F06.plantuml-diagrams",{"title":3078,"icon":3043,"path":3079,"stem":3080,"children":3081,"page":59},"MS SQL Server Start","\u002Fdatabases\u002Fms-sql-server-start","06.databases\u002F02.ms-sql-server-start",[3082,3086,3092,3096],{"title":3083,"path":3084,"stem":3085},"Типи даних у MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fdata-types","06.databases\u002F02.ms-sql-server-start\u002F01.data-types",{"title":3087,"path":3088,"stem":3089,"children":3090},"Індекси у MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fsql-indexes","06.databases\u002F02.ms-sql-server-start\u002F02.sql-indexes",[3091],{"title":3087,"path":3088,"stem":3089},{"title":3093,"path":3094,"stem":3095},"Системні бази даних MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fsystem-databases","06.databases\u002F02.ms-sql-server-start\u002F03.system-databases",{"title":3097,"path":3098,"stem":3099},"Огляд мови SQL та запитів","\u002Fdatabases\u002Fms-sql-server-start\u002Fsql-queries-overview","06.databases\u002F02.ms-sql-server-start\u002F04.sql-queries-overview",{"title":3101,"icon":3043,"path":3102,"stem":3103,"children":3104,"page":59},"SQL","\u002Fdatabases\u002Fsql","06.databases\u002F03.sql",[3105,3109,3113,3117,3121,3125,3129,3133],{"title":3106,"path":3107,"stem":3108},"Налаштування демонстраційної бази даних","\u002Fdatabases\u002Fsql\u002Fsample-database-setup","06.databases\u002F03.sql\u002F00.sample-database-setup",{"title":3110,"path":3111,"stem":3112},"DDL - Створення таблиць (CREATE TABLE)","\u002Fdatabases\u002Fsql\u002Fddl-create-table","06.databases\u002F03.sql\u002F01.ddl-create-table",{"title":3114,"path":3115,"stem":3116},"DDL - Зміна та видалення таблиць (ALTER, DROP)","\u002Fdatabases\u002Fsql\u002Fddl-alter-drop-table","06.databases\u002F03.sql\u002F02.ddl-alter-drop-table",{"title":3118,"path":3119,"stem":3120},"SELECT запити - Основи","\u002Fdatabases\u002Fsql\u002Fselect-queries-fundamentals","06.databases\u002F03.sql\u002F03.select-queries-fundamentals",{"title":3122,"path":3123,"stem":3124},"SELECT запити - Розширені можливості","\u002Fdatabases\u002Fsql\u002Fselect-queries-advanced","06.databases\u002F03.sql\u002F04.select-queries-advanced",{"title":3126,"path":3127,"stem":3128},"INSERT запити - Додавання даних","\u002Fdatabases\u002Fsql\u002Finsert-queries","06.databases\u002F03.sql\u002F05.insert-queries",{"title":3130,"path":3131,"stem":3132},"UPDATE та DELETE запити","\u002Fdatabases\u002Fsql\u002Fupdate-delete-queries","06.databases\u002F03.sql\u002F06.update-delete-queries",{"title":3134,"path":3135,"stem":3136},"Транзакції в SQL","\u002Fdatabases\u002Fsql\u002Ftransactions","06.databases\u002F03.sql\u002F07.transactions",{"title":3138,"icon":3043,"path":3139,"stem":3140,"children":3141,"page":59},"Multi Table Databases","\u002Fdatabases\u002Fmulti-table-databases","06.databases\u002F04.multi-table-databases",[3142,3146,3150,3154,3158,3162],{"title":3143,"path":3144,"stem":3145},"Зв'язки та нормалізація БД","\u002Fdatabases\u002Fmulti-table-databases\u002Frelationships-and-normalization","06.databases\u002F04.multi-table-databases\u002F00.relationships-and-normalization",{"title":3147,"path":3148,"stem":3149},"INNER JOIN - З'єднання таблиць","\u002Fdatabases\u002Fmulti-table-databases\u002Finner-join","06.databases\u002F04.multi-table-databases\u002F01.inner-join",{"title":3151,"path":3152,"stem":3153},"OUTER JOINs - LEFT, RIGHT, FULL","\u002Fdatabases\u002Fmulti-table-databases\u002Fouter-joins","06.databases\u002F04.multi-table-databases\u002F02.outer-joins",{"title":3155,"path":3156,"stem":3157},"CROSS та SELF JOINs","\u002Fdatabases\u002Fmulti-table-databases\u002Fcross-self-joins","06.databases\u002F04.multi-table-databases\u002F03.cross-self-joins",{"title":3159,"path":3160,"stem":3161},"Підзапити (Subqueries)","\u002Fdatabases\u002Fmulti-table-databases\u002Fsubqueries","06.databases\u002F04.multi-table-databases\u002F04.subqueries",{"title":3163,"path":3164,"stem":3165},"Агрегації з JOIN","\u002Fdatabases\u002Fmulti-table-databases\u002Faggregations-with-joins","06.databases\u002F04.multi-table-databases\u002F05.aggregations-with-joins",{"title":3167,"icon":3168,"path":3169,"stem":3170,"children":3171,"page":59},"Aggregate Functions","i-lucide-calculator","\u002Fdatabases\u002Faggregate-functions","06.databases\u002F05.aggregate-functions",[3172,3176,3180],{"title":3173,"path":3174,"stem":3175},"Функції агрегування в MS SQL Server","\u002Fdatabases\u002Faggregate-functions\u002Fintroduction-aggregate-functions","06.databases\u002F05.aggregate-functions\u002F01.introduction-aggregate-functions",{"title":3177,"path":3178,"stem":3179},"Групування даних в MS SQL Server","\u002Fdatabases\u002Faggregate-functions\u002Fgrouping-data","06.databases\u002F05.aggregate-functions\u002F02.grouping-data",{"title":3181,"path":3182,"stem":3183},"Підзапити з агрегатними функціями","\u002Fdatabases\u002Faggregate-functions\u002Fsubqueries-aggregates","06.databases\u002F05.aggregate-functions\u002F03.subqueries-aggregates",{"title":3185,"icon":3186,"path":3187,"stem":3188,"children":3189,"page":59},"Тригери та зберігаємі процедури","i-lucide-database-zap","\u002Fdatabases\u002Ftriggers-stored-procedures","06.databases\u002F07.triggers-stored-procedures",[3190,3194,3198,3202,3206,3210,3214],{"title":3191,"path":3192,"stem":3193},"DML-тригери","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fdml-triggers","06.databases\u002F07.triggers-stored-procedures\u002F01.dml-triggers",{"title":3195,"path":3196,"stem":3197},"DDL-тригери","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fddl-triggers","06.databases\u002F07.triggers-stored-procedures\u002F02.ddl-triggers",{"title":3199,"path":3200,"stem":3201},"Transact-SQL розширення","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Ftransact-sql-extensions","06.databases\u002F07.triggers-stored-procedures\u002F03.transact-sql-extensions",{"title":3203,"path":3204,"stem":3205},"Транзакції","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Ftransactions","06.databases\u002F07.triggers-stored-procedures\u002F04.transactions",{"title":3207,"path":3208,"stem":3209},"Зберігаємі процедури","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fstored-procedures","06.databases\u002F07.triggers-stored-procedures\u002F05.stored-procedures",{"title":3211,"path":3212,"stem":3213},"Користувацькі функції","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fuser-defined-functions","06.databases\u002F07.triggers-stored-procedures\u002F06.user-defined-functions",{"title":3215,"path":3216,"stem":3217},"Безпека баз даних","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fsecurity","06.databases\u002F07.triggers-stored-procedures\u002F08.security",{"title":3215,"icon":793,"path":3219,"stem":3220,"children":3221,"page":59},"\u002Fdatabases\u002Fsecurity","06.databases\u002F08.security",[3222,3226],{"title":3223,"path":3224,"stem":3225},"Вступ до безпеки баз даних","\u002Fdatabases\u002Fsecurity\u002Fintroduction","06.databases\u002F08.security\u002F01.introduction",{"title":3227,"path":3228,"stem":3229},"Системні представлення та метадані","\u002Fdatabases\u002Fsecurity\u002Fsystem-views","06.databases\u002F08.security\u002F02.system-views",{"title":3231,"icon":3232,"path":3233,"stem":3234,"children":3235,"page":59},"Резервне копіювання та відновлення","i-lucide-database-backup","\u002Fdatabases\u002Fbackup-recovery","06.databases\u002F09.backup-recovery",[3236],{"title":3231,"path":3237,"stem":3238},"\u002Fdatabases\u002Fbackup-recovery\u002Fbackup-restore","06.databases\u002F09.backup-recovery\u002F01.backup-restore",{"title":3240,"icon":3241,"path":3242,"stem":3243,"children":3244,"page":59},"Повнотекстовий пошук","i-lucide-search","\u002Fdatabases\u002Ffull-text-search","06.databases\u002F10.full-text-search",[3245],{"title":3240,"path":3246,"stem":3247},"\u002Fdatabases\u002Ffull-text-search\u002Ffull-text-search","06.databases\u002F10.full-text-search\u002F01.full-text-search",{"title":3249,"icon":3250,"path":3251,"stem":3252,"children":3253,"page":59},"Tools","i-lucide-wrench","\u002Ftools","07.tools",[3254,3330],{"title":3255,"icon":3256,"path":3257,"stem":3258,"children":3259},"Docker","i-simple-icons-docker","\u002Ftools\u002Fdocker","07.tools\u002F01.docker\u002Findex",[3260,3262,3266,3270,3274,3278,3282,3286,3290,3294,3298,3302,3306,3310,3314,3318,3322,3326],{"title":3261,"path":3257,"stem":3258},"Docker: від нуля до production",{"title":3263,"path":3264,"stem":3265},"Контейнеризація — від проблеми до рішення","\u002Ftools\u002Fdocker\u002Fcontainerization-concept","07.tools\u002F01.docker\u002F01.containerization-concept",{"title":3267,"path":3268,"stem":3269},"Docker — що це і навіщо?","\u002Ftools\u002Fdocker\u002Fdocker-what-and-why","07.tools\u002F01.docker\u002F02.docker-what-and-why",{"title":3271,"path":3272,"stem":3273},"Архітектура Docker Engine","\u002Ftools\u002Fdocker\u002Fdocker-architecture","07.tools\u002F01.docker\u002F03.docker-architecture",{"title":3275,"path":3276,"stem":3277},"Встановлення Docker","\u002Ftools\u002Fdocker\u002Finstallation","07.tools\u002F01.docker\u002F04.installation",{"title":3279,"path":3280,"stem":3281},"Перший контейнер — docker run","\u002Ftools\u002Fdocker\u002Ffirst-container","07.tools\u002F01.docker\u002F05.first-container",{"title":3283,"path":3284,"stem":3285},"Життєвий цикл контейнера","\u002Ftools\u002Fdocker\u002Fcontainer-lifecycle","07.tools\u002F01.docker\u002F06.container-lifecycle",{"title":3287,"path":3288,"stem":3289},"Docker Images — фундаментальні концепції","\u002Ftools\u002Fdocker\u002Fdocker-images-fundamentals","07.tools\u002F01.docker\u002F07.docker-images-fundamentals",{"title":3291,"path":3292,"stem":3293},"Dockerfile — основи","\u002Ftools\u002Fdocker\u002Fdockerfile-basics","07.tools\u002F01.docker\u002F08.dockerfile-basics",{"title":3295,"path":3296,"stem":3297},"Dockerfile — просунуті техніки","\u002Ftools\u002Fdocker\u002Fdockerfile-advanced","07.tools\u002F01.docker\u002F09.dockerfile-advanced",{"title":3299,"path":3300,"stem":3301},"Build Context та кешування шарів","\u002Ftools\u002Fdocker\u002Fbuild-context-and-cache","07.tools\u002F01.docker\u002F10.build-context-and-cache",{"title":3303,"path":3304,"stem":3305},"Реєстри Docker-образів","\u002Ftools\u002Fdocker\u002Fimage-registries","07.tools\u002F01.docker\u002F11.image-registries",{"title":3307,"path":3308,"stem":3309},"Контейнеризація .NET додатків","\u002Ftools\u002Fdocker\u002Fdotnet-containerization","07.tools\u002F01.docker\u002F12.dotnet-containerization",{"title":3311,"path":3312,"stem":3313},"Томи та збереження даних","\u002Ftools\u002Fdocker\u002Fvolumes-and-data","07.tools\u002F01.docker\u002F13.volumes-and-data",{"title":3315,"path":3316,"stem":3317},"Основи мережі в Docker","\u002Ftools\u002Fdocker\u002Fnetworking-basics","07.tools\u002F01.docker\u002F14.networking-basics",{"title":3319,"path":3320,"stem":3321},"Змінні оточення та конфігурація","\u002Ftools\u002Fdocker\u002Fenvironment-and-configuration","07.tools\u002F01.docker\u002F15.environment-and-configuration",{"title":3323,"path":3324,"stem":3325},"Docker Compose — оркестрація контейнерів","\u002Ftools\u002Fdocker\u002Fdocker-compose-basics","07.tools\u002F01.docker\u002F16.docker-compose-basics",{"title":3327,"path":3328,"stem":3329},"Docker Compose — Multi-Service застосунки","\u002Ftools\u002Fdocker\u002Fcompose-multi-service","07.tools\u002F01.docker\u002F17.compose-multi-service",{"title":3331,"icon":3332,"path":3333,"stem":3334,"children":3335},"Kubernetes","simple-icons:kubernetes","\u002Ftools\u002Fkubernetes","07.tools\u002F02.kubernetes\u002Findex",[3336,3338,3342,3346,3350,3354,3358,3362,3366],{"title":3337,"path":3333,"stem":3334},"Kubernetes: від розробки до production",{"title":3339,"path":3340,"stem":3341},"Kubernetes — коли Docker Compose більше не вистачає","\u002Ftools\u002Fkubernetes\u002Fwhy-kubernetes","07.tools\u002F02.kubernetes\u002F01.why-kubernetes",{"title":3343,"path":3344,"stem":3345},"Архітектура Kubernetes — анатомія кластера","\u002Ftools\u002Fkubernetes\u002Fkubernetes-architecture","07.tools\u002F02.kubernetes\u002F02.kubernetes-architecture",{"title":3347,"path":3348,"stem":3349},"Локальне середовище — minikube, kind та k3s","\u002Ftools\u002Fkubernetes\u002Flocal-environment","07.tools\u002F02.kubernetes\u002F03.local-environment",{"title":3351,"path":3352,"stem":3353},"Pod — атомарна одиниця Kubernetes","\u002Ftools\u002Fkubernetes\u002Fpods-and-containers","07.tools\u002F02.kubernetes\u002F04.pods-and-containers",{"title":3355,"path":3356,"stem":3357},"Патерни використання Pod","\u002Ftools\u002Fkubernetes\u002Fpod-patterns","07.tools\u002F02.kubernetes\u002F05.pod-patterns",{"title":3359,"path":3360,"stem":3361},"Deployment — декларативне управління Pod","\u002Ftools\u002Fkubernetes\u002Fdeployment-basics","07.tools\u002F02.kubernetes\u002F06.deployment-basics",{"title":3363,"path":3364,"stem":3365},"Rolling Updates та управління життєвим циклом Deployment","\u002Ftools\u002Fkubernetes\u002Fdeployment-rolling-updates","07.tools\u002F02.kubernetes\u002F07.deployment-rolling-updates",{"title":3367,"path":3368,"stem":3369},"Service — мережева абстракція для Pod","\u002Ftools\u002Fkubernetes\u002Fservices-networking","07.tools\u002F02.kubernetes\u002F08.services-networking",{"title":3371,"icon":3372,"path":3373,"stem":3374,"children":3375,"page":59},"Software Engineering","i-lucide-code-2","\u002Fsoftware-engineering","09.software-engineering",[3376,3380,3384,3388,3392,3396,3400,3404,3408,3412,3416],{"title":3377,"path":3378,"stem":3379},"1. Аналіз предметної області. Експертні знання та складність","\u002Fsoftware-engineering\u002Fintro-subdomains","09.software-engineering\u002F01.intro-subdomains",{"title":3381,"path":3382,"stem":3383},"2. Обмежені контексти. Інтеграція обмежених контекстів","\u002Fsoftware-engineering\u002Fintegrating-limited-contexts","09.software-engineering\u002F02.integrating-limited-contexts",{"title":3385,"path":3386,"stem":3387},"3. Реалізація простої бізнес-логіки","\u002Fsoftware-engineering\u002Fsimple","09.software-engineering\u002F03.simple",{"title":3389,"path":3390,"stem":3391},"4. Опрацювання складної бізнес-логіки","\u002Fsoftware-engineering\u002Fcomplex-business-logic","09.software-engineering\u002F04.complex-business-logic",{"title":3393,"path":3394,"stem":3395},"5. Моделювання фактора часу. Подієво-орієнтована архітектура.","\u002Fsoftware-engineering\u002Fmodelling-the-time-factor","09.software-engineering\u002F05.modelling-the-time-factor",{"title":3397,"path":3398,"stem":3399},"6. Архітектурні патерни","\u002Fsoftware-engineering\u002Farchitectural-patterns","09.software-engineering\u002F06.architectural-patterns",{"title":3401,"path":3402,"stem":3403},"Паттерни взаємодії","\u002Fsoftware-engineering\u002Fpatterns-of-interaction","09.software-engineering\u002F07.patterns-of-interaction",{"title":3405,"path":3406,"stem":3407},"Евристика проєктування","\u002Fsoftware-engineering\u002Fdesign-heuristics","09.software-engineering\u002F08.design-heuristics",{"title":3409,"path":3410,"stem":3411},"Еволюція проєктних рішень","\u002Fsoftware-engineering\u002Fevolution-of-design-solutions","09.software-engineering\u002F09.evolution-of-design-solutions",{"title":3413,"path":3414,"stem":3415},"EventStorming","\u002Fsoftware-engineering\u002Feventstorming","09.software-engineering\u002F10.eventstorming",{"title":3417,"path":3418,"stem":3419},"DDD на практиці","\u002Fsoftware-engineering\u002Fddd-in-practice","09.software-engineering\u002F11.ddd-in-practice",{"title":3421,"icon":943,"path":3422,"stem":3423,"children":3424,"page":59},"DDD","\u002Fddd","10.ddd",[3425,3429,3433,3437,3441,3445,3449,3453,3457,3461,3465,3469,3473],{"title":3426,"path":3427,"stem":3428},"Аналіз предметної області","\u002Fddd\u002Fdomain-analysis","10.ddd\u002F01.domain-analysis",{"title":3430,"path":3431,"stem":3432},"Експертні знання про предметну область","\u002Fddd\u002Fdomain-expert-knowledge","10.ddd\u002F02.domain-expert-knowledge",{"title":3434,"path":3435,"stem":3436},"Як осмислити складність предметної області","\u002Fddd\u002Fmanaging-domain-complexity","10.ddd\u002F03.managing-domain-complexity",{"title":3438,"path":3439,"stem":3440},"Інтеграція обмежених контекстів","\u002Fddd\u002Fbounded-context-integration","10.ddd\u002F04.bounded-context-integration",{"title":3442,"path":3443,"stem":3444},"Реалізація простої бізнес-логіки","\u002Fddd\u002Fsimple-business-logic","10.ddd\u002F05.simple-business-logic",{"title":3446,"path":3447,"stem":3448},"Обробка складної бізнес-логіки","\u002Fddd\u002Fcomplex-business-logic","10.ddd\u002F06.complex-business-logic",{"title":3450,"path":3451,"stem":3452},"Моделювання фактора часу","\u002Fddd\u002Ftime-modeling","10.ddd\u002F07.time-modeling",{"title":3454,"path":3455,"stem":3456},"Глава 8. Архітектурні Патерни","\u002Fddd\u002Farchitectural-patterns","10.ddd\u002F08.architectural-patterns",{"title":3458,"path":3459,"stem":3460},"Глава 9. Патерни Взаємодії","\u002Fddd\u002Finteraction-patterns","10.ddd\u002F09.interaction-patterns",{"title":3462,"path":3463,"stem":3464},"Глава 10. Проектні Евристики","\u002Fddd\u002Fdesign-heuristics","10.ddd\u002F10.design-heuristics",{"title":3466,"path":3467,"stem":3468},"Глава 11. Еволюція Проектних Рішень","\u002Fddd\u002Fevolution-of-design-decisions","10.ddd\u002F11.evolution-of-design-decisions",{"title":3470,"path":3471,"stem":3472},"Глава 12. EventStorming","\u002Fddd\u002Fevent-storming","10.ddd\u002F12.event-storming",{"title":3474,"path":3475,"stem":3476},"Глава 13. DDD на Практиці","\u002Fddd\u002Fddd-in-practice","10.ddd\u002F13.ddd-in-practice",{"title":3478,"icon":3479,"path":3480,"stem":3481,"children":3482,"page":59},"Media Streaming","i-lucide-video","\u002Fmedia-streaming","11.media-streaming",[3483,3487,3491,3495,3499,3503,3507],{"title":3484,"path":3485,"stem":3486},"01. Магія Стрімінгу: Що відбувається, коли ви натискаєте \"Play\"","\u002Fmedia-streaming\u002Fintroduction","11.media-streaming\u002F01.introduction",{"title":3488,"path":3489,"stem":3490},"02. Анатомія Медіа: Кодеки, Контейнери та Стиснення","\u002Fmedia-streaming\u002Faudio-video-anatomy","11.media-streaming\u002F02.audio-video-anatomy",{"title":3492,"path":3493,"stem":3494},"03. The Gym: FFmpeg Deep Dive","\u002Fmedia-streaming\u002Fffmpeg-gym","11.media-streaming\u002F03.ffmpeg-gym",{"title":3496,"path":3497,"stem":3498},"04. HLS Protocol: HTTP Live Streaming у Деталях","\u002Fmedia-streaming\u002Fhls-protocol","11.media-streaming\u002F04.hls-protocol",{"title":3500,"path":3501,"stem":3502},"05. DASH Protocol: Відкритий Стандарт","\u002Fmedia-streaming\u002Fdash-protocol","11.media-streaming\u002F05.dash-protocol",{"title":3504,"path":3505,"stem":3506},"06. Масштабування: CDN та Adaptive Bitrate","\u002Fmedia-streaming\u002Fcdn-and-adaptive-bitrate","11.media-streaming\u002F06.cdn-and-adaptive-bitrate",{"title":3508,"path":3509,"stem":3510},"07. Війна із Затримкою (Latency)","\u002Fmedia-streaming\u002Frealtime-latency","11.media-streaming\u002F07.realtime-latency",{"title":3512,"icon":3513,"path":3514,"stem":3515,"children":3516,"page":59},"HTML & CSS","i-devicon-html5","\u002Fhtml-css","12.html-css",[3517,3521,3525,3529,3533,3537,3541,3545,3549,3553,3557,3561,3565,3569,3573,3577,3581,3585,3589,3593,3597,3601,3605,3609,3613,3617,3621,3625,3629,3633],{"title":3518,"path":3519,"stem":3520},"Вступ до HTML. Структура документа","\u002Fhtml-css\u002Fintro-html-structure","12.html-css\u002F01.intro-html-structure",{"title":3522,"path":3523,"stem":3524},"Форматування тексту в HTML","\u002Fhtml-css\u002Fhtml-text-formatting","12.html-css\u002F02.html-text-formatting",{"title":3526,"path":3527,"stem":3528},"Посилання та зображення в HTML","\u002Fhtml-css\u002Fhtml-links-images","12.html-css\u002F03.html-links-images",{"title":3530,"path":3531,"stem":3532},"Списки та таблиці в HTML","\u002Fhtml-css\u002Fhtml-lists-tables","12.html-css\u002F04.html-lists-tables",{"title":3534,"path":3535,"stem":3536},"Форми в HTML","\u002Fhtml-css\u002Fhtml-forms","12.html-css\u002F05.html-forms",{"title":3538,"path":3539,"stem":3540},"Семантичні елементи HTML5","\u002Fhtml-css\u002Fhtml-semantic-elements","12.html-css\u002F06.html-semantic-elements",{"title":3542,"path":3543,"stem":3544},"Мультимедіа та розширені елементи HTML","\u002Fhtml-css\u002Fhtml-multimedia-advanced","12.html-css\u002F07.html-multimedia-advanced",{"title":3546,"path":3547,"stem":3548},"Мікророзмітка та SEO в HTML","\u002Fhtml-css\u002Fhtml-microdata-seo","12.html-css\u002F08.html-microdata-seo",{"title":3550,"path":3551,"stem":3552},"Вступ до CSS. Селектори та специфічність","\u002Fhtml-css\u002Fcss-intro-selectors","12.html-css\u002F09.css-intro-selectors",{"title":3554,"path":3555,"stem":3556},"Блокова модель CSS. Відступи. Box Sizing","\u002Fhtml-css\u002Fcss-box-model","12.html-css\u002F10.css-box-model",{"title":3558,"path":3559,"stem":3560},"Розміри у CSS: повний довідник одиниць і ключових слів","\u002Fhtml-css\u002F10a.css-sizing","12.html-css\u002F10a.css-sizing",{"title":3562,"path":3563,"stem":3564},"Типографіка в CSS. Шрифти та текст","\u002Fhtml-css\u002Fcss-typography","12.html-css\u002F11.css-typography",{"title":3566,"path":3567,"stem":3568},"Кольори та фони в CSS","\u002Fhtml-css\u002Fcss-colors-backgrounds","12.html-css\u002F12.css-colors-backgrounds",{"title":3570,"path":3571,"stem":3572},"Тіні та фільтри в CSS","\u002Fhtml-css\u002F12b.css-shadows-filters","12.html-css\u002F12b.css-shadows-filters",{"title":3574,"path":3575,"stem":3576},"CSS Flexbox: Фундамент гнучких макетів","\u002Fhtml-css\u002Fcss-flexbox-fundamentals","12.html-css\u002F13.css-flexbox-fundamentals",{"title":3578,"path":3579,"stem":3580},"CSS Flexbox: Вирівнювання та Позиціонування","\u002Fhtml-css\u002Fcss-flexbox-alignment-sizing-and-patterns","12.html-css\u002F14.css-flexbox-alignment-sizing-and-patterns",{"title":3582,"path":3583,"stem":3584},"CSS Grid. Двовимірний макет. Частина 1","\u002Fhtml-css\u002Fcss-layout-grid","12.html-css\u002F15.css-layout-grid",{"title":3586,"path":3587,"stem":3588},"CSS Grid. Двовимірний макет. Частина 2","\u002Fhtml-css\u002Fcss-layout-grid-advanced","12.html-css\u002F16.css-layout-grid-advanced",{"title":3590,"path":3591,"stem":3592},"Позиціонування в CSS. Z-index. Stacking Context","\u002Fhtml-css\u002Fcss-positioning","12.html-css\u002F17.css-positioning",{"title":3594,"path":3595,"stem":3596},"CSS Анімації та Переходи","\u002Fhtml-css\u002Fcss-animations-transitions","12.html-css\u002F18.css-animations-transitions",{"title":3598,"path":3599,"stem":3600},"Адаптивний дизайн. Media Queries. Частина 1","\u002Fhtml-css\u002Fcss-responsive-media-queries","12.html-css\u002F19.css-responsive-media-queries",{"title":3602,"path":3603,"stem":3604},"Адаптивний дизайн. Частина 2: clamp(), Container Queries, @layer","\u002Fhtml-css\u002Fcss-responsive-advanced","12.html-css\u002F20.css-responsive-advanced",{"title":3606,"path":3607,"stem":3608},"CSS Custom Properties. Методології. Сучасний CSS","\u002Fhtml-css\u002Fcss-variables-methodologies","12.html-css\u002F21.css-variables-methodologies",{"title":3610,"path":3611,"stem":3612},"Сучасний CSS 2023–2025: Нові можливості","\u002Fhtml-css\u002Fcss-modern-features","12.html-css\u002F22.css-modern-features",{"title":3614,"path":3615,"stem":3616},"CSS Nesting, @layer, @scope та @property: нативний препроцесор","\u002Fhtml-css\u002F22a.css-nesting-modern-syntax","12.html-css\u002F22a.css-nesting-modern-syntax",{"title":3618,"path":3619,"stem":3620},"CSS для форм та інтерактивних станів","\u002Fhtml-css\u002Fcss-forms-interactive-states","12.html-css\u002F23.css-forms-interactive-states",{"title":3622,"path":3623,"stem":3624},"Доступність у CSS (CSS Accessibility)","\u002Fhtml-css\u002Fcss-accessibility","12.html-css\u002F24.css-accessibility",{"title":3626,"path":3627,"stem":3628},"CSS-функції та сучасні sizing primitives","\u002Fhtml-css\u002Fcss-functions-sizing","12.html-css\u002F25.css-functions-sizing",{"title":3630,"path":3631,"stem":3632},"Rendering Pipeline і CSS Performance","\u002Fhtml-css\u002Fcss-rendering-performance","12.html-css\u002F26.css-rendering-performance",{"title":3634,"path":3635,"stem":3636},"CSS Best Practices: типові ситуації та правильні рішення","\u002Fhtml-css\u002Fcss-best-practices","12.html-css\u002F27.css-best-practices",{"title":3638,"path":3639,"stem":3640,"children":3641,"page":59},"AWS","\u002Faws","13.aws",[3642,3646,3650,3654,3658,3662,3666,3670,3674,3678,3682,3686,3690,3694,3698,3702,3706,3710],{"title":3643,"path":3644,"stem":3645},"Реєстрація AWS акаунту та студентські програми","\u002Faws\u002Faccount-registration","13.aws\u002F00.account-registration",{"title":3647,"path":3648,"stem":3649},"Вступ до хмарних обчислень та AWS","\u002Faws\u002Fintroduction-to-cloud","13.aws\u002F01.introduction-to-cloud",{"title":3651,"path":3652,"stem":3653},"AWS IAM — Identity and Access Management","\u002Faws\u002Fiam","13.aws\u002F02.iam",{"title":3655,"path":3656,"stem":3657},"AWS IAM CLI — Довідник команд","\u002Faws\u002F02a.iam-doc","13.aws\u002F02a.iam-doc",{"title":3659,"path":3660,"stem":3661},"Docker та контейнеризація в AWS — ECR, ECS та Fargate","\u002Faws\u002Fdocker-ecs","13.aws\u002F03.docker-ecs",{"title":3663,"path":3664,"stem":3665},"AWS ECR \u002F ECS CLI — Довідник команд","\u002Faws\u002F03a.docker-ecs-doc","13.aws\u002F03a.docker-ecs-doc",{"title":3667,"path":3668,"stem":3669},"Amazon EC2 — Elastic Compute Cloud","\u002Faws\u002Fec2","13.aws\u002F04.ec2",{"title":3671,"path":3672,"stem":3673},"AWS EC2 CLI — Довідник команд","\u002Faws\u002F04a.ec2-doc","13.aws\u002F04a.ec2-doc",{"title":3675,"path":3676,"stem":3677},"Elastic Load Balancing та Auto Scaling","\u002Faws\u002Falb-asg","13.aws\u002F05.alb-asg",{"title":3679,"path":3680,"stem":3681},"Amazon S3 — Simple Storage Service","\u002Faws\u002Fs3","13.aws\u002F06.s3",{"title":3683,"path":3684,"stem":3685},"Amazon CloudFront — Content Delivery Network","\u002Faws\u002Fcloudfront","13.aws\u002F07.cloudfront",{"title":3687,"path":3688,"stem":3689},"Amazon RDS — Relational Database Service","\u002Faws\u002Frds","13.aws\u002F08.rds",{"title":3691,"path":3692,"stem":3693},"Amazon DynamoDB — NoSQL Database","\u002Faws\u002Fdynamodb","13.aws\u002F09.dynamodb",{"title":3695,"path":3696,"stem":3697},"AWS Lambda та Serverless Compute","\u002Faws\u002Flambda","13.aws\u002F10.lambda",{"title":3699,"path":3700,"stem":3701},"Amazon Bedrock - Foundation Models, RAG та Agents","\u002Faws\u002Fbedrock","13.aws\u002F22.bedrock",{"title":3703,"path":3704,"stem":3705},"Amazon Rekognition - Комп'ютерний зір","\u002Faws\u002Frekognition","13.aws\u002F23.rekognition",{"title":3707,"path":3708,"stem":3709},"Amazon Textract - Інтелектуальний аналіз документів","\u002Faws\u002Ftextract","13.aws\u002F24.textract",{"title":3711,"path":3712,"stem":3713},"Amazon Polly, Transcribe, Comprehend та Translate","\u002Faws\u002Faudio-nlp-services","13.aws\u002F25.audio-nlp-services",{"title":3715,"path":3716,"stem":3717,"children":3718,"page":59},"Ai Development","\u002Fai-development","14.ai-development",[3719],{"title":3720,"path":3721,"stem":3722,"children":3723,"page":59},"Foundations","\u002Fai-development\u002Ffoundations","14.ai-development\u002F00.foundations",[3724],{"title":3725,"path":3726,"stem":3727},"Модуль 0.1. Що таке Large Language Model (LLM)","\u002Fai-development\u002Ffoundations\u002Fwhat-is-llm","14.ai-development\u002F00.foundations\u002F01.what-is-llm",{"title":3729,"path":3730,"stem":3731,"children":3732,"page":59},"React Native","\u002Freact-native","15.react-native",[3733,3754],{"title":3734,"path":3735,"stem":3736,"children":3737,"page":59},"Version1","\u002Freact-native\u002Fversion1","15.react-native\u002Fversion1",[3738,3742,3746,3750],{"title":3739,"path":3740,"stem":3741},"Що таке React Native","\u002Freact-native\u002Fversion1\u002Fwhat-is-react-native","15.react-native\u002Fversion1\u002F01.what-is-react-native",{"title":3743,"path":3744,"stem":3745},"Як влаштований React Native «під капотом»","\u002Freact-native\u002Fversion1\u002Freact-native-architecture","15.react-native\u002Fversion1\u002F02.react-native-architecture",{"title":3747,"path":3748,"stem":3749},"Від React до React Native: ключові відмінності","\u002Freact-native\u002Fversion1\u002Freact-native-vs-react","15.react-native\u002Fversion1\u002F03.react-native-vs-react",{"title":3751,"path":3752,"stem":3753},"View та Text — фундаментальні будівельні блоки","\u002Freact-native\u002Fversion1\u002Fview-and-text","15.react-native\u002Fversion1\u002F04.view-and-text",{"title":3755,"path":3756,"stem":3757,"children":3758,"page":59},"Version2","\u002Freact-native\u002Fversion2","15.react-native\u002Fversion2",[3759,3763,3767,3771,3775,3779,3783,3787,3791,3795,3799,3803,3807,3811,3815,3819,3823,3827,3831,3835,3839,3843,3847,3851,3855,3859,3863],{"title":3760,"path":3761,"stem":3762},"React Native — навіщо він потрібен","\u002Freact-native\u002Fversion2\u002Fwhy-react-native","15.react-native\u002Fversion2\u002F01.why-react-native",{"title":3764,"path":3765,"stem":3766},"Налаштування середовища розробки","\u002Freact-native\u002Fversion2\u002Fenvironment-setup","15.react-native\u002Fversion2\u002F02.environment-setup",{"title":3768,"path":3769,"stem":3770},"Expo і класичний React Native — два шляхи одного фреймворку","\u002Freact-native\u002Fversion2\u002Fexpo-vs-cli-landscape","15.react-native\u002Fversion2\u002F03.expo-vs-cli-landscape",{"title":3772,"path":3773,"stem":3774},"Середовище Expo — перший запуск","\u002Freact-native\u002Fversion2\u002Fexpo-setup-and-tooling","15.react-native\u002Fversion2\u002F04.expo-setup-and-tooling",{"title":3776,"path":3777,"stem":3778},"Структура проєкту та перші UI-примітиви","\u002Freact-native\u002Fversion2\u002Fproject-structure-and-conventions","15.react-native\u002Fversion2\u002F05.project-structure-and-conventions",{"title":3780,"path":3781,"stem":3782},"Базові компоненти React Native","\u002Freact-native\u002Fversion2\u002Fcore-components","15.react-native\u002Fversion2\u002F06.core-components",{"title":3784,"path":3785,"stem":3786},"Flexbox і layout у React Native","\u002Freact-native\u002Fversion2\u002Fflexbox-and-layout","15.react-native\u002Fversion2\u002F07.flexbox-and-layout",{"title":3788,"path":3789,"stem":3790},"StyleSheet і теми (light \u002F dark)","\u002Freact-native\u002Fversion2\u002Fstylesheet-and-theming","15.react-native\u002Fversion2\u002F08.stylesheet-and-theming",{"title":3792,"path":3793,"stem":3794},"Списки та віртуалізація","\u002Freact-native\u002Fversion2\u002Flists-and-virtualization","15.react-native\u002Fversion2\u002F09.lists-and-virtualization",{"title":3796,"path":3797,"stem":3798},"Форми, ввід і валідація","\u002Freact-native\u002Fversion2\u002Fforms-input-validation","15.react-native\u002Fversion2\u002F10.forms-input-validation",{"title":3800,"path":3801,"stem":3802},"Основи Expo Router","\u002Freact-native\u002Fversion2\u002Fexpo-router-basics","15.react-native\u002Fversion2\u002F11.expo-router-basics",{"title":3804,"path":3805,"stem":3806},"Вкладені навігатори та модалки","\u002Freact-native\u002Fversion2\u002Fnested-navigators-and-modals","15.react-native\u002Fversion2\u002F12.nested-navigators-and-modals",{"title":3808,"path":3809,"stem":3810},"Deep linking і параметри маршрутів","\u002Freact-native\u002Fversion2\u002Fdeep-linking-and-params","15.react-native\u002Fversion2\u002F13.deep-linking-and-params",{"title":3812,"path":3813,"stem":3814},"Робота з мережею та життєвий цикл застосунку","\u002Freact-native\u002Fversion2\u002Fnetworking-and-app-lifecycle","15.react-native\u002Fversion2\u002F14.networking-and-app-lifecycle",{"title":3816,"path":3817,"stem":3818},"Redux Toolkit на мобільних платформах","\u002Freact-native\u002Fversion2\u002Fredux-toolkit-on-mobile","15.react-native\u002Fversion2\u002F15.redux-toolkit-on-mobile",{"title":3820,"path":3821,"stem":3822},"RTK Query на мобільних платформах","\u002Freact-native\u002Fversion2\u002Frtk-query-mobile","15.react-native\u002Fversion2\u002F16.rtk-query-mobile",{"title":3824,"path":3825,"stem":3826},"Автентифікація та Безпечне Зберігання","\u002Freact-native\u002Fversion2\u002Fauth-secure-storage","15.react-native\u002Fversion2\u002F18.auth-secure-storage",{"title":3828,"path":3829,"stem":3830},"Локальне сховище — AsyncStorage, MMKV, SQLite","\u002Freact-native\u002Fversion2\u002Flocal-storage-mmkv-sqlite","15.react-native\u002Fversion2\u002F19.local-storage-mmkv-sqlite",{"title":3832,"path":3833,"stem":3834},"Офлайн-First і синхронізація","\u002Freact-native\u002Fversion2\u002Foffline-first-sync","15.react-native\u002Fversion2\u002F20.offline-first-sync",{"title":3836,"path":3837,"stem":3838},"Камера, медіа та файлова система","\u002Freact-native\u002Fversion2\u002Fcamera-media-filesystem","15.react-native\u002Fversion2\u002F21.camera-media-filesystem",{"title":3840,"path":3841,"stem":3842},"Карти та геолокація","\u002Freact-native\u002Fversion2\u002Fmaps-and-location","15.react-native\u002Fversion2\u002F22.maps-and-location",{"title":3844,"path":3845,"stem":3846},"Жести та дотики","\u002Freact-native\u002Fversion2\u002Fgestures-and-touch","15.react-native\u002Fversion2\u002F23.gestures-and-touch",{"title":3848,"path":3849,"stem":3850},"Анімації з Reanimated","\u002Freact-native\u002Fversion2\u002Freanimated-animations","15.react-native\u002Fversion2\u002F24.reanimated-animations",{"title":3852,"path":3853,"stem":3854},"Push і локальні сповіщення","\u002Freact-native\u002Fversion2\u002Fpush-and-local-notifications","15.react-native\u002Fversion2\u002F25.push-and-local-notifications",{"title":3856,"path":3857,"stem":3858},"Інтернаціоналізація та доступність","\u002Freact-native\u002Fversion2\u002Faccessibility-and-i18n","15.react-native\u002Fversion2\u002F26.accessibility-and-i18n",{"title":3860,"path":3861,"stem":3862},"EAS Build та профілі збірки","\u002Freact-native\u002Fversion2\u002Feas-build-and-profiles","15.react-native\u002Fversion2\u002F29.eas-build-and-profiles",{"title":3864,"path":3865,"stem":3866},"Публікація в App Store та Google Play","\u002Freact-native\u002Fversion2\u002Fapp-store-play-release","15.react-native\u002Fversion2\u002F30.app-store-play-release",{"title":3868,"path":3869,"stem":3870,"children":3871,"page":59},"Ai Python","\u002Fai-python","16.ai-python",[3872,3881,3890,3899,3928,3954,3979,4012,4029,4042,4051,4064,4073,4094,4107,4176],{"title":3873,"path":3874,"stem":3875,"children":3876,"page":59},"Intro To Ai","\u002Fai-python\u002Fintro-to-ai","16.ai-python\u002F01.intro-to-ai",[3877],{"title":3878,"path":3879,"stem":3880},"Вступ до штучного інтелекту та машинного навчання","\u002Fai-python\u002Fintro-to-ai\u002Fintro-to-ai","16.ai-python\u002F01.intro-to-ai\u002F01.intro-to-ai",{"title":3882,"path":3883,"stem":3884,"children":3885,"page":59},"Jupyter Notebook","\u002Fai-python\u002Fjupyter-notebook","16.ai-python\u002F02.jupyter-notebook",[3886],{"title":3887,"path":3888,"stem":3889},"Знайомство з Jupyter Notebook та JupyterLab","\u002Fai-python\u002Fjupyter-notebook\u002Fjupyter-notebook","16.ai-python\u002F02.jupyter-notebook\u002F02.jupyter-notebook",{"title":3891,"path":3892,"stem":3893,"children":3894,"page":59},"Numpy Pandas","\u002Fai-python\u002Fnumpy-pandas","16.ai-python\u002F03.numpy-pandas",[3895],{"title":3896,"path":3897,"stem":3898},"Робота з даними з використанням NumPy і pandas","\u002Fai-python\u002Fnumpy-pandas\u002Fnumpy-pandas","16.ai-python\u002F03.numpy-pandas\u002F03.numpy-pandas",{"title":3900,"path":3901,"stem":3902,"children":3903,"page":59},"Statistics Basics","\u002Fai-python\u002Fstatistics-basics","16.ai-python\u002F04.statistics-basics",[3904,3908,3912,3916,3920,3924],{"title":3905,"path":3906,"stem":3907},"Випадкові величини та їх типи","\u002Fai-python\u002Fstatistics-basics\u002Frandom-variables","16.ai-python\u002F04.statistics-basics\u002F01.random-variables",{"title":3909,"path":3910,"stem":3911},"Міри центральної тенденції","\u002Fai-python\u002Fstatistics-basics\u002Fcentral-tendency","16.ai-python\u002F04.statistics-basics\u002F02.central-tendency",{"title":3913,"path":3914,"stem":3915},"Міри варіації (розсіювання)","\u002Fai-python\u002Fstatistics-basics\u002Fvariability","16.ai-python\u002F04.statistics-basics\u002F03.variability",{"title":3917,"path":3918,"stem":3919},"Розподіли випадкових величин","\u002Fai-python\u002Fstatistics-basics\u002Fdistributions","16.ai-python\u002F04.statistics-basics\u002F04.distributions",{"title":3921,"path":3922,"stem":3923},"Кореляція та взаємозв'язки","\u002Fai-python\u002Fstatistics-basics\u002Fcorrelation","16.ai-python\u002F04.statistics-basics\u002F05.correlation",{"title":3925,"path":3926,"stem":3927},"Викиди та аномалії","\u002Fai-python\u002Fstatistics-basics\u002Foutliers","16.ai-python\u002F04.statistics-basics\u002F06.outliers",{"title":3929,"path":3930,"stem":3931,"children":3932},"Візуалізація даних за допомогою matplotlib","\u002Fai-python\u002Fdata-visualization","16.ai-python\u002F05.data-visualization\u002Findex",[3933,3934,3938,3942,3946,3950],{"title":3929,"path":3930,"stem":3931},{"title":3935,"path":3936,"stem":3937},"Основи matplotlib — Figure, Axes та перший графік","\u002Fai-python\u002Fdata-visualization\u002Fmatplotlib-basics","16.ai-python\u002F05.data-visualization\u002F01.matplotlib-basics",{"title":3939,"path":3940,"stem":3941},"Візуалізація розподілів — гістограми та box plots","\u002Fai-python\u002Fdata-visualization\u002Fdistributions","16.ai-python\u002F05.data-visualization\u002F02.distributions",{"title":3943,"path":3944,"stem":3945},"Візуалізація залежностей — scatter plots та кореляція","\u002Fai-python\u002Fdata-visualization\u002Frelationships","16.ai-python\u002F05.data-visualization\u002F03.relationships",{"title":3947,"path":3948,"stem":3949},"Візуалізація категоріальних даних — bar charts та pie charts","\u002Fai-python\u002Fdata-visualization\u002Fcategorical","16.ai-python\u002F05.data-visualization\u002F04.categorical",{"title":3951,"path":3952,"stem":3953},"Композиції та стилізація — subplots та багатопанельні дашборди","\u002Fai-python\u002Fdata-visualization\u002Fsubplots-styling","16.ai-python\u002F05.data-visualization\u002F05.subplots-styling",{"title":3955,"path":3956,"stem":3957,"children":3958,"page":59},"Linear Regression","\u002Fai-python\u002Flinear-regression","16.ai-python\u002F06.linear-regression",[3959,3963,3967,3971,3975],{"title":3960,"path":3961,"stem":3962},"Регресійна задача та лінійна регресія з однією змінною","\u002Fai-python\u002Flinear-regression\u002Fregression-task","16.ai-python\u002F06.linear-regression\u002F01.regression-task",{"title":3964,"path":3965,"stem":3966},"Метрики якості регресії — як оцінити модель","\u002Fai-python\u002Flinear-regression\u002Fquality-metrics","16.ai-python\u002F06.linear-regression\u002F02.quality-metrics",{"title":3968,"path":3969,"stem":3970},"Градієнтний спуск — як модель навчається","\u002Fai-python\u002Flinear-regression\u002Fgradient-descent","16.ai-python\u002F06.linear-regression\u002F03.gradient-descent",{"title":3972,"path":3973,"stem":3974},"Множинна лінійна регресія — модель з багатьма ознаками","\u002Fai-python\u002Flinear-regression\u002Fmultiple-regression","16.ai-python\u002F06.linear-regression\u002F04.multiple-regression",{"title":3976,"path":3977,"stem":3978},"Практичні завдання та резюме модуля","\u002Fai-python\u002Flinear-regression\u002Fpractice","16.ai-python\u002F06.linear-regression\u002F05.practice",{"title":3980,"path":3981,"stem":3982,"children":3983,"page":59},"Practical Regression","\u002Fai-python\u002Fpractical-regression","16.ai-python\u002F07.practical-regression",[3984,3988,3992,3996,4000,4004,4008],{"title":3985,"path":3986,"stem":3987},"Знайомство з scikit-learn","\u002Fai-python\u002Fpractical-regression\u002Fintro-scikit-learn","16.ai-python\u002F07.practical-regression\u002F01.intro-scikit-learn",{"title":3989,"path":3990,"stem":3991},"Exploratory Data Analysis датасету Housing Prices","\u002Fai-python\u002Fpractical-regression\u002Fhousing-dataset-eda","16.ai-python\u002F07.practical-regression\u002F02.housing-dataset-eda",{"title":3993,"path":3994,"stem":3995},"Попередня обробка даних (Data Preprocessing)","\u002Fai-python\u002Fpractical-regression\u002Fdata-preprocessing","16.ai-python\u002F07.practical-regression\u002F03.data-preprocessing",{"title":3997,"path":3998,"stem":3999},"Train\u002FTest Split та перша повноцінна модель","\u002Fai-python\u002Fpractical-regression\u002Ftrain-test-split","16.ai-python\u002F07.practical-regression\u002F04.train-test-split",{"title":4001,"path":4002,"stem":4003},"Перенавчання та недонавчання","\u002Fai-python\u002Fpractical-regression\u002Foverfitting-underfitting","16.ai-python\u002F07.practical-regression\u002F05.overfitting-underfitting",{"title":4005,"path":4006,"stem":4007},"Крос-валідація (Cross-Validation)","\u002Fai-python\u002Fpractical-regression\u002Fcross-validation","16.ai-python\u002F07.practical-regression\u002F06.cross-validation",{"title":4009,"path":4010,"stem":4011},"Гіперпараметри та їх оптимізація","\u002Fai-python\u002Fpractical-regression\u002Fhyperparameter-tuning","16.ai-python\u002F07.practical-regression\u002F07.hyperparameter-tuning",{"title":4013,"path":4014,"stem":4015,"children":4016,"page":59},"Polynomial Regression","\u002Fai-python\u002Fpolynomial-regression","16.ai-python\u002F08.polynomial-regression",[4017,4021,4025],{"title":4018,"path":4019,"stem":4020},"Нелінійні залежності та поліноміальна регресія","\u002Fai-python\u002Fpolynomial-regression\u002Fnonlinear-patterns","16.ai-python\u002F08.polynomial-regression\u002F01.nonlinear-patterns",{"title":4022,"path":4023,"stem":4024},"Регуляризація в регресії — Ridge та Lasso","\u002Fai-python\u002Fpolynomial-regression\u002Fregularization-methods","16.ai-python\u002F08.polynomial-regression\u002F02.regularization-methods",{"title":4026,"path":4027,"stem":4028},"Практика — поліноміальна регресія та регуляризація на Housing Prices","\u002Fai-python\u002Fpolynomial-regression\u002Fhousing-prices-practice","16.ai-python\u002F08.polynomial-regression\u002F03.housing-prices-practice",{"title":4030,"path":4031,"stem":4032,"children":4033,"page":59},"Decision Trees Random Forest","\u002Fai-python\u002Fdecision-trees-random-forest","16.ai-python\u002F09.decision-trees-random-forest",[4034,4038],{"title":4035,"path":4036,"stem":4037},"Дерева рішень — моделі з прозорою та зрозумілою логікою","\u002Fai-python\u002Fdecision-trees-random-forest\u002Fdecision-trees","16.ai-python\u002F09.decision-trees-random-forest\u002F01.decision-trees",{"title":4039,"path":4040,"stem":4041},"Random Forest — ансамблі дерев рішень","\u002Fai-python\u002Fdecision-trees-random-forest\u002Frandom-forest","16.ai-python\u002F09.decision-trees-random-forest\u002F02.random-forest",{"title":4043,"path":4044,"stem":4045,"children":4046,"page":59},"Gradient Boosting","\u002Fai-python\u002Fgradient-boosting","16.ai-python\u002F10.gradient-boosting",[4047],{"title":4048,"path":4049,"stem":4050},"Градієнтний бустинг та XGBoost — послідовне виправлення помилок","\u002Fai-python\u002Fgradient-boosting\u002Fgradient-boosting-xgboost","16.ai-python\u002F10.gradient-boosting\u002F01.gradient-boosting-xgboost",{"title":4052,"path":4053,"stem":4054,"children":4055,"page":59},"Logistic Regression Classification","\u002Fai-python\u002Flogistic-regression-classification","16.ai-python\u002F11.logistic-regression-classification",[4056,4060],{"title":4057,"path":4058,"stem":4059},"Основи класифікації та логістична регресія","\u002Fai-python\u002Flogistic-regression-classification\u002Fclassification-basics","16.ai-python\u002F11.logistic-regression-classification\u002F01.classification-basics",{"title":4061,"path":4062,"stem":4063},"Метрики якості класифікації","\u002Fai-python\u002Flogistic-regression-classification\u002Fclassification-metrics","16.ai-python\u002F11.logistic-regression-classification\u002F02.classification-metrics",{"title":4065,"path":4066,"stem":4067,"children":4068,"page":59},"Neural Networks Basics","\u002Fai-python\u002Fneural-networks-basics","16.ai-python\u002F12.neural-networks-basics",[4069],{"title":4070,"path":4071,"stem":4072},"Вступ до нейронних мереж — від персептрона до багатошарових мереж","\u002Fai-python\u002Fneural-networks-basics\u002Fperceptron-to-mlp","16.ai-python\u002F12.neural-networks-basics\u002F01.perceptron-to-mlp",{"title":4074,"path":4075,"stem":4076,"children":4077,"page":59},"Pytorch Intro","\u002Fai-python\u002Fpytorch-intro","16.ai-python\u002F13.pytorch-intro",[4078,4082,4086,4090],{"title":4079,"path":4080,"stem":4081},"Тензори та автоматичне диференціювання в PyTorch","\u002Fai-python\u002Fpytorch-intro\u002Ftensors-and-autograd","16.ai-python\u002F13.pytorch-intro\u002F01.tensors-and-autograd",{"title":4083,"path":4084,"stem":4085},"Побудова та тренування нейронних мереж у PyTorch","\u002Fai-python\u002Fpytorch-intro\u002Fbuilding-and-training","16.ai-python\u002F13.pytorch-intro\u002F02.building-and-training",{"title":4087,"path":4088,"stem":4089},"Робота з даними та регуляризація в PyTorch","\u002Fai-python\u002Fpytorch-intro\u002Fdata-and-regularization","16.ai-python\u002F13.pytorch-intro\u002F03.data-and-regularization",{"title":4091,"path":4092,"stem":4093},"Просунуті теми PyTorch — GPU, оптимізація та deployment","\u002Fai-python\u002Fpytorch-intro\u002Fadvanced-topics","16.ai-python\u002F13.pytorch-intro\u002F04.advanced-topics",{"title":4095,"path":4096,"stem":4097,"children":4098,"page":59},"Activation Functions Heart Disease","\u002Fai-python\u002Factivation-functions-heart-disease","16.ai-python\u002F14.activation-functions-heart-disease",[4099,4103],{"title":4100,"path":4101,"stem":4102},"Функції активації та побудова нейронної мережі для передбачення вад серця","\u002Fai-python\u002Factivation-functions-heart-disease\u002Fheart-disease-prediction","16.ai-python\u002F14.activation-functions-heart-disease\u002F01.heart-disease-prediction",{"title":4104,"path":4105,"stem":4106},"Бонус — Повний приклад Student Performance Prediction","\u002Fai-python\u002Factivation-functions-heart-disease\u002Fstudent-performance-bonus","16.ai-python\u002F14.activation-functions-heart-disease\u002F02.student-performance-bonus",{"title":4108,"path":4109,"stem":4110,"children":4111,"page":59},"Cnn Image Classification","\u002Fai-python\u002Fcnn-image-classification","16.ai-python\u002F15.cnn-image-classification",[4112,4116,4120,4124,4128,4132,4136,4140,4144,4148,4152,4156,4160,4164,4168,4172],{"title":4113,"path":4114,"stem":4115},"Вступ до комп'ютерного зору та проблеми Dense-мереж","\u002Fai-python\u002Fcnn-image-classification\u002Fintro-computer-vision","16.ai-python\u002F15.cnn-image-classification\u002F01.intro-computer-vision",{"title":4117,"path":4118,"stem":4119},"Навіщо потрібна згортка — від нейрона-шаблону до ковзного детектора","\u002Fai-python\u002Fcnn-image-classification\u002Fwhy-convolution","16.ai-python\u002F15.cnn-image-classification\u002F02.why-convolution",{"title":4121,"path":4122,"stem":4123},"Згортка крок за кроком — ядро, карта ознак і розмір результату","\u002Fai-python\u002Fcnn-image-classification\u002Fconvolution-step-by-step","16.ai-python\u002F15.cnn-image-classification\u002F03.convolution-step-by-step",{"title":4125,"path":4126,"stem":4127},"Що «бачить» ядро — читаємо карту ознак і класичні фільтри","\u002Fai-python\u002Fcnn-image-classification\u002Ffilters-what-kernel-sees","16.ai-python\u002F15.cnn-image-classification\u002F04.filters-what-kernel-sees",{"title":4129,"path":4130,"stem":4131},"Padding і stride — що робити з краями картинки та її розміром","\u002Fai-python\u002Fcnn-image-classification\u002Fpadding-and-stride","16.ai-python\u002F15.cnn-image-classification\u002F05.padding-and-stride",{"title":4133,"path":4134,"stem":4135},"Ядро, що навчається — від випадкових чисел до детектора країв","\u002Fai-python\u002Fcnn-image-classification\u002Flearnable-kernels","16.ai-python\u002F15.cnn-image-classification\u002F06.learnable-kernels",{"title":4137,"path":4138,"stem":4139},"Пулінг і поле зору — стискаємо карту ознак і дивимося ширше","\u002Fai-python\u002Fcnn-image-classification\u002Fpooling","16.ai-python\u002F15.cnn-image-classification\u002F07.pooling",{"title":4141,"path":4142,"stem":4143},"Багатоканальна згортка — ядро-куб, кольорове фото та підрахунок параметрів","\u002Fai-python\u002Fcnn-image-classification\u002Fmultichannel-convolution","16.ai-python\u002F15.cnn-image-classification\u002F08.multichannel-convolution",{"title":4145,"path":4146,"stem":4147},"Повна CNN для MNIST — збираємо, навчаємо, перевіряємо","\u002Fai-python\u002Fcnn-image-classification\u002Fcnn-mnist","16.ai-python\u002F15.cnn-image-classification\u002F09.cnn-mnist",{"title":4149,"path":4150,"stem":4151},"CNN для CIFAR-10 — коли задача справді складна","\u002Fai-python\u002Fcnn-image-classification\u002Fcnn-cifar10","16.ai-python\u002F15.cnn-image-classification\u002F10.cnn-cifar10",{"title":4153,"path":4154,"stem":4155},"Міні-батчі, DataLoader і швидкість навчання","\u002Fai-python\u002Fcnn-image-classification\u002Fmini-batch-learning-rate","16.ai-python\u002F15.cnn-image-classification\u002F11.mini-batch-learning-rate",{"title":4157,"path":4158,"stem":4159},"Ініціалізація ваг і Batch Normalization","\u002Fai-python\u002Fcnn-image-classification\u002Fweight-init-batchnorm","16.ai-python\u002F15.cnn-image-classification\u002F12.weight-init-batchnorm",{"title":4161,"path":4162,"stem":4163},"LayerNorm і обрізання градієнтів","\u002Fai-python\u002Fcnn-image-classification\u002Flayernorm-gradient-clipping","16.ai-python\u002F15.cnn-image-classification\u002F13.layernorm-gradient-clipping",{"title":4165,"path":4166,"stem":4167},"Аугментація даних","\u002Fai-python\u002Fcnn-image-classification\u002Fdata-augmentation","16.ai-python\u002F15.cnn-image-classification\u002F14.data-augmentation",{"title":4169,"path":4170,"stem":4171},"Глибокі мережі та ResNet","\u002Fai-python\u002Fcnn-image-classification\u002Fdeep-networks-resnet","16.ai-python\u002F15.cnn-image-classification\u002F15.deep-networks-resnet",{"title":4173,"path":4174,"stem":4175},"Пневмонія на рентгені - метрики, transfer learning, Grad-CAM","\u002Fai-python\u002Fcnn-image-classification\u002Fpneumonia-transfer-learning","16.ai-python\u002F15.cnn-image-classification\u002F16.pneumonia-transfer-learning",{"title":4177,"path":4178,"stem":4179,"children":4180,"page":59},"Natural Language Processing","\u002Fai-python\u002Fnatural-language-processing","16.ai-python\u002F16.natural-language-processing",[4181,4185,4189,4193,4197,4201,4205,4209,4213,4217,4221,4225,4229,4233,4237,4241],{"title":4182,"path":4183,"stem":4184},"Текст як дані — чому мова складна для комп'ютера","\u002Fai-python\u002Fnatural-language-processing\u002Ftext-as-data","16.ai-python\u002F16.natural-language-processing\u002F01.text-as-data",{"title":4186,"path":4187,"stem":4188},"Токенізація — розбиття тексту на слова й речення","\u002Fai-python\u002Fnatural-language-processing\u002Ftokenization","16.ai-python\u002F16.natural-language-processing\u002F02.tokenization",{"title":4190,"path":4191,"stem":4192},"Стеммінг, лемматизація та стоп-слова","\u002Fai-python\u002Fnatural-language-processing\u002Fstemming-lemmatization-stopwords","16.ai-python\u002F16.natural-language-processing\u002F03.stemming-lemmatization-stopwords",{"title":4194,"path":4195,"stem":4196},"Корпус та частоти слів","\u002Fai-python\u002Fnatural-language-processing\u002Fcorpus-and-frequency","16.ai-python\u002F16.natural-language-processing\u002F04.corpus-and-frequency",{"title":4198,"path":4199,"stem":4200},"Мішок слів — перше представлення тексту числами","\u002Fai-python\u002Fnatural-language-processing\u002Fbag-of-words","16.ai-python\u002F16.natural-language-processing\u002F05.bag-of-words",{"title":4202,"path":4203,"stem":4204},"Класифікація тексту — baseline на мішку слів","\u002Fai-python\u002Fnatural-language-processing\u002Ftext-classification-baseline","16.ai-python\u002F16.natural-language-processing\u002F06.text-classification-baseline",{"title":4206,"path":4207,"stem":4208},"Від one-hot до embeddings — щільні вектори слів","\u002Fai-python\u002Fnatural-language-processing\u002Ffrom-one-hot-to-embeddings","16.ai-python\u002F16.natural-language-processing\u002F07.from-one-hot-to-embeddings",{"title":4210,"path":4211,"stem":4212},"Word2Vec — навчання векторів слів з контексту","\u002Fai-python\u002Fnatural-language-processing\u002Fword2vec","16.ai-python\u002F16.natural-language-processing\u002F08.word2vec",{"title":4214,"path":4215,"stem":4216},"GloVe — глобальні вектори слів та попередньо навчені моделі","\u002Fai-python\u002Fnatural-language-processing\u002Fglove-pretrained-embeddings","16.ai-python\u002F16.natural-language-processing\u002F09.glove-pretrained-embeddings",{"title":4218,"path":4219,"stem":4220},"Embeddings для класифікації — від мішка слів до векторів","\u002Fai-python\u002Fnatural-language-processing\u002Fembeddings-for-classification","16.ai-python\u002F16.natural-language-processing\u002F10.embeddings-for-classification",{"title":4222,"path":4223,"stem":4224},"Мовні моделі та послідовності — від біграм до батчів","\u002Fai-python\u002Fnatural-language-processing\u002Flanguage-models-and-sequences","16.ai-python\u002F16.natural-language-processing\u002F11.language-models-and-sequences",{"title":4226,"path":4227,"stem":4228},"Рекурентні нейронні мережі (RNN)","\u002Fai-python\u002Fnatural-language-processing\u002Frnn","16.ai-python\u002F16.natural-language-processing\u002F12.rnn",{"title":4230,"path":4231,"stem":4232},"LSTM і GRU — рекурентні мережі з вентилями","\u002Fai-python\u002Fnatural-language-processing\u002Flstm-gru","16.ai-python\u002F16.natural-language-processing\u002F13.lstm-gru",{"title":4234,"path":4235,"stem":4236},"Seq2seq і механізм уваги","\u002Fai-python\u002Fnatural-language-processing\u002Fseq2seq-attention","16.ai-python\u002F16.natural-language-processing\u002F14.seq2seq-attention",{"title":4238,"path":4239,"stem":4240},"Transformer — self-attention замість рекурентності","\u002Fai-python\u002Fnatural-language-processing\u002Ftransformer","16.ai-python\u002F16.natural-language-processing\u002F15.transformer",{"title":4242,"path":4243,"stem":4244},"Готові моделі та Hugging Face — transfer learning","\u002Fai-python\u002Fnatural-language-processing\u002Fpretrained-models-sentiment","16.ai-python\u002F16.natural-language-processing\u002F16.pretrained-models-sentiment",{"title":4246,"icon":658,"path":4247,"stem":4248,"children":4249,"page":59},"Клієнт-серверна архітектура","\u002Fclient-server-architecture","17.client-server-architecture",[4250,4254,4258,4262,4266,4270,4274,4278,4282,4286,4290,4294,4298,4302,4306,4310,4314,4318],{"title":4251,"path":4252,"stem":4253},"Архітектура клієнт-серверних систем та основи Go","\u002Fclient-server-architecture\u002Fclient-server-architecture-and-go","17.client-server-architecture\u002F01.client-server-architecture-and-go",{"title":4255,"path":4256,"stem":4257},"Система типів та модель пам’яті мови Go","\u002Fclient-server-architecture\u002Ftype-system-and-memory-model","17.client-server-architecture\u002F02.type-system-and-memory-model",{"title":4259,"path":4260,"stem":4261},"Інтерфейси та модель конкурентності мови Go","\u002Fclient-server-architecture\u002Finterfaces-and-concurrency-model","17.client-server-architecture\u002F03.interfaces-and-concurrency-model",{"title":4263,"path":4264,"stem":4265},"Сокетне програмування та протокол TCP у Go","\u002Fclient-server-architecture\u002Ftcp-socket-programming","17.client-server-architecture\u002F04.tcp-socket-programming",{"title":4267,"path":4268,"stem":4269},"Протокол UDP та датаграмна передача даних","\u002Fclient-server-architecture\u002Fudp-datagram-transmission","17.client-server-architecture\u002F05.udp-datagram-transmission",{"title":4271,"path":4272,"stem":4273},"Криптографічний захист каналів зв","\u002Fclient-server-architecture\u002Ftls-cryptographic-channel-protection","17.client-server-architecture\u002F06.tls-cryptographic-channel-protection",{"title":4275,"path":4276,"stem":4277},"Прикладні мережеві протоколи DNS та SMTP","\u002Fclient-server-architecture\u002Fdns-smtp-application-protocols","17.client-server-architecture\u002F07.dns-smtp-application-protocols",{"title":4279,"path":4280,"stem":4281},"Протокол HTTP та стандартний вебсервер Go","\u002Fclient-server-architecture\u002Fhttp-protocol-and-web-server","17.client-server-architecture\u002F08.http-protocol-and-web-server",{"title":4283,"path":4284,"stem":4285},"Проєктування REST API та маршрутизація засобами Chi","\u002Fclient-server-architecture\u002Frest-api-design-and-chi-routing","17.client-server-architecture\u002F09.rest-api-design-and-chi-routing",{"title":4287,"path":4288,"stem":4289},"Лекція 10. Шарувата архітектура та конвеєри обробки запитів","\u002Fclient-server-architecture\u002Flayered-architecture-and-middleware-pipelines","17.client-server-architecture\u002F10.layered-architecture-and-middleware-pipelines",{"title":4291,"path":4292,"stem":4293},"Лекція 11. Архітектура та маршрутизація фреймворку Gin","\u002Fclient-server-architecture\u002Fgin-framework-architecture-and-routing","17.client-server-architecture\u002F11.gin-framework-architecture-and-routing",{"title":4295,"path":4296,"stem":4297},"Лекція 12. Валідація даних, безпека та документування у Gin","\u002Fclient-server-architecture\u002Fdata-validation-security-and-documentation-in-gin","17.client-server-architecture\u002F12.data-validation-security-and-documentation-in-gin",{"title":4299,"path":4300,"stem":4301},"Лекція 13. Взаємодія з реляційними СУБД та технології ORM","\u002Fclient-server-architecture\u002Frelational-databases-and-orm","17.client-server-architecture\u002F13.relational-databases-and-orm",{"title":4303,"path":4304,"stem":4305},"Потокова передача даних та протокол WebSocket","\u002Fclient-server-architecture\u002Fstreaming-data-and-websockets","17.client-server-architecture\u002F14.streaming-data-and-websockets",{"title":4307,"path":4308,"stem":4309},"Міжсервісна взаємодія на основі протоколу gRPC","\u002Fclient-server-architecture\u002Fgrpc-inter-service-communication","17.client-server-architecture\u002F15.grpc-inter-service-communication",{"title":4311,"path":4312,"stem":4313},"Асинхронний обмін повідомленнями та протоколи черг","\u002Fclient-server-architecture\u002Fasynchronous-message-exchange-and-queue-protocols","17.client-server-architecture\u002F16.asynchronous-message-exchange-and-queue-protocols",{"title":4315,"path":4316,"stem":4317},"Протоколи потокового медіа та технологія WebRTC","\u002Fclient-server-architecture\u002Fstreaming-media-protocols-and-webrtc","17.client-server-architecture\u002F17.streaming-media-protocols-and-webrtc",{"title":4319,"path":4320,"stem":4321},"Моніторинг, безпека та контейнеризація застосунків","\u002Fclient-server-architecture\u002Fmonitoring-security-and-containerization","17.client-server-architecture\u002F18.monitoring-security-and-containerization",{"title":4323,"icon":2254,"path":4324,"stem":4325,"children":4326,"page":59},"Розробка WEB-застосувань","\u002Fweb-development","18.web-development",[4327,4372,4410,4439,4468,4525,4575,4669,4735,4817,4850,4878,4920,4966,5009],{"title":4328,"icon":658,"path":4329,"stem":4330,"children":4331,"page":59},"Архітектура комп'ютерних мереж та мережеві протоколи","\u002Fweb-development\u002Fnetwork-architecture-and-protocols","18.web-development\u002F01.network-architecture-and-protocols",[4332,4336,4340,4344,4348,4352,4356,4360,4364,4368],{"title":4333,"path":4334,"stem":4335},"Еволюція веброзробки та модель клієнт-сервер","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fweb-evolution-client-server","18.web-development\u002F01.network-architecture-and-protocols\u002F01.web-evolution-client-server",{"title":4337,"path":4338,"stem":4339},"Еталонна модель OSI","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fosi-model","18.web-development\u002F01.network-architecture-and-protocols\u002F02.osi-model",{"title":4341,"path":4342,"stem":4343},"Стек протоколів TCP\u002FIP","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Ftcp-ip-stack","18.web-development\u002F01.network-architecture-and-protocols\u002F03.tcp-ip-stack",{"title":4345,"path":4346,"stem":4347},"IP-адресація, порти та сокети","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fip-addressing-ports-sockets","18.web-development\u002F01.network-architecture-and-protocols\u002F04.ip-addressing-ports-sockets",{"title":4349,"path":4350,"stem":4351},"Протоколи TCP та UDP","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Ftcp-udp-protocols","18.web-development\u002F01.network-architecture-and-protocols\u002F05.tcp-udp-protocols",{"title":4353,"path":4354,"stem":4355},"Система доменних імен DNS","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fdns-system","18.web-development\u002F01.network-architecture-and-protocols\u002F06.dns-system",{"title":4357,"path":4358,"stem":4359},"Протокол SMTP та поштові протоколи","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fsmtp-email-protocols","18.web-development\u002F01.network-architecture-and-protocols\u002F07.smtp-email-protocols",{"title":4361,"path":4362,"stem":4363},"Протокол WebSocket","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fwebsocket-protocol","18.web-development\u002F01.network-architecture-and-protocols\u002F08.websocket-protocol",{"title":4365,"path":4366,"stem":4367},"Протокол SSH","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fssh-protocol","18.web-development\u002F01.network-architecture-and-protocols\u002F09.ssh-protocol",{"title":4369,"path":4370,"stem":4371},"Огляд сучасних серверних технологій","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fmodern-backend-technologies","18.web-development\u002F01.network-architecture-and-protocols\u002F10.modern-backend-technologies",{"title":4373,"icon":4374,"path":4375,"stem":4376,"children":4377,"page":59},"Протокол HTTP та захищена передача даних HTTPS","i-lucide-lock","\u002Fweb-development\u002Fhttp-and-https","18.web-development\u002F02.http-and-https",[4378,4382,4386,4390,4394,4398,4402,4406],{"title":4379,"path":4380,"stem":4381},"Вступ до протоколу HTTP та еволюція веб-технологій","\u002Fweb-development\u002Fhttp-and-https\u002Fintroduction-and-evolution","18.web-development\u002F02.http-and-https\u002F01.introduction-and-evolution",{"title":4383,"path":4384,"stem":4385},"Анатомія HTTP-запиту","\u002Fweb-development\u002Fhttp-and-https\u002Fhttp-request-structure","18.web-development\u002F02.http-and-https\u002F02.http-request-structure",{"title":4387,"path":4388,"stem":4389},"Анатомія HTTP-відповіді","\u002Fweb-development\u002Fhttp-and-https\u002Fhttp-response-structure","18.web-development\u002F02.http-and-https\u002F03.http-response-structure",{"title":4391,"path":4392,"stem":4393},"Методи HTTP та їхня семантика","\u002Fweb-development\u002Fhttp-and-https\u002Fhttp-methods","18.web-development\u002F02.http-and-https\u002F04.http-methods",{"title":4395,"path":4396,"stem":4397},"Коди статусу HTTP та їхнє призначення","\u002Fweb-development\u002Fhttp-and-https\u002Fhttp-status-codes","18.web-development\u002F02.http-and-https\u002F05.http-status-codes",{"title":4399,"path":4400,"stem":4401},"HTTP-заголовки та їхнє призначення","\u002Fweb-development\u002Fhttp-and-https\u002Fhttp-headers","18.web-development\u002F02.http-and-https\u002F06.http-headers",{"title":4403,"path":4404,"stem":4405},"CORS та механізми безпеки HTTP","\u002Fweb-development\u002Fhttp-and-https\u002Fcors-and-security","18.web-development\u002F02.http-and-https\u002F07.cors-and-security",{"title":4407,"path":4408,"stem":4409},"HTTPS та криптографічні основи TLS","\u002Fweb-development\u002Fhttp-and-https\u002Fhttps-and-tls","18.web-development\u002F02.http-and-https\u002F08.https-and-tls",{"title":4411,"icon":2634,"path":4412,"stem":4413,"children":4414,"page":59},"Система типів мови TypeScript","\u002Fweb-development\u002Ftypescript-type-system","18.web-development\u002F03.typescript-type-system",[4415,4419,4423,4427,4431,4435],{"title":4416,"path":4417,"stem":4418},"Знайомство з TypeScript Compiler","\u002Fweb-development\u002Ftypescript-type-system\u002Fintroduction-compiler-config","18.web-development\u002F03.typescript-type-system\u002F01.introduction-compiler-config",{"title":4420,"path":4421,"stem":4422},"Примітивні типи даних: string, number, boolean","\u002Fweb-development\u002Ftypescript-type-system\u002Fprimitive-special-types","18.web-development\u002F03.typescript-type-system\u002F02.primitive-special-types",{"title":4424,"path":4425,"stem":4426},"Масиви, кортежі та об","\u002Fweb-development\u002Ftypescript-type-system\u002Farrays-tuples-objects","18.web-development\u002F03.typescript-type-system\u002F03.arrays-tuples-objects",{"title":4428,"path":4429,"stem":4430},"Псевдоніми типів, Union типи, Intersection типи та літеральні типи","\u002Fweb-development\u002Ftypescript-type-system\u002Funion-intersection-literals","18.web-development\u002F03.typescript-type-system\u002F04.union-intersection-literals",{"title":4432,"path":4433,"stem":4434},"Type Narrowing (звуження типів)","\u002Fweb-development\u002Ftypescript-type-system\u002Ftype-narrowing","18.web-development\u002F03.typescript-type-system\u002F05.type-narrowing",{"title":4436,"path":4437,"stem":4438},"Типізація функцій","\u002Fweb-development\u002Ftypescript-type-system\u002Ffunctions-typing","18.web-development\u002F03.typescript-type-system\u002F06.functions-typing",{"title":4440,"icon":2634,"path":4441,"stem":4442,"children":4443,"page":59},"Розширені засоби мови TypeScript","\u002Fweb-development\u002Ftypescript-advanced","18.web-development\u002F04.typescript-advanced",[4444,4448,4452,4456,4460,4464],{"title":4445,"path":4446,"stem":4447},"Interfaces та Classes","\u002Fweb-development\u002Ftypescript-advanced\u002Finterfaces-classes","18.web-development\u002F04.typescript-advanced\u002F01.interfaces-classes",{"title":4449,"path":4450,"stem":4451},"Основи Generic типів","\u002Fweb-development\u002Ftypescript-advanced\u002Fgenerics-fundamentals","18.web-development\u002F04.typescript-advanced\u002F02.generics-fundamentals",{"title":4453,"path":4454,"stem":4455},"Enums та Decorators","\u002Fweb-development\u002Ftypescript-advanced\u002Fenums-decorators","18.web-development\u002F04.typescript-advanced\u002F03.enums-decorators",{"title":4457,"path":4458,"stem":4459},"Utility Types","\u002Fweb-development\u002Ftypescript-advanced\u002Futility-types","18.web-development\u002F04.typescript-advanced\u002F04.utility-types",{"title":4461,"path":4462,"stem":4463},"Mapped та Conditional Types","\u002Fweb-development\u002Ftypescript-advanced\u002Fmapped-conditional-types","18.web-development\u002F04.typescript-advanced\u002F05.mapped-conditional-types",{"title":4465,"path":4466,"stem":4467},"Модулі та Strict Mode","\u002Fweb-development\u002Ftypescript-advanced\u002Fmodules-strict-mode","18.web-development\u002F04.typescript-advanced\u002F06.modules-strict-mode",{"title":4469,"icon":4470,"path":4471,"stem":4472,"children":4473,"page":59},"Платформа Node.js як середовище виконання","i-devicon-nodejs","\u002Fweb-development\u002Fnodejs-platform","18.web-development\u002F05.nodejs-platform",[4474,4478,4482,4486,4490,4494,4498,4502,4506,4510,4514,4517,4521],{"title":4475,"path":4476,"stem":4477},"Що таке Node.js та його архітектура","\u002Fweb-development\u002Fnodejs-platform\u002Fwhat-is-nodejs","18.web-development\u002F05.nodejs-platform\u002F01.what-is-nodejs",{"title":4479,"path":4480,"stem":4481},"Event Loop — серце Node.js","\u002Fweb-development\u002Fnodejs-platform\u002Fevent-loop","18.web-development\u002F05.nodejs-platform\u002F02.event-loop",{"title":4483,"path":4484,"stem":4485},"Модульні системи: CommonJS vs ES Modules","\u002Fweb-development\u002Fnodejs-platform\u002Fmodule-systems","18.web-development\u002F05.nodejs-platform\u002F03.module-systems",{"title":4487,"path":4488,"stem":4489},"npm та package.json","\u002Fweb-development\u002Fnodejs-platform\u002Fnpm-package-json","18.web-development\u002F05.nodejs-platform\u002F04.npm-package-json",{"title":4491,"path":4492,"stem":4493},"Глобальні об\\","\u002Fweb-development\u002Fnodejs-platform\u002Fglobal-objects","18.web-development\u002F05.nodejs-platform\u002F05.global-objects",{"title":4495,"path":4496,"stem":4497},"Вбудований модуль fs (File System)","\u002Fweb-development\u002Fnodejs-platform\u002Fbuilt-in-modules-fs","18.web-development\u002F05.nodejs-platform\u002F06.built-in-modules-fs",{"title":4499,"path":4500,"stem":4501},"Вбудований модуль path","\u002Fweb-development\u002Fnodejs-platform\u002Fbuilt-in-modules-path","18.web-development\u002F05.nodejs-platform\u002F07.built-in-modules-path",{"title":4503,"path":4504,"stem":4505},"Вбудований модуль http","\u002Fweb-development\u002Fnodejs-platform\u002Fbuilt-in-modules-http","18.web-development\u002F05.nodejs-platform\u002F08.built-in-modules-http",{"title":4507,"path":4508,"stem":4509},"Streams — потоки даних у Node.js","\u002Fweb-development\u002Fnodejs-platform\u002Fstreams","18.web-development\u002F05.nodejs-platform\u002F09.streams",{"title":4511,"path":4512,"stem":4513},"Вбудований модуль util (Utilities)","\u002Fweb-development\u002Fnodejs-platform\u002Fbuilt-in-modules-util","18.web-development\u002F05.nodejs-platform\u002F10.built-in-modules-util",{"title":3319,"path":4515,"stem":4516},"\u002Fweb-development\u002Fnodejs-platform\u002Fenvironment-variables","18.web-development\u002F05.nodejs-platform\u002F11.environment-variables",{"title":4518,"path":4519,"stem":4520},"Інструменти налагодження та розробки","\u002Fweb-development\u002Fnodejs-platform\u002Fdebugging-tools","18.web-development\u002F05.nodejs-platform\u002F12.debugging-tools",{"title":4522,"path":4523,"stem":4524},"Продуктивність та Best Practices","\u002Fweb-development\u002Fnodejs-platform\u002Fperformance-best-practices","18.web-development\u002F05.nodejs-platform\u002F13.performance-best-practices",{"title":4526,"icon":4527,"path":4528,"stem":4529,"children":4530,"page":59},"Асинхронне програмування у Node.js","i-lucide-clock","\u002Fweb-development\u002Fasync-programming-nodejs","18.web-development\u002F06.async-programming-nodejs",[4531,4535,4539,4543,4547,4551,4555,4559,4563,4567,4571],{"title":4532,"path":4533,"stem":4534},"Синхронний vs асинхронний код","\u002Fweb-development\u002Fasync-programming-nodejs\u002Fsync-vs-async","18.web-development\u002F06.async-programming-nodejs\u002F01.sync-vs-async",{"title":4536,"path":4537,"stem":4538},"Callbacks — перша парадигма асинхронності","\u002Fweb-development\u002Fasync-programming-nodejs\u002Fcallbacks","18.web-development\u002F06.async-programming-nodejs\u002F02.callbacks",{"title":4540,"path":4541,"stem":4542},"Promises — стандарт асинхронності","\u002Fweb-development\u002Fasync-programming-nodejs\u002Fpromises","18.web-development\u002F06.async-programming-nodejs\u002F03.promises",{"title":4544,"path":4545,"stem":4546},"Promise комбінатори","\u002Fweb-development\u002Fasync-programming-nodejs\u002Fpromise-combinators","18.web-development\u002F06.async-programming-nodejs\u002F04.promise-combinators",{"title":4548,"path":4549,"stem":4550},"Async\u002FAwait — синтаксичний цукор над Promises","\u002Fweb-development\u002Fasync-programming-nodejs\u002Fasync-await","18.web-development\u002F06.async-programming-nodejs\u002F05.async-await",{"title":4552,"path":4553,"stem":4554},"Паралельне vs послідовне виконання","\u002Fweb-development\u002Fasync-programming-nodejs\u002Fparallel-vs-sequential","18.web-development\u002F06.async-programming-nodejs\u002F06.parallel-vs-sequential",{"title":4556,"path":4557,"stem":4558},"EventEmitter — подієва модель Node.js","\u002Fweb-development\u002Fasync-programming-nodejs\u002Fevent-emitter","18.web-development\u002F06.async-programming-nodejs\u002F07.event-emitter",{"title":4560,"path":4561,"stem":4562},"Worker Threads — багатопотоковість у Node.js","\u002Fweb-development\u002Fasync-programming-nodejs\u002Fworker-threads","18.web-development\u002F06.async-programming-nodejs\u002F08.worker-threads",{"title":4564,"path":4565,"stem":4566},"Child Processes — запуск зовнішніх процесів","\u002Fweb-development\u002Fasync-programming-nodejs\u002Fchild-processes","18.web-development\u002F06.async-programming-nodejs\u002F09.child-processes",{"title":4568,"path":4569,"stem":4570},"Обробка помилок у асинхронному коді","\u002Fweb-development\u002Fasync-programming-nodejs\u002Ferror-handling","18.web-development\u002F06.async-programming-nodejs\u002F10.error-handling",{"title":4572,"path":4573,"stem":4574},"Порівняння Node.js фреймворків","\u002Fweb-development\u002Fasync-programming-nodejs\u002Fnodejs-frameworks","18.web-development\u002F06.async-programming-nodejs\u002F11.nodejs-frameworks",{"title":4576,"icon":4577,"path":4578,"stem":4579,"children":4580,"page":59},"Тема 7. Фреймворк NestJS. Контролери та маршрутизація","i-lucide-route","\u002Fweb-development\u002Fnestjs-controllers-routing","18.web-development\u002F07.nestjs-controllers-routing",[4581,4585,4589,4593,4597,4601,4605,4609,4613,4617,4621,4625,4629,4633,4637,4641,4645,4649,4653,4657,4661,4665],{"title":4582,"path":4583,"stem":4584},"Філософія та архітектура NestJS","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fnestjs-philosophy","18.web-development\u002F07.nestjs-controllers-routing\u002F01.nestjs-philosophy",{"title":4586,"path":4587,"stem":4588},"Три стовпи архітектури: модулі, контролери, провайдери","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fthree-pillars","18.web-development\u002F07.nestjs-controllers-routing\u002F02.three-pillars",{"title":4590,"path":4591,"stem":4592},"Інверсія керування (IoC) та ін","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fioc-and-di","18.web-development\u002F07.nestjs-controllers-routing\u002F03.ioc-and-di",{"title":4594,"path":4595,"stem":4596},"Встановлення NestJS CLI та створення проєкту","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fnestjs-cli-setup","18.web-development\u002F07.nestjs-controllers-routing\u002F04.nestjs-cli-setup",{"title":4598,"path":4599,"stem":4600},"Структура проєкту NestJS та конвенції","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fproject-structure","18.web-development\u002F07.nestjs-controllers-routing\u002F05.project-structure",{"title":4602,"path":4603,"stem":4604},"Контролери: основи маршрутизації","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fcontrollers-basics","18.web-development\u002F07.nestjs-controllers-routing\u002F06.controllers-basics",{"title":4606,"path":4607,"stem":4608},"Декоратори маршрутизації HTTP-методів","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Froute-decorators","18.web-development\u002F07.nestjs-controllers-routing\u002F07.route-decorators",{"title":4610,"path":4611,"stem":4612},"Параметри маршруту та декоратор @Param","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Froute-parameters","18.web-development\u002F07.nestjs-controllers-routing\u002F08.route-parameters",{"title":4614,"path":4615,"stem":4616},"Query-параметри та декоратор @Query","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fquery-parameters","18.web-development\u002F07.nestjs-controllers-routing\u002F09.query-parameters",{"title":4618,"path":4619,"stem":4620},"Тіло запиту та декоратор @Body","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Frequest-body","18.web-development\u002F07.nestjs-controllers-routing\u002F10.request-body",{"title":4622,"path":4623,"stem":4624},"Робота з заголовками запиту та відповіді","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fheaders-decorators","18.web-development\u002F07.nestjs-controllers-routing\u002F11.headers-decorators",{"title":4626,"path":4627,"stem":4628},"Data Transfer Objects (DTO): визначення та призначення","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fdto-introduction","18.web-development\u002F07.nestjs-controllers-routing\u002F12.dto-introduction",{"title":4630,"path":4631,"stem":4632},"Об'єкти Request та Response","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Frequest-response-objects","18.web-development\u002F07.nestjs-controllers-routing\u002F13.request-response-objects",{"title":4634,"path":4635,"stem":4636},"HTTP-статус коди та декоратор @HttpCode","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fhttp-status-codes","18.web-development\u002F07.nestjs-controllers-routing\u002F14.http-status-codes",{"title":4638,"path":4639,"stem":4640},"Перенаправлення (Redirects) та декоратор @Redirect","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fredirects","18.web-development\u002F07.nestjs-controllers-routing\u002F15.redirects",{"title":4642,"path":4643,"stem":4644},"Асинхронні обробники та Observables","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fasync-handlers","18.web-development\u002F07.nestjs-controllers-routing\u002F16.async-handlers",{"title":4646,"path":4647,"stem":4648},"Маршрутизація за піддоменами та версіонування API","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fsub-domain-routing","18.web-development\u002F07.nestjs-controllers-routing\u002F17.sub-domain-routing",{"title":4650,"path":4651,"stem":4652},"Області видимості контролерів (Scopes)","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fcontroller-scopes","18.web-development\u002F07.nestjs-controllers-routing\u002F18.controller-scopes",{"title":4654,"path":4655,"stem":4656},"Основні команди NestJS CLI","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fnestjs-cli-commands","18.web-development\u002F07.nestjs-controllers-routing\u002F19.nestjs-cli-commands",{"title":4658,"path":4659,"stem":4660},"Практичний приклад: створення CRUD-контролера","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fcrud-example","18.web-development\u002F07.nestjs-controllers-routing\u002F20.crud-example",{"title":4662,"path":4663,"stem":4664},"Тестування контролерів","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Ftesting-controllers","18.web-development\u002F07.nestjs-controllers-routing\u002F21.testing-controllers",{"title":4666,"path":4667,"stem":4668},"Best Practices для контролерів та маршрутизації","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fbest-practices","18.web-development\u002F07.nestjs-controllers-routing\u002F22.best-practices",{"title":4670,"icon":4671,"path":4672,"stem":4673,"children":4674,"page":59},"Тема 8. Провайдери, сервіси та модульна система NestJS","i-lucide-package","\u002Fweb-development\u002Fnestjs-providers-modules","18.web-development\u002F08.nestjs-providers-modules",[4675,4679,4683,4687,4691,4695,4699,4703,4707,4711,4715,4719,4723,4727,4731],{"title":4676,"path":4677,"stem":4678},"Концепція провайдерів у NestJS","\u002Fweb-development\u002Fnestjs-providers-modules\u002Fproviders-concept","18.web-development\u002F08.nestjs-providers-modules\u002F01.providers-concept",{"title":4680,"path":4681,"stem":4682},"Сервіси: інкапсуляція бізнес-логіки","\u002Fweb-development\u002Fnestjs-providers-modules\u002Fservices-business-logic","18.web-development\u002F08.nestjs-providers-modules\u002F02.services-business-logic",{"title":4684,"path":4685,"stem":4686},"Практика ін","\u002Fweb-development\u002Fnestjs-providers-modules\u002Fdependency-injection-practice","18.web-development\u002F08.nestjs-providers-modules\u002F03.dependency-injection-practice",{"title":4688,"path":4689,"stem":4690},"Custom Providers: useValue, useClass, useFactory, useExisting","\u002Fweb-development\u002Fnestjs-providers-modules\u002Fcustom-providers","18.web-development\u002F08.nestjs-providers-modules\u002F04.custom-providers",{"title":4692,"path":4693,"stem":4694},"Injection Tokens: рядкові та символьні токени","\u002Fweb-development\u002Fnestjs-providers-modules\u002Finjection-tokens","18.web-development\u002F08.nestjs-providers-modules\u002F05.injection-tokens",{"title":4696,"path":4697,"stem":4698},"Опціональні провайдери та декоратор @Optional","\u002Fweb-development\u002Fnestjs-providers-modules\u002Foptional-providers","18.web-development\u002F08.nestjs-providers-modules\u002F07.optional-providers",{"title":4700,"path":4701,"stem":4702},"Структура модулів: imports, controllers, providers, exports","\u002Fweb-development\u002Fnestjs-providers-modules\u002Fmodules-structure","18.web-development\u002F08.nestjs-providers-modules\u002F08.modules-structure",{"title":4704,"path":4705,"stem":4706},"Feature Modules: ізоляція функціональності","\u002Fweb-development\u002Fnestjs-providers-modules\u002Ffeature-modules","18.web-development\u002F08.nestjs-providers-modules\u002F09.feature-modules",{"title":4708,"path":4709,"stem":4710},"Shared Modules: перевикористання провайдерів","\u002Fweb-development\u002Fnestjs-providers-modules\u002Fshared-modules","18.web-development\u002F08.nestjs-providers-modules\u002F10.shared-modules",{"title":4712,"path":4713,"stem":4714},"Global Modules та декоратор @Global","\u002Fweb-development\u002Fnestjs-providers-modules\u002Fglobal-modules","18.web-development\u002F08.nestjs-providers-modules\u002F11.global-modules",{"title":4716,"path":4717,"stem":4718},"Dynamic Modules: конфігурація під час виконання","\u002Fweb-development\u002Fnestjs-providers-modules\u002Fdynamic-modules","18.web-development\u002F08.nestjs-providers-modules\u002F12.dynamic-modules",{"title":4720,"path":4721,"stem":4722},"Циклічні залежності та forwardRef","\u002Fweb-development\u002Fnestjs-providers-modules\u002Fcircular-dependencies","18.web-development\u002F08.nestjs-providers-modules\u002F13.circular-dependencies",{"title":4724,"path":4725,"stem":4726},"Lifecycle Hooks: хуки життєвого циклу","\u002Fweb-development\u002Fnestjs-providers-modules\u002Flifecycle-hooks","18.web-development\u002F08.nestjs-providers-modules\u002F14.lifecycle-hooks",{"title":4728,"path":4729,"stem":4730},"ModuleRef: динамічний доступ до провайдерів","\u002Fweb-development\u002Fnestjs-providers-modules\u002Fmodule-reference","18.web-development\u002F08.nestjs-providers-modules\u002F15.module-reference",{"title":4732,"path":4733,"stem":4734},"Тестування сервісів та провайдерів","\u002Fweb-development\u002Fnestjs-providers-modules\u002Ftesting-services","18.web-development\u002F08.nestjs-providers-modules\u002F16.testing-services",{"title":4736,"icon":4737,"path":4738,"stem":4739,"children":4740,"page":59},"Тема 9. Валідація даних та конвеєр обробки запитів у NestJS","i-lucide-filter","\u002Fweb-development\u002Fnestjs-validation-pipeline","18.web-development\u002F09.nestjs-validation-pipeline",[4741,4745,4749,4753,4757,4761,4765,4769,4773,4777,4781,4785,4789,4793,4797,4801,4805,4809,4813],{"title":4742,"path":4743,"stem":4744},"Request Pipeline: конвеєр обробки запитів","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Frequest-pipeline","18.web-development\u002F09.nestjs-validation-pipeline\u002F01.request-pipeline",{"title":4746,"path":4747,"stem":4748},"Pipes: концепція трансформації та валідації","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fpipes-concept","18.web-development\u002F09.nestjs-validation-pipeline\u002F02.pipes-concept",{"title":4750,"path":4751,"stem":4752},"Вбудовані pipes: ParseIntPipe, ParseBoolPipe, ParseUUIDPipe","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fbuilt-in-pipes","18.web-development\u002F09.nestjs-validation-pipeline\u002F03.built-in-pipes",{"title":4754,"path":4755,"stem":4756},"ValidationPipe: автоматична валідація DTO","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fvalidation-pipe","18.web-development\u002F09.nestjs-validation-pipeline\u002F04.validation-pipe",{"title":4758,"path":4759,"stem":4760},"Декоратори class-validator для DTO","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fclass-validator-decorators","18.web-development\u002F09.nestjs-validation-pipeline\u002F05.class-validator-decorators",{"title":4762,"path":4763,"stem":4764},"Створення кастомних валідаторів","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fcustom-validators","18.web-development\u002F09.nestjs-validation-pipeline\u002F06.custom-validators",{"title":4766,"path":4767,"stem":4768},"Створення власних Pipes","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fcustom-pipes","18.web-development\u002F09.nestjs-validation-pipeline\u002F07.custom-pipes",{"title":4770,"path":4771,"stem":4772},"Основи Middleware","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fmiddleware-basics","18.web-development\u002F09.nestjs-validation-pipeline\u002F08.middleware-basics",{"title":4774,"path":4775,"stem":4776},"Практичні приклади Middleware","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fmiddleware-examples","18.web-development\u002F09.nestjs-validation-pipeline\u002F09.middleware-examples",{"title":4778,"path":4779,"stem":4780},"Guards: захисні перехоплювачі доступу","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fguards-concept","18.web-development\u002F09.nestjs-validation-pipeline\u002F10.guards-concept",{"title":4782,"path":4783,"stem":4784},"Створення кастомних Guards","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fcustom-guards","18.web-development\u002F09.nestjs-validation-pipeline\u002F11.custom-guards",{"title":4786,"path":4787,"stem":4788},"Interceptors: перехоплення та трансформація відповідей","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Finterceptors-concept","18.web-development\u002F09.nestjs-validation-pipeline\u002F12.interceptors-concept",{"title":4790,"path":4791,"stem":4792},"Практичні приклади Interceptors","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Finterceptor-examples","18.web-development\u002F09.nestjs-validation-pipeline\u002F13.interceptor-examples",{"title":4794,"path":4795,"stem":4796},"Exception Filters: обробка виключень","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fexception-filters","18.web-development\u002F09.nestjs-validation-pipeline\u002F14.exception-filters",{"title":4798,"path":4799,"stem":4800},"Custom Exception Filters: спеціалізовані фільтри","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fcustom-exception-filters","18.web-development\u002F09.nestjs-validation-pipeline\u002F15.custom-exception-filters",{"title":4802,"path":4803,"stem":4804},"Execution Context: контекст виконання","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fexecution-context","18.web-development\u002F09.nestjs-validation-pipeline\u002F16.execution-context",{"title":4806,"path":4807,"stem":4808},"Custom Decorators: власні декоратори","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fcustom-decorators","18.web-development\u002F09.nestjs-validation-pipeline\u002F17.custom-decorators",{"title":4810,"path":4811,"stem":4812},"Global Components: глобальні компоненти","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fglobal-components","18.web-development\u002F09.nestjs-validation-pipeline\u002F18.global-components",{"title":4814,"path":4815,"stem":4816},"Pipeline Best Practices: найкращі практики","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fpipeline-best-practices","18.web-development\u002F09.nestjs-validation-pipeline\u002F19.pipeline-best-practices",{"title":4818,"icon":3043,"path":4819,"stem":4820,"children":4821,"page":59},"Інтеграція реляційних баз даних засобами TypeORM","\u002Fweb-development\u002Ftypeorm-integration","18.web-development\u002F10.typeorm-integration",[4822,4826,4830,4834,4838,4842,4846],{"title":4823,"path":4824,"stem":4825},"Робота з базами даних у Node.js через нативні драйвери","\u002Fweb-development\u002Ftypeorm-integration\u002F01-nodejs-database-drivers","18.web-development\u002F10.typeorm-integration\u002F01-nodejs-database-drivers",{"title":4827,"path":4828,"stem":4829},"ORM та знайомство з TypeORM","\u002Fweb-development\u002Ftypeorm-integration\u002F02-orm-and-typeorm-intro","18.web-development\u002F10.typeorm-integration\u002F02-orm-and-typeorm-intro",{"title":4831,"path":4832,"stem":4833},"Налаштування TypeORM у NestJS проєкті","\u002Fweb-development\u002Ftypeorm-integration\u002F03-typeorm-setup-nestjs","18.web-development\u002F10.typeorm-integration\u002F03-typeorm-setup-nestjs",{"title":4835,"path":4836,"stem":4837},"Entity класи та декоратори TypeORM","\u002Fweb-development\u002Ftypeorm-integration\u002F04-entities-and-decorators","18.web-development\u002F10.typeorm-integration\u002F04-entities-and-decorators",{"title":4839,"path":4840,"stem":4841},"Repository Pattern та CRUD операції","\u002Fweb-development\u002Ftypeorm-integration\u002F05-repository-pattern-crud","18.web-development\u002F10.typeorm-integration\u002F05-repository-pattern-crud",{"title":4843,"path":4844,"stem":4845},"Пагінація та фільтрація даних","\u002Fweb-development\u002Ftypeorm-integration\u002F06-pagination-filtering","18.web-development\u002F10.typeorm-integration\u002F06-pagination-filtering",{"title":4847,"path":4848,"stem":4849},"QueryBuilder для складних запитів","\u002Fweb-development\u002Ftypeorm-integration\u002F07-query-builder","18.web-development\u002F10.typeorm-integration\u002F07-query-builder",{"title":4851,"icon":4852,"path":4853,"stem":4854,"children":4855,"page":59},"Зв'язки між сутностями, міграції та оптимізація запитів","i-lucide-git-branch","\u002Fweb-development\u002Fentity-relations-migrations","18.web-development\u002F11.entity-relations-migrations",[4856,4860,4864,4868,4872],{"title":4857,"path":4858,"stem":4859},"Зв'язки One-to-Many та Many-to-One","\u002Fweb-development\u002Fentity-relations-migrations\u002F01-one-to-many-many-to-one","18.web-development\u002F11.entity-relations-migrations\u002F01-one-to-many-many-to-one",{"title":4861,"path":4862,"stem":4863},"Зв'язки One-to-One та Many-to-Many","\u002Fweb-development\u002Fentity-relations-migrations\u002F02-one-to-one-many-to-many","18.web-development\u002F11.entity-relations-migrations\u002F02-one-to-one-many-to-many",{"title":4865,"path":4866,"stem":4867},"Керування міграціями бази даних","\u002Fweb-development\u002Fentity-relations-migrations\u002F03-migrations-management","18.web-development\u002F11.entity-relations-migrations\u002F03-migrations-management",{"title":4869,"path":4870,"stem":4871},"Транзакції у TypeORM","\u002Fweb-development\u002Fentity-relations-migrations\u002F04-transactions","18.web-development\u002F11.entity-relations-migrations\u002F04-transactions",{"title":4873,"path":4874,"stem":4875,"children":4876},"Індекси та оптимізація запитів","\u002Fweb-development\u002Fentity-relations-migrations\u002F05-indexes-optimization","18.web-development\u002F11.entity-relations-migrations\u002F05-indexes-optimization",[4877],{"title":4873,"path":4874,"stem":4875},{"title":4879,"icon":4880,"path":4881,"stem":4882,"children":4883,"page":59},"Механізми автентифікації у вебзастосунках","i-lucide-key","\u002Fweb-development\u002Fauthentication","18.web-development\u002F12.authentication",[4884,4888,4892,4896,4900,4904,4908,4912,4916],{"title":4885,"path":4886,"stem":4887},"Автентифікація vs Авторизація","\u002Fweb-development\u002Fauthentication\u002F01-authentication-vs-authorization","18.web-development\u002F12.authentication\u002F01-authentication-vs-authorization",{"title":4889,"path":4890,"stem":4891},"Стратегії автентифікації","\u002Fweb-development\u002Fauthentication\u002F02-authentication-strategies","18.web-development\u002F12.authentication\u002F02-authentication-strategies",{"title":4893,"path":4894,"stem":4895},"Автентифікація на основі сесій","\u002Fweb-development\u002Fauthentication\u002F03-session-based-authentication","18.web-development\u002F12.authentication\u002F03-session-based-authentication",{"title":4897,"path":4898,"stem":4899},"Структура JSON Web Token (JWT)","\u002Fweb-development\u002Fauthentication\u002F04-jwt-structure","18.web-development\u002F12.authentication\u002F04-jwt-structure",{"title":4901,"path":4902,"stem":4903},"Інтеграція JWT у NestJS","\u002Fweb-development\u002Fauthentication\u002F05-nestjs-jwt-integration","18.web-development\u002F12.authentication\u002F05-nestjs-jwt-integration",{"title":4905,"path":4906,"stem":4907},"Passport.js стратегії у NestJS","\u002Fweb-development\u002Fauthentication\u002F06-passport-strategies","18.web-development\u002F12.authentication\u002F06-passport-strategies",{"title":4909,"path":4910,"stem":4911},"Безпечне зберігання паролів: хешування та криптографічний захист","\u002Fweb-development\u002Fauthentication\u002F07-password-hashing","18.web-development\u002F12.authentication\u002F07-password-hashing",{"title":4913,"path":4914,"stem":4915},"Refresh Token та безпечне оновлення доступу","\u002Fweb-development\u002Fauthentication\u002F08-refresh-tokens","18.web-development\u002F12.authentication\u002F08-refresh-tokens",{"title":4917,"path":4918,"stem":4919},"OAuth 2.0 та OpenID Connect: делегована автентифікація","\u002Fweb-development\u002Fauthentication\u002F09-oauth2-openid","18.web-development\u002F12.authentication\u002F09-oauth2-openid",{"title":4921,"icon":4922,"path":4923,"stem":4924,"children":4925,"page":59},"Авторизація та безпека серверних застосунків","i-lucide-shield","\u002Fweb-development\u002Fauthorization-security","18.web-development\u002F13.authorization-security",[4926,4930,4934,4938,4942,4946,4950,4954,4958,4962],{"title":4927,"path":4928,"stem":4929},"Моделі авторизації","\u002Fweb-development\u002Fauthorization-security\u002F01-authorization-models","18.web-development\u002F13.authorization-security\u002F01-authorization-models",{"title":4931,"path":4932,"stem":4933},"Реалізація RBAC у NestJS","\u002Fweb-development\u002Fauthorization-security\u002F02-rbac-implementation","18.web-development\u002F13.authorization-security\u002F02-rbac-implementation",{"title":4935,"path":4936,"stem":4937},"Permission-Based Access Control","\u002Fweb-development\u002Fauthorization-security\u002F03-permission-based-access","18.web-development\u002F13.authorization-security\u002F03-permission-based-access",{"title":4939,"path":4940,"stem":4941},"ABAC та бібліотека CASL","\u002Fweb-development\u002Fauthorization-security\u002F04-abac-casl","18.web-development\u002F13.authorization-security\u002F04-abac-casl",{"title":4943,"path":4944,"stem":4945},"Кастомні декоратори та метадані","\u002Fweb-development\u002Fauthorization-security\u002F05-custom-decorators-metadata","18.web-development\u002F13.authorization-security\u002F05-custom-decorators-metadata",{"title":4947,"path":4948,"stem":4949},"Конфігурація CORS","\u002Fweb-development\u002Fauthorization-security\u002F06-cors-configuration","18.web-development\u002F13.authorization-security\u002F06-cors-configuration",{"title":4951,"path":4952,"stem":4953},"Захист через HTTP Security Headers (Helmet)","\u002Fweb-development\u002Fauthorization-security\u002F07-helmet-security-headers","18.web-development\u002F13.authorization-security\u002F07-helmet-security-headers",{"title":4955,"path":4956,"stem":4957},"Rate Limiting та Throttling","\u002Fweb-development\u002Fauthorization-security\u002F08-rate-limiting-throttling","18.web-development\u002F13.authorization-security\u002F08-rate-limiting-throttling",{"title":4959,"path":4960,"stem":4961},"Захист від поширених атак","\u002Fweb-development\u002Fauthorization-security\u002F09-common-attacks-protection","18.web-development\u002F13.authorization-security\u002F09-common-attacks-protection",{"title":4963,"path":4964,"stem":4965},"HTTPS у продакшені","\u002Fweb-development\u002Fauthorization-security\u002F10-https-production","18.web-development\u002F13.authorization-security\u002F10-https-production",{"title":4967,"icon":871,"path":4968,"stem":4969,"children":4970,"page":59},"Комунікація у реальному часі, нотифікації та фонові задачі","\u002Fweb-development\u002Frealtime-notifications-jobs","18.web-development\u002F14.realtime-notifications-jobs",[4971,4975,4979,4983,4987,4991,4994,4997,5001,5005],{"title":4972,"path":4973,"stem":4974},"Методи комунікації у реальному часі","\u002Fweb-development\u002Frealtime-notifications-jobs\u002F01-realtime-communication-methods","18.web-development\u002F14.realtime-notifications-jobs\u002F01-realtime-communication-methods",{"title":4976,"path":4977,"stem":4978},"WebSocket Gateway у NestJS","\u002Fweb-development\u002Frealtime-notifications-jobs\u002F02-websocket-gateway","18.web-development\u002F14.realtime-notifications-jobs\u002F02-websocket-gateway",{"title":4980,"path":4981,"stem":4982},"Lifecycle та Rooms у WebSocket","\u002Fweb-development\u002Frealtime-notifications-jobs\u002F03-websocket-lifecycle-rooms","18.web-development\u002F14.realtime-notifications-jobs\u002F03-websocket-lifecycle-rooms",{"title":4984,"path":4985,"stem":4986},"Server-Sent Events (SSE)","\u002Fweb-development\u002Frealtime-notifications-jobs\u002F04-server-sent-events","18.web-development\u002F14.realtime-notifications-jobs\u002F04-server-sent-events",{"title":4988,"path":4989,"stem":4990},"Архітектура системи нотифікацій","\u002Fweb-development\u002Frealtime-notifications-jobs\u002F05-notification-system","18.web-development\u002F14.realtime-notifications-jobs\u002F05-notification-system",{"title":904,"path":4992,"stem":4993},"\u002Fweb-development\u002Frealtime-notifications-jobs\u002F06-email-notifications","18.web-development\u002F14.realtime-notifications-jobs\u002F06-email-notifications",{"title":900,"path":4995,"stem":4996},"\u002Fweb-development\u002Frealtime-notifications-jobs\u002F07-web-push-notifications","18.web-development\u002F14.realtime-notifications-jobs\u002F07-web-push-notifications",{"title":4998,"path":4999,"stem":5000},"Фонові задачі та черги","\u002Fweb-development\u002Frealtime-notifications-jobs\u002F08-background-jobs-queues","18.web-development\u002F14.realtime-notifications-jobs\u002F08-background-jobs-queues",{"title":5002,"path":5003,"stem":5004},"Планувальники та Cron jobs","\u002Fweb-development\u002Frealtime-notifications-jobs\u002F09-schedulers-cron","18.web-development\u002F14.realtime-notifications-jobs\u002F09-schedulers-cron",{"title":5006,"path":5007,"stem":5008},"Практичні сценарії застосування","\u002Fweb-development\u002Frealtime-notifications-jobs\u002F10-practical-scenarios","18.web-development\u002F14.realtime-notifications-jobs\u002F10-practical-scenarios",{"title":5010,"icon":5011,"path":5012,"stem":5013,"children":5014,"page":59},"Тестування, документування та розгортання застосунків","i-lucide-rocket","\u002Fweb-development\u002Ftesting-documentation-deployment","18.web-development\u002F15.testing-documentation-deployment",[5015,5019,5023,5027,5031,5035,5039,5043,5047,5051],{"title":5016,"path":5017,"stem":5018},"Піраміда тестування та стратегія","\u002Fweb-development\u002Ftesting-documentation-deployment\u002F01-testing-pyramid-strategy","18.web-development\u002F15.testing-documentation-deployment\u002F01-testing-pyramid-strategy",{"title":5020,"path":5021,"stem":5022},"Основи Jest у NestJS","\u002Fweb-development\u002Ftesting-documentation-deployment\u002F02-jest-nestjs-basics","18.web-development\u002F15.testing-documentation-deployment\u002F02-jest-nestjs-basics",{"title":5024,"path":5025,"stem":5026},"Unit-тестування сервісів","\u002Fweb-development\u002Ftesting-documentation-deployment\u002F03-unit-testing-services","18.web-development\u002F15.testing-documentation-deployment\u002F03-unit-testing-services",{"title":5028,"path":5029,"stem":5030},"E2E тестування та покриття коду","\u002Fweb-development\u002Ftesting-documentation-deployment\u002F04-e2e-testing-coverage","18.web-development\u002F15.testing-documentation-deployment\u002F04-e2e-testing-coverage",{"title":5032,"path":5033,"stem":5034},"Swagger, OpenAPI, Scalar та Arazzo","\u002Fweb-development\u002Ftesting-documentation-deployment\u002F05-swagger-openapi","18.web-development\u002F15.testing-documentation-deployment\u002F05-swagger-openapi",{"title":5036,"path":5037,"stem":5038},"Керування конфігурацією","\u002Fweb-development\u002Ftesting-documentation-deployment\u002F06-configuration-management","18.web-development\u002F15.testing-documentation-deployment\u002F06-configuration-management",{"title":5040,"path":5041,"stem":5042},"Docker та контейнеризація","\u002Fweb-development\u002Ftesting-documentation-deployment\u002F07-docker-containerization","18.web-development\u002F15.testing-documentation-deployment\u002F07-docker-containerization",{"title":5044,"path":5045,"stem":5046},"CI\u002FCD Pipelines","\u002Fweb-development\u002Ftesting-documentation-deployment\u002F08-cicd-pipelines","18.web-development\u002F15.testing-documentation-deployment\u002F08-cicd-pipelines",{"title":5048,"path":5049,"stem":5050},"Логування та моніторинг","\u002Fweb-development\u002Ftesting-documentation-deployment\u002F09-logging-monitoring","18.web-development\u002F15.testing-documentation-deployment\u002F09-logging-monitoring",{"title":5052,"path":5053,"stem":5054},"Серіалізація та компресія","\u002Fweb-development\u002Ftesting-documentation-deployment\u002F10-serialization-compression","18.web-development\u002F15.testing-documentation-deployment\u002F10-serialization-compression",{"title":5056,"icon":5057,"path":5058,"stem":5059,"children":5060,"page":59},"AI Core: мислення AI","i-lucide-brain","\u002Fai-core","19.ai-core",[5061,5102,5151,5189],{"title":5062,"icon":5011,"path":5063,"stem":5064,"children":5065,"page":59},"Вхід у професію AI Native Developer","\u002Fai-core\u002Fai-native-developer","19.ai-core\u002F01.ai-native-developer",[5066,5070,5074,5078,5082,5086,5090,5094,5098],{"title":5067,"path":5068,"stem":5069},"Вступ до професії розробника цифрових продуктів","\u002Fai-core\u002Fai-native-developer\u002Fdigital-products","19.ai-core\u002F01.ai-native-developer\u002F01.digital-products",{"title":5071,"path":5072,"stem":5073},"Професія розробника програмного забезпечення","\u002Fai-core\u002Fai-native-developer\u002Fsoftware-developer","19.ai-core\u002F01.ai-native-developer\u002F02.software-developer",{"title":5075,"path":5076,"stem":5077},"Професія AI Native Developer","\u002Fai-core\u002Fai-native-developer\u002Fai-native-developer","19.ai-core\u002F01.ai-native-developer\u002F03.ai-native-developer",{"title":5079,"path":5080,"stem":5081},"Вплив AI на розробку програмного забезпечення","\u002Fai-core\u002Fai-native-developer\u002Fai-impact-on-development","19.ai-core\u002F01.ai-native-developer\u002F04.ai-impact-on-development",{"title":5083,"path":5084,"stem":5085},"Життєвий цикл цифрового продукту","\u002Fai-core\u002Fai-native-developer\u002Fproduct-lifecycle","19.ai-core\u002F01.ai-native-developer\u002F05.product-lifecycle",{"title":5087,"path":5088,"stem":5089},"Застосування AI на етапах створення цифрового продукту","\u002Fai-core\u002Fai-native-developer\u002Fai-in-product-creation","19.ai-core\u002F01.ai-native-developer\u002F06.ai-in-product-creation",{"title":5091,"path":5092,"stem":5093},"Розподіл завдань між людиною та AI","\u002Fai-core\u002Fai-native-developer\u002Fhuman-vs-ai-tasks","19.ai-core\u002F01.ai-native-developer\u002F07.human-vs-ai-tasks",{"title":5095,"path":5096,"stem":5097},"Компетенції AI Native Developer","\u002Fai-core\u002Fai-native-developer\u002Fcompetencies","19.ai-core\u002F01.ai-native-developer\u002F08.competencies",{"title":5099,"path":5100,"stem":5101},"Карта професійного розвитку AI Native Developer","\u002Fai-core\u002Fai-native-developer\u002Fcareer-roadmap","19.ai-core\u002F01.ai-native-developer\u002F09.career-roadmap",{"title":5103,"icon":255,"path":5104,"stem":5105,"children":5106,"page":59},"Штучний інтелект і машинне навчання","\u002Fai-core\u002Fai-and-machine-learning","19.ai-core\u002F02.ai-and-machine-learning",[5107,5111,5115,5119,5123,5127,5131,5135,5139,5143,5147],{"title":5108,"path":5109,"stem":5110},"Штучний інтелект","\u002Fai-core\u002Fai-and-machine-learning\u002Fwhat-is-ai","19.ai-core\u002F02.ai-and-machine-learning\u002F01.what-is-ai",{"title":5112,"path":5113,"stem":5114},"Відмінність AI від інших програмних систем","\u002Fai-core\u002Fai-and-machine-learning\u002Fai-vs-automation","19.ai-core\u002F02.ai-and-machine-learning\u002F02.ai-vs-automation",{"title":5116,"path":5117,"stem":5118},"Завдання штучного інтелекту","\u002Fai-core\u002Fai-and-machine-learning\u002Fai-tasks","19.ai-core\u002F02.ai-and-machine-learning\u002F03.ai-tasks",{"title":5120,"path":5121,"stem":5122},"Machine Learning","\u002Fai-core\u002Fai-and-machine-learning\u002Fmachine-learning","19.ai-core\u002F02.ai-and-machine-learning\u002F04.machine-learning",{"title":5124,"path":5125,"stem":5126},"Machine Learning Workflow","\u002Fai-core\u002Fai-and-machine-learning\u002Fml-workflow","19.ai-core\u002F02.ai-and-machine-learning\u002F05.ml-workflow",{"title":5128,"path":5129,"stem":5130},"Типи машинного навчання","\u002Fai-core\u002Fai-and-machine-learning\u002Fml-types","19.ai-core\u002F02.ai-and-machine-learning\u002F06.ml-types",{"title":5132,"path":5133,"stem":5134},"Generative AI","\u002Fai-core\u002Fai-and-machine-learning\u002Fgenerative-ai","19.ai-core\u002F02.ai-and-machine-learning\u002F07.generative-ai",{"title":5136,"path":5137,"stem":5138},"Типи контенту, створюваного AI","\u002Fai-core\u002Fai-and-machine-learning\u002Fai-content-types","19.ai-core\u002F02.ai-and-machine-learning\u002F08.ai-content-types",{"title":5140,"path":5141,"stem":5142},"Великі мовні моделі","\u002Fai-core\u002Fai-and-machine-learning\u002Flarge-language-models","19.ai-core\u002F02.ai-and-machine-learning\u002F09.large-language-models",{"title":5144,"path":5145,"stem":5146},"Можливості та обмеження Generative AI","\u002Fai-core\u002Fai-and-machine-learning\u002Fcapabilities-and-limitations","19.ai-core\u002F02.ai-and-machine-learning\u002F10.capabilities-and-limitations",{"title":5148,"path":5149,"stem":5150},"Сучасні AI-асистенти","\u002Fai-core\u002Fai-and-machine-learning\u002Fmodern-ai-assistants","19.ai-core\u002F02.ai-and-machine-learning\u002F11.modern-ai-assistants",{"title":5152,"icon":5153,"path":5154,"stem":5155,"children":5156,"page":59},"Постановка завдань для AI: принципи створення промптів","i-lucide-message-square-text","\u002Fai-core\u002Fprompt-engineering","19.ai-core\u002F03.prompt-engineering",[5157,5161,5165,5169,5173,5177,5181,5185],{"title":5158,"path":5159,"stem":5160},"Промпт як інструмент","\u002Fai-core\u002Fprompt-engineering\u002Fprompt-as-tool","19.ai-core\u002F03.prompt-engineering\u002F01.prompt-as-tool",{"title":5162,"path":5163,"stem":5164},"Принципи створення промптів","\u002Fai-core\u002Fprompt-engineering\u002Fprompt-principles","19.ai-core\u002F03.prompt-engineering\u002F02.prompt-principles",{"title":5166,"path":5167,"stem":5168},"Структура промпта","\u002Fai-core\u002Fprompt-engineering\u002Fprompt-structure","19.ai-core\u002F03.prompt-engineering\u002F03.prompt-structure",{"title":5170,"path":5171,"stem":5172},"Види промптів за типом задачі","\u002Fai-core\u002Fprompt-engineering\u002Fprompt-types","19.ai-core\u002F03.prompt-engineering\u002F04.prompt-types",{"title":5174,"path":5175,"stem":5176},"Прийоми посилення промпта","\u002Fai-core\u002Fprompt-engineering\u002Fprompt-enhancement","19.ai-core\u002F03.prompt-engineering\u002F05.prompt-enhancement",{"title":5178,"path":5179,"stem":5180},"Розбір і покращення промпта","\u002Fai-core\u002Fprompt-engineering\u002Fprompt-analysis","19.ai-core\u002F03.prompt-engineering\u002F06.prompt-analysis",{"title":5182,"path":5183,"stem":5184},"Типові помилки під час створення промптів","\u002Fai-core\u002Fprompt-engineering\u002Fcommon-mistakes","19.ai-core\u002F03.prompt-engineering\u002F07.common-mistakes",{"title":5186,"path":5187,"stem":5188},"Практикум: особиста бібліотека промптів","\u002Fai-core\u002Fprompt-engineering\u002Fprompt-library","19.ai-core\u002F03.prompt-engineering\u002F08.prompt-library",{"title":5190,"icon":793,"path":5191,"stem":5192,"children":5193,"page":59},"Перевірка результатів, безпека та AI Native Workflow","\u002Fai-core\u002Fverification-security-workflow","19.ai-core\u002F04.verification-security-workflow",[5194,5198,5202,5206,5210,5214,5218,5222,5226],{"title":5195,"path":5196,"stem":5197},"Межі можливостей AI","\u002Fai-core\u002Fverification-security-workflow\u002Fai-limitations","19.ai-core\u002F04.verification-security-workflow\u002F01.ai-limitations",{"title":5199,"path":5200,"stem":5201},"Галюцинації AI","\u002Fai-core\u002Fverification-security-workflow\u002Fai-hallucinations","19.ai-core\u002F04.verification-security-workflow\u002F02.ai-hallucinations",{"title":5203,"path":5204,"stem":5205},"Критичне мислення під час роботи з AI","\u002Fai-core\u002Fverification-security-workflow\u002Fcritical-thinking","19.ai-core\u002F04.verification-security-workflow\u002F03.critical-thinking",{"title":5207,"path":5208,"stem":5209},"Перевірка результатів роботи AI","\u002Fai-core\u002Fverification-security-workflow\u002Fresult-verification","19.ai-core\u002F04.verification-security-workflow\u002F04.result-verification",{"title":5211,"path":5212,"stem":5213},"Захист даних під час роботи з AI","\u002Fai-core\u002Fverification-security-workflow\u002Fdata-protection","19.ai-core\u002F04.verification-security-workflow\u002F05.data-protection",{"title":5215,"path":5216,"stem":5217},"Авторське право та навчальна доброчесність","\u002Fai-core\u002Fverification-security-workflow\u002Fcopyright-integrity","19.ai-core\u002F04.verification-security-workflow\u002F06.copyright-integrity",{"title":5219,"path":5220,"stem":5221},"Відповідальне використання AI","\u002Fai-core\u002Fverification-security-workflow\u002Fresponsible-use","19.ai-core\u002F04.verification-security-workflow\u002F07.responsible-use",{"title":5223,"path":5224,"stem":5225},"AI Native Workflow","\u002Fai-core\u002Fverification-security-workflow\u002Fai-native-workflow","19.ai-core\u002F04.verification-security-workflow\u002F08.ai-native-workflow",{"title":5227,"path":5228,"stem":5229},"Застосування AI Native Workflow під час створення цифрового продукту","\u002Fai-core\u002Fverification-security-workflow\u002Fworkflow-in-practice","19.ai-core\u002F04.verification-security-workflow\u002F09.workflow-in-practice",{"title":5231,"icon":5232,"path":5233,"stem":5234,"children":5235,"page":59},"AI Developer: Vibe Coding Sprint","i-lucide-code-xml","\u002Fai-developer","20.ai-developer",[5236,5262,5284,5305],{"title":5237,"icon":5238,"path":5239,"stem":5240,"children":5241,"page":59},"Проєктування і чорнова версія","i-lucide-pencil-ruler","\u002Fai-developer\u002Fdraft-creation","20.ai-developer\u002F01.draft-creation",[5242,5246,5250,5254,5258],{"title":5243,"path":5244,"stem":5245},"Парадигма Vibe Coding Workflow","\u002Fai-developer\u002Fdraft-creation\u002Fvibe-coding-workflow","20.ai-developer\u002F01.draft-creation\u002F01.vibe-coding-workflow",{"title":5247,"path":5248,"stem":5249},"AI-середовище швидкої розробки","\u002Fai-developer\u002Fdraft-creation\u002Fai-ide-environment","20.ai-developer\u002F01.draft-creation\u002F02.ai-ide-environment",{"title":5251,"path":5252,"stem":5253},"Користувацьке завдання та межі першої версії","\u002Fai-developer\u002Fdraft-creation\u002Fproduct-scope-and-mvp","20.ai-developer\u002F01.draft-creation\u002F03.product-scope-and-mvp",{"title":5255,"path":5256,"stem":5257},"Архітектура інтерфейсу та стани застосунку","\u002Fai-developer\u002Fdraft-creation\u002Fapplication-architecture-and-states","20.ai-developer\u002F01.draft-creation\u002F04.application-architecture-and-states",{"title":5259,"path":5260,"stem":5261},"Генерація та фіксація чорнової версії","\u002Fai-developer\u002Fdraft-creation\u002Fgenerating-draft-version","20.ai-developer\u002F01.draft-creation\u002F05.generating-draft-version",{"title":5263,"icon":5264,"path":5265,"stem":5266,"children":5267,"page":59},"Перша робоча версія","i-lucide-play-circle","\u002Fai-developer\u002Ffirst-working-version","20.ai-developer\u002F02.first-working-version",[5268,5272,5276,5280],{"title":5269,"path":5270,"stem":5271},"Уточнення контексту проєкту для AI","\u002Fai-developer\u002Ffirst-working-version\u002Frefining-project-context","20.ai-developer\u002F02.first-working-version\u002F01.refining-project-context",{"title":5273,"path":5274,"stem":5275},"Стратегія завдань для AI-розробки","\u002Fai-developer\u002Ffirst-working-version\u002Fai-prompting-strategy","20.ai-developer\u002F02.first-working-version\u002F02.ai-prompting-strategy",{"title":5277,"path":5278,"stem":5279},"Доопрацювання до першої робочої версії","\u002Fai-developer\u002Ffirst-working-version\u002Frefining-to-working-version","20.ai-developer\u002F02.first-working-version\u002F03.refining-to-working-version",{"title":5281,"path":5282,"stem":5283},"Перевірка першої робочої версії","\u002Fai-developer\u002Ffirst-working-version\u002Ftesting-first-working-version","20.ai-developer\u002F02.first-working-version\u002F04.testing-first-working-version",{"title":5285,"icon":3250,"path":5286,"stem":5287,"children":5288,"page":59},"Ітерації, дебагінг та відновлення","\u002Fai-developer\u002Fiteration-debugging-recovery","20.ai-developer\u002F03.iteration-debugging-recovery",[5289,5293,5297,5301],{"title":5290,"path":5291,"stem":5292},"Управління точковими змінами продукту","\u002Fai-developer\u002Fiteration-debugging-recovery\u002Fchange-management","20.ai-developer\u002F03.iteration-debugging-recovery\u002F01.change-management",{"title":5294,"path":5295,"stem":5296},"Надійність інтерфейсу та обробка помилок","\u002Fai-developer\u002Fiteration-debugging-recovery\u002Fscenario-reliability-and-errors","20.ai-developer\u002F03.iteration-debugging-recovery\u002F02.scenario-reliability-and-errors",{"title":5298,"path":5299,"stem":5300},"Керування контекстом і збереження версій","\u002Fai-developer\u002Fiteration-debugging-recovery\u002Fproject-context-and-versions","20.ai-developer\u002F03.iteration-debugging-recovery\u002F03.project-context-and-versions",{"title":5302,"path":5303,"stem":5304},"Збої AI-розробки, ліміти та аварійне відновлення","\u002Fai-developer\u002Fiteration-debugging-recovery\u002Fai-breakdowns-and-recovery","20.ai-developer\u002F03.iteration-debugging-recovery\u002F04.ai-breakdowns-and-recovery",{"title":5306,"icon":5307,"path":5308,"stem":5309,"children":5310,"page":59},"Перевірка та завершення продукту","i-lucide-check-check","\u002Fai-developer\u002Fverification-and-completion","20.ai-developer\u002F04.verification-and-completion",[5311,5315,5319],{"title":5312,"path":5313,"stem":5314},"Комплексний аудит та підсумкове тестування","\u002Fai-developer\u002Fverification-and-completion\u002Ffinal-product-testing","20.ai-developer\u002F04.verification-and-completion\u002F01.final-product-testing",{"title":5316,"path":5317,"stem":5318},"Підготовка підсумкової версії коду","\u002Fai-developer\u002Fverification-and-completion\u002Fpreparing-release-version","20.ai-developer\u002F04.verification-and-completion\u002F02.preparing-release-version",{"title":5320,"path":5321,"stem":5322},"Демонстрація, публікація та критерії оцінювання","\u002Fai-developer\u002Fverification-and-completion\u002Fproduct-showcase-and-publishing","20.ai-developer\u002F04.verification-and-completion\u002F03.product-showcase-and-publishing",{"title":5324,"path":5325,"stem":5326,"children":5327,"page":59},"Tailwind","\u002Ftailwind","21.tailwind",[5328,5332,5336,5340,5344,5348,5352,5356,5360,5364,5368,5372],{"title":5329,"path":5330,"stem":5331},"Що таке Tailwind CSS і навіщо він потрібен","\u002Ftailwind\u002Ftailwind-intro-philosophy","21.tailwind\u002F01.tailwind-intro-philosophy",{"title":5333,"path":5334,"stem":5335},"Встановлення та налаштування Tailwind CSS v4","\u002Ftailwind\u002Ftailwind-installation-setup","21.tailwind\u002F02.tailwind-installation-setup",{"title":5337,"path":5338,"stem":5339},"Utility-класи: основи та система Tailwind","\u002Ftailwind\u002Ftailwind-utility-classes-core","21.tailwind\u002F03.tailwind-utility-classes-core",{"title":5341,"path":5342,"stem":5343},"Layout: Flexbox та Grid через Tailwind","\u002Ftailwind\u002Ftailwind-flexbox-grid","21.tailwind\u002F04.tailwind-flexbox-grid",{"title":5345,"path":5346,"stem":5347},"Кастомізація теми через @theme у Tailwind v4","\u002Ftailwind\u002Ftailwind-theme-customization","21.tailwind\u002F05.tailwind-theme-customization",{"title":5349,"path":5350,"stem":5351},"Варіанти: hover, focus, responsive, dark mode та нові v4","\u002Ftailwind\u002Ftailwind-variants-states","21.tailwind\u002F06.tailwind-variants-states",{"title":5353,"path":5354,"stem":5355},"Типографіка та система кольорів у Tailwind v4","\u002Ftailwind\u002Ftailwind-typography-colors","21.tailwind\u002F07.tailwind-typography-colors",{"title":5357,"path":5358,"stem":5359},"Компоненти та повторюваність: @apply, @utility та патерни","\u002Ftailwind\u002Ftailwind-components-patterns","21.tailwind\u002F08.tailwind-components-patterns",{"title":5361,"path":5362,"stem":5363},"Темна тема та система дизайн-токенів у Tailwind v4","\u002Ftailwind\u002Ftailwind-dark-mode-theming","21.tailwind\u002F09.tailwind-dark-mode-theming",{"title":5365,"path":5366,"stem":5367},"Довільні значення та контейнерні запити у Tailwind v4","\u002Ftailwind\u002Ftailwind-arbitrary-container-queries","21.tailwind\u002F10.tailwind-arbitrary-container-queries",{"title":5369,"path":5370,"stem":5371},"Анімації, трансформації та 3D у Tailwind v4","\u002Ftailwind\u002Ftailwind-animations-transforms","21.tailwind\u002F11.tailwind-animations-transforms",{"title":5373,"path":5374,"stem":5375},"Tailwind CLI, PostCSS та інтеграція з фреймворками","\u002Ftailwind\u002Ftailwind-cli-tooling","21.tailwind\u002F12.tailwind-cli-tooling",{"title":5377,"path":5378,"stem":5379,"children":5380,"page":59},"React Typescript","\u002Freact-typescript","22.react-typescript",[5381,5406,5410,5414,5418,5422,5426,5430,5434,5438,5468,5472,5476,5480,5484],{"title":5382,"path":5383,"stem":5384,"children":5385,"page":59},"From Html To Project","\u002Freact-typescript\u002Ffrom-html-to-project","22.react-typescript\u002F01.from-html-to-project",[5386,5390,5394,5398,5402],{"title":5387,"path":5388,"stem":5389},"Від одного HTML-файлу до повноцінного проєкту","\u002Freact-typescript\u002Ffrom-html-to-project\u002Fevolution","22.react-typescript\u002F01.from-html-to-project\u002F01.evolution",{"title":5391,"path":5392,"stem":5393},"Що таке React","\u002Freact-typescript\u002Ffrom-html-to-project\u002Fwhat-is-react","22.react-typescript\u002F01.from-html-to-project\u002F02.what-is-react",{"title":5395,"path":5396,"stem":5397},"JSX та TSX — синтаксичний цукор, а не магія","\u002Freact-typescript\u002Ffrom-html-to-project\u002Fjsx-tsx-syntax","22.react-typescript\u002F01.from-html-to-project\u002F03.jsx-tsx-syntax",{"title":5399,"path":5400,"stem":5401},"Компоненти — будівельні блоки інтерфейсу","\u002Freact-typescript\u002Ffrom-html-to-project\u002Fcomponents","22.react-typescript\u002F01.from-html-to-project\u002F04.components",{"title":5403,"path":5404,"stem":5405},"JSX — розмітка всередині TypeScript","\u002Freact-typescript\u002Ffrom-html-to-project\u002Fjsx-expressions","22.react-typescript\u002F01.from-html-to-project\u002F05.jsx-expressions",{"title":5407,"path":5408,"stem":5409},"Хук useReducer: структуроване управління складним станом","\u002Freact-typescript\u002Fuse-reducer","22.react-typescript\u002F23.use-reducer",{"title":5411,"path":5412,"stem":5413},"Context API: передавання даних без «пропс-дрілінгу»","\u002Freact-typescript\u002Fcontext-api","22.react-typescript\u002F24.context-api",{"title":5415,"path":5416,"stem":5417},"Синхронізація з ефектами: хук useEffect та функції очищення","\u002Freact-typescript\u002Fuse-effect","22.react-typescript\u002F27.use-effect",{"title":5419,"path":5420,"stem":5421},"Можливо, вам не потрібен ефект: антипатерни та альтернативи","\u002Freact-typescript\u002Fyou-might-not-need-effect","22.react-typescript\u002F28.you-might-not-need-effect",{"title":5423,"path":5424,"stem":5425},"Життєвий цикл реактивних ефектів: мислення процесами синхронізації","\u002Freact-typescript\u002Flifecycle-of-reactive-effects","22.react-typescript\u002F29.lifecycle-of-reactive-effects",{"title":5427,"path":5428,"stem":5429},"Розділення подій та ефектів: реактивна проти нереактивної логіки","\u002Freact-typescript\u002Fseparating-events-from-effects","22.react-typescript\u002F30.separating-events-from-effects",{"title":5431,"path":5432,"stem":5433},"Видалення зайвих залежностей ефектів та оптимізація синхронізації","\u002Freact-typescript\u002Fremoving-effect-dependencies","22.react-typescript\u002F31.removing-effect-dependencies",{"title":5435,"path":5436,"stem":5437},"Кастомні хуки: повторне використання та композиція реактивної логіки","\u002Freact-typescript\u002Fcustom-hooks","22.react-typescript\u002F32.custom-hooks",{"title":5439,"path":5440,"stem":5441,"children":5442},"React Router v7: Маршрутизація в SPA","\u002Freact-typescript\u002Freact-router-v7","22.react-typescript\u002F33.react-router-v7\u002Findex",[5443,5444,5448,5452,5456,5460,5464],{"title":5439,"path":5440,"stem":5441},{"title":5445,"path":5446,"stem":5447},"Встановлення та базова конфігурація React Router v7","\u002Freact-typescript\u002Freact-router-v7\u002Finstallation-setup","22.react-typescript\u002F33.react-router-v7\u002F01.installation-setup",{"title":5449,"path":5450,"stem":5451},"Вкладені маршрути та Outlet: архітектура складних макетів","\u002Freact-typescript\u002Freact-router-v7\u002Fnested-routes-outlet","22.react-typescript\u002F33.react-router-v7\u002F02.nested-routes-outlet",{"title":5453,"path":5454,"stem":5455},"Динамічні маршрути та параметри URL","\u002Freact-typescript\u002Freact-router-v7\u002Fdynamic-routes-params","22.react-typescript\u002F33.react-router-v7\u002F03.dynamic-routes-params",{"title":5457,"path":5458,"stem":5459},"Навігація та корисні хуки React Router","\u002Freact-typescript\u002Freact-router-v7\u002Fnavigation-hooks","22.react-typescript\u002F33.react-router-v7\u002F04.navigation-hooks",{"title":5461,"path":5462,"stem":5463},"Обробка помилок та 404: ErrorBoundary і fallback-маршрути","\u002Freact-typescript\u002Freact-router-v7\u002Ferror-handling-404","22.react-typescript\u002F33.react-router-v7\u002F05.error-handling-404",{"title":5465,"path":5466,"stem":5467},"Data Router API: альтернативний синтаксис через createBrowserRouter","\u002Freact-typescript\u002Freact-router-v7\u002Fdata-router-api-examples","22.react-typescript\u002F33.react-router-v7\u002F06.data-router-api-examples",{"title":5469,"path":5470,"stem":5471},"Axios: HTTP-клієнт із розширеними можливостями","\u002Freact-typescript\u002Faxios","22.react-typescript\u002F34.axios",{"title":5473,"path":5474,"stem":5475},"Redux: класичний підхід до глобального стану","\u002Freact-typescript\u002Fredux-classic","22.react-typescript\u002F35.redux-classic",{"title":5477,"path":5478,"stem":5479},"Redux Toolkit: сучасний стандарт Redux","\u002Freact-typescript\u002Fredux-toolkit","22.react-typescript\u002F36.redux-toolkit",{"title":5481,"path":5482,"stem":5483},"RTK Query: запити до сервера без болю","\u002Freact-typescript\u002Frtk-query-tanstack-query","22.react-typescript\u002F38.rtk-query-tanstack-query",{"title":5485,"path":5486,"stem":5487},"React Hook Form + Zod: типобезпечна валідація форм","\u002Freact-typescript\u002Freact-hook-form-zod","22.react-typescript\u002F39.react-hook-form-zod",{"title":5489,"path":5490,"stem":5491},"Тестування компонентів діаграм та пісочниць","\u002Ftest-components","98.test-components",{"id":5493,"title":2945,"body":5494,"description":22883,"extension":22884,"links":22885,"meta":22886,"navigation":5849,"path":2946,"seo":22887,"stem":2947,"__hash__":22888},"docs\u002F05.python\u002F02.advanced\u002F05.dunder-methods.md",{"type":5495,"value":5496,"toc":22803},"minimark",[5497,5501,5511,5515,5589,5603,5632,5660,5688,5691,5740,5743,5747,5752,5767,5789,6050,6054,6069,6157,6179,6182,6241,6244,6248,6255,6402,6404,6408,6417,6423,6489,6503,6901,6919,6926,6936,7424,7471,7473,7477,7481,7484,7590,7597,8333,8382,8393,8405,8428,8507,8513,8538,8924,8934,8940,8943,8959,8971,8979,8992,9143,9155,9503,9549,9587,9589,9593,9597,9600,9644,9650,10715,10816,10820,10829,10985,11002,11009,11024,11395,11397,11401,11405,11408,11525,11529,11536,12907,12991,12999,13012,13037,13409,13438,13440,13446,13450,13459,13707,13711,13720,14473,14515,14521,14533,14681,14683,14687,14699,14704,14738,14885,14889,14896,15777,15847,15855,15872,16153,16160,16171,16426,16460,16462,16466,16470,16473,16523,16527,17157,17200,17207,17212,17467,17469,17473,17477,17480,17701,17705,17810,17837,17938,18050,18142,18144,18148,18155,18158,18313,18320,18326,18456,18463,18472,18603,18605,18609,18616,18620,18623,18659,18663,18671,22077,22079,22083,22449,22451,22455,22701,22703,22707,22714,22717,22786,22799],[5498,5499,2945],"h1",{"id":5500},"магічні-методи-dunder-та-емуляція-протоколів",[5502,5503,5505,5506,5510],"h2",{"id":5504},"проблема-чому-працює-і-з-числами-і-з-рядками","Проблема: чому ",[5507,5508,5509],"code",{},"+"," працює і з числами, і з рядками?",[5512,5513,5514],"p",{},"Подивіться на ці три рядки коду і спробуйте відповісти на просте запитання: чому вони взагалі працюють?",[5516,5517,5522],"pre",{"className":5518,"code":5519,"language":5520,"meta":5521,"style":5521},"language-python shiki shiki-themes light-plus dark-plus dark-plus","result = 42 + 8          # int + int\ntext   = \"Hello\" + \" World\"  # str + str\npath   = Path(\"\u002Fusr\") \u002F \"bin\" \u002F \"python\"  # Path \u002F str\n","python","",[5507,5523,5524,5547,5565],{"__ignoreMap":5521},[5525,5526,5529,5533,5537,5540,5543],"span",{"class":5527,"line":5528},"line",1,[5525,5530,5532],{"class":5531},"sHH4Y","result = ",[5525,5534,5536],{"class":5535},"sJj4R","42",[5525,5538,5539],{"class":5531}," + ",[5525,5541,5542],{"class":5535},"8",[5525,5544,5546],{"class":5545},"spJ8K","          # int + int\n",[5525,5548,5550,5553,5557,5559,5562],{"class":5527,"line":5549},2,[5525,5551,5552],{"class":5531},"text   = ",[5525,5554,5556],{"class":5555},"sbdoH","\"Hello\"",[5525,5558,5539],{"class":5531},[5525,5560,5561],{"class":5555},"\" World\"",[5525,5563,5564],{"class":5545},"  # str + str\n",[5525,5566,5568,5571,5574,5577,5580,5583,5586],{"class":5527,"line":5567},3,[5525,5569,5570],{"class":5531},"path   = Path(",[5525,5572,5573],{"class":5555},"\"\u002Fusr\"",[5525,5575,5576],{"class":5531},") \u002F ",[5525,5578,5579],{"class":5555},"\"bin\"",[5525,5581,5582],{"class":5531}," \u002F ",[5525,5584,5585],{"class":5555},"\"python\"",[5525,5587,5588],{"class":5545},"  # Path \u002F str\n",[5512,5590,5591,5592,5594,5595,5598,5599,5602],{},"Оператор ",[5507,5593,5509],{}," додає числа. Той самий оператор зклеює рядки. Оператор ",[5507,5596,5597],{},"\u002F"," ділить числа, але у ",[5507,5600,5601],{},"pathlib.Path"," він конструює шляхи файлової системи. Як один і той самий синтаксичний символ може означати абсолютно різні операції залежно від типу об'єкта?",[5512,5604,5605,5606,5610,5611,5614,5615,5614,5618,5614,5621,5614,5624,5627,5628,5631],{},"Відповідь: ",[5607,5608,5609],"strong",{},"протоколи через dunder-методи",". Усе, що ви вважаєте «вбудованою магією» Python — ",[5507,5612,5613],{},"len([1, 2, 3])",", ",[5507,5616,5617],{},"for x in obj",[5507,5619,5620],{},"with open(...) as f",[5507,5622,5623],{},"obj[0]",[5507,5625,5626],{},"str(obj)"," — насправді є ",[5607,5629,5630],{},"викликами спеціальних методів"," на об'єктах. Python просто перекладає синтаксичний цукор у методи.",[5512,5633,5634,5635,5638,5639,5642,5643,5638,5646,5642,5649,5638,5652,5655,5656,5659],{},"Коли ви пишете ",[5507,5636,5637],{},"a + b",", Python виконує ",[5507,5640,5641],{},"a.__add__(b)",". Коли ви пишете ",[5507,5644,5645],{},"len(obj)",[5507,5647,5648],{},"obj.__len__()",[5507,5650,5651],{},"with obj as x",[5507,5653,5654],{},"obj.__enter__()"," і потім ",[5507,5657,5658],{},"obj.__exit__(...)",".",[5512,5661,5662,5663,5666,5667,5670,5671,5673,5674,5677,5678,5673,5681,5684,5685,5659],{},"Це означає, що ",[5607,5664,5665],{},"будь-який ваш клас може брати участь у будь-якому синтаксисі Python"," — варто лише реалізувати відповідний протокол. Ваш клас ",[5507,5668,5669],{},"Vector"," може складатися через ",[5507,5672,5509],{},". Ваш клас ",[5507,5675,5676],{},"Database"," може використовуватись у ",[5507,5679,5680],{},"with",[5507,5682,5683],{},"Grid"," може індексуватись через ",[5507,5686,5687],{},"grid[x][y]",[5512,5689,5690],{},"Саме ця система і є темою цієї статті.",[5692,5693,5694,5700,5715,5720],"card-group",{},[5695,5696,5699],"card",{"icon":5697,"title":5698},"i-heroicons-eye","Прозорий синтаксис","Оператори, вбудовані функції та конструкції мови — все це виклики методів. Знаючи протоколи, ви точно розумієте, що відбувається за будь-яким синтаксисом Python.",[5695,5701,5704,5705,5614,5708,5614,5711,5714],{"icon":5702,"title":5703},"i-heroicons-puzzle-piece","Розширюваність","Ваші класи стають «першокласними громадянами» мови. ",[5507,5706,5707],{},"Path",[5507,5709,5710],{},"Decimal",[5507,5712,5713],{},"datetime"," — усе це звичайні класи, що реалізують dunder-методи.",[5695,5716,5719],{"icon":5717,"title":5718},"i-heroicons-arrow-path","Інтеграція з екосистемою","Будь-яка бібліотека, що очікує «iterable» або «context manager», автоматично працює з вашим класом, якщо він реалізує відповідний протокол.",[5695,5721,5724,5725,5728,5729,5732,5733,5728,5736,5739],{"icon":5722,"title":5723},"i-heroicons-document-text","Читабельний API","Замість ",[5507,5726,5727],{},"vector.add(other)"," — ",[5507,5730,5731],{},"vector + other",". Замість ",[5507,5734,5735],{},"collection.length()",[5507,5737,5738],{},"len(collection)",". Ваш код читається як природна мова.",[5741,5742],"hr",{},[5502,5744,5746],{"id":5745},"частина-i-природа-dunder-методів","Частина I: Природа dunder-методів",[5748,5749,5751],"h3",{"id":5750},"що-таке-протокол-у-python","Що таке «протокол» у Python",[5512,5753,5754,5755,5758,5759,5762,5763,5766],{},"У мовах зі статичною типізацією (Java, C#) інтерфейси є формальними контрактами: клас ",[5607,5756,5757],{},"зобов'язаний"," оголосити, що він реалізує ",[5507,5760,5761],{},"Iterable\u003CT>",", інакше компілятор відмовить. Python обирає інший шлях — ",[5607,5764,5765],{},"структурна типізація"," (duck typing).",[5512,5768,5769,5770,5773,5774,5777,5778,5781,5782,5785,5786,5659],{},"Якщо об'єкт має метод ",[5507,5771,5772],{},"__iter__",", він є ітерабельним — незалежно від того, чи успадковує він щось від ",[5507,5775,5776],{},"collections.abc.Iterable",". Якщо об'єкт має ",[5507,5779,5780],{},"__len__"," і ",[5507,5783,5784],{},"__getitem__",", він є послідовністю. Набір таких методів, що разом реалізують певну поведінку, і є ",[5607,5787,5788],{},"протоколом",[5790,5791,5792],"plant-uml",{},[5516,5793,5797],{"className":5794,"code":5795,"language":5796,"meta":5521,"style":5521},"language-plantuml shiki shiki-themes light-plus dark-plus dark-plus","@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\nskinparam ArrowColor #6366f1\nskinparam node {\n    BackgroundColor #f3f4f6\n    BorderColor #d1d5db\n}\n\npackage \"Синтаксис Python (оператори, функції)\" {\n    node \"a + b\" as ADD #fee2e2\n    node \"len(obj)\" as LEN #fee2e2\n    node \"str(obj)\" as STR #fee2e2\n    node \"obj[key]\" as IDX #fee2e2\n    node \"for x in obj\" as ITER #fee2e2\n    node \"with obj as x\" as CTX #fee2e2\n    node \"obj == other\" as EQ #fee2e2\n}\n\npackage \"Dunder-методи (протоколи)\" {\n    node \"__add__(self, other)\" as DADD #d1fae5\n    node \"__len__(self)\" as DLEN #d1fae5\n    node \"__str__(self)\" as DSTR #d1fae5\n    node \"__getitem__(self, key)\" as DIDX #d1fae5\n    node \"__iter__(self)\" as DITER #d1fae5\n    node \"__enter__ \u002F __exit__\" as DCTX #d1fae5\n    node \"__eq__(self, other)\" as DEQ #d1fae5\n}\n\nADD --> DADD : транслюється у\nLEN --> DLEN : транслюється у\nSTR --> DSTR : транслюється у\nIDX --> DIDX : транслюється у\nITER --> DITER : транслюється у\nCTX --> DCTX : транслюється у\nEQ --> DEQ : транслюється у\n\nnote bottom of DCTX\n  CPython виконує трансляцію\n  синтаксису у виклики методів\n  на рівні байткоду (CALL_INTRINSIC)\nend note\n@enduml\n","plantuml",[5507,5798,5799,5804,5809,5814,5820,5826,5832,5838,5844,5851,5857,5863,5869,5875,5881,5887,5893,5899,5904,5909,5915,5921,5927,5933,5939,5945,5951,5957,5962,5967,5973,5979,5985,5991,5997,6003,6009,6014,6020,6026,6032,6038,6044],{"__ignoreMap":5521},[5525,5800,5801],{"class":5527,"line":5528},[5525,5802,5803],{},"@startuml\n",[5525,5805,5806],{"class":5527,"line":5549},[5525,5807,5808],{},"skinparam style plain\n",[5525,5810,5811],{"class":5527,"line":5567},[5525,5812,5813],{},"skinparam backgroundColor #ffffff\n",[5525,5815,5817],{"class":5527,"line":5816},4,[5525,5818,5819],{},"skinparam ArrowColor #6366f1\n",[5525,5821,5823],{"class":5527,"line":5822},5,[5525,5824,5825],{},"skinparam node {\n",[5525,5827,5829],{"class":5527,"line":5828},6,[5525,5830,5831],{},"    BackgroundColor #f3f4f6\n",[5525,5833,5835],{"class":5527,"line":5834},7,[5525,5836,5837],{},"    BorderColor #d1d5db\n",[5525,5839,5841],{"class":5527,"line":5840},8,[5525,5842,5843],{},"}\n",[5525,5845,5847],{"class":5527,"line":5846},9,[5525,5848,5850],{"emptyLinePlaceholder":5849},true,"\n",[5525,5852,5854],{"class":5527,"line":5853},10,[5525,5855,5856],{},"package \"Синтаксис Python (оператори, функції)\" {\n",[5525,5858,5860],{"class":5527,"line":5859},11,[5525,5861,5862],{},"    node \"a + b\" as ADD #fee2e2\n",[5525,5864,5866],{"class":5527,"line":5865},12,[5525,5867,5868],{},"    node \"len(obj)\" as LEN #fee2e2\n",[5525,5870,5872],{"class":5527,"line":5871},13,[5525,5873,5874],{},"    node \"str(obj)\" as STR #fee2e2\n",[5525,5876,5878],{"class":5527,"line":5877},14,[5525,5879,5880],{},"    node \"obj[key]\" as IDX #fee2e2\n",[5525,5882,5884],{"class":5527,"line":5883},15,[5525,5885,5886],{},"    node \"for x in obj\" as ITER #fee2e2\n",[5525,5888,5890],{"class":5527,"line":5889},16,[5525,5891,5892],{},"    node \"with obj as x\" as CTX #fee2e2\n",[5525,5894,5896],{"class":5527,"line":5895},17,[5525,5897,5898],{},"    node \"obj == other\" as EQ #fee2e2\n",[5525,5900,5902],{"class":5527,"line":5901},18,[5525,5903,5843],{},[5525,5905,5907],{"class":5527,"line":5906},19,[5525,5908,5850],{"emptyLinePlaceholder":5849},[5525,5910,5912],{"class":5527,"line":5911},20,[5525,5913,5914],{},"package \"Dunder-методи (протоколи)\" {\n",[5525,5916,5918],{"class":5527,"line":5917},21,[5525,5919,5920],{},"    node \"__add__(self, other)\" as DADD #d1fae5\n",[5525,5922,5924],{"class":5527,"line":5923},22,[5525,5925,5926],{},"    node \"__len__(self)\" as DLEN #d1fae5\n",[5525,5928,5930],{"class":5527,"line":5929},23,[5525,5931,5932],{},"    node \"__str__(self)\" as DSTR #d1fae5\n",[5525,5934,5936],{"class":5527,"line":5935},24,[5525,5937,5938],{},"    node \"__getitem__(self, key)\" as DIDX #d1fae5\n",[5525,5940,5942],{"class":5527,"line":5941},25,[5525,5943,5944],{},"    node \"__iter__(self)\" as DITER #d1fae5\n",[5525,5946,5948],{"class":5527,"line":5947},26,[5525,5949,5950],{},"    node \"__enter__ \u002F __exit__\" as DCTX #d1fae5\n",[5525,5952,5954],{"class":5527,"line":5953},27,[5525,5955,5956],{},"    node \"__eq__(self, other)\" as DEQ #d1fae5\n",[5525,5958,5960],{"class":5527,"line":5959},28,[5525,5961,5843],{},[5525,5963,5965],{"class":5527,"line":5964},29,[5525,5966,5850],{"emptyLinePlaceholder":5849},[5525,5968,5970],{"class":5527,"line":5969},30,[5525,5971,5972],{},"ADD --> DADD : транслюється у\n",[5525,5974,5976],{"class":5527,"line":5975},31,[5525,5977,5978],{},"LEN --> DLEN : транслюється у\n",[5525,5980,5982],{"class":5527,"line":5981},32,[5525,5983,5984],{},"STR --> DSTR : транслюється у\n",[5525,5986,5988],{"class":5527,"line":5987},33,[5525,5989,5990],{},"IDX --> DIDX : транслюється у\n",[5525,5992,5994],{"class":5527,"line":5993},34,[5525,5995,5996],{},"ITER --> DITER : транслюється у\n",[5525,5998,6000],{"class":5527,"line":5999},35,[5525,6001,6002],{},"CTX --> DCTX : транслюється у\n",[5525,6004,6006],{"class":5527,"line":6005},36,[5525,6007,6008],{},"EQ --> DEQ : транслюється у\n",[5525,6010,6012],{"class":5527,"line":6011},37,[5525,6013,5850],{"emptyLinePlaceholder":5849},[5525,6015,6017],{"class":5527,"line":6016},38,[5525,6018,6019],{},"note bottom of DCTX\n",[5525,6021,6023],{"class":5527,"line":6022},39,[5525,6024,6025],{},"  CPython виконує трансляцію\n",[5525,6027,6029],{"class":5527,"line":6028},40,[5525,6030,6031],{},"  синтаксису у виклики методів\n",[5525,6033,6035],{"class":5527,"line":6034},41,[5525,6036,6037],{},"  на рівні байткоду (CALL_INTRINSIC)\n",[5525,6039,6041],{"class":5527,"line":6040},42,[5525,6042,6043],{},"end note\n",[5525,6045,6047],{"class":5527,"line":6046},43,[5525,6048,6049],{},"@enduml\n",[5748,6051,6053],{"id":6052},"як-python-знаходить-dunder-методи-обхід-через-тип-а-не-екземпляр","Як Python знаходить dunder-методи: обхід через тип, а не екземпляр",[5512,6055,6056,6057,6060,6061,6064,6065,6068],{},"Ось критично важлива деталь, яку більшість розробників не знає. При виклику вбудованих операторів Python ",[5607,6058,6059],{},"не"," шукає dunder-метод в ",[5507,6062,6063],{},"__dict__"," екземпляра — він шукає його безпосередньо у ",[5607,6066,6067],{},"класі"," (типі) об'єкта.",[5516,6070,6072],{"className":5518,"code":6071,"language":5520,"meta":5521,"style":5521},"class Weird:\n    pass\n\nobj = Weird()\n\n# Динамічно додаємо __len__ на екземпляр (не в клас)\nobj.__len__ = lambda: 42\n\n# Інтуїтивно здається, що len(obj) поверне 42...\nprint(len(obj))   # TypeError: object of type 'Weird' has no len()\n",[5507,6073,6074,6087,6093,6097,6102,6106,6111,6131,6135,6140],{"__ignoreMap":5521},[5525,6075,6076,6080,6084],{"class":5527,"line":5528},[5525,6077,6079],{"class":6078},"su1O8","class",[5525,6081,6083],{"class":6082},"sN1BT"," Weird",[5525,6085,6086],{"class":5531},":\n",[5525,6088,6089],{"class":5527,"line":5549},[5525,6090,6092],{"class":6091},"s8xlr","    pass\n",[5525,6094,6095],{"class":5527,"line":5567},[5525,6096,5850],{"emptyLinePlaceholder":5849},[5525,6098,6099],{"class":5527,"line":5816},[5525,6100,6101],{"class":5531},"obj = Weird()\n",[5525,6103,6104],{"class":5527,"line":5822},[5525,6105,5850],{"emptyLinePlaceholder":5849},[5525,6107,6108],{"class":5527,"line":5828},[5525,6109,6110],{"class":5545},"# Динамічно додаємо __len__ на екземпляр (не в клас)\n",[5525,6112,6113,6116,6119,6122,6125,6128],{"class":5527,"line":5834},[5525,6114,6115],{"class":5531},"obj.",[5525,6117,5780],{"class":6118},"s8Opu",[5525,6120,6121],{"class":5531}," = ",[5525,6123,6124],{"class":6078},"lambda",[5525,6126,6127],{"class":5531},": ",[5525,6129,6130],{"class":5535},"42\n",[5525,6132,6133],{"class":5527,"line":5840},[5525,6134,5850],{"emptyLinePlaceholder":5849},[5525,6136,6137],{"class":5527,"line":5846},[5525,6138,6139],{"class":5545},"# Інтуїтивно здається, що len(obj) поверне 42...\n",[5525,6141,6142,6145,6148,6151,6154],{"class":5527,"line":5853},[5525,6143,6144],{"class":6118},"print",[5525,6146,6147],{"class":5531},"(",[5525,6149,6150],{"class":6118},"len",[5525,6152,6153],{"class":5531},"(obj))   ",[5525,6155,6156],{"class":5545},"# TypeError: object of type 'Weird' has no len()\n",[6158,6159,6160,6162,6163,6166,6167,6170,6171,6174,6175,6178],"warning",{},[5507,6161,5645],{}," викликає ",[5507,6164,6165],{},"type(obj).__len__(obj)"," — тобто шукає метод у класі та передає екземпляр явно. Dunder-методи, визначені на рівні ",[5607,6168,6169],{},"екземпляра",", ігноруються при використанні через оператори та вбудовані функції. Це зроблено навмисно — для безпеки та передбачуваності (і для прискорення CPython через спеціальні слоти типу ",[5507,6172,6173],{},"tp_len"," у C-структурі ",[5507,6176,6177],{},"PyTypeObject",").",[5512,6180,6181],{},"Але якщо ви визначаєте метод у класі — все працює:",[5516,6183,6185],{"className":5518,"code":6184,"language":5520,"meta":5521,"style":5521},"class Weird:\n    def __len__(self):\n        return 42\n\nobj = Weird()\nprint(len(obj))   # 42 ✅\n",[5507,6186,6187,6195,6212,6220,6224,6228],{"__ignoreMap":5521},[5525,6188,6189,6191,6193],{"class":5527,"line":5528},[5525,6190,6079],{"class":6078},[5525,6192,6083],{"class":6082},[5525,6194,6086],{"class":5531},[5525,6196,6197,6200,6203,6205,6209],{"class":5527,"line":5549},[5525,6198,6199],{"class":6078},"    def",[5525,6201,6202],{"class":6118}," __len__",[5525,6204,6147],{"class":5531},[5525,6206,6208],{"class":6207},"siwwj","self",[5525,6210,6211],{"class":5531},"):\n",[5525,6213,6214,6217],{"class":5527,"line":5567},[5525,6215,6216],{"class":6091},"        return",[5525,6218,6219],{"class":5535}," 42\n",[5525,6221,6222],{"class":5527,"line":5816},[5525,6223,5850],{"emptyLinePlaceholder":5849},[5525,6225,6226],{"class":5527,"line":5822},[5525,6227,6101],{"class":5531},[5525,6229,6230,6232,6234,6236,6238],{"class":5527,"line":5828},[5525,6231,6144],{"class":6118},[5525,6233,6147],{"class":5531},[5525,6235,6150],{"class":6118},[5525,6237,6153],{"class":5531},[5525,6239,6240],{"class":5545},"# 42 ✅\n",[5512,6242,6243],{},"Саме тому dunder-методи завжди визначаються у тілі класу, а не динамічно на екземплярах.",[5748,6245,6247],{"id":6246},"повна-таблиця-протоколів","Повна таблиця протоколів",[5512,6249,6250,6251,6254],{},"Перш ніж зануритись у деталі, корисно побачити повну картину. Dunder-методи згруповані у ",[5607,6252,6253],{},"протоколи"," — кожен протокол відповідає певному синтаксису або вбудованій функції.",[6256,6257,6258,6280,6312,6327,6350,6371,6376,6384,6392,6397],"field-group",{},[6259,6260,6263,6264,6266,6267,5614,6270,6266,6273,6276,6277,5659],"field",{"name":6261,"type":6262},"Протокол представлення","__str__, __repr__, __format__, __bytes__","Перетворення об'єкта на рядок. ",[5507,6265,5626],{}," → ",[5507,6268,6269],{},"__str__",[5507,6271,6272],{},"repr(obj)",[5507,6274,6275],{},"__repr__",", f-рядки з форматом → ",[5507,6278,6279],{},"__format__",[6259,6281,6284,6285,5614,6288,5614,6291,5614,6294,5614,6297,5614,6300,6303,6304,6307,6308,6311],{"name":6282,"type":6283},"Протокол порівняння","__eq__, __ne__, __lt__, __le__, __gt__, __ge__","Оператори ",[5507,6286,6287],{},"==",[5507,6289,6290],{},"!=",[5507,6292,6293],{},"\u003C",[5507,6295,6296],{},"\u003C=",[5507,6298,6299],{},">",[5507,6301,6302],{},">=",". Декоратор ",[5507,6305,6306],{},"@functools.total_ordering"," дозволяє визначити лише ",[5507,6309,6310],{},"__eq__"," і один порядковий метод.",[6259,6313,6316,6317,6320,6321,6324,6325,5659],{"name":6314,"type":6315},"Протокол хешування","__hash__","Використання об'єкта як ключа ",[5507,6318,6319],{},"dict"," або елемента ",[5507,6322,6323],{},"set",". Нерозривно пов'язаний з ",[5507,6326,6310],{},[6259,6328,6331,6332,6335,6336,6339,6340,6335,6343,6346,6347,6178],{"name":6329,"type":6330},"Арифметичний протокол","__add__, __sub__, __mul__, __truediv__, __floordiv__, __mod__, __pow__, __radd__, __iadd__, ...","Бінарні арифметичні оператори. ",[5507,6333,6334],{},"r","-варіанти (",[5507,6337,6338],{},"__radd__",") — для правого операнда. ",[5507,6341,6342],{},"i",[5507,6344,6345],{},"__iadd__",") — для операторів присвоєння (",[5507,6348,6349],{},"+=",[6259,6351,6354,6355,5614,6358,5614,6361,6364,6365,5614,6368,6178],{"name":6352,"type":6353},"Унарний протокол","__neg__, __pos__, __abs__, __invert__, __bool__, __int__, __float__, __complex__","Унарні оператори (",[5507,6356,6357],{},"-obj",[5507,6359,6360],{},"+obj",[5507,6362,6363],{},"~obj",") та перетворення типів (",[5507,6366,6367],{},"bool(obj)",[5507,6369,6370],{},"int(obj)",[6259,6372,6375],{"name":6373,"type":6374},"Контейнерний протокол","__len__, __getitem__, __setitem__, __delitem__, __contains__, __iter__, __next__, __reversed__","Послідовності, відображення, ітератори. Основа для власних колекцій.",[6259,6377,6380,6383],{"name":6378,"type":6379},"Протокол виклику","__call__",[5507,6381,6382],{},"obj(args)"," — перетворення екземпляра на callable. Основа для декораторів-класів та функторів.",[6259,6385,6388,6389,6391],{"name":6386,"type":6387},"Протокол контекстного менеджера","__enter__, __exit__","Конструкція ",[5507,6390,5651],{},". Гарантоване виконання коду при вході та виході з блоку.",[6259,6393,6396],{"name":6394,"type":6395},"Протокол атрибутів","__getattr__, __setattr__, __delattr__, __getattribute__","Перехоплення читання, запису та видалення атрибутів. Основа для ORM-полів та проксі-об'єктів.",[6259,6398,6401],{"name":6399,"type":6400},"Протокол дескриптора","__get__, __set__, __delete__, __set_name__","Детально розглянуто в окремій статті про дескриптори.",[5741,6403],{},[5502,6405,6407],{"id":6406},"частина-ii-протокол-представлення","Частина II: Протокол представлення",[5748,6409,6411,6413,6414,6416],{"id":6410},"__repr__-проти-__str__-два-різних-призначення",[5507,6412,6275],{}," проти ",[5507,6415,6269],{},": два різних призначення",[5512,6418,6419,6420,5659],{},"Це найчастіше джерело плутанини серед початківців. Обидва методи повертають рядкове представлення об'єкта, але мають ",[5607,6421,6422],{},"різну аудиторію та контракт",[6424,6425,6426,6445],"table",{},[6427,6428,6429],"thead",{},[6430,6431,6432,6436,6439,6442],"tr",{},[6433,6434,6435],"th",{},"Метод",[6433,6437,6438],{},"Аудиторія",[6433,6440,6441],{},"Призначення",[6433,6443,6444],{},"Виклик",[6446,6447,6448,6469],"tbody",{},[6430,6449,6450,6455,6458,6464],{},[6451,6452,6453],"td",{},[5507,6454,6275],{},[6451,6456,6457],{},"Розробник",[6451,6459,6460,6461],{},"Однозначне, детальне представлення для налагодження. В ідеалі: ",[5507,6462,6463],{},"eval(repr(obj)) == obj",[6451,6465,6466,6468],{},[5507,6467,6272],{},", REPL, логи",[6430,6470,6471,6475,6478,6481],{},[6451,6472,6473],{},[5507,6474,6269],{},[6451,6476,6477],{},"Кінцевий користувач",[6451,6479,6480],{},"Читабельне, «красиве» представлення",[6451,6482,6483,5614,6485,6488],{},[5507,6484,5626],{},[5507,6486,6487],{},"print(obj)",", f-рядки",[5512,6490,6491,6494,6495,6497,6498,6500,6501,5659],{},[5607,6492,6493],{},"Правило резерву:"," якщо ",[5507,6496,6269],{}," не визначено, Python використовує ",[5507,6499,6275],{}," як резервний. Тому якщо ви визначаєте лише один метод — визначайте ",[5507,6502,6275],{},[5516,6504,6506],{"className":5518,"code":6505,"language":5520,"meta":5521,"style":5521},"from datetime import datetime\n\nclass LogEntry:\n    \"\"\"Запис у журналі подій системи.\"\"\"\n    \n    def __init__(self, level: str, message: str, timestamp: datetime | None = None):\n        self.level = level\n        self.message = message\n        self.timestamp = timestamp or datetime.now()\n    \n    def __repr__(self) -> str:\n        # Для розробника: точна інформація, з якої можна відновити об'єкт\n        # Мета: eval(repr(entry)) == entry (якщо реалізовано __eq__)\n        return (\n            f\"LogEntry(\"\n            f\"level={self.level!r}, \"\n            f\"message={self.message!r}, \"\n            f\"timestamp={self.timestamp!r}\"\n            f\")\"\n        )\n    \n    def __str__(self) -> str:\n        # Для користувача: читабельний однорядковий формат логу\n        ts = self.timestamp.strftime(\"%Y-%m-%d %H:%M:%S\")\n        return f\"[{ts}] {self.level:8s} | {self.message}\"\n\n\nentry = LogEntry(\"ERROR\", \"Зʼєднання з базою даних втрачено\")\n\nprint(str(entry))\n# [2024-03-15 14:22:10] ERROR    | Зʼєднання з базою даних втрачено\n\nprint(repr(entry))\n# LogEntry(level='ERROR', message='Зʼєднання з базою даних втрачено', timestamp=datetime.datetime(2024, 3, 15, 14, 22, 10, 451233))\n\n# В REPL (інтерактивному режимі) Python автоматично показує repr():\n# >>> entry\n# LogEntry(level='ERROR', ...)\n",[5507,6507,6508,6522,6526,6535,6540,6545,6592,6600,6607,6620,6624,6642,6647,6652,6659,6667,6686,6702,6719,6726,6731,6735,6752,6757,6779,6819,6823,6827,6842,6846,6857,6862,6866,6877,6882,6886,6891,6896],{"__ignoreMap":5521},[5525,6509,6510,6513,6516,6519],{"class":5527,"line":5528},[5525,6511,6512],{"class":6091},"from",[5525,6514,6515],{"class":5531}," datetime ",[5525,6517,6518],{"class":6091},"import",[5525,6520,6521],{"class":5531}," datetime\n",[5525,6523,6524],{"class":5527,"line":5549},[5525,6525,5850],{"emptyLinePlaceholder":5849},[5525,6527,6528,6530,6533],{"class":5527,"line":5567},[5525,6529,6079],{"class":6078},[5525,6531,6532],{"class":6082}," LogEntry",[5525,6534,6086],{"class":5531},[5525,6536,6537],{"class":5527,"line":5816},[5525,6538,6539],{"class":5555},"    \"\"\"Запис у журналі подій системи.\"\"\"\n",[5525,6541,6542],{"class":5527,"line":5822},[5525,6543,6544],{"class":5531},"    \n",[5525,6546,6547,6549,6552,6554,6556,6558,6561,6563,6566,6568,6571,6573,6575,6577,6580,6583,6586,6588,6590],{"class":5527,"line":5828},[5525,6548,6199],{"class":6078},[5525,6550,6551],{"class":6118}," __init__",[5525,6553,6147],{"class":5531},[5525,6555,6208],{"class":6207},[5525,6557,5614],{"class":5531},[5525,6559,6560],{"class":6207},"level",[5525,6562,6127],{"class":5531},[5525,6564,6565],{"class":6082},"str",[5525,6567,5614],{"class":5531},[5525,6569,6570],{"class":6207},"message",[5525,6572,6127],{"class":5531},[5525,6574,6565],{"class":6082},[5525,6576,5614],{"class":5531},[5525,6578,6579],{"class":6207},"timestamp",[5525,6581,6582],{"class":5531},": datetime | ",[5525,6584,6585],{"class":6078},"None",[5525,6587,6121],{"class":5531},[5525,6589,6585],{"class":6078},[5525,6591,6211],{"class":5531},[5525,6593,6594,6597],{"class":5527,"line":5834},[5525,6595,6596],{"class":6078},"        self",[5525,6598,6599],{"class":5531},".level = level\n",[5525,6601,6602,6604],{"class":5527,"line":5840},[5525,6603,6596],{"class":6078},[5525,6605,6606],{"class":5531},".message = message\n",[5525,6608,6609,6611,6614,6617],{"class":5527,"line":5846},[5525,6610,6596],{"class":6078},[5525,6612,6613],{"class":5531},".timestamp = timestamp ",[5525,6615,6616],{"class":6078},"or",[5525,6618,6619],{"class":5531}," datetime.now()\n",[5525,6621,6622],{"class":5527,"line":5853},[5525,6623,6544],{"class":5531},[5525,6625,6626,6628,6631,6633,6635,6638,6640],{"class":5527,"line":5859},[5525,6627,6199],{"class":6078},[5525,6629,6630],{"class":6118}," __repr__",[5525,6632,6147],{"class":5531},[5525,6634,6208],{"class":6207},[5525,6636,6637],{"class":5531},") -> ",[5525,6639,6565],{"class":6082},[5525,6641,6086],{"class":5531},[5525,6643,6644],{"class":5527,"line":5865},[5525,6645,6646],{"class":5545},"        # Для розробника: точна інформація, з якої можна відновити об'єкт\n",[5525,6648,6649],{"class":5527,"line":5871},[5525,6650,6651],{"class":5545},"        # Мета: eval(repr(entry)) == entry (якщо реалізовано __eq__)\n",[5525,6653,6654,6656],{"class":5527,"line":5877},[5525,6655,6216],{"class":6091},[5525,6657,6658],{"class":5531}," (\n",[5525,6660,6661,6664],{"class":5527,"line":5883},[5525,6662,6663],{"class":6078},"            f",[5525,6665,6666],{"class":5555},"\"LogEntry(\"\n",[5525,6668,6669,6671,6674,6677,6680,6683],{"class":5527,"line":5889},[5525,6670,6663],{"class":6078},[5525,6672,6673],{"class":5555},"\"level=",[5525,6675,6676],{"class":6078},"{self",[5525,6678,6679],{"class":5531},".level",[5525,6681,6682],{"class":6078},"!r}",[5525,6684,6685],{"class":5555},", \"\n",[5525,6687,6688,6690,6693,6695,6698,6700],{"class":5527,"line":5895},[5525,6689,6663],{"class":6078},[5525,6691,6692],{"class":5555},"\"message=",[5525,6694,6676],{"class":6078},[5525,6696,6697],{"class":5531},".message",[5525,6699,6682],{"class":6078},[5525,6701,6685],{"class":5555},[5525,6703,6704,6706,6709,6711,6714,6716],{"class":5527,"line":5901},[5525,6705,6663],{"class":6078},[5525,6707,6708],{"class":5555},"\"timestamp=",[5525,6710,6676],{"class":6078},[5525,6712,6713],{"class":5531},".timestamp",[5525,6715,6682],{"class":6078},[5525,6717,6718],{"class":5555},"\"\n",[5525,6720,6721,6723],{"class":5527,"line":5906},[5525,6722,6663],{"class":6078},[5525,6724,6725],{"class":5555},"\")\"\n",[5525,6727,6728],{"class":5527,"line":5911},[5525,6729,6730],{"class":5531},"        )\n",[5525,6732,6733],{"class":5527,"line":5917},[5525,6734,6544],{"class":5531},[5525,6736,6737,6739,6742,6744,6746,6748,6750],{"class":5527,"line":5923},[5525,6738,6199],{"class":6078},[5525,6740,6741],{"class":6118}," __str__",[5525,6743,6147],{"class":5531},[5525,6745,6208],{"class":6207},[5525,6747,6637],{"class":5531},[5525,6749,6565],{"class":6082},[5525,6751,6086],{"class":5531},[5525,6753,6754],{"class":5527,"line":5929},[5525,6755,6756],{"class":5545},"        # Для користувача: читабельний однорядковий формат логу\n",[5525,6758,6759,6762,6764,6767,6770,6773,6776],{"class":5527,"line":5935},[5525,6760,6761],{"class":5531},"        ts = ",[5525,6763,6208],{"class":6078},[5525,6765,6766],{"class":5531},".timestamp.strftime(",[5525,6768,6769],{"class":5555},"\"%Y-%m-",[5525,6771,6772],{"class":6078},"%d",[5525,6774,6775],{"class":5555}," %H:%M:%S\"",[5525,6777,6778],{"class":5531},")\n",[5525,6780,6781,6783,6786,6789,6792,6795,6798,6801,6803,6805,6808,6811,6813,6815,6817],{"class":5527,"line":5941},[5525,6782,6216],{"class":6091},[5525,6784,6785],{"class":6078}," f",[5525,6787,6788],{"class":5555},"\"[",[5525,6790,6791],{"class":6078},"{",[5525,6793,6794],{"class":5531},"ts",[5525,6796,6797],{"class":6078},"}",[5525,6799,6800],{"class":5555},"] ",[5525,6802,6676],{"class":6078},[5525,6804,6679],{"class":5531},[5525,6806,6807],{"class":6078},":8s}",[5525,6809,6810],{"class":5555}," | ",[5525,6812,6676],{"class":6078},[5525,6814,6697],{"class":5531},[5525,6816,6797],{"class":6078},[5525,6818,6718],{"class":5555},[5525,6820,6821],{"class":5527,"line":5947},[5525,6822,5850],{"emptyLinePlaceholder":5849},[5525,6824,6825],{"class":5527,"line":5953},[5525,6826,5850],{"emptyLinePlaceholder":5849},[5525,6828,6829,6832,6835,6837,6840],{"class":5527,"line":5959},[5525,6830,6831],{"class":5531},"entry = LogEntry(",[5525,6833,6834],{"class":5555},"\"ERROR\"",[5525,6836,5614],{"class":5531},[5525,6838,6839],{"class":5555},"\"Зʼєднання з базою даних втрачено\"",[5525,6841,6778],{"class":5531},[5525,6843,6844],{"class":5527,"line":5964},[5525,6845,5850],{"emptyLinePlaceholder":5849},[5525,6847,6848,6850,6852,6854],{"class":5527,"line":5969},[5525,6849,6144],{"class":6118},[5525,6851,6147],{"class":5531},[5525,6853,6565],{"class":6082},[5525,6855,6856],{"class":5531},"(entry))\n",[5525,6858,6859],{"class":5527,"line":5975},[5525,6860,6861],{"class":5545},"# [2024-03-15 14:22:10] ERROR    | Зʼєднання з базою даних втрачено\n",[5525,6863,6864],{"class":5527,"line":5981},[5525,6865,5850],{"emptyLinePlaceholder":5849},[5525,6867,6868,6870,6872,6875],{"class":5527,"line":5987},[5525,6869,6144],{"class":6118},[5525,6871,6147],{"class":5531},[5525,6873,6874],{"class":6118},"repr",[5525,6876,6856],{"class":5531},[5525,6878,6879],{"class":5527,"line":5993},[5525,6880,6881],{"class":5545},"# LogEntry(level='ERROR', message='Зʼєднання з базою даних втрачено', timestamp=datetime.datetime(2024, 3, 15, 14, 22, 10, 451233))\n",[5525,6883,6884],{"class":5527,"line":5999},[5525,6885,5850],{"emptyLinePlaceholder":5849},[5525,6887,6888],{"class":5527,"line":6005},[5525,6889,6890],{"class":5545},"# В REPL (інтерактивному режимі) Python автоматично показує repr():\n",[5525,6892,6893],{"class":5527,"line":6011},[5525,6894,6895],{"class":5545},"# >>> entry\n",[5525,6897,6898],{"class":5527,"line":6016},[5525,6899,6900],{"class":5545},"# LogEntry(level='ERROR', ...)\n",[6902,6903,6904,6905,6908,6909,6127,6911,6914,6915,6918],"tip",{},"Зверніть увагу на ",[5507,6906,6907],{},"!r"," у f-рядку всередині ",[5507,6910,6275],{},[5507,6912,6913],{},"{self.level!r}"," еквівалентно ",[5507,6916,6917],{},"{repr(self.level)}",". Це гарантує, що рядкові поля будуть оточені лапками у виводі, а сам вивід залишатиметься валідним Python-виразом.",[5748,6920,6922,6923,6925],{"id":6921},"метод-__format__-власний-форматний-рядок","Метод ",[5507,6924,6279],{},": власний форматний рядок",[5512,6927,6928,6929,6931,6932,6935],{},"Є ще третій метод представлення, про який часто забувають: ",[5507,6930,6279],{},". Він викликається, коли об'єкт використовується у f-рядку або функції ",[5507,6933,6934],{},"format()"," зі специфікатором формату.",[5516,6937,6939],{"className":5518,"code":6938,"language":5520,"meta":5521,"style":5521},"class Temperature:\n    \"\"\"Температура з підтримкою форматування у різних шкалах.\"\"\"\n    \n    def __init__(self, celsius: float):\n        self.celsius = celsius\n    \n    @property\n    def fahrenheit(self) -> float:\n        return self.celsius * 9\u002F5 + 32\n    \n    @property\n    def kelvin(self) -> float:\n        return self.celsius + 273.15\n    \n    def __repr__(self) -> str:\n        return f\"Temperature({self.celsius})\"\n    \n    def __str__(self) -> str:\n        return f\"{self.celsius:.1f}°C\"\n    \n    def __format__(self, spec: str) -> str:\n        \"\"\"\n        Підтримувані специфікатори:\n        - 'C' або '' → Цельсій\n        - 'F'        → Фаренгейт\n        - 'K'        → Кельвін\n        \"\"\"\n        if spec == 'F':\n            return f\"{self.fahrenheit:.1f}°F\"\n        elif spec == 'K':\n            return f\"{self.kelvin:.2f}K\"\n        else:\n            return str(self)  # Цельсій за замовчуванням\n\n\nt = Temperature(100)\n\nprint(f\"Вода кипить при {t}\")      # Вода кипить при 100.0°C\nprint(f\"Вода кипить при {t:F}\")    # Вода кипить при 212.0°F\nprint(f\"Вода кипить при {t:K}\")    # Вода кипить при 373.15K\nprint(f\"Вода кипить при {t:C}\")    # Вода кипить при 100.0°C\n",[5507,6940,6941,6950,6955,6959,6981,6988,6992,7000,7017,7040,7044,7050,7067,7079,7083,7099,7118,7122,7138,7157,7161,7187,7192,7197,7202,7207,7212,7216,7229,7248,7260,7279,7286,7303,7307,7311,7321,7325,7352,7377,7401],{"__ignoreMap":5521},[5525,6942,6943,6945,6948],{"class":5527,"line":5528},[5525,6944,6079],{"class":6078},[5525,6946,6947],{"class":6082}," Temperature",[5525,6949,6086],{"class":5531},[5525,6951,6952],{"class":5527,"line":5549},[5525,6953,6954],{"class":5555},"    \"\"\"Температура з підтримкою форматування у різних шкалах.\"\"\"\n",[5525,6956,6957],{"class":5527,"line":5567},[5525,6958,6544],{"class":5531},[5525,6960,6961,6963,6965,6967,6969,6971,6974,6976,6979],{"class":5527,"line":5816},[5525,6962,6199],{"class":6078},[5525,6964,6551],{"class":6118},[5525,6966,6147],{"class":5531},[5525,6968,6208],{"class":6207},[5525,6970,5614],{"class":5531},[5525,6972,6973],{"class":6207},"celsius",[5525,6975,6127],{"class":5531},[5525,6977,6978],{"class":6082},"float",[5525,6980,6211],{"class":5531},[5525,6982,6983,6985],{"class":5527,"line":5822},[5525,6984,6596],{"class":6078},[5525,6986,6987],{"class":5531},".celsius = celsius\n",[5525,6989,6990],{"class":5527,"line":5828},[5525,6991,6544],{"class":5531},[5525,6993,6994,6997],{"class":5527,"line":5834},[5525,6995,6996],{"class":6118},"    @",[5525,6998,6999],{"class":6082},"property\n",[5525,7001,7002,7004,7007,7009,7011,7013,7015],{"class":5527,"line":5840},[5525,7003,6199],{"class":6078},[5525,7005,7006],{"class":6118}," fahrenheit",[5525,7008,6147],{"class":5531},[5525,7010,6208],{"class":6207},[5525,7012,6637],{"class":5531},[5525,7014,6978],{"class":6082},[5525,7016,6086],{"class":5531},[5525,7018,7019,7021,7024,7027,7030,7032,7035,7037],{"class":5527,"line":5846},[5525,7020,6216],{"class":6091},[5525,7022,7023],{"class":6078}," self",[5525,7025,7026],{"class":5531},".celsius * ",[5525,7028,7029],{"class":5535},"9",[5525,7031,5597],{"class":5531},[5525,7033,7034],{"class":5535},"5",[5525,7036,5539],{"class":5531},[5525,7038,7039],{"class":5535},"32\n",[5525,7041,7042],{"class":5527,"line":5853},[5525,7043,6544],{"class":5531},[5525,7045,7046,7048],{"class":5527,"line":5859},[5525,7047,6996],{"class":6118},[5525,7049,6999],{"class":6082},[5525,7051,7052,7054,7057,7059,7061,7063,7065],{"class":5527,"line":5865},[5525,7053,6199],{"class":6078},[5525,7055,7056],{"class":6118}," kelvin",[5525,7058,6147],{"class":5531},[5525,7060,6208],{"class":6207},[5525,7062,6637],{"class":5531},[5525,7064,6978],{"class":6082},[5525,7066,6086],{"class":5531},[5525,7068,7069,7071,7073,7076],{"class":5527,"line":5871},[5525,7070,6216],{"class":6091},[5525,7072,7023],{"class":6078},[5525,7074,7075],{"class":5531},".celsius + ",[5525,7077,7078],{"class":5535},"273.15\n",[5525,7080,7081],{"class":5527,"line":5877},[5525,7082,6544],{"class":5531},[5525,7084,7085,7087,7089,7091,7093,7095,7097],{"class":5527,"line":5883},[5525,7086,6199],{"class":6078},[5525,7088,6630],{"class":6118},[5525,7090,6147],{"class":5531},[5525,7092,6208],{"class":6207},[5525,7094,6637],{"class":5531},[5525,7096,6565],{"class":6082},[5525,7098,6086],{"class":5531},[5525,7100,7101,7103,7105,7108,7110,7113,7115],{"class":5527,"line":5889},[5525,7102,6216],{"class":6091},[5525,7104,6785],{"class":6078},[5525,7106,7107],{"class":5555},"\"Temperature(",[5525,7109,6676],{"class":6078},[5525,7111,7112],{"class":5531},".celsius",[5525,7114,6797],{"class":6078},[5525,7116,7117],{"class":5555},")\"\n",[5525,7119,7120],{"class":5527,"line":5895},[5525,7121,6544],{"class":5531},[5525,7123,7124,7126,7128,7130,7132,7134,7136],{"class":5527,"line":5901},[5525,7125,6199],{"class":6078},[5525,7127,6741],{"class":6118},[5525,7129,6147],{"class":5531},[5525,7131,6208],{"class":6207},[5525,7133,6637],{"class":5531},[5525,7135,6565],{"class":6082},[5525,7137,6086],{"class":5531},[5525,7139,7140,7142,7144,7147,7149,7151,7154],{"class":5527,"line":5906},[5525,7141,6216],{"class":6091},[5525,7143,6785],{"class":6078},[5525,7145,7146],{"class":5555},"\"",[5525,7148,6676],{"class":6078},[5525,7150,7112],{"class":5531},[5525,7152,7153],{"class":6078},":.1f}",[5525,7155,7156],{"class":5555},"°C\"\n",[5525,7158,7159],{"class":5527,"line":5911},[5525,7160,6544],{"class":5531},[5525,7162,7163,7165,7168,7170,7172,7174,7177,7179,7181,7183,7185],{"class":5527,"line":5917},[5525,7164,6199],{"class":6078},[5525,7166,7167],{"class":6118}," __format__",[5525,7169,6147],{"class":5531},[5525,7171,6208],{"class":6207},[5525,7173,5614],{"class":5531},[5525,7175,7176],{"class":6207},"spec",[5525,7178,6127],{"class":5531},[5525,7180,6565],{"class":6082},[5525,7182,6637],{"class":5531},[5525,7184,6565],{"class":6082},[5525,7186,6086],{"class":5531},[5525,7188,7189],{"class":5527,"line":5923},[5525,7190,7191],{"class":5555},"        \"\"\"\n",[5525,7193,7194],{"class":5527,"line":5929},[5525,7195,7196],{"class":5555},"        Підтримувані специфікатори:\n",[5525,7198,7199],{"class":5527,"line":5935},[5525,7200,7201],{"class":5555},"        - 'C' або '' → Цельсій\n",[5525,7203,7204],{"class":5527,"line":5941},[5525,7205,7206],{"class":5555},"        - 'F'        → Фаренгейт\n",[5525,7208,7209],{"class":5527,"line":5947},[5525,7210,7211],{"class":5555},"        - 'K'        → Кельвін\n",[5525,7213,7214],{"class":5527,"line":5953},[5525,7215,7191],{"class":5555},[5525,7217,7218,7221,7224,7227],{"class":5527,"line":5959},[5525,7219,7220],{"class":6091},"        if",[5525,7222,7223],{"class":5531}," spec == ",[5525,7225,7226],{"class":5555},"'F'",[5525,7228,6086],{"class":5531},[5525,7230,7231,7234,7236,7238,7240,7243,7245],{"class":5527,"line":5964},[5525,7232,7233],{"class":6091},"            return",[5525,7235,6785],{"class":6078},[5525,7237,7146],{"class":5555},[5525,7239,6676],{"class":6078},[5525,7241,7242],{"class":5531},".fahrenheit",[5525,7244,7153],{"class":6078},[5525,7246,7247],{"class":5555},"°F\"\n",[5525,7249,7250,7253,7255,7258],{"class":5527,"line":5969},[5525,7251,7252],{"class":6091},"        elif",[5525,7254,7223],{"class":5531},[5525,7256,7257],{"class":5555},"'K'",[5525,7259,6086],{"class":5531},[5525,7261,7262,7264,7266,7268,7270,7273,7276],{"class":5527,"line":5975},[5525,7263,7233],{"class":6091},[5525,7265,6785],{"class":6078},[5525,7267,7146],{"class":5555},[5525,7269,6676],{"class":6078},[5525,7271,7272],{"class":5531},".kelvin",[5525,7274,7275],{"class":6078},":.2f}",[5525,7277,7278],{"class":5555},"K\"\n",[5525,7280,7281,7284],{"class":5527,"line":5981},[5525,7282,7283],{"class":6091},"        else",[5525,7285,6086],{"class":5531},[5525,7287,7288,7290,7293,7295,7297,7300],{"class":5527,"line":5987},[5525,7289,7233],{"class":6091},[5525,7291,7292],{"class":6082}," str",[5525,7294,6147],{"class":5531},[5525,7296,6208],{"class":6078},[5525,7298,7299],{"class":5531},")  ",[5525,7301,7302],{"class":5545},"# Цельсій за замовчуванням\n",[5525,7304,7305],{"class":5527,"line":5993},[5525,7306,5850],{"emptyLinePlaceholder":5849},[5525,7308,7309],{"class":5527,"line":5999},[5525,7310,5850],{"emptyLinePlaceholder":5849},[5525,7312,7313,7316,7319],{"class":5527,"line":6005},[5525,7314,7315],{"class":5531},"t = Temperature(",[5525,7317,7318],{"class":5535},"100",[5525,7320,6778],{"class":5531},[5525,7322,7323],{"class":5527,"line":6011},[5525,7324,5850],{"emptyLinePlaceholder":5849},[5525,7326,7327,7329,7331,7334,7337,7339,7342,7344,7346,7349],{"class":5527,"line":6016},[5525,7328,6144],{"class":6118},[5525,7330,6147],{"class":5531},[5525,7332,7333],{"class":6078},"f",[5525,7335,7336],{"class":5555},"\"Вода кипить при ",[5525,7338,6791],{"class":6078},[5525,7340,7341],{"class":5531},"t",[5525,7343,6797],{"class":6078},[5525,7345,7146],{"class":5555},[5525,7347,7348],{"class":5531},")      ",[5525,7350,7351],{"class":5545},"# Вода кипить при 100.0°C\n",[5525,7353,7354,7356,7358,7360,7362,7364,7366,7369,7371,7374],{"class":5527,"line":6022},[5525,7355,6144],{"class":6118},[5525,7357,6147],{"class":5531},[5525,7359,7333],{"class":6078},[5525,7361,7336],{"class":5555},[5525,7363,6791],{"class":6078},[5525,7365,7341],{"class":5531},[5525,7367,7368],{"class":6078},":F}",[5525,7370,7146],{"class":5555},[5525,7372,7373],{"class":5531},")    ",[5525,7375,7376],{"class":5545},"# Вода кипить при 212.0°F\n",[5525,7378,7379,7381,7383,7385,7387,7389,7391,7394,7396,7398],{"class":5527,"line":6028},[5525,7380,6144],{"class":6118},[5525,7382,6147],{"class":5531},[5525,7384,7333],{"class":6078},[5525,7386,7336],{"class":5555},[5525,7388,6791],{"class":6078},[5525,7390,7341],{"class":5531},[5525,7392,7393],{"class":6078},":K}",[5525,7395,7146],{"class":5555},[5525,7397,7373],{"class":5531},[5525,7399,7400],{"class":5545},"# Вода кипить при 373.15K\n",[5525,7402,7403,7405,7407,7409,7411,7413,7415,7418,7420,7422],{"class":5527,"line":6034},[5525,7404,6144],{"class":6118},[5525,7406,6147],{"class":5531},[5525,7408,7333],{"class":6078},[5525,7410,7336],{"class":5555},[5525,7412,6791],{"class":6078},[5525,7414,7341],{"class":5531},[5525,7416,7417],{"class":6078},":C}",[5525,7419,7146],{"class":5555},[5525,7421,7373],{"class":5531},[5525,7423,7351],{"class":5545},[7425,7426,7428,7440,7449,7457,7465],"terminal-preview",{"title":7427},"python temperature.py",[7429,7430,7432,7437,7438],"div",{"className":7431},[5527],[5525,7433,7436],{"className":7434},[7435],"opacity-40","$"," ",[5607,7439,7427],{},[7429,7441,7443,7444],{"className":7442},[5527],"Вода кипить при ",[5525,7445,7448],{"className":7446},[7447],"text-yellow-400","100.0°C",[7429,7450,7443,7452],{"className":7451},[5527],[5525,7453,7456],{"className":7454},[7455],"text-orange-400","212.0°F",[7429,7458,7443,7460],{"className":7459},[5527],[5525,7461,7464],{"className":7462},[7463],"text-blue-400","373.15K",[7429,7466,7443,7468],{"className":7467},[5527],[5525,7469,7448],{"className":7470},[7447],[5741,7472],{},[5502,7474,7476],{"id":7475},"частина-iii-протокол-порівняння-та-хешування","Частина III: Протокол порівняння та хешування",[5748,7478,7480],{"id":7479},"оператори-порівняння-шість-методів","Оператори порівняння: шість методів",[5512,7482,7483],{},"Python транслює кожен оператор порівняння у відповідний dunder-метод:",[6424,7485,7486,7498],{},[6427,7487,7488],{},[6430,7489,7490,7493,7495],{},[6433,7491,7492],{},"Оператор",[6433,7494,6435],{},[6433,7496,7497],{},"Назва",[6446,7499,7500,7515,7530,7545,7560,7575],{},[6430,7501,7502,7507,7512],{},[6451,7503,7504],{},[5507,7505,7506],{},"a == b",[6451,7508,7509],{},[5507,7510,7511],{},"a.__eq__(b)",[6451,7513,7514],{},"Рівність",[6430,7516,7517,7522,7527],{},[6451,7518,7519],{},[5507,7520,7521],{},"a != b",[6451,7523,7524],{},[5507,7525,7526],{},"a.__ne__(b)",[6451,7528,7529],{},"Нерівність",[6430,7531,7532,7537,7542],{},[6451,7533,7534],{},[5507,7535,7536],{},"a \u003C b",[6451,7538,7539],{},[5507,7540,7541],{},"a.__lt__(b)",[6451,7543,7544],{},"Менше",[6430,7546,7547,7552,7557],{},[6451,7548,7549],{},[5507,7550,7551],{},"a \u003C= b",[6451,7553,7554],{},[5507,7555,7556],{},"a.__le__(b)",[6451,7558,7559],{},"Менше або рівне",[6430,7561,7562,7567,7572],{},[6451,7563,7564],{},[5507,7565,7566],{},"a > b",[6451,7568,7569],{},[5507,7570,7571],{},"a.__gt__(b)",[6451,7573,7574],{},"Більше",[6430,7576,7577,7582,7587],{},[6451,7578,7579],{},[5507,7580,7581],{},"a >= b",[6451,7583,7584],{},[5507,7585,7586],{},"a.__ge__(b)",[6451,7588,7589],{},"Більше або рівне",[5512,7591,7592,7593,7596],{},"Розглянемо практичний приклад: клас ",[5507,7594,7595],{},"Version"," для семантичного версіонування.",[5516,7598,7600],{"className":5518,"code":7599,"language":5520,"meta":5521,"style":5521},"from __future__ import annotations\n\nclass Version:\n    \"\"\"Семантична версія у форматі MAJOR.MINOR.PATCH (SemVer).\"\"\"\n    \n    def __init__(self, major: int, minor: int, patch: int):\n        self.major = major\n        self.minor = minor\n        self.patch = patch\n    \n    def __repr__(self) -> str:\n        return f\"Version({self.major}, {self.minor}, {self.patch})\"\n    \n    def __str__(self) -> str:\n        return f\"{self.major}.{self.minor}.{self.patch}\"\n    \n    def _as_tuple(self) -> tuple[int, int, int]:\n        \"\"\"Допоміжний метод: представлення як tuple для порівнянь.\"\"\"\n        return (self.major, self.minor, self.patch)\n    \n    def __eq__(self, other: object) -> bool:\n        if not isinstance(other, Version):\n            return NotImplemented  # не False! — важлива відмінність\n        return self._as_tuple() == other._as_tuple()\n    \n    def __lt__(self, other: Version) -> bool:\n        if not isinstance(other, Version):\n            return NotImplemented\n        return self._as_tuple() \u003C other._as_tuple()\n    \n    def __le__(self, other: Version) -> bool:\n        if not isinstance(other, Version):\n            return NotImplemented\n        return self._as_tuple() \u003C= other._as_tuple()\n    \n    # __gt__ і __ge__ Python може вивести сам через @total_ordering,\n    # але явне визначення краще для продуктивності та читабельності\n    def __gt__(self, other: Version) -> bool:\n        if not isinstance(other, Version):\n            return NotImplemented\n        return self._as_tuple() > other._as_tuple()\n    \n    def __ge__(self, other: Version) -> bool:\n        if not isinstance(other, Version):\n            return NotImplemented\n        return self._as_tuple() >= other._as_tuple()\n\n\nv1 = Version(1, 2, 3)\nv2 = Version(1, 10, 0)\nv3 = Version(1, 2, 3)\n\nprint(v1 == v3)   # True\nprint(v1 \u003C v2)    # True  (1.2.3 \u003C 1.10.0)\nprint(v2 > v1)    # True\nprint(v1 >= v3)   # True\n\n# Тепер можна сортувати список версій!\nversions = [Version(2, 0, 0), Version(1, 9, 1), Version(1, 2, 3)]\nprint(sorted(versions))\n# [Version(1, 2, 3), Version(1, 9, 1), Version(2, 0, 0)]\n",[5507,7601,7602,7615,7619,7628,7633,7637,7677,7684,7691,7698,7702,7718,7754,7758,7774,7806,7810,7837,7842,7864,7868,7896,7909,7919,7928,7932,7954,7964,7971,7980,7984,8005,8015,8021,8030,8034,8039,8044,8065,8075,8081,8090,8094,8115,8126,8133,8143,8148,8153,8174,8194,8212,8217,8228,8239,8249,8259,8264,8270,8314,8327],{"__ignoreMap":5521},[5525,7603,7604,7606,7609,7612],{"class":5527,"line":5528},[5525,7605,6512],{"class":6091},[5525,7607,7608],{"class":6207}," __future__",[5525,7610,7611],{"class":6091}," import",[5525,7613,7614],{"class":5531}," annotations\n",[5525,7616,7617],{"class":5527,"line":5549},[5525,7618,5850],{"emptyLinePlaceholder":5849},[5525,7620,7621,7623,7626],{"class":5527,"line":5567},[5525,7622,6079],{"class":6078},[5525,7624,7625],{"class":6082}," Version",[5525,7627,6086],{"class":5531},[5525,7629,7630],{"class":5527,"line":5816},[5525,7631,7632],{"class":5555},"    \"\"\"Семантична версія у форматі MAJOR.MINOR.PATCH (SemVer).\"\"\"\n",[5525,7634,7635],{"class":5527,"line":5822},[5525,7636,6544],{"class":5531},[5525,7638,7639,7641,7643,7645,7647,7649,7652,7654,7657,7659,7662,7664,7666,7668,7671,7673,7675],{"class":5527,"line":5828},[5525,7640,6199],{"class":6078},[5525,7642,6551],{"class":6118},[5525,7644,6147],{"class":5531},[5525,7646,6208],{"class":6207},[5525,7648,5614],{"class":5531},[5525,7650,7651],{"class":6207},"major",[5525,7653,6127],{"class":5531},[5525,7655,7656],{"class":6082},"int",[5525,7658,5614],{"class":5531},[5525,7660,7661],{"class":6207},"minor",[5525,7663,6127],{"class":5531},[5525,7665,7656],{"class":6082},[5525,7667,5614],{"class":5531},[5525,7669,7670],{"class":6207},"patch",[5525,7672,6127],{"class":5531},[5525,7674,7656],{"class":6082},[5525,7676,6211],{"class":5531},[5525,7678,7679,7681],{"class":5527,"line":5834},[5525,7680,6596],{"class":6078},[5525,7682,7683],{"class":5531},".major = major\n",[5525,7685,7686,7688],{"class":5527,"line":5840},[5525,7687,6596],{"class":6078},[5525,7689,7690],{"class":5531},".minor = minor\n",[5525,7692,7693,7695],{"class":5527,"line":5846},[5525,7694,6596],{"class":6078},[5525,7696,7697],{"class":5531},".patch = patch\n",[5525,7699,7700],{"class":5527,"line":5853},[5525,7701,6544],{"class":5531},[5525,7703,7704,7706,7708,7710,7712,7714,7716],{"class":5527,"line":5859},[5525,7705,6199],{"class":6078},[5525,7707,6630],{"class":6118},[5525,7709,6147],{"class":5531},[5525,7711,6208],{"class":6207},[5525,7713,6637],{"class":5531},[5525,7715,6565],{"class":6082},[5525,7717,6086],{"class":5531},[5525,7719,7720,7722,7724,7727,7729,7732,7734,7736,7738,7741,7743,7745,7747,7750,7752],{"class":5527,"line":5865},[5525,7721,6216],{"class":6091},[5525,7723,6785],{"class":6078},[5525,7725,7726],{"class":5555},"\"Version(",[5525,7728,6676],{"class":6078},[5525,7730,7731],{"class":5531},".major",[5525,7733,6797],{"class":6078},[5525,7735,5614],{"class":5555},[5525,7737,6676],{"class":6078},[5525,7739,7740],{"class":5531},".minor",[5525,7742,6797],{"class":6078},[5525,7744,5614],{"class":5555},[5525,7746,6676],{"class":6078},[5525,7748,7749],{"class":5531},".patch",[5525,7751,6797],{"class":6078},[5525,7753,7117],{"class":5555},[5525,7755,7756],{"class":5527,"line":5871},[5525,7757,6544],{"class":5531},[5525,7759,7760,7762,7764,7766,7768,7770,7772],{"class":5527,"line":5877},[5525,7761,6199],{"class":6078},[5525,7763,6741],{"class":6118},[5525,7765,6147],{"class":5531},[5525,7767,6208],{"class":6207},[5525,7769,6637],{"class":5531},[5525,7771,6565],{"class":6082},[5525,7773,6086],{"class":5531},[5525,7775,7776,7778,7780,7782,7784,7786,7788,7790,7792,7794,7796,7798,7800,7802,7804],{"class":5527,"line":5883},[5525,7777,6216],{"class":6091},[5525,7779,6785],{"class":6078},[5525,7781,7146],{"class":5555},[5525,7783,6676],{"class":6078},[5525,7785,7731],{"class":5531},[5525,7787,6797],{"class":6078},[5525,7789,5659],{"class":5555},[5525,7791,6676],{"class":6078},[5525,7793,7740],{"class":5531},[5525,7795,6797],{"class":6078},[5525,7797,5659],{"class":5555},[5525,7799,6676],{"class":6078},[5525,7801,7749],{"class":5531},[5525,7803,6797],{"class":6078},[5525,7805,6718],{"class":5555},[5525,7807,7808],{"class":5527,"line":5889},[5525,7809,6544],{"class":5531},[5525,7811,7812,7814,7817,7819,7821,7824,7826,7828,7830,7832,7834],{"class":5527,"line":5895},[5525,7813,6199],{"class":6078},[5525,7815,7816],{"class":6118}," _as_tuple",[5525,7818,6147],{"class":5531},[5525,7820,6208],{"class":6207},[5525,7822,7823],{"class":5531},") -> tuple[",[5525,7825,7656],{"class":6082},[5525,7827,5614],{"class":5531},[5525,7829,7656],{"class":6082},[5525,7831,5614],{"class":5531},[5525,7833,7656],{"class":6082},[5525,7835,7836],{"class":5531},"]:\n",[5525,7838,7839],{"class":5527,"line":5901},[5525,7840,7841],{"class":5555},"        \"\"\"Допоміжний метод: представлення як tuple для порівнянь.\"\"\"\n",[5525,7843,7844,7846,7849,7851,7854,7856,7859,7861],{"class":5527,"line":5906},[5525,7845,6216],{"class":6091},[5525,7847,7848],{"class":5531}," (",[5525,7850,6208],{"class":6078},[5525,7852,7853],{"class":5531},".major, ",[5525,7855,6208],{"class":6078},[5525,7857,7858],{"class":5531},".minor, ",[5525,7860,6208],{"class":6078},[5525,7862,7863],{"class":5531},".patch)\n",[5525,7865,7866],{"class":5527,"line":5911},[5525,7867,6544],{"class":5531},[5525,7869,7870,7872,7875,7877,7879,7881,7884,7886,7889,7891,7894],{"class":5527,"line":5917},[5525,7871,6199],{"class":6078},[5525,7873,7874],{"class":6118}," __eq__",[5525,7876,6147],{"class":5531},[5525,7878,6208],{"class":6207},[5525,7880,5614],{"class":5531},[5525,7882,7883],{"class":6207},"other",[5525,7885,6127],{"class":5531},[5525,7887,7888],{"class":6082},"object",[5525,7890,6637],{"class":5531},[5525,7892,7893],{"class":6082},"bool",[5525,7895,6086],{"class":5531},[5525,7897,7898,7900,7903,7906],{"class":5527,"line":5923},[5525,7899,7220],{"class":6091},[5525,7901,7902],{"class":6078}," not",[5525,7904,7905],{"class":6118}," isinstance",[5525,7907,7908],{"class":5531},"(other, Version):\n",[5525,7910,7911,7913,7916],{"class":5527,"line":5929},[5525,7912,7233],{"class":6091},[5525,7914,7915],{"class":6078}," NotImplemented",[5525,7917,7918],{"class":5545},"  # не False! — важлива відмінність\n",[5525,7920,7921,7923,7925],{"class":5527,"line":5935},[5525,7922,6216],{"class":6091},[5525,7924,7023],{"class":6078},[5525,7926,7927],{"class":5531},"._as_tuple() == other._as_tuple()\n",[5525,7929,7930],{"class":5527,"line":5941},[5525,7931,6544],{"class":5531},[5525,7933,7934,7936,7939,7941,7943,7945,7947,7950,7952],{"class":5527,"line":5947},[5525,7935,6199],{"class":6078},[5525,7937,7938],{"class":6118}," __lt__",[5525,7940,6147],{"class":5531},[5525,7942,6208],{"class":6207},[5525,7944,5614],{"class":5531},[5525,7946,7883],{"class":6207},[5525,7948,7949],{"class":5531},": Version) -> ",[5525,7951,7893],{"class":6082},[5525,7953,6086],{"class":5531},[5525,7955,7956,7958,7960,7962],{"class":5527,"line":5953},[5525,7957,7220],{"class":6091},[5525,7959,7902],{"class":6078},[5525,7961,7905],{"class":6118},[5525,7963,7908],{"class":5531},[5525,7965,7966,7968],{"class":5527,"line":5959},[5525,7967,7233],{"class":6091},[5525,7969,7970],{"class":6078}," NotImplemented\n",[5525,7972,7973,7975,7977],{"class":5527,"line":5964},[5525,7974,6216],{"class":6091},[5525,7976,7023],{"class":6078},[5525,7978,7979],{"class":5531},"._as_tuple() \u003C other._as_tuple()\n",[5525,7981,7982],{"class":5527,"line":5969},[5525,7983,6544],{"class":5531},[5525,7985,7986,7988,7991,7993,7995,7997,7999,8001,8003],{"class":5527,"line":5975},[5525,7987,6199],{"class":6078},[5525,7989,7990],{"class":6118}," __le__",[5525,7992,6147],{"class":5531},[5525,7994,6208],{"class":6207},[5525,7996,5614],{"class":5531},[5525,7998,7883],{"class":6207},[5525,8000,7949],{"class":5531},[5525,8002,7893],{"class":6082},[5525,8004,6086],{"class":5531},[5525,8006,8007,8009,8011,8013],{"class":5527,"line":5981},[5525,8008,7220],{"class":6091},[5525,8010,7902],{"class":6078},[5525,8012,7905],{"class":6118},[5525,8014,7908],{"class":5531},[5525,8016,8017,8019],{"class":5527,"line":5987},[5525,8018,7233],{"class":6091},[5525,8020,7970],{"class":6078},[5525,8022,8023,8025,8027],{"class":5527,"line":5993},[5525,8024,6216],{"class":6091},[5525,8026,7023],{"class":6078},[5525,8028,8029],{"class":5531},"._as_tuple() \u003C= other._as_tuple()\n",[5525,8031,8032],{"class":5527,"line":5999},[5525,8033,6544],{"class":5531},[5525,8035,8036],{"class":5527,"line":6005},[5525,8037,8038],{"class":5545},"    # __gt__ і __ge__ Python може вивести сам через @total_ordering,\n",[5525,8040,8041],{"class":5527,"line":6011},[5525,8042,8043],{"class":5545},"    # але явне визначення краще для продуктивності та читабельності\n",[5525,8045,8046,8048,8051,8053,8055,8057,8059,8061,8063],{"class":5527,"line":6016},[5525,8047,6199],{"class":6078},[5525,8049,8050],{"class":6118}," __gt__",[5525,8052,6147],{"class":5531},[5525,8054,6208],{"class":6207},[5525,8056,5614],{"class":5531},[5525,8058,7883],{"class":6207},[5525,8060,7949],{"class":5531},[5525,8062,7893],{"class":6082},[5525,8064,6086],{"class":5531},[5525,8066,8067,8069,8071,8073],{"class":5527,"line":6022},[5525,8068,7220],{"class":6091},[5525,8070,7902],{"class":6078},[5525,8072,7905],{"class":6118},[5525,8074,7908],{"class":5531},[5525,8076,8077,8079],{"class":5527,"line":6028},[5525,8078,7233],{"class":6091},[5525,8080,7970],{"class":6078},[5525,8082,8083,8085,8087],{"class":5527,"line":6034},[5525,8084,6216],{"class":6091},[5525,8086,7023],{"class":6078},[5525,8088,8089],{"class":5531},"._as_tuple() > other._as_tuple()\n",[5525,8091,8092],{"class":5527,"line":6040},[5525,8093,6544],{"class":5531},[5525,8095,8096,8098,8101,8103,8105,8107,8109,8111,8113],{"class":5527,"line":6046},[5525,8097,6199],{"class":6078},[5525,8099,8100],{"class":6118}," __ge__",[5525,8102,6147],{"class":5531},[5525,8104,6208],{"class":6207},[5525,8106,5614],{"class":5531},[5525,8108,7883],{"class":6207},[5525,8110,7949],{"class":5531},[5525,8112,7893],{"class":6082},[5525,8114,6086],{"class":5531},[5525,8116,8118,8120,8122,8124],{"class":5527,"line":8117},44,[5525,8119,7220],{"class":6091},[5525,8121,7902],{"class":6078},[5525,8123,7905],{"class":6118},[5525,8125,7908],{"class":5531},[5525,8127,8129,8131],{"class":5527,"line":8128},45,[5525,8130,7233],{"class":6091},[5525,8132,7970],{"class":6078},[5525,8134,8136,8138,8140],{"class":5527,"line":8135},46,[5525,8137,6216],{"class":6091},[5525,8139,7023],{"class":6078},[5525,8141,8142],{"class":5531},"._as_tuple() >= other._as_tuple()\n",[5525,8144,8146],{"class":5527,"line":8145},47,[5525,8147,5850],{"emptyLinePlaceholder":5849},[5525,8149,8151],{"class":5527,"line":8150},48,[5525,8152,5850],{"emptyLinePlaceholder":5849},[5525,8154,8156,8159,8162,8164,8167,8169,8172],{"class":5527,"line":8155},49,[5525,8157,8158],{"class":5531},"v1 = Version(",[5525,8160,8161],{"class":5535},"1",[5525,8163,5614],{"class":5531},[5525,8165,8166],{"class":5535},"2",[5525,8168,5614],{"class":5531},[5525,8170,8171],{"class":5535},"3",[5525,8173,6778],{"class":5531},[5525,8175,8177,8180,8182,8184,8187,8189,8192],{"class":5527,"line":8176},50,[5525,8178,8179],{"class":5531},"v2 = Version(",[5525,8181,8161],{"class":5535},[5525,8183,5614],{"class":5531},[5525,8185,8186],{"class":5535},"10",[5525,8188,5614],{"class":5531},[5525,8190,8191],{"class":5535},"0",[5525,8193,6778],{"class":5531},[5525,8195,8197,8200,8202,8204,8206,8208,8210],{"class":5527,"line":8196},51,[5525,8198,8199],{"class":5531},"v3 = Version(",[5525,8201,8161],{"class":5535},[5525,8203,5614],{"class":5531},[5525,8205,8166],{"class":5535},[5525,8207,5614],{"class":5531},[5525,8209,8171],{"class":5535},[5525,8211,6778],{"class":5531},[5525,8213,8215],{"class":5527,"line":8214},52,[5525,8216,5850],{"emptyLinePlaceholder":5849},[5525,8218,8220,8222,8225],{"class":5527,"line":8219},53,[5525,8221,6144],{"class":6118},[5525,8223,8224],{"class":5531},"(v1 == v3)   ",[5525,8226,8227],{"class":5545},"# True\n",[5525,8229,8231,8233,8236],{"class":5527,"line":8230},54,[5525,8232,6144],{"class":6118},[5525,8234,8235],{"class":5531},"(v1 \u003C v2)    ",[5525,8237,8238],{"class":5545},"# True  (1.2.3 \u003C 1.10.0)\n",[5525,8240,8242,8244,8247],{"class":5527,"line":8241},55,[5525,8243,6144],{"class":6118},[5525,8245,8246],{"class":5531},"(v2 > v1)    ",[5525,8248,8227],{"class":5545},[5525,8250,8252,8254,8257],{"class":5527,"line":8251},56,[5525,8253,6144],{"class":6118},[5525,8255,8256],{"class":5531},"(v1 >= v3)   ",[5525,8258,8227],{"class":5545},[5525,8260,8262],{"class":5527,"line":8261},57,[5525,8263,5850],{"emptyLinePlaceholder":5849},[5525,8265,8267],{"class":5527,"line":8266},58,[5525,8268,8269],{"class":5545},"# Тепер можна сортувати список версій!\n",[5525,8271,8273,8276,8278,8280,8282,8284,8286,8289,8291,8293,8295,8297,8299,8301,8303,8305,8307,8309,8311],{"class":5527,"line":8272},59,[5525,8274,8275],{"class":5531},"versions = [Version(",[5525,8277,8166],{"class":5535},[5525,8279,5614],{"class":5531},[5525,8281,8191],{"class":5535},[5525,8283,5614],{"class":5531},[5525,8285,8191],{"class":5535},[5525,8287,8288],{"class":5531},"), Version(",[5525,8290,8161],{"class":5535},[5525,8292,5614],{"class":5531},[5525,8294,7029],{"class":5535},[5525,8296,5614],{"class":5531},[5525,8298,8161],{"class":5535},[5525,8300,8288],{"class":5531},[5525,8302,8161],{"class":5535},[5525,8304,5614],{"class":5531},[5525,8306,8166],{"class":5535},[5525,8308,5614],{"class":5531},[5525,8310,8171],{"class":5535},[5525,8312,8313],{"class":5531},")]\n",[5525,8315,8317,8319,8321,8324],{"class":5527,"line":8316},60,[5525,8318,6144],{"class":6118},[5525,8320,6147],{"class":5531},[5525,8322,8323],{"class":6118},"sorted",[5525,8325,8326],{"class":5531},"(versions))\n",[5525,8328,8330],{"class":5527,"line":8329},61,[5525,8331,8332],{"class":5545},"# [Version(1, 2, 3), Version(1, 9, 1), Version(2, 0, 0)]\n",[7425,8334,8336,8344,8353,8360,8367,8374],{"title":8335},"python version.py",[7429,8337,8339,7437,8342],{"className":8338},[5527],[5525,8340,7436],{"className":8341},[7435],[5607,8343,8335],{},[7429,8345,8347,8348],{"className":8346},[5527],"v1 == v3: ",[5525,8349,8352],{"className":8350},[8351],"text-green-400","True",[7429,8354,8356,8357],{"className":8355},[5527],"v1 \u003C v2: ",[5525,8358,8352],{"className":8359},[8351],[7429,8361,8363,8364],{"className":8362},[5527],"v2 > v1: ",[5525,8365,8352],{"className":8366},[8351],[7429,8368,8370,8371],{"className":8369},[5527],"v1 >= v3: ",[5525,8372,8352],{"className":8373},[8351],[7429,8375,8377,8378],{"className":8376},[5527],"sorted: ",[5525,8379,8381],{"className":8380},[7463],"[Version(1, 2, 3), Version(1, 9, 1), Version(2, 0, 0)]",[5748,8383,8385,8388,8389,8392],{"id":8384},"notimplemented-vs-false-критична-різниця",[5507,8386,8387],{},"NotImplemented"," vs ",[5507,8390,8391],{},"False",": критична різниця",[5512,8394,8395,8396,8398,8399,8401,8402,8404],{},"Зверніть увагу: при невідповідному типі методи повертають ",[5507,8397,8387],{},", а не ",[5507,8400,8391],{},". Це ",[5607,8403,6059],{}," синтаксична помилка — це спеціальний синглтон CPython, який сигналізує інтерпретатору: «я не знаю, як порівнювати з цим типом, спробуй спитати іншу сторону».",[5512,8406,8407,8408,8410,8411,8413,8414,8417,8418,8421,8422,8424,8425,6178],{},"Коли ",[5507,8409,7511],{}," повертає ",[5507,8412,8387],{},", Python автоматично спробує ",[5507,8415,8416],{},"b.__eq__(a)"," — це механізм ",[5607,8419,8420],{},"відображення операторів"," (reflected operators). Якщо обидва повертають ",[5507,8423,8387],{},", Python вдається до порівняння по ідентичності (",[5507,8426,8427],{},"is",[5516,8429,8431],{"className":5518,"code":8430,"language":5520,"meta":5521,"style":5521},"v = Version(1, 0, 0)\n\n# Повертає NotImplemented → Python спробує \"42\".__eq__(v) → теж NotImplemented\n# → Python використовує identity comparison → False\nprint(v == \"1.0.0\")   # False (без помилки!)\nprint(v == 42)        # False (без помилки!)\n\n# Якби ми повернули False замість NotImplemented:\n# Порівняння \"1.0.0\" == v теж спрацювало б неправильно\n",[5507,8432,8433,8450,8454,8459,8464,8480,8493,8497,8502],{"__ignoreMap":5521},[5525,8434,8435,8438,8440,8442,8444,8446,8448],{"class":5527,"line":5528},[5525,8436,8437],{"class":5531},"v = Version(",[5525,8439,8161],{"class":5535},[5525,8441,5614],{"class":5531},[5525,8443,8191],{"class":5535},[5525,8445,5614],{"class":5531},[5525,8447,8191],{"class":5535},[5525,8449,6778],{"class":5531},[5525,8451,8452],{"class":5527,"line":5549},[5525,8453,5850],{"emptyLinePlaceholder":5849},[5525,8455,8456],{"class":5527,"line":5567},[5525,8457,8458],{"class":5545},"# Повертає NotImplemented → Python спробує \"42\".__eq__(v) → теж NotImplemented\n",[5525,8460,8461],{"class":5527,"line":5816},[5525,8462,8463],{"class":5545},"# → Python використовує identity comparison → False\n",[5525,8465,8466,8468,8471,8474,8477],{"class":5527,"line":5822},[5525,8467,6144],{"class":6118},[5525,8469,8470],{"class":5531},"(v == ",[5525,8472,8473],{"class":5555},"\"1.0.0\"",[5525,8475,8476],{"class":5531},")   ",[5525,8478,8479],{"class":5545},"# False (без помилки!)\n",[5525,8481,8482,8484,8486,8488,8491],{"class":5527,"line":5828},[5525,8483,6144],{"class":6118},[5525,8485,8470],{"class":5531},[5525,8487,5536],{"class":5535},[5525,8489,8490],{"class":5531},")        ",[5525,8492,8479],{"class":5545},[5525,8494,8495],{"class":5527,"line":5834},[5525,8496,5850],{"emptyLinePlaceholder":5849},[5525,8498,8499],{"class":5527,"line":5840},[5525,8500,8501],{"class":5545},"# Якби ми повернули False замість NotImplemented:\n",[5525,8503,8504],{"class":5527,"line":5846},[5525,8505,8506],{"class":5545},"# Порівняння \"1.0.0\" == v теж спрацювало б неправильно\n",[5748,8508,8510,8512],{"id":8509},"functoolstotal_ordering-мінімальна-реалізація",[5507,8511,6306],{},": мінімальна реалізація",[5512,8514,8515,8516,6307,8519,5781,8521,8524,8525,5614,8528,5614,8531,5614,8534,8537],{},"Якщо вам потрібно лише визначити порядок, але не хочеться писати всі шість методів, ",[5507,8517,8518],{},"functools.total_ordering",[5507,8520,6310],{},[5607,8522,8523],{},"один"," з ",[5507,8526,8527],{},"__lt__",[5507,8529,8530],{},"__le__",[5507,8532,8533],{},"__gt__",[5507,8535,8536],{},"__ge__"," — решту Python виведе автоматично.",[5516,8539,8541],{"className":5518,"code":8540,"language":5520,"meta":5521,"style":5521},"from functools import total_ordering\n\n@total_ordering\nclass Priority:\n    \"\"\"Пріоритет завдання: LOW \u003C MEDIUM \u003C HIGH \u003C CRITICAL.\"\"\"\n    \n    _LEVELS = {\"LOW\": 0, \"MEDIUM\": 1, \"HIGH\": 2, \"CRITICAL\": 3}\n    \n    def __init__(self, level: str):\n        if level not in self._LEVELS:\n            raise ValueError(f\"Невідомий рівень: {level}\")\n        self.level = level\n    \n    def __repr__(self) -> str:\n        return f\"Priority({self.level!r})\"\n    \n    def __eq__(self, other: object) -> bool:\n        if not isinstance(other, Priority):\n            return NotImplemented\n        return self._LEVELS[self.level] == self._LEVELS[other.level]\n    \n    def __lt__(self, other: Priority) -> bool:\n        if not isinstance(other, Priority):\n            return NotImplemented\n        return self._LEVELS[self.level] \u003C self._LEVELS[other.level]\n    \n    # __le__, __gt__, __ge__ — total_ordering виведе сам!\n\n\np1 = Priority(\"LOW\")\np2 = Priority(\"HIGH\")\n\nprint(p1 \u003C p2)   # True  ← наш __lt__\nprint(p1 > p2)   # False ← виведено total_ordering через __lt__ та __eq__\nprint(p2 >= p1)  # True  ← виведено total_ordering\n",[5507,8542,8543,8555,8559,8564,8573,8578,8582,8623,8627,8647,8665,8690,8696,8700,8716,8733,8737,8761,8772,8778,8797,8801,8822,8832,8838,8855,8859,8864,8868,8872,8881,8890,8894,8904,8914],{"__ignoreMap":5521},[5525,8544,8545,8547,8550,8552],{"class":5527,"line":5528},[5525,8546,6512],{"class":6091},[5525,8548,8549],{"class":5531}," functools ",[5525,8551,6518],{"class":6091},[5525,8553,8554],{"class":5531}," total_ordering\n",[5525,8556,8557],{"class":5527,"line":5549},[5525,8558,5850],{"emptyLinePlaceholder":5849},[5525,8560,8561],{"class":5527,"line":5567},[5525,8562,8563],{"class":6118},"@total_ordering\n",[5525,8565,8566,8568,8571],{"class":5527,"line":5816},[5525,8567,6079],{"class":6078},[5525,8569,8570],{"class":6082}," Priority",[5525,8572,6086],{"class":5531},[5525,8574,8575],{"class":5527,"line":5822},[5525,8576,8577],{"class":5555},"    \"\"\"Пріоритет завдання: LOW \u003C MEDIUM \u003C HIGH \u003C CRITICAL.\"\"\"\n",[5525,8579,8580],{"class":5527,"line":5828},[5525,8581,6544],{"class":5531},[5525,8583,8584,8587,8590,8592,8594,8596,8599,8601,8603,8605,8608,8610,8612,8614,8617,8619,8621],{"class":5527,"line":5834},[5525,8585,8586],{"class":5531},"    _LEVELS = {",[5525,8588,8589],{"class":5555},"\"LOW\"",[5525,8591,6127],{"class":5531},[5525,8593,8191],{"class":5535},[5525,8595,5614],{"class":5531},[5525,8597,8598],{"class":5555},"\"MEDIUM\"",[5525,8600,6127],{"class":5531},[5525,8602,8161],{"class":5535},[5525,8604,5614],{"class":5531},[5525,8606,8607],{"class":5555},"\"HIGH\"",[5525,8609,6127],{"class":5531},[5525,8611,8166],{"class":5535},[5525,8613,5614],{"class":5531},[5525,8615,8616],{"class":5555},"\"CRITICAL\"",[5525,8618,6127],{"class":5531},[5525,8620,8171],{"class":5535},[5525,8622,5843],{"class":5531},[5525,8624,8625],{"class":5527,"line":5840},[5525,8626,6544],{"class":5531},[5525,8628,8629,8631,8633,8635,8637,8639,8641,8643,8645],{"class":5527,"line":5846},[5525,8630,6199],{"class":6078},[5525,8632,6551],{"class":6118},[5525,8634,6147],{"class":5531},[5525,8636,6208],{"class":6207},[5525,8638,5614],{"class":5531},[5525,8640,6560],{"class":6207},[5525,8642,6127],{"class":5531},[5525,8644,6565],{"class":6082},[5525,8646,6211],{"class":5531},[5525,8648,8649,8651,8654,8657,8660,8662],{"class":5527,"line":5853},[5525,8650,7220],{"class":6091},[5525,8652,8653],{"class":5531}," level ",[5525,8655,8656],{"class":6078},"not",[5525,8658,8659],{"class":6078}," in",[5525,8661,7023],{"class":6078},[5525,8663,8664],{"class":5531},"._LEVELS:\n",[5525,8666,8667,8670,8673,8675,8677,8680,8682,8684,8686,8688],{"class":5527,"line":5859},[5525,8668,8669],{"class":6091},"            raise",[5525,8671,8672],{"class":6082}," ValueError",[5525,8674,6147],{"class":5531},[5525,8676,7333],{"class":6078},[5525,8678,8679],{"class":5555},"\"Невідомий рівень: ",[5525,8681,6791],{"class":6078},[5525,8683,6560],{"class":5531},[5525,8685,6797],{"class":6078},[5525,8687,7146],{"class":5555},[5525,8689,6778],{"class":5531},[5525,8691,8692,8694],{"class":5527,"line":5865},[5525,8693,6596],{"class":6078},[5525,8695,6599],{"class":5531},[5525,8697,8698],{"class":5527,"line":5871},[5525,8699,6544],{"class":5531},[5525,8701,8702,8704,8706,8708,8710,8712,8714],{"class":5527,"line":5877},[5525,8703,6199],{"class":6078},[5525,8705,6630],{"class":6118},[5525,8707,6147],{"class":5531},[5525,8709,6208],{"class":6207},[5525,8711,6637],{"class":5531},[5525,8713,6565],{"class":6082},[5525,8715,6086],{"class":5531},[5525,8717,8718,8720,8722,8725,8727,8729,8731],{"class":5527,"line":5883},[5525,8719,6216],{"class":6091},[5525,8721,6785],{"class":6078},[5525,8723,8724],{"class":5555},"\"Priority(",[5525,8726,6676],{"class":6078},[5525,8728,6679],{"class":5531},[5525,8730,6682],{"class":6078},[5525,8732,7117],{"class":5555},[5525,8734,8735],{"class":5527,"line":5889},[5525,8736,6544],{"class":5531},[5525,8738,8739,8741,8743,8745,8747,8749,8751,8753,8755,8757,8759],{"class":5527,"line":5895},[5525,8740,6199],{"class":6078},[5525,8742,7874],{"class":6118},[5525,8744,6147],{"class":5531},[5525,8746,6208],{"class":6207},[5525,8748,5614],{"class":5531},[5525,8750,7883],{"class":6207},[5525,8752,6127],{"class":5531},[5525,8754,7888],{"class":6082},[5525,8756,6637],{"class":5531},[5525,8758,7893],{"class":6082},[5525,8760,6086],{"class":5531},[5525,8762,8763,8765,8767,8769],{"class":5527,"line":5901},[5525,8764,7220],{"class":6091},[5525,8766,7902],{"class":6078},[5525,8768,7905],{"class":6118},[5525,8770,8771],{"class":5531},"(other, Priority):\n",[5525,8773,8774,8776],{"class":5527,"line":5906},[5525,8775,7233],{"class":6091},[5525,8777,7970],{"class":6078},[5525,8779,8780,8782,8784,8787,8789,8792,8794],{"class":5527,"line":5911},[5525,8781,6216],{"class":6091},[5525,8783,7023],{"class":6078},[5525,8785,8786],{"class":5531},"._LEVELS[",[5525,8788,6208],{"class":6078},[5525,8790,8791],{"class":5531},".level] == ",[5525,8793,6208],{"class":6078},[5525,8795,8796],{"class":5531},"._LEVELS[other.level]\n",[5525,8798,8799],{"class":5527,"line":5917},[5525,8800,6544],{"class":5531},[5525,8802,8803,8805,8807,8809,8811,8813,8815,8818,8820],{"class":5527,"line":5923},[5525,8804,6199],{"class":6078},[5525,8806,7938],{"class":6118},[5525,8808,6147],{"class":5531},[5525,8810,6208],{"class":6207},[5525,8812,5614],{"class":5531},[5525,8814,7883],{"class":6207},[5525,8816,8817],{"class":5531},": Priority) -> ",[5525,8819,7893],{"class":6082},[5525,8821,6086],{"class":5531},[5525,8823,8824,8826,8828,8830],{"class":5527,"line":5929},[5525,8825,7220],{"class":6091},[5525,8827,7902],{"class":6078},[5525,8829,7905],{"class":6118},[5525,8831,8771],{"class":5531},[5525,8833,8834,8836],{"class":5527,"line":5935},[5525,8835,7233],{"class":6091},[5525,8837,7970],{"class":6078},[5525,8839,8840,8842,8844,8846,8848,8851,8853],{"class":5527,"line":5941},[5525,8841,6216],{"class":6091},[5525,8843,7023],{"class":6078},[5525,8845,8786],{"class":5531},[5525,8847,6208],{"class":6078},[5525,8849,8850],{"class":5531},".level] \u003C ",[5525,8852,6208],{"class":6078},[5525,8854,8796],{"class":5531},[5525,8856,8857],{"class":5527,"line":5947},[5525,8858,6544],{"class":5531},[5525,8860,8861],{"class":5527,"line":5953},[5525,8862,8863],{"class":5545},"    # __le__, __gt__, __ge__ — total_ordering виведе сам!\n",[5525,8865,8866],{"class":5527,"line":5959},[5525,8867,5850],{"emptyLinePlaceholder":5849},[5525,8869,8870],{"class":5527,"line":5964},[5525,8871,5850],{"emptyLinePlaceholder":5849},[5525,8873,8874,8877,8879],{"class":5527,"line":5969},[5525,8875,8876],{"class":5531},"p1 = Priority(",[5525,8878,8589],{"class":5555},[5525,8880,6778],{"class":5531},[5525,8882,8883,8886,8888],{"class":5527,"line":5975},[5525,8884,8885],{"class":5531},"p2 = Priority(",[5525,8887,8607],{"class":5555},[5525,8889,6778],{"class":5531},[5525,8891,8892],{"class":5527,"line":5981},[5525,8893,5850],{"emptyLinePlaceholder":5849},[5525,8895,8896,8898,8901],{"class":5527,"line":5987},[5525,8897,6144],{"class":6118},[5525,8899,8900],{"class":5531},"(p1 \u003C p2)   ",[5525,8902,8903],{"class":5545},"# True  ← наш __lt__\n",[5525,8905,8906,8908,8911],{"class":5527,"line":5993},[5525,8907,6144],{"class":6118},[5525,8909,8910],{"class":5531},"(p1 > p2)   ",[5525,8912,8913],{"class":5545},"# False ← виведено total_ordering через __lt__ та __eq__\n",[5525,8915,8916,8918,8921],{"class":5527,"line":5999},[5525,8917,6144],{"class":6118},[5525,8919,8920],{"class":5531},"(p2 >= p1)  ",[5525,8922,8923],{"class":5545},"# True  ← виведено total_ordering\n",[6158,8925,8926,8929,8930,8933],{},[5507,8927,8928],{},"@total_ordering"," зручний, але ",[5607,8931,8932],{},"повільніший"," за явне визначення всіх методів: кожен виведений метод виконує додаткові виклики. Для класів, що порівнюються дуже часто (наприклад, ключі у великих структурах даних), краще визначити всі методи явно.",[5748,8935,8937,8939],{"id":8936},"__hash__-та-контракт-рівності",[5507,8938,6315],{}," та контракт рівності",[5512,8941,8942],{},"Ось одне з найважливіших правил Python, порушення якого породжує важко відтворювані баги:",[8944,8945,8946],"blockquote",{},[5512,8947,8948,8958],{},[5607,8949,8950,8951,8953,8954,8957],{},"Якщо ",[5507,8952,7506],{},", то ",[5507,8955,8956],{},"hash(a) == hash(b)"," — обов'язково.","\nЗворотне не вимагається: різні об'єкти можуть мати однаковий хеш (колізія).",[5512,8960,8961,8962,8964,8965,8967,8968,8970],{},"Ця вимога необхідна тому, що словники (",[5507,8963,6319],{},") та множини (",[5507,8966,6323],{},") використовують хеш як індекс для швидкого пошуку. Якщо два «рівних» об'єкти мають різні хеші, ",[5507,8969,6319],{}," просто не знайде один через інший.",[5512,8972,8973],{},[5607,8974,8975,8976,8978],{},"Що відбувається при перевизначенні ",[5507,8977,6310],{},":",[5512,8980,8981,8982,8984,8985,8991],{},"CPython слідкує за цим контрактом автоматично: якщо ви визначаєте ",[5507,8983,6310],{}," у класі, Python ",[5607,8986,8987,8988],{},"автоматично встановлює ",[5507,8989,8990],{},"__hash__ = None",", роблячи об'єкти нехешованими (тобто їх не можна використовувати як ключ словника або елемент множини).",[5516,8993,8995],{"className":5518,"code":8994,"language":5520,"meta":5521,"style":5521},"class BadPoint:\n    def __init__(self, x, y):\n        self.x = x\n        self.y = y\n    \n    def __eq__(self, other):\n        return isinstance(other, BadPoint) and self.x == other.x and self.y == other.y\n    # __hash__ не визначено → автоматично None\n\np = BadPoint(1, 2)\nprint(hash(p))          # TypeError: unhashable type: 'BadPoint'\ns = {p}                 # TypeError: unhashable type: 'BadPoint'\nd = {p: \"value\"}        # TypeError: unhashable type: 'BadPoint'\n",[5507,8996,8997,9006,9028,9035,9042,9046,9062,9086,9091,9095,9108,9123,9130],{"__ignoreMap":5521},[5525,8998,8999,9001,9004],{"class":5527,"line":5528},[5525,9000,6079],{"class":6078},[5525,9002,9003],{"class":6082}," BadPoint",[5525,9005,6086],{"class":5531},[5525,9007,9008,9010,9012,9014,9016,9018,9021,9023,9026],{"class":5527,"line":5549},[5525,9009,6199],{"class":6078},[5525,9011,6551],{"class":6118},[5525,9013,6147],{"class":5531},[5525,9015,6208],{"class":6207},[5525,9017,5614],{"class":5531},[5525,9019,9020],{"class":6207},"x",[5525,9022,5614],{"class":5531},[5525,9024,9025],{"class":6207},"y",[5525,9027,6211],{"class":5531},[5525,9029,9030,9032],{"class":5527,"line":5567},[5525,9031,6596],{"class":6078},[5525,9033,9034],{"class":5531},".x = x\n",[5525,9036,9037,9039],{"class":5527,"line":5816},[5525,9038,6596],{"class":6078},[5525,9040,9041],{"class":5531},".y = y\n",[5525,9043,9044],{"class":5527,"line":5822},[5525,9045,6544],{"class":5531},[5525,9047,9048,9050,9052,9054,9056,9058,9060],{"class":5527,"line":5828},[5525,9049,6199],{"class":6078},[5525,9051,7874],{"class":6118},[5525,9053,6147],{"class":5531},[5525,9055,6208],{"class":6207},[5525,9057,5614],{"class":5531},[5525,9059,7883],{"class":6207},[5525,9061,6211],{"class":5531},[5525,9063,9064,9066,9068,9071,9074,9076,9079,9081,9083],{"class":5527,"line":5834},[5525,9065,6216],{"class":6091},[5525,9067,7905],{"class":6118},[5525,9069,9070],{"class":5531},"(other, BadPoint) ",[5525,9072,9073],{"class":6078},"and",[5525,9075,7023],{"class":6078},[5525,9077,9078],{"class":5531},".x == other.x ",[5525,9080,9073],{"class":6078},[5525,9082,7023],{"class":6078},[5525,9084,9085],{"class":5531},".y == other.y\n",[5525,9087,9088],{"class":5527,"line":5840},[5525,9089,9090],{"class":5545},"    # __hash__ не визначено → автоматично None\n",[5525,9092,9093],{"class":5527,"line":5846},[5525,9094,5850],{"emptyLinePlaceholder":5849},[5525,9096,9097,9100,9102,9104,9106],{"class":5527,"line":5853},[5525,9098,9099],{"class":5531},"p = BadPoint(",[5525,9101,8161],{"class":5535},[5525,9103,5614],{"class":5531},[5525,9105,8166],{"class":5535},[5525,9107,6778],{"class":5531},[5525,9109,9110,9112,9114,9117,9120],{"class":5527,"line":5859},[5525,9111,6144],{"class":6118},[5525,9113,6147],{"class":5531},[5525,9115,9116],{"class":6118},"hash",[5525,9118,9119],{"class":5531},"(p))          ",[5525,9121,9122],{"class":5545},"# TypeError: unhashable type: 'BadPoint'\n",[5525,9124,9125,9128],{"class":5527,"line":5865},[5525,9126,9127],{"class":5531},"s = {p}                 ",[5525,9129,9122],{"class":5545},[5525,9131,9132,9135,9138,9141],{"class":5527,"line":5871},[5525,9133,9134],{"class":5531},"d = {p: ",[5525,9136,9137],{"class":5555},"\"value\"",[5525,9139,9140],{"class":5531},"}        ",[5525,9142,9122],{"class":5545},[5512,9144,9145,9146,9148,9149,9152,9153,8978],{},"Щоб об'єкт залишався хешованим після перевизначення ",[5507,9147,6310],{},", потрібно ",[5607,9150,9151],{},"явно"," визначити ",[5507,9154,6315],{},[5516,9156,9158],{"className":5518,"code":9157,"language":5520,"meta":5521,"style":5521},"class Point:\n    \"\"\"Незмінна точка у 2D просторі.\"\"\"\n    \n    def __init__(self, x: float, y: float):\n        self.x = x\n        self.y = y\n    \n    def __repr__(self) -> str:\n        return f\"Point({self.x}, {self.y})\"\n    \n    def __eq__(self, other: object) -> bool:\n        if not isinstance(other, Point):\n            return NotImplemented\n        return self.x == other.x and self.y == other.y\n    \n    def __hash__(self) -> int:\n        # hash() від tuple гарантує сумісність з контрактом:\n        # якщо self == other, то self._as_tuple() == other._as_tuple()\n        # тому hash(self._as_tuple()) == hash(other._as_tuple())\n        return hash((self.x, self.y))\n\n\np1 = Point(1.0, 2.0)\np2 = Point(1.0, 2.0)  # інший об'єкт, але рівний p1\n\nprint(p1 == p2)           # True\nprint(hash(p1) == hash(p2))  # True ✅ контракт виконано\n\n# Тепер Point можна використовувати як ключ словника і в множині\nvisited = {p1, p2}\nprint(len(visited))   # 1 — Python розпізнав їх як рівні\n\ncache = {p1: \"result\"}\nprint(cache[p2])      # \"result\" — знайдено через p2, хоча додавали через p1\n",[5507,9159,9160,9169,9174,9178,9206,9212,9218,9222,9238,9265,9269,9293,9304,9310,9324,9328,9345,9350,9355,9360,9380,9384,9388,9403,9419,9423,9432,9451,9455,9460,9465,9479,9483,9493],{"__ignoreMap":5521},[5525,9161,9162,9164,9167],{"class":5527,"line":5528},[5525,9163,6079],{"class":6078},[5525,9165,9166],{"class":6082}," Point",[5525,9168,6086],{"class":5531},[5525,9170,9171],{"class":5527,"line":5549},[5525,9172,9173],{"class":5555},"    \"\"\"Незмінна точка у 2D просторі.\"\"\"\n",[5525,9175,9176],{"class":5527,"line":5567},[5525,9177,6544],{"class":5531},[5525,9179,9180,9182,9184,9186,9188,9190,9192,9194,9196,9198,9200,9202,9204],{"class":5527,"line":5816},[5525,9181,6199],{"class":6078},[5525,9183,6551],{"class":6118},[5525,9185,6147],{"class":5531},[5525,9187,6208],{"class":6207},[5525,9189,5614],{"class":5531},[5525,9191,9020],{"class":6207},[5525,9193,6127],{"class":5531},[5525,9195,6978],{"class":6082},[5525,9197,5614],{"class":5531},[5525,9199,9025],{"class":6207},[5525,9201,6127],{"class":5531},[5525,9203,6978],{"class":6082},[5525,9205,6211],{"class":5531},[5525,9207,9208,9210],{"class":5527,"line":5822},[5525,9209,6596],{"class":6078},[5525,9211,9034],{"class":5531},[5525,9213,9214,9216],{"class":5527,"line":5828},[5525,9215,6596],{"class":6078},[5525,9217,9041],{"class":5531},[5525,9219,9220],{"class":5527,"line":5834},[5525,9221,6544],{"class":5531},[5525,9223,9224,9226,9228,9230,9232,9234,9236],{"class":5527,"line":5840},[5525,9225,6199],{"class":6078},[5525,9227,6630],{"class":6118},[5525,9229,6147],{"class":5531},[5525,9231,6208],{"class":6207},[5525,9233,6637],{"class":5531},[5525,9235,6565],{"class":6082},[5525,9237,6086],{"class":5531},[5525,9239,9240,9242,9244,9247,9249,9252,9254,9256,9258,9261,9263],{"class":5527,"line":5846},[5525,9241,6216],{"class":6091},[5525,9243,6785],{"class":6078},[5525,9245,9246],{"class":5555},"\"Point(",[5525,9248,6676],{"class":6078},[5525,9250,9251],{"class":5531},".x",[5525,9253,6797],{"class":6078},[5525,9255,5614],{"class":5555},[5525,9257,6676],{"class":6078},[5525,9259,9260],{"class":5531},".y",[5525,9262,6797],{"class":6078},[5525,9264,7117],{"class":5555},[5525,9266,9267],{"class":5527,"line":5853},[5525,9268,6544],{"class":5531},[5525,9270,9271,9273,9275,9277,9279,9281,9283,9285,9287,9289,9291],{"class":5527,"line":5859},[5525,9272,6199],{"class":6078},[5525,9274,7874],{"class":6118},[5525,9276,6147],{"class":5531},[5525,9278,6208],{"class":6207},[5525,9280,5614],{"class":5531},[5525,9282,7883],{"class":6207},[5525,9284,6127],{"class":5531},[5525,9286,7888],{"class":6082},[5525,9288,6637],{"class":5531},[5525,9290,7893],{"class":6082},[5525,9292,6086],{"class":5531},[5525,9294,9295,9297,9299,9301],{"class":5527,"line":5865},[5525,9296,7220],{"class":6091},[5525,9298,7902],{"class":6078},[5525,9300,7905],{"class":6118},[5525,9302,9303],{"class":5531},"(other, Point):\n",[5525,9305,9306,9308],{"class":5527,"line":5871},[5525,9307,7233],{"class":6091},[5525,9309,7970],{"class":6078},[5525,9311,9312,9314,9316,9318,9320,9322],{"class":5527,"line":5877},[5525,9313,6216],{"class":6091},[5525,9315,7023],{"class":6078},[5525,9317,9078],{"class":5531},[5525,9319,9073],{"class":6078},[5525,9321,7023],{"class":6078},[5525,9323,9085],{"class":5531},[5525,9325,9326],{"class":5527,"line":5883},[5525,9327,6544],{"class":5531},[5525,9329,9330,9332,9335,9337,9339,9341,9343],{"class":5527,"line":5889},[5525,9331,6199],{"class":6078},[5525,9333,9334],{"class":6118}," __hash__",[5525,9336,6147],{"class":5531},[5525,9338,6208],{"class":6207},[5525,9340,6637],{"class":5531},[5525,9342,7656],{"class":6082},[5525,9344,6086],{"class":5531},[5525,9346,9347],{"class":5527,"line":5895},[5525,9348,9349],{"class":5545},"        # hash() від tuple гарантує сумісність з контрактом:\n",[5525,9351,9352],{"class":5527,"line":5901},[5525,9353,9354],{"class":5545},"        # якщо self == other, то self._as_tuple() == other._as_tuple()\n",[5525,9356,9357],{"class":5527,"line":5906},[5525,9358,9359],{"class":5545},"        # тому hash(self._as_tuple()) == hash(other._as_tuple())\n",[5525,9361,9362,9364,9367,9370,9372,9375,9377],{"class":5527,"line":5911},[5525,9363,6216],{"class":6091},[5525,9365,9366],{"class":6118}," hash",[5525,9368,9369],{"class":5531},"((",[5525,9371,6208],{"class":6078},[5525,9373,9374],{"class":5531},".x, ",[5525,9376,6208],{"class":6078},[5525,9378,9379],{"class":5531},".y))\n",[5525,9381,9382],{"class":5527,"line":5917},[5525,9383,5850],{"emptyLinePlaceholder":5849},[5525,9385,9386],{"class":5527,"line":5923},[5525,9387,5850],{"emptyLinePlaceholder":5849},[5525,9389,9390,9393,9396,9398,9401],{"class":5527,"line":5929},[5525,9391,9392],{"class":5531},"p1 = Point(",[5525,9394,9395],{"class":5535},"1.0",[5525,9397,5614],{"class":5531},[5525,9399,9400],{"class":5535},"2.0",[5525,9402,6778],{"class":5531},[5525,9404,9405,9408,9410,9412,9414,9416],{"class":5527,"line":5935},[5525,9406,9407],{"class":5531},"p2 = Point(",[5525,9409,9395],{"class":5535},[5525,9411,5614],{"class":5531},[5525,9413,9400],{"class":5535},[5525,9415,7299],{"class":5531},[5525,9417,9418],{"class":5545},"# інший об'єкт, але рівний p1\n",[5525,9420,9421],{"class":5527,"line":5941},[5525,9422,5850],{"emptyLinePlaceholder":5849},[5525,9424,9425,9427,9430],{"class":5527,"line":5947},[5525,9426,6144],{"class":6118},[5525,9428,9429],{"class":5531},"(p1 == p2)           ",[5525,9431,8227],{"class":5545},[5525,9433,9434,9436,9438,9440,9443,9445,9448],{"class":5527,"line":5953},[5525,9435,6144],{"class":6118},[5525,9437,6147],{"class":5531},[5525,9439,9116],{"class":6118},[5525,9441,9442],{"class":5531},"(p1) == ",[5525,9444,9116],{"class":6118},[5525,9446,9447],{"class":5531},"(p2))  ",[5525,9449,9450],{"class":5545},"# True ✅ контракт виконано\n",[5525,9452,9453],{"class":5527,"line":5959},[5525,9454,5850],{"emptyLinePlaceholder":5849},[5525,9456,9457],{"class":5527,"line":5964},[5525,9458,9459],{"class":5545},"# Тепер Point можна використовувати як ключ словника і в множині\n",[5525,9461,9462],{"class":5527,"line":5969},[5525,9463,9464],{"class":5531},"visited = {p1, p2}\n",[5525,9466,9467,9469,9471,9473,9476],{"class":5527,"line":5975},[5525,9468,6144],{"class":6118},[5525,9470,6147],{"class":5531},[5525,9472,6150],{"class":6118},[5525,9474,9475],{"class":5531},"(visited))   ",[5525,9477,9478],{"class":5545},"# 1 — Python розпізнав їх як рівні\n",[5525,9480,9481],{"class":5527,"line":5981},[5525,9482,5850],{"emptyLinePlaceholder":5849},[5525,9484,9485,9488,9491],{"class":5527,"line":5987},[5525,9486,9487],{"class":5531},"cache = {p1: ",[5525,9489,9490],{"class":5555},"\"result\"",[5525,9492,5843],{"class":5531},[5525,9494,9495,9497,9500],{"class":5527,"line":5993},[5525,9496,6144],{"class":6118},[5525,9498,9499],{"class":5531},"(cache[p2])      ",[5525,9501,9502],{"class":5545},"# \"result\" — знайдено через p2, хоча додавали через p1\n",[7425,9504,9506,9514,9521,9528,9541],{"title":9505},"python point_hash.py",[7429,9507,9509,7437,9512],{"className":9508},[5527],[5525,9510,7436],{"className":9511},[7435],[5607,9513,9505],{},[7429,9515,9517,9518],{"className":9516},[5527],"p1 == p2: ",[5525,9519,8352],{"className":9520},[8351],[7429,9522,9524,9525],{"className":9523},[5527],"hash(p1) == hash(p2): ",[5525,9526,8352],{"className":9527},[8351],[7429,9529,9531,9532,9535,9536],{"className":9530},[5527],"len(visited): ",[5525,9533,8161],{"className":9534},[7447],"  ",[5525,9537,9540],{"className":9538},[9539],"text-gray-400","# два однакових об'єкти злилися в один елемент set",[7429,9542,9544,9545],{"className":9543},[5527],"cache[p2]: ",[5525,9546,9548],{"className":9547},[7463],"'result'",[9550,9551,9552,9555,9556,9559,9560,9562,9563,9565,9566,9569,9570,9572,9573,9576,9577,9580,9581,9583,9584,9586],"important",{},[5607,9553,9554],{},"Хешування та мутабельність."," Мутабельні об'єкти, як правило, ",[5607,9557,9558],{},"не повинні"," бути хешованими. Уявіть: ви додали ",[5507,9561,5512],{}," у ",[5507,9564,6323],{},", потім змінили ",[5507,9567,9568],{},"p.x"," — хеш змінився, але множина не знає про це. Тепер ",[5507,9571,5512],{}," «загублено» всередині множини. Саме тому ",[5507,9574,9575],{},"list"," не є хешованим, а ",[5507,9578,9579],{},"tuple"," — є. Якщо ваш клас мутабельний і ви хочете ",[5507,9582,6310],{}," — не визначайте ",[5507,9585,6315],{}," і приймайте, що об'єкти будуть нехешованими.",[5741,9588],{},[5502,9590,9592],{"id":9591},"частина-iv-арифметичний-протокол","Частина IV: Арифметичний протокол",[5748,9594,9596],{"id":9595},"бінарні-оператори-ліві-праві-та-in-place-варіанти","Бінарні оператори: ліві, праві та in-place варіанти",[5512,9598,9599],{},"Арифметичний протокол Python містить три рівні для кожного оператора:",[6256,9601,9602,9615,9631],{},[6259,9603,9606,9607,6266,9609,9611,9612,9614],{"name":9604,"type":9605},"__add__(self, other)","Лівий оператор","Викликається для лівого операнда: ",[5507,9608,5637],{},[5507,9610,5641],{},". Якщо повертає ",[5507,9613,8387],{},", Python пробує правий варіант.",[6259,9616,9619,9620,6127,9622,6266,9624,9627,9628,6178],{"name":9617,"type":9618},"__radd__(self, other)","Правий (reflected) оператор","Викликається для правого операнда, якщо лівий повернув ",[5507,9621,8387],{},[5507,9623,5637],{},[5507,9625,9626],{},"b.__radd__(a)",". Необхідний для сумісності з вбудованими типами (наприклад, ",[5507,9629,9630],{},"5 + my_obj",[6259,9632,9635,9636,9639,9640,9643],{"name":9633,"type":9634},"__iadd__(self, other)","In-place оператор","Викликається для ",[5507,9637,9638],{},"a += b",". Якщо не визначено — Python використовує ",[5507,9641,9642],{},"__add__"," та перепризначає змінну. Для мутабельних об'єктів варто визначати явно, щоб уникнути створення нового об'єкта.",[5512,9645,9646,9647,9649],{},"Побудуємо клас ",[5507,9648,5669],{}," для двовимірного вектора — класичний приклад, що добре ілюструє всі три рівні:",[5516,9651,9653],{"className":5518,"code":9652,"language":5520,"meta":5521,"style":5521},"from __future__ import annotations\nimport math\n\nclass Vector:\n    \"\"\"Двовимірний вектор з підтримкою арифметики.\"\"\"\n    \n    def __init__(self, x: float, y: float):\n        self.x = x\n        self.y = y\n    \n    def __repr__(self) -> str:\n        return f\"Vector({self.x}, {self.y})\"\n    \n    def __str__(self) -> str:\n        return f\"({self.x}, {self.y})\"\n    \n    # --- Лівий оператор + ---\n    def __add__(self, other: Vector) -> Vector:\n        if not isinstance(other, Vector):\n            return NotImplemented\n        return Vector(self.x + other.x, self.y + other.y)\n    \n    # --- Правий оператор + (для: scalar + Vector — не підходить,\n    #     але для Vector + Vector з іншого класу) ---\n    def __radd__(self, other: object) -> Vector:\n        # Тут можна підтримати sum([v1, v2, v3]):\n        # sum() починає з 0 + v1 → 0.__add__(v1) → NotImplemented\n        # → v1.__radd__(0) → тут ми обробляємо int(0)\n        if other == 0:\n            return self  # нейтральний елемент для sum()\n        return NotImplemented\n    \n    # --- In-place += ---\n    def __iadd__(self, other: Vector) -> Vector:\n        if not isinstance(other, Vector):\n            return NotImplemented\n        # Мутуємо self, повертаємо self — не створюємо новий об'єкт\n        self.x += other.x\n        self.y += other.y\n        return self\n    \n    # --- Субтракція ---\n    def __sub__(self, other: Vector) -> Vector:\n        if not isinstance(other, Vector):\n            return NotImplemented\n        return Vector(self.x - other.x, self.y - other.y)\n    \n    # --- Множення: вектор * скаляр ---\n    def __mul__(self, scalar: float) -> Vector:\n        if not isinstance(scalar, (int, float)):\n            return NotImplemented\n        return Vector(self.x * scalar, self.y * scalar)\n    \n    # --- Множення: скаляр * вектор (2.0 * v) ---\n    def __rmul__(self, scalar: float) -> Vector:\n        return self.__mul__(scalar)  # комутативна операція\n    \n    # --- Унарний мінус: -v ---\n    def __neg__(self) -> Vector:\n        return Vector(-self.x, -self.y)\n    \n    # --- Абсолютне значення: довжина вектора ---\n    def __abs__(self) -> float:\n        return math.sqrt(self.x ** 2 + self.y ** 2)\n    \n    # --- bool: ненульовий вектор ---\n    def __bool__(self) -> bool:\n        return bool(self.x or self.y)\n    \n    def __eq__(self, other: object) -> bool:\n        if not isinstance(other, Vector):\n            return NotImplemented\n        return self.x == other.x and self.y == other.y\n\n\n# Демонстрація\nv1 = Vector(1, 2)\nv2 = Vector(3, 4)\n\nprint(v1 + v2)          # (4, 6)\nprint(v2 - v1)          # (2, 2)\nprint(v1 * 3.0)         # (3.0, 6.0)\nprint(2.0 * v1)         # (2.0, 4.0)  ← __rmul__ у дії\nprint(-v1)              # (-1, -2)\nprint(abs(v2))          # 5.0 (теорема Піфагора: √(9+16))\nprint(bool(Vector(0,0)))  # False\nprint(bool(v1))           # True\n\n# Магія __radd__: sum() тепер працює зі списком векторів!\nvectors = [Vector(1, 0), Vector(0, 2), Vector(3, 1)]\ntotal = sum(vectors)    # sum(iterable, start=0): 0 + v1 + v2 + v3\nprint(total)            # (4, 3)\n\n# In-place оператор: мутує v1, не створює новий об'єкт\noriginal_id = id(v1)\nv1 += Vector(10, 10)\nprint(v1)               # (11, 12)\nprint(id(v1) == original_id)  # True — той самий об'єкт!\n",[5507,9654,9655,9665,9672,9676,9685,9690,9694,9722,9728,9734,9738,9754,9779,9783,9799,9824,9828,9833,9851,9862,9868,9885,9889,9894,9899,9921,9926,9931,9936,9947,9956,9962,9966,9971,9988,9998,10004,10009,10016,10023,10030,10034,10039,10056,10066,10072,10088,10092,10097,10119,10139,10145,10161,10165,10170,10191,10208,10212,10217,10230,10247,10251,10257,10275,10301,10306,10312,10330,10351,10356,10381,10392,10399,10414,10419,10424,10430,10444,10459,10464,10475,10486,10503,10518,10529,10545,10570,10584,10589,10595,10626,10641,10652,10657,10663,10675,10689,10700],{"__ignoreMap":5521},[5525,9656,9657,9659,9661,9663],{"class":5527,"line":5528},[5525,9658,6512],{"class":6091},[5525,9660,7608],{"class":6207},[5525,9662,7611],{"class":6091},[5525,9664,7614],{"class":5531},[5525,9666,9667,9669],{"class":5527,"line":5549},[5525,9668,6518],{"class":6091},[5525,9670,9671],{"class":5531}," math\n",[5525,9673,9674],{"class":5527,"line":5567},[5525,9675,5850],{"emptyLinePlaceholder":5849},[5525,9677,9678,9680,9683],{"class":5527,"line":5816},[5525,9679,6079],{"class":6078},[5525,9681,9682],{"class":6082}," Vector",[5525,9684,6086],{"class":5531},[5525,9686,9687],{"class":5527,"line":5822},[5525,9688,9689],{"class":5555},"    \"\"\"Двовимірний вектор з підтримкою арифметики.\"\"\"\n",[5525,9691,9692],{"class":5527,"line":5828},[5525,9693,6544],{"class":5531},[5525,9695,9696,9698,9700,9702,9704,9706,9708,9710,9712,9714,9716,9718,9720],{"class":5527,"line":5834},[5525,9697,6199],{"class":6078},[5525,9699,6551],{"class":6118},[5525,9701,6147],{"class":5531},[5525,9703,6208],{"class":6207},[5525,9705,5614],{"class":5531},[5525,9707,9020],{"class":6207},[5525,9709,6127],{"class":5531},[5525,9711,6978],{"class":6082},[5525,9713,5614],{"class":5531},[5525,9715,9025],{"class":6207},[5525,9717,6127],{"class":5531},[5525,9719,6978],{"class":6082},[5525,9721,6211],{"class":5531},[5525,9723,9724,9726],{"class":5527,"line":5840},[5525,9725,6596],{"class":6078},[5525,9727,9034],{"class":5531},[5525,9729,9730,9732],{"class":5527,"line":5846},[5525,9731,6596],{"class":6078},[5525,9733,9041],{"class":5531},[5525,9735,9736],{"class":5527,"line":5853},[5525,9737,6544],{"class":5531},[5525,9739,9740,9742,9744,9746,9748,9750,9752],{"class":5527,"line":5859},[5525,9741,6199],{"class":6078},[5525,9743,6630],{"class":6118},[5525,9745,6147],{"class":5531},[5525,9747,6208],{"class":6207},[5525,9749,6637],{"class":5531},[5525,9751,6565],{"class":6082},[5525,9753,6086],{"class":5531},[5525,9755,9756,9758,9760,9763,9765,9767,9769,9771,9773,9775,9777],{"class":5527,"line":5865},[5525,9757,6216],{"class":6091},[5525,9759,6785],{"class":6078},[5525,9761,9762],{"class":5555},"\"Vector(",[5525,9764,6676],{"class":6078},[5525,9766,9251],{"class":5531},[5525,9768,6797],{"class":6078},[5525,9770,5614],{"class":5555},[5525,9772,6676],{"class":6078},[5525,9774,9260],{"class":5531},[5525,9776,6797],{"class":6078},[5525,9778,7117],{"class":5555},[5525,9780,9781],{"class":5527,"line":5871},[5525,9782,6544],{"class":5531},[5525,9784,9785,9787,9789,9791,9793,9795,9797],{"class":5527,"line":5877},[5525,9786,6199],{"class":6078},[5525,9788,6741],{"class":6118},[5525,9790,6147],{"class":5531},[5525,9792,6208],{"class":6207},[5525,9794,6637],{"class":5531},[5525,9796,6565],{"class":6082},[5525,9798,6086],{"class":5531},[5525,9800,9801,9803,9805,9808,9810,9812,9814,9816,9818,9820,9822],{"class":5527,"line":5883},[5525,9802,6216],{"class":6091},[5525,9804,6785],{"class":6078},[5525,9806,9807],{"class":5555},"\"(",[5525,9809,6676],{"class":6078},[5525,9811,9251],{"class":5531},[5525,9813,6797],{"class":6078},[5525,9815,5614],{"class":5555},[5525,9817,6676],{"class":6078},[5525,9819,9260],{"class":5531},[5525,9821,6797],{"class":6078},[5525,9823,7117],{"class":5555},[5525,9825,9826],{"class":5527,"line":5889},[5525,9827,6544],{"class":5531},[5525,9829,9830],{"class":5527,"line":5895},[5525,9831,9832],{"class":5545},"    # --- Лівий оператор + ---\n",[5525,9834,9835,9837,9840,9842,9844,9846,9848],{"class":5527,"line":5901},[5525,9836,6199],{"class":6078},[5525,9838,9839],{"class":6118}," __add__",[5525,9841,6147],{"class":5531},[5525,9843,6208],{"class":6207},[5525,9845,5614],{"class":5531},[5525,9847,7883],{"class":6207},[5525,9849,9850],{"class":5531},": Vector) -> Vector:\n",[5525,9852,9853,9855,9857,9859],{"class":5527,"line":5906},[5525,9854,7220],{"class":6091},[5525,9856,7902],{"class":6078},[5525,9858,7905],{"class":6118},[5525,9860,9861],{"class":5531},"(other, Vector):\n",[5525,9863,9864,9866],{"class":5527,"line":5911},[5525,9865,7233],{"class":6091},[5525,9867,7970],{"class":6078},[5525,9869,9870,9872,9875,9877,9880,9882],{"class":5527,"line":5917},[5525,9871,6216],{"class":6091},[5525,9873,9874],{"class":5531}," Vector(",[5525,9876,6208],{"class":6078},[5525,9878,9879],{"class":5531},".x + other.x, ",[5525,9881,6208],{"class":6078},[5525,9883,9884],{"class":5531},".y + other.y)\n",[5525,9886,9887],{"class":5527,"line":5923},[5525,9888,6544],{"class":5531},[5525,9890,9891],{"class":5527,"line":5929},[5525,9892,9893],{"class":5545},"    # --- Правий оператор + (для: scalar + Vector — не підходить,\n",[5525,9895,9896],{"class":5527,"line":5935},[5525,9897,9898],{"class":5545},"    #     але для Vector + Vector з іншого класу) ---\n",[5525,9900,9901,9903,9906,9908,9910,9912,9914,9916,9918],{"class":5527,"line":5941},[5525,9902,6199],{"class":6078},[5525,9904,9905],{"class":6118}," __radd__",[5525,9907,6147],{"class":5531},[5525,9909,6208],{"class":6207},[5525,9911,5614],{"class":5531},[5525,9913,7883],{"class":6207},[5525,9915,6127],{"class":5531},[5525,9917,7888],{"class":6082},[5525,9919,9920],{"class":5531},") -> Vector:\n",[5525,9922,9923],{"class":5527,"line":5947},[5525,9924,9925],{"class":5545},"        # Тут можна підтримати sum([v1, v2, v3]):\n",[5525,9927,9928],{"class":5527,"line":5953},[5525,9929,9930],{"class":5545},"        # sum() починає з 0 + v1 → 0.__add__(v1) → NotImplemented\n",[5525,9932,9933],{"class":5527,"line":5959},[5525,9934,9935],{"class":5545},"        # → v1.__radd__(0) → тут ми обробляємо int(0)\n",[5525,9937,9938,9940,9943,9945],{"class":5527,"line":5964},[5525,9939,7220],{"class":6091},[5525,9941,9942],{"class":5531}," other == ",[5525,9944,8191],{"class":5535},[5525,9946,6086],{"class":5531},[5525,9948,9949,9951,9953],{"class":5527,"line":5969},[5525,9950,7233],{"class":6091},[5525,9952,7023],{"class":6078},[5525,9954,9955],{"class":5545},"  # нейтральний елемент для sum()\n",[5525,9957,9958,9960],{"class":5527,"line":5975},[5525,9959,6216],{"class":6091},[5525,9961,7970],{"class":6078},[5525,9963,9964],{"class":5527,"line":5981},[5525,9965,6544],{"class":5531},[5525,9967,9968],{"class":5527,"line":5987},[5525,9969,9970],{"class":5545},"    # --- In-place += ---\n",[5525,9972,9973,9975,9978,9980,9982,9984,9986],{"class":5527,"line":5993},[5525,9974,6199],{"class":6078},[5525,9976,9977],{"class":6118}," __iadd__",[5525,9979,6147],{"class":5531},[5525,9981,6208],{"class":6207},[5525,9983,5614],{"class":5531},[5525,9985,7883],{"class":6207},[5525,9987,9850],{"class":5531},[5525,9989,9990,9992,9994,9996],{"class":5527,"line":5999},[5525,9991,7220],{"class":6091},[5525,9993,7902],{"class":6078},[5525,9995,7905],{"class":6118},[5525,9997,9861],{"class":5531},[5525,9999,10000,10002],{"class":5527,"line":6005},[5525,10001,7233],{"class":6091},[5525,10003,7970],{"class":6078},[5525,10005,10006],{"class":5527,"line":6011},[5525,10007,10008],{"class":5545},"        # Мутуємо self, повертаємо self — не створюємо новий об'єкт\n",[5525,10010,10011,10013],{"class":5527,"line":6016},[5525,10012,6596],{"class":6078},[5525,10014,10015],{"class":5531},".x += other.x\n",[5525,10017,10018,10020],{"class":5527,"line":6022},[5525,10019,6596],{"class":6078},[5525,10021,10022],{"class":5531},".y += other.y\n",[5525,10024,10025,10027],{"class":5527,"line":6028},[5525,10026,6216],{"class":6091},[5525,10028,10029],{"class":6078}," self\n",[5525,10031,10032],{"class":5527,"line":6034},[5525,10033,6544],{"class":5531},[5525,10035,10036],{"class":5527,"line":6040},[5525,10037,10038],{"class":5545},"    # --- Субтракція ---\n",[5525,10040,10041,10043,10046,10048,10050,10052,10054],{"class":5527,"line":6046},[5525,10042,6199],{"class":6078},[5525,10044,10045],{"class":6118}," __sub__",[5525,10047,6147],{"class":5531},[5525,10049,6208],{"class":6207},[5525,10051,5614],{"class":5531},[5525,10053,7883],{"class":6207},[5525,10055,9850],{"class":5531},[5525,10057,10058,10060,10062,10064],{"class":5527,"line":8117},[5525,10059,7220],{"class":6091},[5525,10061,7902],{"class":6078},[5525,10063,7905],{"class":6118},[5525,10065,9861],{"class":5531},[5525,10067,10068,10070],{"class":5527,"line":8128},[5525,10069,7233],{"class":6091},[5525,10071,7970],{"class":6078},[5525,10073,10074,10076,10078,10080,10083,10085],{"class":5527,"line":8135},[5525,10075,6216],{"class":6091},[5525,10077,9874],{"class":5531},[5525,10079,6208],{"class":6078},[5525,10081,10082],{"class":5531},".x - other.x, ",[5525,10084,6208],{"class":6078},[5525,10086,10087],{"class":5531},".y - other.y)\n",[5525,10089,10090],{"class":5527,"line":8145},[5525,10091,6544],{"class":5531},[5525,10093,10094],{"class":5527,"line":8150},[5525,10095,10096],{"class":5545},"    # --- Множення: вектор * скаляр ---\n",[5525,10098,10099,10101,10104,10106,10108,10110,10113,10115,10117],{"class":5527,"line":8155},[5525,10100,6199],{"class":6078},[5525,10102,10103],{"class":6118}," __mul__",[5525,10105,6147],{"class":5531},[5525,10107,6208],{"class":6207},[5525,10109,5614],{"class":5531},[5525,10111,10112],{"class":6207},"scalar",[5525,10114,6127],{"class":5531},[5525,10116,6978],{"class":6082},[5525,10118,9920],{"class":5531},[5525,10120,10121,10123,10125,10127,10130,10132,10134,10136],{"class":5527,"line":8176},[5525,10122,7220],{"class":6091},[5525,10124,7902],{"class":6078},[5525,10126,7905],{"class":6118},[5525,10128,10129],{"class":5531},"(scalar, (",[5525,10131,7656],{"class":6082},[5525,10133,5614],{"class":5531},[5525,10135,6978],{"class":6082},[5525,10137,10138],{"class":5531},")):\n",[5525,10140,10141,10143],{"class":5527,"line":8196},[5525,10142,7233],{"class":6091},[5525,10144,7970],{"class":6078},[5525,10146,10147,10149,10151,10153,10156,10158],{"class":5527,"line":8214},[5525,10148,6216],{"class":6091},[5525,10150,9874],{"class":5531},[5525,10152,6208],{"class":6078},[5525,10154,10155],{"class":5531},".x * scalar, ",[5525,10157,6208],{"class":6078},[5525,10159,10160],{"class":5531},".y * scalar)\n",[5525,10162,10163],{"class":5527,"line":8219},[5525,10164,6544],{"class":5531},[5525,10166,10167],{"class":5527,"line":8230},[5525,10168,10169],{"class":5545},"    # --- Множення: скаляр * вектор (2.0 * v) ---\n",[5525,10171,10172,10174,10177,10179,10181,10183,10185,10187,10189],{"class":5527,"line":8241},[5525,10173,6199],{"class":6078},[5525,10175,10176],{"class":6118}," __rmul__",[5525,10178,6147],{"class":5531},[5525,10180,6208],{"class":6207},[5525,10182,5614],{"class":5531},[5525,10184,10112],{"class":6207},[5525,10186,6127],{"class":5531},[5525,10188,6978],{"class":6082},[5525,10190,9920],{"class":5531},[5525,10192,10193,10195,10197,10199,10202,10205],{"class":5527,"line":8251},[5525,10194,6216],{"class":6091},[5525,10196,7023],{"class":6078},[5525,10198,5659],{"class":5531},[5525,10200,10201],{"class":6118},"__mul__",[5525,10203,10204],{"class":5531},"(scalar)  ",[5525,10206,10207],{"class":5545},"# комутативна операція\n",[5525,10209,10210],{"class":5527,"line":8261},[5525,10211,6544],{"class":5531},[5525,10213,10214],{"class":5527,"line":8266},[5525,10215,10216],{"class":5545},"    # --- Унарний мінус: -v ---\n",[5525,10218,10219,10221,10224,10226,10228],{"class":5527,"line":8272},[5525,10220,6199],{"class":6078},[5525,10222,10223],{"class":6118}," __neg__",[5525,10225,6147],{"class":5531},[5525,10227,6208],{"class":6207},[5525,10229,9920],{"class":5531},[5525,10231,10232,10234,10237,10239,10242,10244],{"class":5527,"line":8316},[5525,10233,6216],{"class":6091},[5525,10235,10236],{"class":5531}," Vector(-",[5525,10238,6208],{"class":6078},[5525,10240,10241],{"class":5531},".x, -",[5525,10243,6208],{"class":6078},[5525,10245,10246],{"class":5531},".y)\n",[5525,10248,10249],{"class":5527,"line":8329},[5525,10250,6544],{"class":5531},[5525,10252,10254],{"class":5527,"line":10253},62,[5525,10255,10256],{"class":5545},"    # --- Абсолютне значення: довжина вектора ---\n",[5525,10258,10260,10262,10265,10267,10269,10271,10273],{"class":5527,"line":10259},63,[5525,10261,6199],{"class":6078},[5525,10263,10264],{"class":6118}," __abs__",[5525,10266,6147],{"class":5531},[5525,10268,6208],{"class":6207},[5525,10270,6637],{"class":5531},[5525,10272,6978],{"class":6082},[5525,10274,6086],{"class":5531},[5525,10276,10278,10280,10283,10285,10288,10290,10292,10294,10297,10299],{"class":5527,"line":10277},64,[5525,10279,6216],{"class":6091},[5525,10281,10282],{"class":5531}," math.sqrt(",[5525,10284,6208],{"class":6078},[5525,10286,10287],{"class":5531},".x ** ",[5525,10289,8166],{"class":5535},[5525,10291,5539],{"class":5531},[5525,10293,6208],{"class":6078},[5525,10295,10296],{"class":5531},".y ** ",[5525,10298,8166],{"class":5535},[5525,10300,6778],{"class":5531},[5525,10302,10304],{"class":5527,"line":10303},65,[5525,10305,6544],{"class":5531},[5525,10307,10309],{"class":5527,"line":10308},66,[5525,10310,10311],{"class":5545},"    # --- bool: ненульовий вектор ---\n",[5525,10313,10315,10317,10320,10322,10324,10326,10328],{"class":5527,"line":10314},67,[5525,10316,6199],{"class":6078},[5525,10318,10319],{"class":6118}," __bool__",[5525,10321,6147],{"class":5531},[5525,10323,6208],{"class":6207},[5525,10325,6637],{"class":5531},[5525,10327,7893],{"class":6082},[5525,10329,6086],{"class":5531},[5525,10331,10333,10335,10338,10340,10342,10345,10347,10349],{"class":5527,"line":10332},68,[5525,10334,6216],{"class":6091},[5525,10336,10337],{"class":6082}," bool",[5525,10339,6147],{"class":5531},[5525,10341,6208],{"class":6078},[5525,10343,10344],{"class":5531},".x ",[5525,10346,6616],{"class":6091},[5525,10348,7023],{"class":6078},[5525,10350,10246],{"class":5531},[5525,10352,10354],{"class":5527,"line":10353},69,[5525,10355,6544],{"class":5531},[5525,10357,10359,10361,10363,10365,10367,10369,10371,10373,10375,10377,10379],{"class":5527,"line":10358},70,[5525,10360,6199],{"class":6078},[5525,10362,7874],{"class":6118},[5525,10364,6147],{"class":5531},[5525,10366,6208],{"class":6207},[5525,10368,5614],{"class":5531},[5525,10370,7883],{"class":6207},[5525,10372,6127],{"class":5531},[5525,10374,7888],{"class":6082},[5525,10376,6637],{"class":5531},[5525,10378,7893],{"class":6082},[5525,10380,6086],{"class":5531},[5525,10382,10384,10386,10388,10390],{"class":5527,"line":10383},71,[5525,10385,7220],{"class":6091},[5525,10387,7902],{"class":6078},[5525,10389,7905],{"class":6118},[5525,10391,9861],{"class":5531},[5525,10393,10395,10397],{"class":5527,"line":10394},72,[5525,10396,7233],{"class":6091},[5525,10398,7970],{"class":6078},[5525,10400,10402,10404,10406,10408,10410,10412],{"class":5527,"line":10401},73,[5525,10403,6216],{"class":6091},[5525,10405,7023],{"class":6078},[5525,10407,9078],{"class":5531},[5525,10409,9073],{"class":6078},[5525,10411,7023],{"class":6078},[5525,10413,9085],{"class":5531},[5525,10415,10417],{"class":5527,"line":10416},74,[5525,10418,5850],{"emptyLinePlaceholder":5849},[5525,10420,10422],{"class":5527,"line":10421},75,[5525,10423,5850],{"emptyLinePlaceholder":5849},[5525,10425,10427],{"class":5527,"line":10426},76,[5525,10428,10429],{"class":5545},"# Демонстрація\n",[5525,10431,10433,10436,10438,10440,10442],{"class":5527,"line":10432},77,[5525,10434,10435],{"class":5531},"v1 = Vector(",[5525,10437,8161],{"class":5535},[5525,10439,5614],{"class":5531},[5525,10441,8166],{"class":5535},[5525,10443,6778],{"class":5531},[5525,10445,10447,10450,10452,10454,10457],{"class":5527,"line":10446},78,[5525,10448,10449],{"class":5531},"v2 = Vector(",[5525,10451,8171],{"class":5535},[5525,10453,5614],{"class":5531},[5525,10455,10456],{"class":5535},"4",[5525,10458,6778],{"class":5531},[5525,10460,10462],{"class":5527,"line":10461},79,[5525,10463,5850],{"emptyLinePlaceholder":5849},[5525,10465,10467,10469,10472],{"class":5527,"line":10466},80,[5525,10468,6144],{"class":6118},[5525,10470,10471],{"class":5531},"(v1 + v2)          ",[5525,10473,10474],{"class":5545},"# (4, 6)\n",[5525,10476,10478,10480,10483],{"class":5527,"line":10477},81,[5525,10479,6144],{"class":6118},[5525,10481,10482],{"class":5531},"(v2 - v1)          ",[5525,10484,10485],{"class":5545},"# (2, 2)\n",[5525,10487,10489,10491,10494,10497,10500],{"class":5527,"line":10488},82,[5525,10490,6144],{"class":6118},[5525,10492,10493],{"class":5531},"(v1 * ",[5525,10495,10496],{"class":5535},"3.0",[5525,10498,10499],{"class":5531},")         ",[5525,10501,10502],{"class":5545},"# (3.0, 6.0)\n",[5525,10504,10506,10508,10510,10512,10515],{"class":5527,"line":10505},83,[5525,10507,6144],{"class":6118},[5525,10509,6147],{"class":5531},[5525,10511,9400],{"class":5535},[5525,10513,10514],{"class":5531}," * v1)         ",[5525,10516,10517],{"class":5545},"# (2.0, 4.0)  ← __rmul__ у дії\n",[5525,10519,10521,10523,10526],{"class":5527,"line":10520},84,[5525,10522,6144],{"class":6118},[5525,10524,10525],{"class":5531},"(-v1)              ",[5525,10527,10528],{"class":5545},"# (-1, -2)\n",[5525,10530,10532,10534,10536,10539,10542],{"class":5527,"line":10531},85,[5525,10533,6144],{"class":6118},[5525,10535,6147],{"class":5531},[5525,10537,10538],{"class":6118},"abs",[5525,10540,10541],{"class":5531},"(v2))          ",[5525,10543,10544],{"class":5545},"# 5.0 (теорема Піфагора: √(9+16))\n",[5525,10546,10548,10550,10552,10554,10557,10559,10562,10564,10567],{"class":5527,"line":10547},86,[5525,10549,6144],{"class":6118},[5525,10551,6147],{"class":5531},[5525,10553,7893],{"class":6082},[5525,10555,10556],{"class":5531},"(Vector(",[5525,10558,8191],{"class":5535},[5525,10560,10561],{"class":5531},",",[5525,10563,8191],{"class":5535},[5525,10565,10566],{"class":5531},")))  ",[5525,10568,10569],{"class":5545},"# False\n",[5525,10571,10573,10575,10577,10579,10582],{"class":5527,"line":10572},87,[5525,10574,6144],{"class":6118},[5525,10576,6147],{"class":5531},[5525,10578,7893],{"class":6082},[5525,10580,10581],{"class":5531},"(v1))           ",[5525,10583,8227],{"class":5545},[5525,10585,10587],{"class":5527,"line":10586},88,[5525,10588,5850],{"emptyLinePlaceholder":5849},[5525,10590,10592],{"class":5527,"line":10591},89,[5525,10593,10594],{"class":5545},"# Магія __radd__: sum() тепер працює зі списком векторів!\n",[5525,10596,10598,10601,10603,10605,10607,10610,10612,10614,10616,10618,10620,10622,10624],{"class":5527,"line":10597},90,[5525,10599,10600],{"class":5531},"vectors = [Vector(",[5525,10602,8161],{"class":5535},[5525,10604,5614],{"class":5531},[5525,10606,8191],{"class":5535},[5525,10608,10609],{"class":5531},"), Vector(",[5525,10611,8191],{"class":5535},[5525,10613,5614],{"class":5531},[5525,10615,8166],{"class":5535},[5525,10617,10609],{"class":5531},[5525,10619,8171],{"class":5535},[5525,10621,5614],{"class":5531},[5525,10623,8161],{"class":5535},[5525,10625,8313],{"class":5531},[5525,10627,10629,10632,10635,10638],{"class":5527,"line":10628},91,[5525,10630,10631],{"class":5531},"total = ",[5525,10633,10634],{"class":6118},"sum",[5525,10636,10637],{"class":5531},"(vectors)    ",[5525,10639,10640],{"class":5545},"# sum(iterable, start=0): 0 + v1 + v2 + v3\n",[5525,10642,10644,10646,10649],{"class":5527,"line":10643},92,[5525,10645,6144],{"class":6118},[5525,10647,10648],{"class":5531},"(total)            ",[5525,10650,10651],{"class":5545},"# (4, 3)\n",[5525,10653,10655],{"class":5527,"line":10654},93,[5525,10656,5850],{"emptyLinePlaceholder":5849},[5525,10658,10660],{"class":5527,"line":10659},94,[5525,10661,10662],{"class":5545},"# In-place оператор: мутує v1, не створює новий об'єкт\n",[5525,10664,10666,10669,10672],{"class":5527,"line":10665},95,[5525,10667,10668],{"class":5531},"original_id = ",[5525,10670,10671],{"class":6118},"id",[5525,10673,10674],{"class":5531},"(v1)\n",[5525,10676,10678,10681,10683,10685,10687],{"class":5527,"line":10677},96,[5525,10679,10680],{"class":5531},"v1 += Vector(",[5525,10682,8186],{"class":5535},[5525,10684,5614],{"class":5531},[5525,10686,8186],{"class":5535},[5525,10688,6778],{"class":5531},[5525,10690,10692,10694,10697],{"class":5527,"line":10691},97,[5525,10693,6144],{"class":6118},[5525,10695,10696],{"class":5531},"(v1)               ",[5525,10698,10699],{"class":5545},"# (11, 12)\n",[5525,10701,10703,10705,10707,10709,10712],{"class":5527,"line":10702},98,[5525,10704,6144],{"class":6118},[5525,10706,6147],{"class":5531},[5525,10708,10671],{"class":6118},[5525,10710,10711],{"class":5531},"(v1) == original_id)  ",[5525,10713,10714],{"class":5545},"# True — той самий об'єкт!\n",[7425,10716,10718,10726,10734,10742,10750,10762,10770,10778,10786,10793,10801,10809],{"title":10717},"python vector.py",[7429,10719,10721,7437,10724],{"className":10720},[5527],[5525,10722,7436],{"className":10723},[7435],[5607,10725,10717],{},[7429,10727,10729,10730],{"className":10728},[5527],"v1 + v2: ",[5525,10731,10733],{"className":10732},[7463],"(4, 6)",[7429,10735,10737,10738],{"className":10736},[5527],"v2 - v1: ",[5525,10739,10741],{"className":10740},[7463],"(2, 2)",[7429,10743,10745,10746],{"className":10744},[5527],"v1 * 3.0: ",[5525,10747,10749],{"className":10748},[7463],"(3.0, 6.0)",[7429,10751,10753,10754,9535,10758],{"className":10752},[5527],"2.0 * v1: ",[5525,10755,10757],{"className":10756},[7463],"(2.0, 4.0)",[5525,10759,10761],{"className":10760},[9539],"# __rmul__",[7429,10763,10765,10766],{"className":10764},[5527],"-v1: ",[5525,10767,10769],{"className":10768},[7463],"(-1, -2)",[7429,10771,10773,10774],{"className":10772},[5527],"abs(v2): ",[5525,10775,10777],{"className":10776},[8351],"5.0",[7429,10779,10781,10782],{"className":10780},[5527],"bool(Vector(0,0)): ",[5525,10783,8391],{"className":10784},[10785],"text-rose-400",[7429,10787,10789,10790],{"className":10788},[5527],"bool(v1): ",[5525,10791,8352],{"className":10792},[8351],[7429,10794,10796,10797],{"className":10795},[5527],"sum(vectors): ",[5525,10798,10800],{"className":10799},[7463],"(4, 3)",[7429,10802,10804,10805],{"className":10803},[5527],"v1 після +=: ",[5525,10806,10808],{"className":10807},[7463],"(11, 12)",[7429,10810,10812,10813],{"className":10811},[5527],"той самий об'єкт: ",[5525,10814,8352],{"className":10815},[8351],[5748,10817,10819],{"id":10818},"алгоритм-вирішення-бінарного-оператора","Алгоритм вирішення бінарного оператора",[5512,10821,10822,10823,10825,10826,10828],{},"Щоб остаточно зрозуміти, як Python вибирає між ",[5507,10824,9642],{}," та ",[5507,10827,6338],{},", розглянемо повний алгоритм:",[5790,10830,10831],{},[5516,10832,10834],{"className":5794,"code":10833,"language":5796,"meta":5521,"style":5521},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\nskinparam ArrowColor #6366f1\n\nstart\n\n:Python обчислює a + b;\n\nif (type(b) є підкласом type(a)?) then (Так)\n    :Спробувати b.__radd__(a) першим\\n(підкласи мають перевагу);\n    if (результат != NotImplemented?) then (Так)\n        :Повернути результат;\n        stop\n    endif\nendif\n\n:Спробувати a.__add__(b);\n\nif (результат != NotImplemented?) then (Так)\n    :Повернути результат;\n    stop\nelse (NotImplemented)\n    :Спробувати b.__radd__(a);\n    if (результат != NotImplemented?) then (Так)\n        :Повернути результат;\n        stop\n    else (NotImplemented)\n        :Підняти TypeError;\n        stop\n    endif\nendif\n@enduml\n",[5507,10835,10836,10840,10844,10848,10852,10856,10861,10865,10870,10874,10879,10884,10889,10894,10899,10904,10909,10913,10918,10922,10927,10932,10937,10942,10947,10951,10955,10959,10964,10969,10973,10977,10981],{"__ignoreMap":5521},[5525,10837,10838],{"class":5527,"line":5528},[5525,10839,5803],{},[5525,10841,10842],{"class":5527,"line":5549},[5525,10843,5808],{},[5525,10845,10846],{"class":5527,"line":5567},[5525,10847,5813],{},[5525,10849,10850],{"class":5527,"line":5816},[5525,10851,5819],{},[5525,10853,10854],{"class":5527,"line":5822},[5525,10855,5850],{"emptyLinePlaceholder":5849},[5525,10857,10858],{"class":5527,"line":5828},[5525,10859,10860],{},"start\n",[5525,10862,10863],{"class":5527,"line":5834},[5525,10864,5850],{"emptyLinePlaceholder":5849},[5525,10866,10867],{"class":5527,"line":5840},[5525,10868,10869],{},":Python обчислює a + b;\n",[5525,10871,10872],{"class":5527,"line":5846},[5525,10873,5850],{"emptyLinePlaceholder":5849},[5525,10875,10876],{"class":5527,"line":5853},[5525,10877,10878],{},"if (type(b) є підкласом type(a)?) then (Так)\n",[5525,10880,10881],{"class":5527,"line":5859},[5525,10882,10883],{},"    :Спробувати b.__radd__(a) першим\\n(підкласи мають перевагу);\n",[5525,10885,10886],{"class":5527,"line":5865},[5525,10887,10888],{},"    if (результат != NotImplemented?) then (Так)\n",[5525,10890,10891],{"class":5527,"line":5871},[5525,10892,10893],{},"        :Повернути результат;\n",[5525,10895,10896],{"class":5527,"line":5877},[5525,10897,10898],{},"        stop\n",[5525,10900,10901],{"class":5527,"line":5883},[5525,10902,10903],{},"    endif\n",[5525,10905,10906],{"class":5527,"line":5889},[5525,10907,10908],{},"endif\n",[5525,10910,10911],{"class":5527,"line":5895},[5525,10912,5850],{"emptyLinePlaceholder":5849},[5525,10914,10915],{"class":5527,"line":5901},[5525,10916,10917],{},":Спробувати a.__add__(b);\n",[5525,10919,10920],{"class":5527,"line":5906},[5525,10921,5850],{"emptyLinePlaceholder":5849},[5525,10923,10924],{"class":5527,"line":5911},[5525,10925,10926],{},"if (результат != NotImplemented?) then (Так)\n",[5525,10928,10929],{"class":5527,"line":5917},[5525,10930,10931],{},"    :Повернути результат;\n",[5525,10933,10934],{"class":5527,"line":5923},[5525,10935,10936],{},"    stop\n",[5525,10938,10939],{"class":5527,"line":5929},[5525,10940,10941],{},"else (NotImplemented)\n",[5525,10943,10944],{"class":5527,"line":5935},[5525,10945,10946],{},"    :Спробувати b.__radd__(a);\n",[5525,10948,10949],{"class":5527,"line":5941},[5525,10950,10888],{},[5525,10952,10953],{"class":5527,"line":5947},[5525,10954,10893],{},[5525,10956,10957],{"class":5527,"line":5953},[5525,10958,10898],{},[5525,10960,10961],{"class":5527,"line":5959},[5525,10962,10963],{},"    else (NotImplemented)\n",[5525,10965,10966],{"class":5527,"line":5964},[5525,10967,10968],{},"        :Підняти TypeError;\n",[5525,10970,10971],{"class":5527,"line":5969},[5525,10972,10898],{},[5525,10974,10975],{"class":5527,"line":5975},[5525,10976,10903],{},[5525,10978,10979],{"class":5527,"line":5981},[5525,10980,10908],{},[5525,10982,10983],{"class":5527,"line":5987},[5525,10984,6049],{},[5512,10986,10987,10988,10991,10992,6266,10995,10997,10998,11001],{},"Ця поведінка пояснює, чому ",[5507,10989,10990],{},"5 + Vector(1, 2)"," працює: ",[5507,10993,10994],{},"int.__add__(Vector)",[5507,10996,8387],{},", тоді Python пробує ",[5507,10999,11000],{},"Vector.__radd__(5)"," → успіх (якщо реалізовано).",[5748,11003,11005,11006],{"id":11004},"протокол-матричного-множення-__matmul__","Протокол матричного множення: ",[5507,11007,11008],{},"__matmul__",[5512,11010,11011,11012,11015,11016,11019,11020,11023],{},"Python 3.5 (PEP 465) додав спеціальний оператор ",[5507,11013,11014],{},"@"," для матричного множення, щоб бібліотеки на кшталт NumPy могли писати ",[5507,11017,11018],{},"A @ B"," замість ",[5507,11021,11022],{},"np.dot(A, B)",". Він слідує тій самій схемі:",[5516,11025,11027],{"className":5518,"code":11026,"language":5520,"meta":5521,"style":5521},"class Matrix:\n    \"\"\"Спрощена матриця 2x2 для демонстрації @ оператора.\"\"\"\n    \n    def __init__(self, data: list[list[float]]):\n        self.data = data\n    \n    def __repr__(self) -> str:\n        return f\"Matrix({self.data})\"\n    \n    def __matmul__(self, other: Matrix) -> Matrix:\n        \"\"\"Матричне множення через оператор @.\"\"\"\n        if not isinstance(other, Matrix):\n            return NotImplemented\n        a, b = self.data, other.data\n        return Matrix([\n            [a[0][0]*b[0][0] + a[0][1]*b[1][0],  a[0][0]*b[0][1] + a[0][1]*b[1][1]],\n            [a[1][0]*b[0][0] + a[1][1]*b[1][0],  a[1][0]*b[0][1] + a[1][1]*b[1][1]],\n        ])\n\n\nA = Matrix([[1, 2], [3, 4]])\nB = Matrix([[5, 6], [7, 8]])\nC = A @ B   # __matmul__ у дії\nprint(C)    # Matrix([[19, 22], [43, 50]])\n",[5507,11028,11029,11038,11043,11047,11070,11077,11081,11097,11115,11119,11137,11142,11153,11159,11169,11176,11250,11318,11323,11327,11331,11354,11377,11385],{"__ignoreMap":5521},[5525,11030,11031,11033,11036],{"class":5527,"line":5528},[5525,11032,6079],{"class":6078},[5525,11034,11035],{"class":6082}," Matrix",[5525,11037,6086],{"class":5531},[5525,11039,11040],{"class":5527,"line":5549},[5525,11041,11042],{"class":5555},"    \"\"\"Спрощена матриця 2x2 для демонстрації @ оператора.\"\"\"\n",[5525,11044,11045],{"class":5527,"line":5567},[5525,11046,6544],{"class":5531},[5525,11048,11049,11051,11053,11055,11057,11059,11062,11065,11067],{"class":5527,"line":5816},[5525,11050,6199],{"class":6078},[5525,11052,6551],{"class":6118},[5525,11054,6147],{"class":5531},[5525,11056,6208],{"class":6207},[5525,11058,5614],{"class":5531},[5525,11060,11061],{"class":6207},"data",[5525,11063,11064],{"class":5531},": list[list[",[5525,11066,6978],{"class":6082},[5525,11068,11069],{"class":5531},"]]):\n",[5525,11071,11072,11074],{"class":5527,"line":5822},[5525,11073,6596],{"class":6078},[5525,11075,11076],{"class":5531},".data = data\n",[5525,11078,11079],{"class":5527,"line":5828},[5525,11080,6544],{"class":5531},[5525,11082,11083,11085,11087,11089,11091,11093,11095],{"class":5527,"line":5834},[5525,11084,6199],{"class":6078},[5525,11086,6630],{"class":6118},[5525,11088,6147],{"class":5531},[5525,11090,6208],{"class":6207},[5525,11092,6637],{"class":5531},[5525,11094,6565],{"class":6082},[5525,11096,6086],{"class":5531},[5525,11098,11099,11101,11103,11106,11108,11111,11113],{"class":5527,"line":5840},[5525,11100,6216],{"class":6091},[5525,11102,6785],{"class":6078},[5525,11104,11105],{"class":5555},"\"Matrix(",[5525,11107,6676],{"class":6078},[5525,11109,11110],{"class":5531},".data",[5525,11112,6797],{"class":6078},[5525,11114,7117],{"class":5555},[5525,11116,11117],{"class":5527,"line":5846},[5525,11118,6544],{"class":5531},[5525,11120,11121,11123,11126,11128,11130,11132,11134],{"class":5527,"line":5853},[5525,11122,6199],{"class":6078},[5525,11124,11125],{"class":6118}," __matmul__",[5525,11127,6147],{"class":5531},[5525,11129,6208],{"class":6207},[5525,11131,5614],{"class":5531},[5525,11133,7883],{"class":6207},[5525,11135,11136],{"class":5531},": Matrix) -> Matrix:\n",[5525,11138,11139],{"class":5527,"line":5859},[5525,11140,11141],{"class":5555},"        \"\"\"Матричне множення через оператор @.\"\"\"\n",[5525,11143,11144,11146,11148,11150],{"class":5527,"line":5865},[5525,11145,7220],{"class":6091},[5525,11147,7902],{"class":6078},[5525,11149,7905],{"class":6118},[5525,11151,11152],{"class":5531},"(other, Matrix):\n",[5525,11154,11155,11157],{"class":5527,"line":5871},[5525,11156,7233],{"class":6091},[5525,11158,7970],{"class":6078},[5525,11160,11161,11164,11166],{"class":5527,"line":5877},[5525,11162,11163],{"class":5531},"        a, b = ",[5525,11165,6208],{"class":6078},[5525,11167,11168],{"class":5531},".data, other.data\n",[5525,11170,11171,11173],{"class":5527,"line":5883},[5525,11172,6216],{"class":6091},[5525,11174,11175],{"class":5531}," Matrix([\n",[5525,11177,11178,11181,11183,11186,11188,11191,11193,11195,11197,11200,11202,11204,11206,11208,11210,11212,11214,11217,11219,11221,11223,11225,11227,11229,11231,11233,11235,11237,11239,11241,11243,11245,11247],{"class":5527,"line":5889},[5525,11179,11180],{"class":5531},"            [a[",[5525,11182,8191],{"class":5535},[5525,11184,11185],{"class":5531},"][",[5525,11187,8191],{"class":5535},[5525,11189,11190],{"class":5531},"]*b[",[5525,11192,8191],{"class":5535},[5525,11194,11185],{"class":5531},[5525,11196,8191],{"class":5535},[5525,11198,11199],{"class":5531},"] + a[",[5525,11201,8191],{"class":5535},[5525,11203,11185],{"class":5531},[5525,11205,8161],{"class":5535},[5525,11207,11190],{"class":5531},[5525,11209,8161],{"class":5535},[5525,11211,11185],{"class":5531},[5525,11213,8191],{"class":5535},[5525,11215,11216],{"class":5531},"],  a[",[5525,11218,8191],{"class":5535},[5525,11220,11185],{"class":5531},[5525,11222,8191],{"class":5535},[5525,11224,11190],{"class":5531},[5525,11226,8191],{"class":5535},[5525,11228,11185],{"class":5531},[5525,11230,8161],{"class":5535},[5525,11232,11199],{"class":5531},[5525,11234,8191],{"class":5535},[5525,11236,11185],{"class":5531},[5525,11238,8161],{"class":5535},[5525,11240,11190],{"class":5531},[5525,11242,8161],{"class":5535},[5525,11244,11185],{"class":5531},[5525,11246,8161],{"class":5535},[5525,11248,11249],{"class":5531},"]],\n",[5525,11251,11252,11254,11256,11258,11260,11262,11264,11266,11268,11270,11272,11274,11276,11278,11280,11282,11284,11286,11288,11290,11292,11294,11296,11298,11300,11302,11304,11306,11308,11310,11312,11314,11316],{"class":5527,"line":5895},[5525,11253,11180],{"class":5531},[5525,11255,8161],{"class":5535},[5525,11257,11185],{"class":5531},[5525,11259,8191],{"class":5535},[5525,11261,11190],{"class":5531},[5525,11263,8191],{"class":5535},[5525,11265,11185],{"class":5531},[5525,11267,8191],{"class":5535},[5525,11269,11199],{"class":5531},[5525,11271,8161],{"class":5535},[5525,11273,11185],{"class":5531},[5525,11275,8161],{"class":5535},[5525,11277,11190],{"class":5531},[5525,11279,8161],{"class":5535},[5525,11281,11185],{"class":5531},[5525,11283,8191],{"class":5535},[5525,11285,11216],{"class":5531},[5525,11287,8161],{"class":5535},[5525,11289,11185],{"class":5531},[5525,11291,8191],{"class":5535},[5525,11293,11190],{"class":5531},[5525,11295,8191],{"class":5535},[5525,11297,11185],{"class":5531},[5525,11299,8161],{"class":5535},[5525,11301,11199],{"class":5531},[5525,11303,8161],{"class":5535},[5525,11305,11185],{"class":5531},[5525,11307,8161],{"class":5535},[5525,11309,11190],{"class":5531},[5525,11311,8161],{"class":5535},[5525,11313,11185],{"class":5531},[5525,11315,8161],{"class":5535},[5525,11317,11249],{"class":5531},[5525,11319,11320],{"class":5527,"line":5901},[5525,11321,11322],{"class":5531},"        ])\n",[5525,11324,11325],{"class":5527,"line":5906},[5525,11326,5850],{"emptyLinePlaceholder":5849},[5525,11328,11329],{"class":5527,"line":5911},[5525,11330,5850],{"emptyLinePlaceholder":5849},[5525,11332,11333,11336,11338,11340,11342,11345,11347,11349,11351],{"class":5527,"line":5917},[5525,11334,11335],{"class":5531},"A = Matrix([[",[5525,11337,8161],{"class":5535},[5525,11339,5614],{"class":5531},[5525,11341,8166],{"class":5535},[5525,11343,11344],{"class":5531},"], [",[5525,11346,8171],{"class":5535},[5525,11348,5614],{"class":5531},[5525,11350,10456],{"class":5535},[5525,11352,11353],{"class":5531},"]])\n",[5525,11355,11356,11359,11361,11363,11366,11368,11371,11373,11375],{"class":5527,"line":5923},[5525,11357,11358],{"class":5531},"B = Matrix([[",[5525,11360,7034],{"class":5535},[5525,11362,5614],{"class":5531},[5525,11364,11365],{"class":5535},"6",[5525,11367,11344],{"class":5531},[5525,11369,11370],{"class":5535},"7",[5525,11372,5614],{"class":5531},[5525,11374,5542],{"class":5535},[5525,11376,11353],{"class":5531},[5525,11378,11379,11382],{"class":5527,"line":5929},[5525,11380,11381],{"class":5531},"C = A @ B   ",[5525,11383,11384],{"class":5545},"# __matmul__ у дії\n",[5525,11386,11387,11389,11392],{"class":5527,"line":5935},[5525,11388,6144],{"class":6118},[5525,11390,11391],{"class":5531},"(C)    ",[5525,11393,11394],{"class":5545},"# Matrix([[19, 22], [43, 50]])\n",[5741,11396],{},[5502,11398,11400],{"id":11399},"частина-v-контейнерний-протокол","Частина V: Контейнерний протокол",[5748,11402,11404],{"id":11403},"емуляція-колекцій-повний-набір-методів","Емуляція колекцій: повний набір методів",[5512,11406,11407],{},"Контейнерний протокол дозволяє вашому класу поводитись як вбудована колекція — список, словник або множина. Ключові методи:",[6256,11409,11410,11429,11453,11461,11468,11483,11503,11512],{},[6259,11411,11414,11415,11417,11418,6494,11420,11423,11424,6266,11427,5659],{"name":11412,"type":11413},"__len__(self) -> int","Довжина","Викликається ",[5507,11416,5645],{},". Повинен повертати невід'ємне ціле число. Також неявно використовується у ",[5507,11419,6367],{},[5507,11421,11422],{},"__bool__"," не визначено: ",[5507,11425,11426],{},"len == 0",[5507,11428,8391],{},[6259,11430,11414,11433,11436,11437,11440,11441,11444,11445,11448,11449,11452],{"name":11431,"type":11432},"__getitem__(self, key)","Читання елемента",[5507,11434,11435],{},"obj[key]",". Для послідовностей ",[5507,11438,11439],{},"key"," — цілочисельний індекс або ",[5507,11442,11443],{},"slice",". Для відображень — довільний hashable ключ. При виході за межі повинен підіймати ",[5507,11446,11447],{},"IndexError"," (послідовності) або ",[5507,11450,11451],{},"KeyError"," (відображення).",[6259,11454,11414,11457,11460],{"name":11455,"type":11456},"__setitem__(self, key, value)","Запис елемента",[5507,11458,11459],{},"obj[key] = value",". Робить колекцію мутабельною.",[6259,11462,11414,11465,5659],{"name":11463,"type":11464},"__delitem__(self, key)","Видалення елемента",[5507,11466,11467],{},"del obj[key]",[6259,11469,11472,11473,6127,11476,11479,11480,11482],{"name":11470,"type":11471},"__contains__(self, item) -> bool","Перевірка належності","Викликається оператором ",[5507,11474,11475],{},"in",[5507,11477,11478],{},"item in obj",". Якщо не визначено — Python ітерує по всьому об'єкту через ",[5507,11481,5772],{}," (O(n)), тому для словників та множин важливо визначати явно (O(1)).",[6259,11484,11414,11487,5614,11489,5614,11492,11495,11496,11499,11500,5659],{"name":11485,"type":11486},"__iter__(self)","Ітерація",[5507,11488,5617],{},[5507,11490,11491],{},"list(obj)",[5507,11493,11494],{},"*unpacking",". Повинен повертати ",[5607,11497,11498],{},"ітератор"," — об'єкт з методом ",[5507,11501,11502],{},"__next__",[6259,11504,11507,11508,11511],{"name":11505,"type":11506},"__next__(self)","Наступний елемент ітератора","Повертає наступний елемент або підіймає ",[5507,11509,11510],{},"StopIteration"," коли елементи вичерпано.",[6259,11513,11414,11516,11519,11520,10825,11522,11524],{"name":11514,"type":11515},"__reversed__(self)","Зворотня ітерація",[5507,11517,11518],{},"reversed(obj)",". Якщо не визначено — Python намагається використати ",[5507,11521,5780],{},[5507,11523,5784],{}," для зворотньої ітерації.",[5748,11526,11528],{"id":11527},"практика-власна-кільцева-черга","Практика: власна кільцева черга",[5512,11530,11531,11532,11535],{},"Побудуємо ",[5507,11533,11534],{},"RingBuffer"," — кільцеву буферну структуру даних фіксованого розміру. Коли буфер повний, нові елементи перезаписують найстаріші. Це класична структура для обробки потоків даних у реальному часі.",[5516,11537,11539],{"className":5518,"code":11538,"language":5520,"meta":5521,"style":5521},"from __future__ import annotations\nfrom typing import Iterator, TypeVar, Generic\n\nT = TypeVar('T')\n\n\nclass RingBuffer(Generic[T]):\n    \"\"\"\n    Кільцева черга фіксованого розміру.\n    \n    При переповненні найстаріші елементи автоматично\n    витісняються новими — без виключень, без збоїв.\n    Ефективне використання пам'яті: фіксований розмір назавжди.\n    \"\"\"\n    \n    def __init__(self, capacity: int):\n        if capacity \u003C= 0:\n            raise ValueError(\"Ємність буфера повинна бути > 0\")\n        self._capacity = capacity\n        self._buffer: list[T | None] = [None] * capacity\n        self._head = 0   # індекс для читання (найстаріший елемент)\n        self._tail = 0   # індекс для запису (наступна вільна позиція)\n        self._size = 0   # кількість актуальних елементів\n    \n    # --- Протокол представлення ---\n    \n    def __repr__(self) -> str:\n        items = list(self)  # використовує __iter__\n        return f\"RingBuffer(capacity={self._capacity}, items={items})\"\n    \n    def __str__(self) -> str:\n        items = list(self)\n        return f\"RingBuffer[{', '.join(str(x) for x in items)}]\"\n    \n    # --- Контейнерний протокол ---\n    \n    def __len__(self) -> int:\n        \"\"\"Кількість актуальних елементів у буфері.\"\"\"\n        return self._size\n    \n    def __bool__(self) -> bool:\n        \"\"\"True якщо буфер не порожній.\"\"\"\n        return self._size > 0\n    \n    def __contains__(self, item: object) -> bool:\n        \"\"\"Перевірка наявності елемента: O(n).\"\"\"\n        for element in self:\n            if element == item:\n                return True\n        return False\n    \n    def __getitem__(self, index: int) -> T:\n        \"\"\"\n        Читання за індексом від голови (0 = найстаріший).\n        Підтримує від'ємні індекси: -1 = найновіший.\n        \"\"\"\n        if not (-self._size \u003C= index \u003C self._size):\n            raise IndexError(\n                f\"Індекс {index} виходить за межі буфера розміром {self._size}\"\n            )\n        if index \u003C 0:\n            index += self._size\n        real_index = (self._head + index) % self._capacity\n        return self._buffer[real_index]  # type: ignore[return-value]\n    \n    def __iter__(self) -> Iterator[T]:\n        \"\"\"Ітерація від найстарішого до найновішого елемента.\"\"\"\n        for i in range(self._size):\n            yield self._buffer[(self._head + i) % self._capacity]  # type: ignore[misc]\n    \n    def __reversed__(self) -> Iterator[T]:\n        \"\"\"Зворотня ітерація: від найновішого до найстарішого.\"\"\"\n        for i in range(self._size - 1, -1, -1):\n            yield self._buffer[(self._head + i) % self._capacity]  # type: ignore[misc]\n    \n    # --- Мутуючі операції ---\n    \n    def append(self, item: T) -> None:\n        \"\"\"\n        Додає елемент у кінець буфера.\n        Якщо буфер повний — витісняє найстаріший елемент.\n        \"\"\"\n        self._buffer[self._tail] = item\n        self._tail = (self._tail + 1) % self._capacity\n        \n        if self._size \u003C self._capacity:\n            self._size += 1\n        else:\n            # Буфер повний: голова теж рухається вперед (витіснення)\n            self._head = (self._head + 1) % self._capacity\n    \n    def popleft(self) -> T:\n        \"\"\"Вилучає та повертає найстаріший елемент.\"\"\"\n        if self._size == 0:\n            raise IndexError(\"popleft() з порожнього буфера\")\n        item = self._buffer[self._head]\n        self._buffer[self._head] = None  # звільняємо посилання (GC)\n        self._head = (self._head + 1) % self._capacity\n        self._size -= 1\n        return item  # type: ignore[return-value]\n\n\n# --- Демонстрація ---\n\nbuf: RingBuffer[int] = RingBuffer(capacity=4)\n\n# Наповнюємо буфер\nfor i in range(1, 5):\n    buf.append(i)\n\nprint(buf)          # RingBuffer[1, 2, 3, 4]\nprint(len(buf))     # 4\nprint(buf[0])       # 1  (найстаріший)\nprint(buf[-1])      # 4  (найновіший)\nprint(3 in buf)     # True\n\n# Витіснення: додаємо при повному буфері\nbuf.append(5)       # витісняє 1\nbuf.append(6)       # витісняє 2\nprint(buf)          # RingBuffer[3, 4, 5, 6]\n\n# Зворотня ітерація\nprint(list(reversed(buf)))  # [6, 5, 4, 3]\n\n# for-цикл через __iter__\nprint([x * 2 for x in buf])  # [6, 8, 10, 12]\n\n# popleft\noldest = buf.popleft()\nprint(f\"Вилучено: {oldest}, залишок: {buf}\")\n# Вилучено: 3, залишок: RingBuffer[4, 5, 6]\n",[5507,11540,11541,11551,11563,11567,11577,11581,11585,11595,11600,11605,11609,11614,11619,11624,11628,11632,11653,11664,11677,11684,11701,11713,11725,11737,11741,11746,11750,11766,11782,11810,11814,11830,11842,11880,11884,11889,11893,11909,11914,11923,11927,11943,11948,11960,11964,11990,11995,12009,12017,12025,12032,12036,12059,12063,12068,12073,12077,12096,12106,12132,12137,12148,12157,12172,12184,12188,12202,12207,12225,12248,12252,12265,12270,12300,12318,12322,12327,12331,12353,12357,12362,12367,12371,12383,12404,12409,12423,12434,12440,12445,12465,12469,12482,12487,12500,12513,12527,12543,12561,12571,12581,12586,12591,12597,12602,12622,12627,12633,12654,12660,12665,12676,12691,12707,12723,12739,12744,12750,12764,12776,12786,12791,12797,12817,12822,12828,12851,12856,12862,12868,12901],{"__ignoreMap":5521},[5525,11542,11543,11545,11547,11549],{"class":5527,"line":5528},[5525,11544,6512],{"class":6091},[5525,11546,7608],{"class":6207},[5525,11548,7611],{"class":6091},[5525,11550,7614],{"class":5531},[5525,11552,11553,11555,11558,11560],{"class":5527,"line":5549},[5525,11554,6512],{"class":6091},[5525,11556,11557],{"class":5531}," typing ",[5525,11559,6518],{"class":6091},[5525,11561,11562],{"class":5531}," Iterator, TypeVar, Generic\n",[5525,11564,11565],{"class":5527,"line":5567},[5525,11566,5850],{"emptyLinePlaceholder":5849},[5525,11568,11569,11572,11575],{"class":5527,"line":5816},[5525,11570,11571],{"class":5531},"T = TypeVar(",[5525,11573,11574],{"class":5555},"'T'",[5525,11576,6778],{"class":5531},[5525,11578,11579],{"class":5527,"line":5822},[5525,11580,5850],{"emptyLinePlaceholder":5849},[5525,11582,11583],{"class":5527,"line":5828},[5525,11584,5850],{"emptyLinePlaceholder":5849},[5525,11586,11587,11589,11592],{"class":5527,"line":5834},[5525,11588,6079],{"class":6078},[5525,11590,11591],{"class":6082}," RingBuffer",[5525,11593,11594],{"class":5531},"(Generic[T]):\n",[5525,11596,11597],{"class":5527,"line":5840},[5525,11598,11599],{"class":5555},"    \"\"\"\n",[5525,11601,11602],{"class":5527,"line":5846},[5525,11603,11604],{"class":5555},"    Кільцева черга фіксованого розміру.\n",[5525,11606,11607],{"class":5527,"line":5853},[5525,11608,6544],{"class":5555},[5525,11610,11611],{"class":5527,"line":5859},[5525,11612,11613],{"class":5555},"    При переповненні найстаріші елементи автоматично\n",[5525,11615,11616],{"class":5527,"line":5865},[5525,11617,11618],{"class":5555},"    витісняються новими — без виключень, без збоїв.\n",[5525,11620,11621],{"class":5527,"line":5871},[5525,11622,11623],{"class":5555},"    Ефективне використання пам'яті: фіксований розмір назавжди.\n",[5525,11625,11626],{"class":5527,"line":5877},[5525,11627,11599],{"class":5555},[5525,11629,11630],{"class":5527,"line":5883},[5525,11631,6544],{"class":5531},[5525,11633,11634,11636,11638,11640,11642,11644,11647,11649,11651],{"class":5527,"line":5889},[5525,11635,6199],{"class":6078},[5525,11637,6551],{"class":6118},[5525,11639,6147],{"class":5531},[5525,11641,6208],{"class":6207},[5525,11643,5614],{"class":5531},[5525,11645,11646],{"class":6207},"capacity",[5525,11648,6127],{"class":5531},[5525,11650,7656],{"class":6082},[5525,11652,6211],{"class":5531},[5525,11654,11655,11657,11660,11662],{"class":5527,"line":5895},[5525,11656,7220],{"class":6091},[5525,11658,11659],{"class":5531}," capacity \u003C= ",[5525,11661,8191],{"class":5535},[5525,11663,6086],{"class":5531},[5525,11665,11666,11668,11670,11672,11675],{"class":5527,"line":5901},[5525,11667,8669],{"class":6091},[5525,11669,8672],{"class":6082},[5525,11671,6147],{"class":5531},[5525,11673,11674],{"class":5555},"\"Ємність буфера повинна бути > 0\"",[5525,11676,6778],{"class":5531},[5525,11678,11679,11681],{"class":5527,"line":5906},[5525,11680,6596],{"class":6078},[5525,11682,11683],{"class":5531},"._capacity = capacity\n",[5525,11685,11686,11688,11691,11693,11696,11698],{"class":5527,"line":5911},[5525,11687,6596],{"class":6078},[5525,11689,11690],{"class":5531},"._buffer: list[T | ",[5525,11692,6585],{"class":6078},[5525,11694,11695],{"class":5531},"] = [",[5525,11697,6585],{"class":6078},[5525,11699,11700],{"class":5531},"] * capacity\n",[5525,11702,11703,11705,11708,11710],{"class":5527,"line":5917},[5525,11704,6596],{"class":6078},[5525,11706,11707],{"class":5531},"._head = ",[5525,11709,8191],{"class":5535},[5525,11711,11712],{"class":5545},"   # індекс для читання (найстаріший елемент)\n",[5525,11714,11715,11717,11720,11722],{"class":5527,"line":5923},[5525,11716,6596],{"class":6078},[5525,11718,11719],{"class":5531},"._tail = ",[5525,11721,8191],{"class":5535},[5525,11723,11724],{"class":5545},"   # індекс для запису (наступна вільна позиція)\n",[5525,11726,11727,11729,11732,11734],{"class":5527,"line":5929},[5525,11728,6596],{"class":6078},[5525,11730,11731],{"class":5531},"._size = ",[5525,11733,8191],{"class":5535},[5525,11735,11736],{"class":5545},"   # кількість актуальних елементів\n",[5525,11738,11739],{"class":5527,"line":5935},[5525,11740,6544],{"class":5531},[5525,11742,11743],{"class":5527,"line":5941},[5525,11744,11745],{"class":5545},"    # --- Протокол представлення ---\n",[5525,11747,11748],{"class":5527,"line":5947},[5525,11749,6544],{"class":5531},[5525,11751,11752,11754,11756,11758,11760,11762,11764],{"class":5527,"line":5953},[5525,11753,6199],{"class":6078},[5525,11755,6630],{"class":6118},[5525,11757,6147],{"class":5531},[5525,11759,6208],{"class":6207},[5525,11761,6637],{"class":5531},[5525,11763,6565],{"class":6082},[5525,11765,6086],{"class":5531},[5525,11767,11768,11771,11773,11775,11777,11779],{"class":5527,"line":5959},[5525,11769,11770],{"class":5531},"        items = ",[5525,11772,9575],{"class":6082},[5525,11774,6147],{"class":5531},[5525,11776,6208],{"class":6078},[5525,11778,7299],{"class":5531},[5525,11780,11781],{"class":5545},"# використовує __iter__\n",[5525,11783,11784,11786,11788,11791,11793,11796,11798,11801,11803,11806,11808],{"class":5527,"line":5964},[5525,11785,6216],{"class":6091},[5525,11787,6785],{"class":6078},[5525,11789,11790],{"class":5555},"\"RingBuffer(capacity=",[5525,11792,6676],{"class":6078},[5525,11794,11795],{"class":5531},"._capacity",[5525,11797,6797],{"class":6078},[5525,11799,11800],{"class":5555},", items=",[5525,11802,6791],{"class":6078},[5525,11804,11805],{"class":5531},"items",[5525,11807,6797],{"class":6078},[5525,11809,7117],{"class":5555},[5525,11811,11812],{"class":5527,"line":5969},[5525,11813,6544],{"class":5531},[5525,11815,11816,11818,11820,11822,11824,11826,11828],{"class":5527,"line":5975},[5525,11817,6199],{"class":6078},[5525,11819,6741],{"class":6118},[5525,11821,6147],{"class":5531},[5525,11823,6208],{"class":6207},[5525,11825,6637],{"class":5531},[5525,11827,6565],{"class":6082},[5525,11829,6086],{"class":5531},[5525,11831,11832,11834,11836,11838,11840],{"class":5527,"line":5981},[5525,11833,11770],{"class":5531},[5525,11835,9575],{"class":6082},[5525,11837,6147],{"class":5531},[5525,11839,6208],{"class":6078},[5525,11841,6778],{"class":5531},[5525,11843,11844,11846,11848,11851,11853,11856,11859,11861,11864,11867,11870,11872,11875,11877],{"class":5527,"line":5987},[5525,11845,6216],{"class":6091},[5525,11847,6785],{"class":6078},[5525,11849,11850],{"class":5555},"\"RingBuffer[",[5525,11852,6791],{"class":6078},[5525,11854,11855],{"class":5555},"', '",[5525,11857,11858],{"class":5531},".join(",[5525,11860,6565],{"class":6082},[5525,11862,11863],{"class":5531},"(x) ",[5525,11865,11866],{"class":6091},"for",[5525,11868,11869],{"class":5531}," x ",[5525,11871,11475],{"class":6091},[5525,11873,11874],{"class":5531}," items)",[5525,11876,6797],{"class":6078},[5525,11878,11879],{"class":5555},"]\"\n",[5525,11881,11882],{"class":5527,"line":5993},[5525,11883,6544],{"class":5531},[5525,11885,11886],{"class":5527,"line":5999},[5525,11887,11888],{"class":5545},"    # --- Контейнерний протокол ---\n",[5525,11890,11891],{"class":5527,"line":6005},[5525,11892,6544],{"class":5531},[5525,11894,11895,11897,11899,11901,11903,11905,11907],{"class":5527,"line":6011},[5525,11896,6199],{"class":6078},[5525,11898,6202],{"class":6118},[5525,11900,6147],{"class":5531},[5525,11902,6208],{"class":6207},[5525,11904,6637],{"class":5531},[5525,11906,7656],{"class":6082},[5525,11908,6086],{"class":5531},[5525,11910,11911],{"class":5527,"line":6016},[5525,11912,11913],{"class":5555},"        \"\"\"Кількість актуальних елементів у буфері.\"\"\"\n",[5525,11915,11916,11918,11920],{"class":5527,"line":6022},[5525,11917,6216],{"class":6091},[5525,11919,7023],{"class":6078},[5525,11921,11922],{"class":5531},"._size\n",[5525,11924,11925],{"class":5527,"line":6028},[5525,11926,6544],{"class":5531},[5525,11928,11929,11931,11933,11935,11937,11939,11941],{"class":5527,"line":6034},[5525,11930,6199],{"class":6078},[5525,11932,10319],{"class":6118},[5525,11934,6147],{"class":5531},[5525,11936,6208],{"class":6207},[5525,11938,6637],{"class":5531},[5525,11940,7893],{"class":6082},[5525,11942,6086],{"class":5531},[5525,11944,11945],{"class":5527,"line":6040},[5525,11946,11947],{"class":5555},"        \"\"\"True якщо буфер не порожній.\"\"\"\n",[5525,11949,11950,11952,11954,11957],{"class":5527,"line":6046},[5525,11951,6216],{"class":6091},[5525,11953,7023],{"class":6078},[5525,11955,11956],{"class":5531},"._size > ",[5525,11958,11959],{"class":5535},"0\n",[5525,11961,11962],{"class":5527,"line":8117},[5525,11963,6544],{"class":5531},[5525,11965,11966,11968,11971,11973,11975,11977,11980,11982,11984,11986,11988],{"class":5527,"line":8128},[5525,11967,6199],{"class":6078},[5525,11969,11970],{"class":6118}," __contains__",[5525,11972,6147],{"class":5531},[5525,11974,6208],{"class":6207},[5525,11976,5614],{"class":5531},[5525,11978,11979],{"class":6207},"item",[5525,11981,6127],{"class":5531},[5525,11983,7888],{"class":6082},[5525,11985,6637],{"class":5531},[5525,11987,7893],{"class":6082},[5525,11989,6086],{"class":5531},[5525,11991,11992],{"class":5527,"line":8135},[5525,11993,11994],{"class":5555},"        \"\"\"Перевірка наявності елемента: O(n).\"\"\"\n",[5525,11996,11997,12000,12003,12005,12007],{"class":5527,"line":8145},[5525,11998,11999],{"class":6091},"        for",[5525,12001,12002],{"class":5531}," element ",[5525,12004,11475],{"class":6091},[5525,12006,7023],{"class":6078},[5525,12008,6086],{"class":5531},[5525,12010,12011,12014],{"class":5527,"line":8150},[5525,12012,12013],{"class":6091},"            if",[5525,12015,12016],{"class":5531}," element == item:\n",[5525,12018,12019,12022],{"class":5527,"line":8155},[5525,12020,12021],{"class":6091},"                return",[5525,12023,12024],{"class":6078}," True\n",[5525,12026,12027,12029],{"class":5527,"line":8176},[5525,12028,6216],{"class":6091},[5525,12030,12031],{"class":6078}," False\n",[5525,12033,12034],{"class":5527,"line":8196},[5525,12035,6544],{"class":5531},[5525,12037,12038,12040,12043,12045,12047,12049,12052,12054,12056],{"class":5527,"line":8214},[5525,12039,6199],{"class":6078},[5525,12041,12042],{"class":6118}," __getitem__",[5525,12044,6147],{"class":5531},[5525,12046,6208],{"class":6207},[5525,12048,5614],{"class":5531},[5525,12050,12051],{"class":6207},"index",[5525,12053,6127],{"class":5531},[5525,12055,7656],{"class":6082},[5525,12057,12058],{"class":5531},") -> T:\n",[5525,12060,12061],{"class":5527,"line":8219},[5525,12062,7191],{"class":5555},[5525,12064,12065],{"class":5527,"line":8230},[5525,12066,12067],{"class":5555},"        Читання за індексом від голови (0 = найстаріший).\n",[5525,12069,12070],{"class":5527,"line":8241},[5525,12071,12072],{"class":5555},"        Підтримує від'ємні індекси: -1 = найновіший.\n",[5525,12074,12075],{"class":5527,"line":8251},[5525,12076,7191],{"class":5555},[5525,12078,12079,12081,12083,12086,12088,12091,12093],{"class":5527,"line":8261},[5525,12080,7220],{"class":6091},[5525,12082,7902],{"class":6078},[5525,12084,12085],{"class":5531}," (-",[5525,12087,6208],{"class":6078},[5525,12089,12090],{"class":5531},"._size \u003C= index \u003C ",[5525,12092,6208],{"class":6078},[5525,12094,12095],{"class":5531},"._size):\n",[5525,12097,12098,12100,12103],{"class":5527,"line":8266},[5525,12099,8669],{"class":6091},[5525,12101,12102],{"class":6082}," IndexError",[5525,12104,12105],{"class":5531},"(\n",[5525,12107,12108,12111,12114,12116,12118,12120,12123,12125,12128,12130],{"class":5527,"line":8272},[5525,12109,12110],{"class":6078},"                f",[5525,12112,12113],{"class":5555},"\"Індекс ",[5525,12115,6791],{"class":6078},[5525,12117,12051],{"class":5531},[5525,12119,6797],{"class":6078},[5525,12121,12122],{"class":5555}," виходить за межі буфера розміром ",[5525,12124,6676],{"class":6078},[5525,12126,12127],{"class":5531},"._size",[5525,12129,6797],{"class":6078},[5525,12131,6718],{"class":5555},[5525,12133,12134],{"class":5527,"line":8316},[5525,12135,12136],{"class":5531},"            )\n",[5525,12138,12139,12141,12144,12146],{"class":5527,"line":8329},[5525,12140,7220],{"class":6091},[5525,12142,12143],{"class":5531}," index \u003C ",[5525,12145,8191],{"class":5535},[5525,12147,6086],{"class":5531},[5525,12149,12150,12153,12155],{"class":5527,"line":10253},[5525,12151,12152],{"class":5531},"            index += ",[5525,12154,6208],{"class":6078},[5525,12156,11922],{"class":5531},[5525,12158,12159,12162,12164,12167,12169],{"class":5527,"line":10259},[5525,12160,12161],{"class":5531},"        real_index = (",[5525,12163,6208],{"class":6078},[5525,12165,12166],{"class":5531},"._head + index) % ",[5525,12168,6208],{"class":6078},[5525,12170,12171],{"class":5531},"._capacity\n",[5525,12173,12174,12176,12178,12181],{"class":5527,"line":10277},[5525,12175,6216],{"class":6091},[5525,12177,7023],{"class":6078},[5525,12179,12180],{"class":5531},"._buffer[real_index]  ",[5525,12182,12183],{"class":5545},"# type: ignore[return-value]\n",[5525,12185,12186],{"class":5527,"line":10303},[5525,12187,6544],{"class":5531},[5525,12189,12190,12192,12195,12197,12199],{"class":5527,"line":10308},[5525,12191,6199],{"class":6078},[5525,12193,12194],{"class":6118}," __iter__",[5525,12196,6147],{"class":5531},[5525,12198,6208],{"class":6207},[5525,12200,12201],{"class":5531},") -> Iterator[T]:\n",[5525,12203,12204],{"class":5527,"line":10314},[5525,12205,12206],{"class":5555},"        \"\"\"Ітерація від найстарішого до найновішого елемента.\"\"\"\n",[5525,12208,12209,12211,12214,12216,12219,12221,12223],{"class":5527,"line":10332},[5525,12210,11999],{"class":6091},[5525,12212,12213],{"class":5531}," i ",[5525,12215,11475],{"class":6091},[5525,12217,12218],{"class":6118}," range",[5525,12220,6147],{"class":5531},[5525,12222,6208],{"class":6078},[5525,12224,12095],{"class":5531},[5525,12226,12227,12230,12232,12235,12237,12240,12242,12245],{"class":5527,"line":10353},[5525,12228,12229],{"class":6091},"            yield",[5525,12231,7023],{"class":6078},[5525,12233,12234],{"class":5531},"._buffer[(",[5525,12236,6208],{"class":6078},[5525,12238,12239],{"class":5531},"._head + i) % ",[5525,12241,6208],{"class":6078},[5525,12243,12244],{"class":5531},"._capacity]  ",[5525,12246,12247],{"class":5545},"# type: ignore[misc]\n",[5525,12249,12250],{"class":5527,"line":10358},[5525,12251,6544],{"class":5531},[5525,12253,12254,12256,12259,12261,12263],{"class":5527,"line":10383},[5525,12255,6199],{"class":6078},[5525,12257,12258],{"class":6118}," __reversed__",[5525,12260,6147],{"class":5531},[5525,12262,6208],{"class":6207},[5525,12264,12201],{"class":5531},[5525,12266,12267],{"class":5527,"line":10394},[5525,12268,12269],{"class":5555},"        \"\"\"Зворотня ітерація: від найновішого до найстарішого.\"\"\"\n",[5525,12271,12272,12274,12276,12278,12280,12282,12284,12287,12289,12292,12294,12296,12298],{"class":5527,"line":10401},[5525,12273,11999],{"class":6091},[5525,12275,12213],{"class":5531},[5525,12277,11475],{"class":6091},[5525,12279,12218],{"class":6118},[5525,12281,6147],{"class":5531},[5525,12283,6208],{"class":6078},[5525,12285,12286],{"class":5531},"._size - ",[5525,12288,8161],{"class":5535},[5525,12290,12291],{"class":5531},", -",[5525,12293,8161],{"class":5535},[5525,12295,12291],{"class":5531},[5525,12297,8161],{"class":5535},[5525,12299,6211],{"class":5531},[5525,12301,12302,12304,12306,12308,12310,12312,12314,12316],{"class":5527,"line":10416},[5525,12303,12229],{"class":6091},[5525,12305,7023],{"class":6078},[5525,12307,12234],{"class":5531},[5525,12309,6208],{"class":6078},[5525,12311,12239],{"class":5531},[5525,12313,6208],{"class":6078},[5525,12315,12244],{"class":5531},[5525,12317,12247],{"class":5545},[5525,12319,12320],{"class":5527,"line":10421},[5525,12321,6544],{"class":5531},[5525,12323,12324],{"class":5527,"line":10426},[5525,12325,12326],{"class":5545},"    # --- Мутуючі операції ---\n",[5525,12328,12329],{"class":5527,"line":10432},[5525,12330,6544],{"class":5531},[5525,12332,12333,12335,12338,12340,12342,12344,12346,12349,12351],{"class":5527,"line":10446},[5525,12334,6199],{"class":6078},[5525,12336,12337],{"class":6118}," append",[5525,12339,6147],{"class":5531},[5525,12341,6208],{"class":6207},[5525,12343,5614],{"class":5531},[5525,12345,11979],{"class":6207},[5525,12347,12348],{"class":5531},": T) -> ",[5525,12350,6585],{"class":6078},[5525,12352,6086],{"class":5531},[5525,12354,12355],{"class":5527,"line":10461},[5525,12356,7191],{"class":5555},[5525,12358,12359],{"class":5527,"line":10466},[5525,12360,12361],{"class":5555},"        Додає елемент у кінець буфера.\n",[5525,12363,12364],{"class":5527,"line":10477},[5525,12365,12366],{"class":5555},"        Якщо буфер повний — витісняє найстаріший елемент.\n",[5525,12368,12369],{"class":5527,"line":10488},[5525,12370,7191],{"class":5555},[5525,12372,12373,12375,12378,12380],{"class":5527,"line":10505},[5525,12374,6596],{"class":6078},[5525,12376,12377],{"class":5531},"._buffer[",[5525,12379,6208],{"class":6078},[5525,12381,12382],{"class":5531},"._tail] = item\n",[5525,12384,12385,12387,12390,12392,12395,12397,12400,12402],{"class":5527,"line":10520},[5525,12386,6596],{"class":6078},[5525,12388,12389],{"class":5531},"._tail = (",[5525,12391,6208],{"class":6078},[5525,12393,12394],{"class":5531},"._tail + ",[5525,12396,8161],{"class":5535},[5525,12398,12399],{"class":5531},") % ",[5525,12401,6208],{"class":6078},[5525,12403,12171],{"class":5531},[5525,12405,12406],{"class":5527,"line":10531},[5525,12407,12408],{"class":5531},"        \n",[5525,12410,12411,12413,12415,12418,12420],{"class":5527,"line":10547},[5525,12412,7220],{"class":6091},[5525,12414,7023],{"class":6078},[5525,12416,12417],{"class":5531},"._size \u003C ",[5525,12419,6208],{"class":6078},[5525,12421,12422],{"class":5531},"._capacity:\n",[5525,12424,12425,12428,12431],{"class":5527,"line":10572},[5525,12426,12427],{"class":6078},"            self",[5525,12429,12430],{"class":5531},"._size += ",[5525,12432,12433],{"class":5535},"1\n",[5525,12435,12436,12438],{"class":5527,"line":10586},[5525,12437,7283],{"class":6091},[5525,12439,6086],{"class":5531},[5525,12441,12442],{"class":5527,"line":10591},[5525,12443,12444],{"class":5545},"            # Буфер повний: голова теж рухається вперед (витіснення)\n",[5525,12446,12447,12449,12452,12454,12457,12459,12461,12463],{"class":5527,"line":10597},[5525,12448,12427],{"class":6078},[5525,12450,12451],{"class":5531},"._head = (",[5525,12453,6208],{"class":6078},[5525,12455,12456],{"class":5531},"._head + ",[5525,12458,8161],{"class":5535},[5525,12460,12399],{"class":5531},[5525,12462,6208],{"class":6078},[5525,12464,12171],{"class":5531},[5525,12466,12467],{"class":5527,"line":10628},[5525,12468,6544],{"class":5531},[5525,12470,12471,12473,12476,12478,12480],{"class":5527,"line":10643},[5525,12472,6199],{"class":6078},[5525,12474,12475],{"class":6118}," popleft",[5525,12477,6147],{"class":5531},[5525,12479,6208],{"class":6207},[5525,12481,12058],{"class":5531},[5525,12483,12484],{"class":5527,"line":10654},[5525,12485,12486],{"class":5555},"        \"\"\"Вилучає та повертає найстаріший елемент.\"\"\"\n",[5525,12488,12489,12491,12493,12496,12498],{"class":5527,"line":10659},[5525,12490,7220],{"class":6091},[5525,12492,7023],{"class":6078},[5525,12494,12495],{"class":5531},"._size == ",[5525,12497,8191],{"class":5535},[5525,12499,6086],{"class":5531},[5525,12501,12502,12504,12506,12508,12511],{"class":5527,"line":10665},[5525,12503,8669],{"class":6091},[5525,12505,12102],{"class":6082},[5525,12507,6147],{"class":5531},[5525,12509,12510],{"class":5555},"\"popleft() з порожнього буфера\"",[5525,12512,6778],{"class":5531},[5525,12514,12515,12518,12520,12522,12524],{"class":5527,"line":10677},[5525,12516,12517],{"class":5531},"        item = ",[5525,12519,6208],{"class":6078},[5525,12521,12377],{"class":5531},[5525,12523,6208],{"class":6078},[5525,12525,12526],{"class":5531},"._head]\n",[5525,12528,12529,12531,12533,12535,12538,12540],{"class":5527,"line":10691},[5525,12530,6596],{"class":6078},[5525,12532,12377],{"class":5531},[5525,12534,6208],{"class":6078},[5525,12536,12537],{"class":5531},"._head] = ",[5525,12539,6585],{"class":6078},[5525,12541,12542],{"class":5545},"  # звільняємо посилання (GC)\n",[5525,12544,12545,12547,12549,12551,12553,12555,12557,12559],{"class":5527,"line":10702},[5525,12546,6596],{"class":6078},[5525,12548,12451],{"class":5531},[5525,12550,6208],{"class":6078},[5525,12552,12456],{"class":5531},[5525,12554,8161],{"class":5535},[5525,12556,12399],{"class":5531},[5525,12558,6208],{"class":6078},[5525,12560,12171],{"class":5531},[5525,12562,12564,12566,12569],{"class":5527,"line":12563},99,[5525,12565,6596],{"class":6078},[5525,12567,12568],{"class":5531},"._size -= ",[5525,12570,12433],{"class":5535},[5525,12572,12574,12576,12579],{"class":5527,"line":12573},100,[5525,12575,6216],{"class":6091},[5525,12577,12578],{"class":5531}," item  ",[5525,12580,12183],{"class":5545},[5525,12582,12584],{"class":5527,"line":12583},101,[5525,12585,5850],{"emptyLinePlaceholder":5849},[5525,12587,12589],{"class":5527,"line":12588},102,[5525,12590,5850],{"emptyLinePlaceholder":5849},[5525,12592,12594],{"class":5527,"line":12593},103,[5525,12595,12596],{"class":5545},"# --- Демонстрація ---\n",[5525,12598,12600],{"class":5527,"line":12599},104,[5525,12601,5850],{"emptyLinePlaceholder":5849},[5525,12603,12605,12608,12610,12613,12615,12618,12620],{"class":5527,"line":12604},105,[5525,12606,12607],{"class":5531},"buf: RingBuffer[",[5525,12609,7656],{"class":6082},[5525,12611,12612],{"class":5531},"] = RingBuffer(",[5525,12614,11646],{"class":6207},[5525,12616,12617],{"class":5531},"=",[5525,12619,10456],{"class":5535},[5525,12621,6778],{"class":5531},[5525,12623,12625],{"class":5527,"line":12624},106,[5525,12626,5850],{"emptyLinePlaceholder":5849},[5525,12628,12630],{"class":5527,"line":12629},107,[5525,12631,12632],{"class":5545},"# Наповнюємо буфер\n",[5525,12634,12636,12638,12640,12642,12644,12646,12648,12650,12652],{"class":5527,"line":12635},108,[5525,12637,11866],{"class":6091},[5525,12639,12213],{"class":5531},[5525,12641,11475],{"class":6091},[5525,12643,12218],{"class":6118},[5525,12645,6147],{"class":5531},[5525,12647,8161],{"class":5535},[5525,12649,5614],{"class":5531},[5525,12651,7034],{"class":5535},[5525,12653,6211],{"class":5531},[5525,12655,12657],{"class":5527,"line":12656},109,[5525,12658,12659],{"class":5531},"    buf.append(i)\n",[5525,12661,12663],{"class":5527,"line":12662},110,[5525,12664,5850],{"emptyLinePlaceholder":5849},[5525,12666,12668,12670,12673],{"class":5527,"line":12667},111,[5525,12669,6144],{"class":6118},[5525,12671,12672],{"class":5531},"(buf)          ",[5525,12674,12675],{"class":5545},"# RingBuffer[1, 2, 3, 4]\n",[5525,12677,12679,12681,12683,12685,12688],{"class":5527,"line":12678},112,[5525,12680,6144],{"class":6118},[5525,12682,6147],{"class":5531},[5525,12684,6150],{"class":6118},[5525,12686,12687],{"class":5531},"(buf))     ",[5525,12689,12690],{"class":5545},"# 4\n",[5525,12692,12694,12696,12699,12701,12704],{"class":5527,"line":12693},113,[5525,12695,6144],{"class":6118},[5525,12697,12698],{"class":5531},"(buf[",[5525,12700,8191],{"class":5535},[5525,12702,12703],{"class":5531},"])       ",[5525,12705,12706],{"class":5545},"# 1  (найстаріший)\n",[5525,12708,12710,12712,12715,12717,12720],{"class":5527,"line":12709},114,[5525,12711,6144],{"class":6118},[5525,12713,12714],{"class":5531},"(buf[-",[5525,12716,8161],{"class":5535},[5525,12718,12719],{"class":5531},"])      ",[5525,12721,12722],{"class":5545},"# 4  (найновіший)\n",[5525,12724,12726,12728,12730,12732,12734,12737],{"class":5527,"line":12725},115,[5525,12727,6144],{"class":6118},[5525,12729,6147],{"class":5531},[5525,12731,8171],{"class":5535},[5525,12733,8659],{"class":6091},[5525,12735,12736],{"class":5531}," buf)     ",[5525,12738,8227],{"class":5545},[5525,12740,12742],{"class":5527,"line":12741},116,[5525,12743,5850],{"emptyLinePlaceholder":5849},[5525,12745,12747],{"class":5527,"line":12746},117,[5525,12748,12749],{"class":5545},"# Витіснення: додаємо при повному буфері\n",[5525,12751,12753,12756,12758,12761],{"class":5527,"line":12752},118,[5525,12754,12755],{"class":5531},"buf.append(",[5525,12757,7034],{"class":5535},[5525,12759,12760],{"class":5531},")       ",[5525,12762,12763],{"class":5545},"# витісняє 1\n",[5525,12765,12767,12769,12771,12773],{"class":5527,"line":12766},119,[5525,12768,12755],{"class":5531},[5525,12770,11365],{"class":5535},[5525,12772,12760],{"class":5531},[5525,12774,12775],{"class":5545},"# витісняє 2\n",[5525,12777,12779,12781,12783],{"class":5527,"line":12778},120,[5525,12780,6144],{"class":6118},[5525,12782,12672],{"class":5531},[5525,12784,12785],{"class":5545},"# RingBuffer[3, 4, 5, 6]\n",[5525,12787,12789],{"class":5527,"line":12788},121,[5525,12790,5850],{"emptyLinePlaceholder":5849},[5525,12792,12794],{"class":5527,"line":12793},122,[5525,12795,12796],{"class":5545},"# Зворотня ітерація\n",[5525,12798,12800,12802,12804,12806,12808,12811,12814],{"class":5527,"line":12799},123,[5525,12801,6144],{"class":6118},[5525,12803,6147],{"class":5531},[5525,12805,9575],{"class":6082},[5525,12807,6147],{"class":5531},[5525,12809,12810],{"class":6118},"reversed",[5525,12812,12813],{"class":5531},"(buf)))  ",[5525,12815,12816],{"class":5545},"# [6, 5, 4, 3]\n",[5525,12818,12820],{"class":5527,"line":12819},124,[5525,12821,5850],{"emptyLinePlaceholder":5849},[5525,12823,12825],{"class":5527,"line":12824},125,[5525,12826,12827],{"class":5545},"# for-цикл через __iter__\n",[5525,12829,12831,12833,12836,12838,12841,12843,12845,12848],{"class":5527,"line":12830},126,[5525,12832,6144],{"class":6118},[5525,12834,12835],{"class":5531},"([x * ",[5525,12837,8166],{"class":5535},[5525,12839,12840],{"class":6091}," for",[5525,12842,11869],{"class":5531},[5525,12844,11475],{"class":6091},[5525,12846,12847],{"class":5531}," buf])  ",[5525,12849,12850],{"class":5545},"# [6, 8, 10, 12]\n",[5525,12852,12854],{"class":5527,"line":12853},127,[5525,12855,5850],{"emptyLinePlaceholder":5849},[5525,12857,12859],{"class":5527,"line":12858},128,[5525,12860,12861],{"class":5545},"# popleft\n",[5525,12863,12865],{"class":5527,"line":12864},129,[5525,12866,12867],{"class":5531},"oldest = buf.popleft()\n",[5525,12869,12871,12873,12875,12877,12880,12882,12885,12887,12890,12892,12895,12897,12899],{"class":5527,"line":12870},130,[5525,12872,6144],{"class":6118},[5525,12874,6147],{"class":5531},[5525,12876,7333],{"class":6078},[5525,12878,12879],{"class":5555},"\"Вилучено: ",[5525,12881,6791],{"class":6078},[5525,12883,12884],{"class":5531},"oldest",[5525,12886,6797],{"class":6078},[5525,12888,12889],{"class":5555},", залишок: ",[5525,12891,6791],{"class":6078},[5525,12893,12894],{"class":5531},"buf",[5525,12896,6797],{"class":6078},[5525,12898,7146],{"class":5555},[5525,12900,6778],{"class":5531},[5525,12902,12904],{"class":5527,"line":12903},131,[5525,12905,12906],{"class":5545},"# Вилучено: 3, залишок: RingBuffer[4, 5, 6]\n",[7425,12908,12910,12918,12927,12934,12941,12948,12955,12963,12971,12979],{"title":12909},"python ring_buffer.py",[7429,12911,12913,7437,12916],{"className":12912},[5527],[5525,12914,7436],{"className":12915},[7435],[5607,12917,12909],{},[7429,12919,12921,12922,12926],{"className":12920},[5527],"RingBuffer[",[5525,12923,12925],{"className":12924},[7463],"1, 2, 3, 4","]",[7429,12928,12930,12931],{"className":12929},[5527],"len: ",[5525,12932,10456],{"className":12933},[7447],[7429,12935,12937,12938],{"className":12936},[5527],"buf[0]: ",[5525,12939,8161],{"className":12940},[7447],[7429,12942,12944,12945],{"className":12943},[5527],"buf[-1]: ",[5525,12946,10456],{"className":12947},[7447],[7429,12949,12951,12952],{"className":12950},[5527],"3 in buf: ",[5525,12953,8352],{"className":12954},[8351],[7429,12956,12958,12959,12926],{"className":12957},[5527],"після витіснення: RingBuffer[",[5525,12960,12962],{"className":12961},[7463],"3, 4, 5, 6",[7429,12964,12966,12967,12926],{"className":12965},[5527],"reversed: [",[5525,12968,12970],{"className":12969},[7463],"6, 5, 4, 3",[7429,12972,12974,12975,12926],{"className":12973},[5527],"x*2: [",[5525,12976,12978],{"className":12977},[7463],"6, 8, 10, 12",[7429,12980,12982,12983,12986,12987,12926],{"className":12981},[5527],"Вилучено: ",[5525,12984,8171],{"className":12985},[7447],", залишок: RingBuffer[",[5525,12988,12990],{"className":12989},[7463],"4, 5, 6",[5748,12992,12994,12995,5539,12997],{"id":12993},"ітератор-як-окремий-обєкт-__iter__-__next__","Ітератор як окремий об'єкт: ",[5507,12996,5772],{},[5507,12998,11502],{},[5512,13000,13001,13002,13004,13005,13008,13009,13011],{},"У прикладі вище ",[5507,13003,11534],{}," використовує ",[5507,13006,13007],{},"yield"," всередині ",[5507,13010,5772],{}," — це генераторна функція, яка автоматично повертає ітератор. Але важливо розуміти, що Python розрізняє два поняття:",[13013,13014,13015,13025],"ul",{},[13016,13017,13018,13021,13022,13024],"li",{},[5607,13019,13020],{},"Ітерабельний об'єкт"," (iterable): має ",[5507,13023,5772],{},", що повертає ітератор. Може ітеруватись багаторазово.",[13016,13026,13027,13030,13031,13033,13034,13036],{},[5607,13028,13029],{},"Ітератор"," (iterator): має ",[5507,13032,11502],{},", що повертає наступний елемент або підіймає ",[5507,13035,11510],{},". Ітерується лише один раз.",[5516,13038,13040],{"className":5518,"code":13039,"language":5520,"meta":5521,"style":5521},"class CountDown:\n    \"\"\"Ітерабельний об'єкт: від n до 1.\"\"\"\n    \n    def __init__(self, start: int):\n        self.start = start\n    \n    def __iter__(self) -> CountDownIterator:\n        # Кожного разу повертаємо НОВИЙ ітератор → можна ітерувати багаторазово\n        return CountDownIterator(self.start)\n\n\nclass CountDownIterator:\n    \"\"\"Ітератор для CountDown: зберігає поточний стан обходу.\"\"\"\n    \n    def __init__(self, current: int):\n        self._current = current\n    \n    def __iter__(self) -> CountDownIterator:\n        # Ітератор теж має __iter__ (повертає себе) — вимога протоколу\n        return self\n    \n    def __next__(self) -> int:\n        if self._current \u003C= 0:\n            raise StopIteration\n        value = self._current\n        self._current -= 1\n        return value\n\n\ncountdown = CountDown(3)\n\n# Перша ітерація\nprint(list(countdown))   # [3, 2, 1]\n\n# Друга ітерація — повний обхід знову, бо __iter__ повертає новий об'єкт\nprint(list(countdown))   # [3, 2, 1]   ← не порожній!\n\n# Але безпосередньо ітератор — одноразовий\nit = iter(countdown)     # iter(obj) викликає obj.__iter__()\nprint(next(it))          # 3\nprint(next(it))          # 2\nprint(list(it))          # [1]  ← залишок\nprint(list(it))          # []   ← вичерпано\n",[5507,13041,13042,13051,13056,13060,13081,13088,13092,13105,13110,13122,13126,13130,13139,13144,13148,13169,13176,13180,13192,13197,13203,13207,13224,13237,13244,13254,13263,13270,13274,13278,13287,13291,13296,13310,13314,13319,13332,13336,13341,13355,13370,13383,13396],{"__ignoreMap":5521},[5525,13043,13044,13046,13049],{"class":5527,"line":5528},[5525,13045,6079],{"class":6078},[5525,13047,13048],{"class":6082}," CountDown",[5525,13050,6086],{"class":5531},[5525,13052,13053],{"class":5527,"line":5549},[5525,13054,13055],{"class":5555},"    \"\"\"Ітерабельний об'єкт: від n до 1.\"\"\"\n",[5525,13057,13058],{"class":5527,"line":5567},[5525,13059,6544],{"class":5531},[5525,13061,13062,13064,13066,13068,13070,13072,13075,13077,13079],{"class":5527,"line":5816},[5525,13063,6199],{"class":6078},[5525,13065,6551],{"class":6118},[5525,13067,6147],{"class":5531},[5525,13069,6208],{"class":6207},[5525,13071,5614],{"class":5531},[5525,13073,13074],{"class":6207},"start",[5525,13076,6127],{"class":5531},[5525,13078,7656],{"class":6082},[5525,13080,6211],{"class":5531},[5525,13082,13083,13085],{"class":5527,"line":5822},[5525,13084,6596],{"class":6078},[5525,13086,13087],{"class":5531},".start = start\n",[5525,13089,13090],{"class":5527,"line":5828},[5525,13091,6544],{"class":5531},[5525,13093,13094,13096,13098,13100,13102],{"class":5527,"line":5834},[5525,13095,6199],{"class":6078},[5525,13097,12194],{"class":6118},[5525,13099,6147],{"class":5531},[5525,13101,6208],{"class":6207},[5525,13103,13104],{"class":5531},") -> CountDownIterator:\n",[5525,13106,13107],{"class":5527,"line":5840},[5525,13108,13109],{"class":5545},"        # Кожного разу повертаємо НОВИЙ ітератор → можна ітерувати багаторазово\n",[5525,13111,13112,13114,13117,13119],{"class":5527,"line":5846},[5525,13113,6216],{"class":6091},[5525,13115,13116],{"class":5531}," CountDownIterator(",[5525,13118,6208],{"class":6078},[5525,13120,13121],{"class":5531},".start)\n",[5525,13123,13124],{"class":5527,"line":5853},[5525,13125,5850],{"emptyLinePlaceholder":5849},[5525,13127,13128],{"class":5527,"line":5859},[5525,13129,5850],{"emptyLinePlaceholder":5849},[5525,13131,13132,13134,13137],{"class":5527,"line":5865},[5525,13133,6079],{"class":6078},[5525,13135,13136],{"class":6082}," CountDownIterator",[5525,13138,6086],{"class":5531},[5525,13140,13141],{"class":5527,"line":5871},[5525,13142,13143],{"class":5555},"    \"\"\"Ітератор для CountDown: зберігає поточний стан обходу.\"\"\"\n",[5525,13145,13146],{"class":5527,"line":5877},[5525,13147,6544],{"class":5531},[5525,13149,13150,13152,13154,13156,13158,13160,13163,13165,13167],{"class":5527,"line":5883},[5525,13151,6199],{"class":6078},[5525,13153,6551],{"class":6118},[5525,13155,6147],{"class":5531},[5525,13157,6208],{"class":6207},[5525,13159,5614],{"class":5531},[5525,13161,13162],{"class":6207},"current",[5525,13164,6127],{"class":5531},[5525,13166,7656],{"class":6082},[5525,13168,6211],{"class":5531},[5525,13170,13171,13173],{"class":5527,"line":5889},[5525,13172,6596],{"class":6078},[5525,13174,13175],{"class":5531},"._current = current\n",[5525,13177,13178],{"class":5527,"line":5895},[5525,13179,6544],{"class":5531},[5525,13181,13182,13184,13186,13188,13190],{"class":5527,"line":5901},[5525,13183,6199],{"class":6078},[5525,13185,12194],{"class":6118},[5525,13187,6147],{"class":5531},[5525,13189,6208],{"class":6207},[5525,13191,13104],{"class":5531},[5525,13193,13194],{"class":5527,"line":5906},[5525,13195,13196],{"class":5545},"        # Ітератор теж має __iter__ (повертає себе) — вимога протоколу\n",[5525,13198,13199,13201],{"class":5527,"line":5911},[5525,13200,6216],{"class":6091},[5525,13202,10029],{"class":6078},[5525,13204,13205],{"class":5527,"line":5917},[5525,13206,6544],{"class":5531},[5525,13208,13209,13211,13214,13216,13218,13220,13222],{"class":5527,"line":5923},[5525,13210,6199],{"class":6078},[5525,13212,13213],{"class":6118}," __next__",[5525,13215,6147],{"class":5531},[5525,13217,6208],{"class":6207},[5525,13219,6637],{"class":5531},[5525,13221,7656],{"class":6082},[5525,13223,6086],{"class":5531},[5525,13225,13226,13228,13230,13233,13235],{"class":5527,"line":5929},[5525,13227,7220],{"class":6091},[5525,13229,7023],{"class":6078},[5525,13231,13232],{"class":5531},"._current \u003C= ",[5525,13234,8191],{"class":5535},[5525,13236,6086],{"class":5531},[5525,13238,13239,13241],{"class":5527,"line":5935},[5525,13240,8669],{"class":6091},[5525,13242,13243],{"class":6082}," StopIteration\n",[5525,13245,13246,13249,13251],{"class":5527,"line":5941},[5525,13247,13248],{"class":5531},"        value = ",[5525,13250,6208],{"class":6078},[5525,13252,13253],{"class":5531},"._current\n",[5525,13255,13256,13258,13261],{"class":5527,"line":5947},[5525,13257,6596],{"class":6078},[5525,13259,13260],{"class":5531},"._current -= ",[5525,13262,12433],{"class":5535},[5525,13264,13265,13267],{"class":5527,"line":5953},[5525,13266,6216],{"class":6091},[5525,13268,13269],{"class":5531}," value\n",[5525,13271,13272],{"class":5527,"line":5959},[5525,13273,5850],{"emptyLinePlaceholder":5849},[5525,13275,13276],{"class":5527,"line":5964},[5525,13277,5850],{"emptyLinePlaceholder":5849},[5525,13279,13280,13283,13285],{"class":5527,"line":5969},[5525,13281,13282],{"class":5531},"countdown = CountDown(",[5525,13284,8171],{"class":5535},[5525,13286,6778],{"class":5531},[5525,13288,13289],{"class":5527,"line":5975},[5525,13290,5850],{"emptyLinePlaceholder":5849},[5525,13292,13293],{"class":5527,"line":5981},[5525,13294,13295],{"class":5545},"# Перша ітерація\n",[5525,13297,13298,13300,13302,13304,13307],{"class":5527,"line":5987},[5525,13299,6144],{"class":6118},[5525,13301,6147],{"class":5531},[5525,13303,9575],{"class":6082},[5525,13305,13306],{"class":5531},"(countdown))   ",[5525,13308,13309],{"class":5545},"# [3, 2, 1]\n",[5525,13311,13312],{"class":5527,"line":5993},[5525,13313,5850],{"emptyLinePlaceholder":5849},[5525,13315,13316],{"class":5527,"line":5999},[5525,13317,13318],{"class":5545},"# Друга ітерація — повний обхід знову, бо __iter__ повертає новий об'єкт\n",[5525,13320,13321,13323,13325,13327,13329],{"class":5527,"line":6005},[5525,13322,6144],{"class":6118},[5525,13324,6147],{"class":5531},[5525,13326,9575],{"class":6082},[5525,13328,13306],{"class":5531},[5525,13330,13331],{"class":5545},"# [3, 2, 1]   ← не порожній!\n",[5525,13333,13334],{"class":5527,"line":6011},[5525,13335,5850],{"emptyLinePlaceholder":5849},[5525,13337,13338],{"class":5527,"line":6016},[5525,13339,13340],{"class":5545},"# Але безпосередньо ітератор — одноразовий\n",[5525,13342,13343,13346,13349,13352],{"class":5527,"line":6022},[5525,13344,13345],{"class":5531},"it = ",[5525,13347,13348],{"class":6118},"iter",[5525,13350,13351],{"class":5531},"(countdown)     ",[5525,13353,13354],{"class":5545},"# iter(obj) викликає obj.__iter__()\n",[5525,13356,13357,13359,13361,13364,13367],{"class":5527,"line":6028},[5525,13358,6144],{"class":6118},[5525,13360,6147],{"class":5531},[5525,13362,13363],{"class":6118},"next",[5525,13365,13366],{"class":5531},"(it))          ",[5525,13368,13369],{"class":5545},"# 3\n",[5525,13371,13372,13374,13376,13378,13380],{"class":5527,"line":6034},[5525,13373,6144],{"class":6118},[5525,13375,6147],{"class":5531},[5525,13377,13363],{"class":6118},[5525,13379,13366],{"class":5531},[5525,13381,13382],{"class":5545},"# 2\n",[5525,13384,13385,13387,13389,13391,13393],{"class":5527,"line":6040},[5525,13386,6144],{"class":6118},[5525,13388,6147],{"class":5531},[5525,13390,9575],{"class":6082},[5525,13392,13366],{"class":5531},[5525,13394,13395],{"class":5545},"# [1]  ← залишок\n",[5525,13397,13398,13400,13402,13404,13406],{"class":5527,"line":6046},[5525,13399,6144],{"class":6118},[5525,13401,6147],{"class":5531},[5525,13403,9575],{"class":6082},[5525,13405,13366],{"class":5531},[5525,13407,13408],{"class":5545},"# []   ← вичерпано\n",[6902,13410,13411,13413,13414,13417,13418,13421,13422,13425,13426,13428,13429,13432,13433,13435,13436,5659],{},[5507,13412,5617],{}," під капотом виконує: ",[5507,13415,13416],{},"_iter = iter(obj)"," (виклик ",[5507,13419,13420],{},"obj.__iter__()","), потім у циклі ",[5507,13423,13424],{},"x = next(_iter)"," до ",[5507,13427,11510],{},". Вбудована функція ",[5507,13430,13431],{},"iter()"," перевіряє також наявність ",[5507,13434,5784],{}," — для зворотньої сумісності зі старими класами, що не мають ",[5507,13437,5772],{},[5741,13439],{},[5502,13441,13443,13444],{"id":13442},"частина-vi-протокол-виклику-__call__","Частина VI: Протокол виклику — ",[5507,13445,6379],{},[5748,13447,13449],{"id":13448},"обєкти-як-функції","Об'єкти як функції",[5512,13451,6922,13452,13454,13455,13458],{},[5507,13453,6379],{}," перетворює екземпляр класу на ",[5607,13456,13457],{},"callable"," — об'єкт, який можна викликати з дужками, як функцію. Це відкриває архітектурний простір між функціями та класами: callable-об'єкт може зберігати стан між викликами, на відміну від звичайної функції.",[5516,13460,13462],{"className":5518,"code":13461,"language":5520,"meta":5521,"style":5521},"class Multiplier:\n    \"\"\"Callable-об'єкт: множить вхідне значення на фіксований коефіцієнт.\"\"\"\n    \n    def __init__(self, factor: float):\n        self.factor = factor\n    \n    def __repr__(self) -> str:\n        return f\"Multiplier(factor={self.factor})\"\n    \n    def __call__(self, value: float) -> float:\n        \"\"\"Викликається як: multiplier(value)\"\"\"\n        return value * self.factor\n\n\ndouble = Multiplier(2)\ntriple = Multiplier(3)\n\nprint(double(5))    # 10.0\nprint(triple(5))    # 15.0\nprint(double(triple(4)))  # double(12) = 24.0\n\n# Перевірка callable\nimport inspect\nprint(callable(double))            # True\nprint(inspect.isfunction(double))  # False — це не функція, а callable об'єкт\n",[5507,13463,13464,13473,13478,13482,13503,13510,13514,13530,13548,13552,13578,13583,13595,13599,13603,13612,13621,13625,13640,13654,13668,13672,13677,13684,13697],{"__ignoreMap":5521},[5525,13465,13466,13468,13471],{"class":5527,"line":5528},[5525,13467,6079],{"class":6078},[5525,13469,13470],{"class":6082}," Multiplier",[5525,13472,6086],{"class":5531},[5525,13474,13475],{"class":5527,"line":5549},[5525,13476,13477],{"class":5555},"    \"\"\"Callable-об'єкт: множить вхідне значення на фіксований коефіцієнт.\"\"\"\n",[5525,13479,13480],{"class":5527,"line":5567},[5525,13481,6544],{"class":5531},[5525,13483,13484,13486,13488,13490,13492,13494,13497,13499,13501],{"class":5527,"line":5816},[5525,13485,6199],{"class":6078},[5525,13487,6551],{"class":6118},[5525,13489,6147],{"class":5531},[5525,13491,6208],{"class":6207},[5525,13493,5614],{"class":5531},[5525,13495,13496],{"class":6207},"factor",[5525,13498,6127],{"class":5531},[5525,13500,6978],{"class":6082},[5525,13502,6211],{"class":5531},[5525,13504,13505,13507],{"class":5527,"line":5822},[5525,13506,6596],{"class":6078},[5525,13508,13509],{"class":5531},".factor = factor\n",[5525,13511,13512],{"class":5527,"line":5828},[5525,13513,6544],{"class":5531},[5525,13515,13516,13518,13520,13522,13524,13526,13528],{"class":5527,"line":5834},[5525,13517,6199],{"class":6078},[5525,13519,6630],{"class":6118},[5525,13521,6147],{"class":5531},[5525,13523,6208],{"class":6207},[5525,13525,6637],{"class":5531},[5525,13527,6565],{"class":6082},[5525,13529,6086],{"class":5531},[5525,13531,13532,13534,13536,13539,13541,13544,13546],{"class":5527,"line":5840},[5525,13533,6216],{"class":6091},[5525,13535,6785],{"class":6078},[5525,13537,13538],{"class":5555},"\"Multiplier(factor=",[5525,13540,6676],{"class":6078},[5525,13542,13543],{"class":5531},".factor",[5525,13545,6797],{"class":6078},[5525,13547,7117],{"class":5555},[5525,13549,13550],{"class":5527,"line":5846},[5525,13551,6544],{"class":5531},[5525,13553,13554,13556,13559,13561,13563,13565,13568,13570,13572,13574,13576],{"class":5527,"line":5853},[5525,13555,6199],{"class":6078},[5525,13557,13558],{"class":6118}," __call__",[5525,13560,6147],{"class":5531},[5525,13562,6208],{"class":6207},[5525,13564,5614],{"class":5531},[5525,13566,13567],{"class":6207},"value",[5525,13569,6127],{"class":5531},[5525,13571,6978],{"class":6082},[5525,13573,6637],{"class":5531},[5525,13575,6978],{"class":6082},[5525,13577,6086],{"class":5531},[5525,13579,13580],{"class":5527,"line":5859},[5525,13581,13582],{"class":5555},"        \"\"\"Викликається як: multiplier(value)\"\"\"\n",[5525,13584,13585,13587,13590,13592],{"class":5527,"line":5865},[5525,13586,6216],{"class":6091},[5525,13588,13589],{"class":5531}," value * ",[5525,13591,6208],{"class":6078},[5525,13593,13594],{"class":5531},".factor\n",[5525,13596,13597],{"class":5527,"line":5871},[5525,13598,5850],{"emptyLinePlaceholder":5849},[5525,13600,13601],{"class":5527,"line":5877},[5525,13602,5850],{"emptyLinePlaceholder":5849},[5525,13604,13605,13608,13610],{"class":5527,"line":5883},[5525,13606,13607],{"class":5531},"double = Multiplier(",[5525,13609,8166],{"class":5535},[5525,13611,6778],{"class":5531},[5525,13613,13614,13617,13619],{"class":5527,"line":5889},[5525,13615,13616],{"class":5531},"triple = Multiplier(",[5525,13618,8171],{"class":5535},[5525,13620,6778],{"class":5531},[5525,13622,13623],{"class":5527,"line":5895},[5525,13624,5850],{"emptyLinePlaceholder":5849},[5525,13626,13627,13629,13632,13634,13637],{"class":5527,"line":5901},[5525,13628,6144],{"class":6118},[5525,13630,13631],{"class":5531},"(double(",[5525,13633,7034],{"class":5535},[5525,13635,13636],{"class":5531},"))    ",[5525,13638,13639],{"class":5545},"# 10.0\n",[5525,13641,13642,13644,13647,13649,13651],{"class":5527,"line":5906},[5525,13643,6144],{"class":6118},[5525,13645,13646],{"class":5531},"(triple(",[5525,13648,7034],{"class":5535},[5525,13650,13636],{"class":5531},[5525,13652,13653],{"class":5545},"# 15.0\n",[5525,13655,13656,13658,13661,13663,13665],{"class":5527,"line":5911},[5525,13657,6144],{"class":6118},[5525,13659,13660],{"class":5531},"(double(triple(",[5525,13662,10456],{"class":5535},[5525,13664,10566],{"class":5531},[5525,13666,13667],{"class":5545},"# double(12) = 24.0\n",[5525,13669,13670],{"class":5527,"line":5917},[5525,13671,5850],{"emptyLinePlaceholder":5849},[5525,13673,13674],{"class":5527,"line":5923},[5525,13675,13676],{"class":5545},"# Перевірка callable\n",[5525,13678,13679,13681],{"class":5527,"line":5929},[5525,13680,6518],{"class":6091},[5525,13682,13683],{"class":5531}," inspect\n",[5525,13685,13686,13688,13690,13692,13695],{"class":5527,"line":5935},[5525,13687,6144],{"class":6118},[5525,13689,6147],{"class":5531},[5525,13691,13457],{"class":6118},[5525,13693,13694],{"class":5531},"(double))            ",[5525,13696,8227],{"class":5545},[5525,13698,13699,13701,13704],{"class":5527,"line":5941},[5525,13700,6144],{"class":6118},[5525,13702,13703],{"class":5531},"(inspect.isfunction(double))  ",[5525,13705,13706],{"class":5545},"# False — це не функція, а callable об'єкт\n",[5748,13708,13710],{"id":13709},"практичний-сценарій-lru-кеш-як-callable-клас","Практичний сценарій: LRU-кеш як callable-клас",[5512,13712,13713,13714,5728,13716,13719],{},"Найпоширеніший виробничий сценарій для ",[5507,13715,6379],{},[5607,13717,13718],{},"декоратори у вигляді класів",". Клас-декоратор може зберігати стан (наприклад, кеш результатів, лічильник викликів, дані авторизації) між викликами.",[5516,13721,13723],{"className":5518,"code":13722,"language":5520,"meta":5521,"style":5521},"from __future__ import annotations\nfrom collections import OrderedDict\nfrom typing import Callable, TypeVar, ParamSpec\nimport functools\n\nP = ParamSpec('P')\nR = TypeVar('R')\n\n\nclass LRUCache:\n    \"\"\"\n    Декоратор-клас: кешує результати функції з витісненням\n    найменш нещодавно використаних (Least Recently Used) записів.\n    \n    Використання:\n        @LRUCache(maxsize=128)\n        def expensive_function(x): ...\n    \"\"\"\n    \n    def __init__(self, maxsize: int = 128):\n        self.maxsize = maxsize\n        self._cache: OrderedDict = OrderedDict()\n        self._hits = 0\n        self._misses = 0\n        self._func: Callable | None = None\n    \n    def __call__(self, *args, **kwargs):\n        \"\"\"\n        Два режими роботи:\n        1. Якщо func ще не встановлено (@LRUCache(128)) → отримуємо функцію\n        2. Якщо func встановлено → виконуємо з кешуванням\n        \"\"\"\n        if self._func is None:\n            # Перший виклик: args[0] — це декорована функція\n            func = args[0]\n            self._func = func\n            functools.update_wrapper(self, func)\n            return self\n        \n        # Другий+ виклики: args — це аргументи декорованої функції\n        key = (args, tuple(sorted(kwargs.items())))\n        \n        if key in self._cache:\n            # Cache hit: переміщуємо на кінець (нещодавно використаний)\n            self._cache.move_to_end(key)\n            self._hits += 1\n            return self._cache[key]\n        \n        # Cache miss: обчислюємо результат\n        result = self._func(*args, **kwargs)\n        self._cache[key] = result\n        self._misses += 1\n        \n        # Витіснення найстарішого запису при переповненні\n        if len(self._cache) > self.maxsize:\n            self._cache.popitem(last=False)\n        \n        return result\n    \n    @property\n    def cache_info(self) -> dict:\n        return {\n            \"hits\": self._hits,\n            \"misses\": self._misses,\n            \"maxsize\": self.maxsize,\n            \"currsize\": len(self._cache),\n        }\n    \n    def cache_clear(self) -> None:\n        self._cache.clear()\n        self._hits = 0\n        self._misses = 0\n\n\n# Декорування: @LRUCache(maxsize=4) → LRUCache(4).__call__(fibonacci)\n@LRUCache(maxsize=4)\ndef fibonacci(n: int) -> int:\n    \"\"\"Класичний рекурсивний Fibonacci — без кешу дуже повільний.\"\"\"\n    if n \u003C= 1:\n        return n\n    return fibonacci(n - 1) + fibonacci(n - 2)\n\n\nprint(fibonacci(10))   # 55\nprint(fibonacci(10))   # 55 (з кешу)\nprint(fibonacci(8))    # 21\nprint(fibonacci.cache_info)\n# {'hits': ..., 'misses': ..., 'maxsize': 4, 'currsize': 4}\n",[5507,13724,13725,13735,13747,13758,13765,13769,13779,13789,13793,13797,13806,13810,13815,13820,13824,13829,13834,13839,13843,13847,13873,13880,13887,13896,13905,13919,13923,13947,13951,13956,13961,13966,13970,13986,13991,14001,14008,14018,14024,14028,14033,14047,14051,14065,14070,14077,14086,14095,14099,14104,14114,14121,14130,14134,14139,14158,14174,14178,14185,14189,14195,14212,14219,14231,14243,14255,14271,14276,14280,14297,14304,14312,14320,14324,14328,14333,14348,14371,14376,14388,14395,14412,14416,14420,14435,14448,14461,14468],{"__ignoreMap":5521},[5525,13726,13727,13729,13731,13733],{"class":5527,"line":5528},[5525,13728,6512],{"class":6091},[5525,13730,7608],{"class":6207},[5525,13732,7611],{"class":6091},[5525,13734,7614],{"class":5531},[5525,13736,13737,13739,13742,13744],{"class":5527,"line":5549},[5525,13738,6512],{"class":6091},[5525,13740,13741],{"class":5531}," collections ",[5525,13743,6518],{"class":6091},[5525,13745,13746],{"class":5531}," OrderedDict\n",[5525,13748,13749,13751,13753,13755],{"class":5527,"line":5567},[5525,13750,6512],{"class":6091},[5525,13752,11557],{"class":5531},[5525,13754,6518],{"class":6091},[5525,13756,13757],{"class":5531}," Callable, TypeVar, ParamSpec\n",[5525,13759,13760,13762],{"class":5527,"line":5816},[5525,13761,6518],{"class":6091},[5525,13763,13764],{"class":5531}," functools\n",[5525,13766,13767],{"class":5527,"line":5822},[5525,13768,5850],{"emptyLinePlaceholder":5849},[5525,13770,13771,13774,13777],{"class":5527,"line":5828},[5525,13772,13773],{"class":5531},"P = ParamSpec(",[5525,13775,13776],{"class":5555},"'P'",[5525,13778,6778],{"class":5531},[5525,13780,13781,13784,13787],{"class":5527,"line":5834},[5525,13782,13783],{"class":5531},"R = TypeVar(",[5525,13785,13786],{"class":5555},"'R'",[5525,13788,6778],{"class":5531},[5525,13790,13791],{"class":5527,"line":5840},[5525,13792,5850],{"emptyLinePlaceholder":5849},[5525,13794,13795],{"class":5527,"line":5846},[5525,13796,5850],{"emptyLinePlaceholder":5849},[5525,13798,13799,13801,13804],{"class":5527,"line":5853},[5525,13800,6079],{"class":6078},[5525,13802,13803],{"class":6082}," LRUCache",[5525,13805,6086],{"class":5531},[5525,13807,13808],{"class":5527,"line":5859},[5525,13809,11599],{"class":5555},[5525,13811,13812],{"class":5527,"line":5865},[5525,13813,13814],{"class":5555},"    Декоратор-клас: кешує результати функції з витісненням\n",[5525,13816,13817],{"class":5527,"line":5871},[5525,13818,13819],{"class":5555},"    найменш нещодавно використаних (Least Recently Used) записів.\n",[5525,13821,13822],{"class":5527,"line":5877},[5525,13823,6544],{"class":5555},[5525,13825,13826],{"class":5527,"line":5883},[5525,13827,13828],{"class":5555},"    Використання:\n",[5525,13830,13831],{"class":5527,"line":5889},[5525,13832,13833],{"class":5555},"        @LRUCache(maxsize=128)\n",[5525,13835,13836],{"class":5527,"line":5895},[5525,13837,13838],{"class":5555},"        def expensive_function(x): ...\n",[5525,13840,13841],{"class":5527,"line":5901},[5525,13842,11599],{"class":5555},[5525,13844,13845],{"class":5527,"line":5906},[5525,13846,6544],{"class":5531},[5525,13848,13849,13851,13853,13855,13857,13859,13862,13864,13866,13868,13871],{"class":5527,"line":5911},[5525,13850,6199],{"class":6078},[5525,13852,6551],{"class":6118},[5525,13854,6147],{"class":5531},[5525,13856,6208],{"class":6207},[5525,13858,5614],{"class":5531},[5525,13860,13861],{"class":6207},"maxsize",[5525,13863,6127],{"class":5531},[5525,13865,7656],{"class":6082},[5525,13867,6121],{"class":5531},[5525,13869,13870],{"class":5535},"128",[5525,13872,6211],{"class":5531},[5525,13874,13875,13877],{"class":5527,"line":5917},[5525,13876,6596],{"class":6078},[5525,13878,13879],{"class":5531},".maxsize = maxsize\n",[5525,13881,13882,13884],{"class":5527,"line":5923},[5525,13883,6596],{"class":6078},[5525,13885,13886],{"class":5531},"._cache: OrderedDict = OrderedDict()\n",[5525,13888,13889,13891,13894],{"class":5527,"line":5929},[5525,13890,6596],{"class":6078},[5525,13892,13893],{"class":5531},"._hits = ",[5525,13895,11959],{"class":5535},[5525,13897,13898,13900,13903],{"class":5527,"line":5935},[5525,13899,6596],{"class":6078},[5525,13901,13902],{"class":5531},"._misses = ",[5525,13904,11959],{"class":5535},[5525,13906,13907,13909,13912,13914,13916],{"class":5527,"line":5941},[5525,13908,6596],{"class":6078},[5525,13910,13911],{"class":5531},"._func: Callable | ",[5525,13913,6585],{"class":6078},[5525,13915,6121],{"class":5531},[5525,13917,13918],{"class":6078},"None\n",[5525,13920,13921],{"class":5527,"line":5947},[5525,13922,6544],{"class":5531},[5525,13924,13925,13927,13929,13931,13933,13936,13939,13942,13945],{"class":5527,"line":5953},[5525,13926,6199],{"class":6078},[5525,13928,13558],{"class":6118},[5525,13930,6147],{"class":5531},[5525,13932,6208],{"class":6207},[5525,13934,13935],{"class":5531},", *",[5525,13937,13938],{"class":6207},"args",[5525,13940,13941],{"class":5531},", **",[5525,13943,13944],{"class":6207},"kwargs",[5525,13946,6211],{"class":5531},[5525,13948,13949],{"class":5527,"line":5959},[5525,13950,7191],{"class":5555},[5525,13952,13953],{"class":5527,"line":5964},[5525,13954,13955],{"class":5555},"        Два режими роботи:\n",[5525,13957,13958],{"class":5527,"line":5969},[5525,13959,13960],{"class":5555},"        1. Якщо func ще не встановлено (@LRUCache(128)) → отримуємо функцію\n",[5525,13962,13963],{"class":5527,"line":5975},[5525,13964,13965],{"class":5555},"        2. Якщо func встановлено → виконуємо з кешуванням\n",[5525,13967,13968],{"class":5527,"line":5981},[5525,13969,7191],{"class":5555},[5525,13971,13972,13974,13976,13979,13981,13984],{"class":5527,"line":5987},[5525,13973,7220],{"class":6091},[5525,13975,7023],{"class":6078},[5525,13977,13978],{"class":5531},"._func ",[5525,13980,8427],{"class":6078},[5525,13982,13983],{"class":6078}," None",[5525,13985,6086],{"class":5531},[5525,13987,13988],{"class":5527,"line":5993},[5525,13989,13990],{"class":5545},"            # Перший виклик: args[0] — це декорована функція\n",[5525,13992,13993,13996,13998],{"class":5527,"line":5999},[5525,13994,13995],{"class":5531},"            func = args[",[5525,13997,8191],{"class":5535},[5525,13999,14000],{"class":5531},"]\n",[5525,14002,14003,14005],{"class":5527,"line":6005},[5525,14004,12427],{"class":6078},[5525,14006,14007],{"class":5531},"._func = func\n",[5525,14009,14010,14013,14015],{"class":5527,"line":6011},[5525,14011,14012],{"class":5531},"            functools.update_wrapper(",[5525,14014,6208],{"class":6078},[5525,14016,14017],{"class":5531},", func)\n",[5525,14019,14020,14022],{"class":5527,"line":6016},[5525,14021,7233],{"class":6091},[5525,14023,10029],{"class":6078},[5525,14025,14026],{"class":5527,"line":6022},[5525,14027,12408],{"class":5531},[5525,14029,14030],{"class":5527,"line":6028},[5525,14031,14032],{"class":5545},"        # Другий+ виклики: args — це аргументи декорованої функції\n",[5525,14034,14035,14038,14040,14042,14044],{"class":5527,"line":6034},[5525,14036,14037],{"class":5531},"        key = (args, ",[5525,14039,9579],{"class":6082},[5525,14041,6147],{"class":5531},[5525,14043,8323],{"class":6118},[5525,14045,14046],{"class":5531},"(kwargs.items())))\n",[5525,14048,14049],{"class":5527,"line":6040},[5525,14050,12408],{"class":5531},[5525,14052,14053,14055,14058,14060,14062],{"class":5527,"line":6046},[5525,14054,7220],{"class":6091},[5525,14056,14057],{"class":5531}," key ",[5525,14059,11475],{"class":6078},[5525,14061,7023],{"class":6078},[5525,14063,14064],{"class":5531},"._cache:\n",[5525,14066,14067],{"class":5527,"line":8117},[5525,14068,14069],{"class":5545},"            # Cache hit: переміщуємо на кінець (нещодавно використаний)\n",[5525,14071,14072,14074],{"class":5527,"line":8128},[5525,14073,12427],{"class":6078},[5525,14075,14076],{"class":5531},"._cache.move_to_end(key)\n",[5525,14078,14079,14081,14084],{"class":5527,"line":8135},[5525,14080,12427],{"class":6078},[5525,14082,14083],{"class":5531},"._hits += ",[5525,14085,12433],{"class":5535},[5525,14087,14088,14090,14092],{"class":5527,"line":8145},[5525,14089,7233],{"class":6091},[5525,14091,7023],{"class":6078},[5525,14093,14094],{"class":5531},"._cache[key]\n",[5525,14096,14097],{"class":5527,"line":8150},[5525,14098,12408],{"class":5531},[5525,14100,14101],{"class":5527,"line":8155},[5525,14102,14103],{"class":5545},"        # Cache miss: обчислюємо результат\n",[5525,14105,14106,14109,14111],{"class":5527,"line":8176},[5525,14107,14108],{"class":5531},"        result = ",[5525,14110,6208],{"class":6078},[5525,14112,14113],{"class":5531},"._func(*args, **kwargs)\n",[5525,14115,14116,14118],{"class":5527,"line":8196},[5525,14117,6596],{"class":6078},[5525,14119,14120],{"class":5531},"._cache[key] = result\n",[5525,14122,14123,14125,14128],{"class":5527,"line":8214},[5525,14124,6596],{"class":6078},[5525,14126,14127],{"class":5531},"._misses += ",[5525,14129,12433],{"class":5535},[5525,14131,14132],{"class":5527,"line":8219},[5525,14133,12408],{"class":5531},[5525,14135,14136],{"class":5527,"line":8230},[5525,14137,14138],{"class":5545},"        # Витіснення найстарішого запису при переповненні\n",[5525,14140,14141,14143,14146,14148,14150,14153,14155],{"class":5527,"line":8241},[5525,14142,7220],{"class":6091},[5525,14144,14145],{"class":6118}," len",[5525,14147,6147],{"class":5531},[5525,14149,6208],{"class":6078},[5525,14151,14152],{"class":5531},"._cache) > ",[5525,14154,6208],{"class":6078},[5525,14156,14157],{"class":5531},".maxsize:\n",[5525,14159,14160,14162,14165,14168,14170,14172],{"class":5527,"line":8251},[5525,14161,12427],{"class":6078},[5525,14163,14164],{"class":5531},"._cache.popitem(",[5525,14166,14167],{"class":6207},"last",[5525,14169,12617],{"class":5531},[5525,14171,8391],{"class":6078},[5525,14173,6778],{"class":5531},[5525,14175,14176],{"class":5527,"line":8261},[5525,14177,12408],{"class":5531},[5525,14179,14180,14182],{"class":5527,"line":8266},[5525,14181,6216],{"class":6091},[5525,14183,14184],{"class":5531}," result\n",[5525,14186,14187],{"class":5527,"line":8272},[5525,14188,6544],{"class":5531},[5525,14190,14191,14193],{"class":5527,"line":8316},[5525,14192,6996],{"class":6118},[5525,14194,6999],{"class":6082},[5525,14196,14197,14199,14202,14204,14206,14208,14210],{"class":5527,"line":8329},[5525,14198,6199],{"class":6078},[5525,14200,14201],{"class":6118}," cache_info",[5525,14203,6147],{"class":5531},[5525,14205,6208],{"class":6207},[5525,14207,6637],{"class":5531},[5525,14209,6319],{"class":6082},[5525,14211,6086],{"class":5531},[5525,14213,14214,14216],{"class":5527,"line":10253},[5525,14215,6216],{"class":6091},[5525,14217,14218],{"class":5531}," {\n",[5525,14220,14221,14224,14226,14228],{"class":5527,"line":10259},[5525,14222,14223],{"class":5555},"            \"hits\"",[5525,14225,6127],{"class":5531},[5525,14227,6208],{"class":6078},[5525,14229,14230],{"class":5531},"._hits,\n",[5525,14232,14233,14236,14238,14240],{"class":5527,"line":10277},[5525,14234,14235],{"class":5555},"            \"misses\"",[5525,14237,6127],{"class":5531},[5525,14239,6208],{"class":6078},[5525,14241,14242],{"class":5531},"._misses,\n",[5525,14244,14245,14248,14250,14252],{"class":5527,"line":10303},[5525,14246,14247],{"class":5555},"            \"maxsize\"",[5525,14249,6127],{"class":5531},[5525,14251,6208],{"class":6078},[5525,14253,14254],{"class":5531},".maxsize,\n",[5525,14256,14257,14260,14262,14264,14266,14268],{"class":5527,"line":10308},[5525,14258,14259],{"class":5555},"            \"currsize\"",[5525,14261,6127],{"class":5531},[5525,14263,6150],{"class":6118},[5525,14265,6147],{"class":5531},[5525,14267,6208],{"class":6078},[5525,14269,14270],{"class":5531},"._cache),\n",[5525,14272,14273],{"class":5527,"line":10314},[5525,14274,14275],{"class":5531},"        }\n",[5525,14277,14278],{"class":5527,"line":10332},[5525,14279,6544],{"class":5531},[5525,14281,14282,14284,14287,14289,14291,14293,14295],{"class":5527,"line":10353},[5525,14283,6199],{"class":6078},[5525,14285,14286],{"class":6118}," cache_clear",[5525,14288,6147],{"class":5531},[5525,14290,6208],{"class":6207},[5525,14292,6637],{"class":5531},[5525,14294,6585],{"class":6078},[5525,14296,6086],{"class":5531},[5525,14298,14299,14301],{"class":5527,"line":10358},[5525,14300,6596],{"class":6078},[5525,14302,14303],{"class":5531},"._cache.clear()\n",[5525,14305,14306,14308,14310],{"class":5527,"line":10383},[5525,14307,6596],{"class":6078},[5525,14309,13893],{"class":5531},[5525,14311,11959],{"class":5535},[5525,14313,14314,14316,14318],{"class":5527,"line":10394},[5525,14315,6596],{"class":6078},[5525,14317,13902],{"class":5531},[5525,14319,11959],{"class":5535},[5525,14321,14322],{"class":5527,"line":10401},[5525,14323,5850],{"emptyLinePlaceholder":5849},[5525,14325,14326],{"class":5527,"line":10416},[5525,14327,5850],{"emptyLinePlaceholder":5849},[5525,14329,14330],{"class":5527,"line":10421},[5525,14331,14332],{"class":5545},"# Декорування: @LRUCache(maxsize=4) → LRUCache(4).__call__(fibonacci)\n",[5525,14334,14335,14338,14340,14342,14344,14346],{"class":5527,"line":10426},[5525,14336,14337],{"class":6118},"@LRUCache",[5525,14339,6147],{"class":5531},[5525,14341,13861],{"class":6207},[5525,14343,12617],{"class":5531},[5525,14345,10456],{"class":5535},[5525,14347,6778],{"class":5531},[5525,14349,14350,14353,14356,14358,14361,14363,14365,14367,14369],{"class":5527,"line":10432},[5525,14351,14352],{"class":6078},"def",[5525,14354,14355],{"class":6118}," fibonacci",[5525,14357,6147],{"class":5531},[5525,14359,14360],{"class":6207},"n",[5525,14362,6127],{"class":5531},[5525,14364,7656],{"class":6082},[5525,14366,6637],{"class":5531},[5525,14368,7656],{"class":6082},[5525,14370,6086],{"class":5531},[5525,14372,14373],{"class":5527,"line":10446},[5525,14374,14375],{"class":5555},"    \"\"\"Класичний рекурсивний Fibonacci — без кешу дуже повільний.\"\"\"\n",[5525,14377,14378,14381,14384,14386],{"class":5527,"line":10461},[5525,14379,14380],{"class":6091},"    if",[5525,14382,14383],{"class":5531}," n \u003C= ",[5525,14385,8161],{"class":5535},[5525,14387,6086],{"class":5531},[5525,14389,14390,14392],{"class":5527,"line":10466},[5525,14391,6216],{"class":6091},[5525,14393,14394],{"class":5531}," n\n",[5525,14396,14397,14400,14403,14405,14408,14410],{"class":5527,"line":10477},[5525,14398,14399],{"class":6091},"    return",[5525,14401,14402],{"class":5531}," fibonacci(n - ",[5525,14404,8161],{"class":5535},[5525,14406,14407],{"class":5531},") + fibonacci(n - ",[5525,14409,8166],{"class":5535},[5525,14411,6778],{"class":5531},[5525,14413,14414],{"class":5527,"line":10488},[5525,14415,5850],{"emptyLinePlaceholder":5849},[5525,14417,14418],{"class":5527,"line":10505},[5525,14419,5850],{"emptyLinePlaceholder":5849},[5525,14421,14422,14424,14427,14429,14432],{"class":5527,"line":10520},[5525,14423,6144],{"class":6118},[5525,14425,14426],{"class":5531},"(fibonacci(",[5525,14428,8186],{"class":5535},[5525,14430,14431],{"class":5531},"))   ",[5525,14433,14434],{"class":5545},"# 55\n",[5525,14436,14437,14439,14441,14443,14445],{"class":5527,"line":10531},[5525,14438,6144],{"class":6118},[5525,14440,14426],{"class":5531},[5525,14442,8186],{"class":5535},[5525,14444,14431],{"class":5531},[5525,14446,14447],{"class":5545},"# 55 (з кешу)\n",[5525,14449,14450,14452,14454,14456,14458],{"class":5527,"line":10547},[5525,14451,6144],{"class":6118},[5525,14453,14426],{"class":5531},[5525,14455,5542],{"class":5535},[5525,14457,13636],{"class":5531},[5525,14459,14460],{"class":5545},"# 21\n",[5525,14462,14463,14465],{"class":5527,"line":10572},[5525,14464,6144],{"class":6118},[5525,14466,14467],{"class":5531},"(fibonacci.cache_info)\n",[5525,14469,14470],{"class":5527,"line":10586},[5525,14471,14472],{"class":5545},"# {'hits': ..., 'misses': ..., 'maxsize': 4, 'currsize': 4}\n",[7425,14474,14476,14484,14492,14499,14507],{"title":14475},"python lru_cache.py",[7429,14477,14479,7437,14482],{"className":14478},[5527],[5525,14480,7436],{"className":14481},[7435],[5607,14483,14475],{},[7429,14485,14487,14488],{"className":14486},[5527],"fibonacci(10): ",[5525,14489,14491],{"className":14490},[8351],"55",[7429,14493,14495,14496],{"className":14494},[5527],"fibonacci(10) [cache]: ",[5525,14497,14491],{"className":14498},[8351],[7429,14500,14502,14503],{"className":14501},[5527],"fibonacci(8): ",[5525,14504,14506],{"className":14505},[8351],"21",[7429,14508,14510,14511],{"className":14509},[5527],"cache_info: ",[5525,14512,14514],{"className":14513},[7463],"{'hits': 1, 'misses': 11, 'maxsize': 4, 'currsize': 4}",[5748,14516,14518,14520],{"id":14517},"__call__-та-перевірка-callable",[5507,14519,6379],{}," та перевірка callable",[5512,14522,14523,14524,8410,14527,14529,14530,14532],{},"Вбудована функція ",[5507,14525,14526],{},"callable(obj)",[5507,14528,8352],{},", якщо об'єкт має ",[5507,14531,6379],{},". Це дозволяє писати код, що однаково працює і з функціями, і з callable-класами:",[5516,14534,14536],{"className":5518,"code":14535,"language":5520,"meta":5521,"style":5521},"def apply_twice(func_or_callable, value):\n    \"\"\"Застосовує callable двічі до значення.\"\"\"\n    if not callable(func_or_callable):\n        raise TypeError(f\"Очікується callable, отримано {type(func_or_callable)}\")\n    return func_or_callable(func_or_callable(value))\n\n\n# Звичайна функція\nprint(apply_twice(lambda x: x + 1, 5))   # 7\n\n# Callable-об'єкт\ndoubler = Multiplier(2)\nprint(apply_twice(doubler, 3))            # 12  (3*2*2)\n",[5507,14537,14538,14556,14561,14573,14602,14609,14613,14617,14622,14648,14652,14657,14666],{"__ignoreMap":5521},[5525,14539,14540,14542,14545,14547,14550,14552,14554],{"class":5527,"line":5528},[5525,14541,14352],{"class":6078},[5525,14543,14544],{"class":6118}," apply_twice",[5525,14546,6147],{"class":5531},[5525,14548,14549],{"class":6207},"func_or_callable",[5525,14551,5614],{"class":5531},[5525,14553,13567],{"class":6207},[5525,14555,6211],{"class":5531},[5525,14557,14558],{"class":5527,"line":5549},[5525,14559,14560],{"class":5555},"    \"\"\"Застосовує callable двічі до значення.\"\"\"\n",[5525,14562,14563,14565,14567,14570],{"class":5527,"line":5567},[5525,14564,14380],{"class":6091},[5525,14566,7902],{"class":6078},[5525,14568,14569],{"class":6118}," callable",[5525,14571,14572],{"class":5531},"(func_or_callable):\n",[5525,14574,14575,14578,14581,14583,14585,14588,14590,14593,14596,14598,14600],{"class":5527,"line":5816},[5525,14576,14577],{"class":6091},"        raise",[5525,14579,14580],{"class":6082}," TypeError",[5525,14582,6147],{"class":5531},[5525,14584,7333],{"class":6078},[5525,14586,14587],{"class":5555},"\"Очікується callable, отримано ",[5525,14589,6791],{"class":6078},[5525,14591,14592],{"class":6082},"type",[5525,14594,14595],{"class":5531},"(func_or_callable)",[5525,14597,6797],{"class":6078},[5525,14599,7146],{"class":5555},[5525,14601,6778],{"class":5531},[5525,14603,14604,14606],{"class":5527,"line":5822},[5525,14605,14399],{"class":6091},[5525,14607,14608],{"class":5531}," func_or_callable(func_or_callable(value))\n",[5525,14610,14611],{"class":5527,"line":5828},[5525,14612,5850],{"emptyLinePlaceholder":5849},[5525,14614,14615],{"class":5527,"line":5834},[5525,14616,5850],{"emptyLinePlaceholder":5849},[5525,14618,14619],{"class":5527,"line":5840},[5525,14620,14621],{"class":5545},"# Звичайна функція\n",[5525,14623,14624,14626,14629,14631,14634,14637,14639,14641,14643,14645],{"class":5527,"line":5846},[5525,14625,6144],{"class":6118},[5525,14627,14628],{"class":5531},"(apply_twice(",[5525,14630,6124],{"class":6078},[5525,14632,14633],{"class":6207}," x",[5525,14635,14636],{"class":5531},": x + ",[5525,14638,8161],{"class":5535},[5525,14640,5614],{"class":5531},[5525,14642,7034],{"class":5535},[5525,14644,14431],{"class":5531},[5525,14646,14647],{"class":5545},"# 7\n",[5525,14649,14650],{"class":5527,"line":5853},[5525,14651,5850],{"emptyLinePlaceholder":5849},[5525,14653,14654],{"class":5527,"line":5859},[5525,14655,14656],{"class":5545},"# Callable-об'єкт\n",[5525,14658,14659,14662,14664],{"class":5527,"line":5865},[5525,14660,14661],{"class":5531},"doubler = Multiplier(",[5525,14663,8166],{"class":5535},[5525,14665,6778],{"class":5531},[5525,14667,14668,14670,14673,14675,14678],{"class":5527,"line":5871},[5525,14669,6144],{"class":6118},[5525,14671,14672],{"class":5531},"(apply_twice(doubler, ",[5525,14674,8171],{"class":5535},[5525,14676,14677],{"class":5531},"))            ",[5525,14679,14680],{"class":5545},"# 12  (3*2*2)\n",[5741,14682],{},[5502,14684,14686],{"id":14685},"частина-vii-протокол-контекстного-менеджера","Частина VII: Протокол контекстного менеджера",[5748,14688,14690,14692,14693,10825,14696],{"id":14689},"with-під-капотом-__enter__-та-__exit__",[5507,14691,5680],{}," під капотом: ",[5507,14694,14695],{},"__enter__",[5507,14697,14698],{},"__exit__",[5512,14700,6388,14701,14703],{},[5507,14702,5680],{}," — одна з найелегантніших в Python. Вона гарантує виконання коду очищення (закриття файлів, звільнення lock'ів, відкат транзакцій) навіть при виникненні виключення. За цим стоять два методи:",[6256,14705,14706,14721],{},[6259,14707,14710,14711,14713,14714,14717,14718,14720],{"name":14708,"type":14709},"__enter__(self)","() -> Any","Викликається на початку блоку ",[5507,14712,5680],{},". Повернене значення прив'язується до змінної після ",[5507,14715,14716],{},"as"," (якщо вона є). Може повертати ",[5507,14719,6208],{}," або будь-який інший об'єкт.",[6259,14722,14725,14726,14728,14729,14731,14732,14734,14735,14737],{"name":14723,"type":14724},"__exit__(self, exc_type, exc_val, exc_tb)","(type | None, Exception | None, TracebackType | None) -> bool | None","Викликається при виході з блоку ",[5507,14727,5680],{}," — завжди, навіть при виключенні. Якщо виключення сталося, отримує його тип, значення та трасування стека. Якщо повертає ",[5507,14730,8352],{}," — виключення пригнічується (не поширюється далі). Якщо ",[5507,14733,8391],{}," або ",[5507,14736,6585],{}," — виключення продовжує розповсюджуватись.",[5516,14739,14741],{"className":5518,"code":14740,"language":5520,"meta":5521,"style":5521},"# Що відбувається при виконанні:\nwith some_obj as x:\n    do_something(x)\n\n# Еквівалентно:\n_mgr = some_obj\nx = _mgr.__enter__()\n_exc = True\ntry:\n    try:\n        do_something(x)\n    except:\n        _exc = False\n        if not _mgr.__exit__(*sys.exc_info()):\n            raise\nfinally:\n    if _exc:\n        _mgr.__exit__(None, None, None)\n",[5507,14742,14743,14748,14760,14765,14769,14774,14779,14789,14797,14804,14811,14816,14823,14831,14845,14850,14857,14864],{"__ignoreMap":5521},[5525,14744,14745],{"class":5527,"line":5528},[5525,14746,14747],{"class":5545},"# Що відбувається при виконанні:\n",[5525,14749,14750,14752,14755,14757],{"class":5527,"line":5549},[5525,14751,5680],{"class":6091},[5525,14753,14754],{"class":5531}," some_obj ",[5525,14756,14716],{"class":6091},[5525,14758,14759],{"class":5531}," x:\n",[5525,14761,14762],{"class":5527,"line":5567},[5525,14763,14764],{"class":5531},"    do_something(x)\n",[5525,14766,14767],{"class":5527,"line":5816},[5525,14768,5850],{"emptyLinePlaceholder":5849},[5525,14770,14771],{"class":5527,"line":5822},[5525,14772,14773],{"class":5545},"# Еквівалентно:\n",[5525,14775,14776],{"class":5527,"line":5828},[5525,14777,14778],{"class":5531},"_mgr = some_obj\n",[5525,14780,14781,14784,14786],{"class":5527,"line":5834},[5525,14782,14783],{"class":5531},"x = _mgr.",[5525,14785,14695],{"class":6118},[5525,14787,14788],{"class":5531},"()\n",[5525,14790,14791,14794],{"class":5527,"line":5840},[5525,14792,14793],{"class":5531},"_exc = ",[5525,14795,14796],{"class":6078},"True\n",[5525,14798,14799,14802],{"class":5527,"line":5846},[5525,14800,14801],{"class":6091},"try",[5525,14803,6086],{"class":5531},[5525,14805,14806,14809],{"class":5527,"line":5853},[5525,14807,14808],{"class":6091},"    try",[5525,14810,6086],{"class":5531},[5525,14812,14813],{"class":5527,"line":5859},[5525,14814,14815],{"class":5531},"        do_something(x)\n",[5525,14817,14818,14821],{"class":5527,"line":5865},[5525,14819,14820],{"class":6091},"    except",[5525,14822,6086],{"class":5531},[5525,14824,14825,14828],{"class":5527,"line":5871},[5525,14826,14827],{"class":5531},"        _exc = ",[5525,14829,14830],{"class":6078},"False\n",[5525,14832,14833,14835,14837,14840,14842],{"class":5527,"line":5877},[5525,14834,7220],{"class":6091},[5525,14836,7902],{"class":6078},[5525,14838,14839],{"class":5531}," _mgr.",[5525,14841,14698],{"class":6118},[5525,14843,14844],{"class":5531},"(*sys.exc_info()):\n",[5525,14846,14847],{"class":5527,"line":5883},[5525,14848,14849],{"class":6091},"            raise\n",[5525,14851,14852,14855],{"class":5527,"line":5889},[5525,14853,14854],{"class":6091},"finally",[5525,14856,6086],{"class":5531},[5525,14858,14859,14861],{"class":5527,"line":5895},[5525,14860,14380],{"class":6091},[5525,14862,14863],{"class":5531}," _exc:\n",[5525,14865,14866,14869,14871,14873,14875,14877,14879,14881,14883],{"class":5527,"line":5901},[5525,14867,14868],{"class":5531},"        _mgr.",[5525,14870,14698],{"class":6118},[5525,14872,6147],{"class":5531},[5525,14874,6585],{"class":6078},[5525,14876,5614],{"class":5531},[5525,14878,6585],{"class":6078},[5525,14880,5614],{"class":5531},[5525,14882,6585],{"class":6078},[5525,14884,6778],{"class":5531},[5748,14886,14888],{"id":14887},"побудова-власного-контекстного-менеджера","Побудова власного контекстного менеджера",[5512,14890,14891,14892,14895],{},"Реалізуємо ",[5507,14893,14894],{},"ManagedTransaction"," — спрощений аналог транзакції бази даних:",[5516,14897,14899],{"className":5518,"code":14898,"language":5520,"meta":5521,"style":5521},"from __future__ import annotations\nimport logging\nfrom types import TracebackType\nfrom typing import Type\n\nlogger = logging.getLogger(__name__)\n\n\nclass ManagedTransaction:\n    \"\"\"\n    Контекстний менеджер для транзакцій бази даних.\n    \n    Використання:\n        with ManagedTransaction(connection) as tx:\n            tx.execute(\"INSERT INTO ...\")\n            tx.execute(\"UPDATE ...\")\n        # При виході без виключення — COMMIT\n        # При виключенні — автоматичний ROLLBACK\n    \"\"\"\n    \n    def __init__(self, connection):\n        self._conn = connection\n        self._operations: list[str] = []\n        self._committed = False\n    \n    def __enter__(self) -> ManagedTransaction:\n        \"\"\"\n        Починає транзакцію.\n        Повертає self — щоб блок `as tx` отримав об'єкт транзакції.\n        \"\"\"\n        logger.debug(\"Транзакція розпочата\")\n        self._conn.begin()\n        return self\n    \n    def __exit__(\n        self,\n        exc_type: Type[BaseException] | None,\n        exc_val: BaseException | None,\n        exc_tb: TracebackType | None,\n    ) -> bool:\n        \"\"\"\n        Завершує транзакцію.\n        \n        exc_type is None → виконання пройшло успішно → COMMIT\n        exc_type is not None → виникло виключення → ROLLBACK\n        \n        Повертаємо False → не пригнічуємо виключення.\n        \"\"\"\n        if exc_type is None:\n            # Нормальний вихід: зберігаємо зміни\n            self._conn.commit()\n            self._committed = True\n            logger.info(f\"Транзакція закомічена ({len(self._operations)} операцій)\")\n        else:\n            # Виключення: відкатуємо всі зміни\n            self._conn.rollback()\n            logger.error(\n                f\"Транзакція відкочена через {exc_type.__name__}: {exc_val}\"\n            )\n        \n        return False  # не пригнічуємо виключення\n    \n    def execute(self, sql: str, params: tuple = ()) -> None:\n        \"\"\"Виконує SQL-запит у рамках транзакції.\"\"\"\n        self._operations.append(sql)\n        self._conn.execute(sql, params)\n\n\n# --- Симуляція з'єднання ---\n\nclass FakeConnection:\n    def begin(self):    print(\"  [DB] BEGIN TRANSACTION\")\n    def commit(self):   print(\"  [DB] COMMIT\")\n    def rollback(self): print(\"  [DB] ROLLBACK\")\n    def execute(self, sql, params=()):\n        print(f\"  [DB] EXECUTE: {sql} | params={params}\")\n\n\nconn = FakeConnection()\n\n# Сценарій 1: успішна транзакція\nprint(\"=== Сценарій 1: успіх ===\")\nwith ManagedTransaction(conn) as tx:\n    tx.execute(\"INSERT INTO orders (user_id) VALUES (?)\", (42,))\n    tx.execute(\"UPDATE inventory SET qty = qty - 1 WHERE id = ?\", (7,))\n# → автоматичний COMMIT\n\nprint()\n\n# Сценарій 2: виключення всередині → автоматичний ROLLBACK\nprint(\"=== Сценарій 2: помилка ===\")\ntry:\n    with ManagedTransaction(conn) as tx:\n        tx.execute(\"INSERT INTO orders (user_id) VALUES (?)\", (99,))\n        raise ValueError(\"Недостатньо коштів на рахунку\")\n        tx.execute(\"UPDATE inventory SET qty = qty - 1 WHERE id = ?\", (3,))\nexcept ValueError as e:\n    print(f\"Перехоплено: {e}\")\n# → автоматичний ROLLBACK, виключення продовжило розповсюджуватись\n",[5507,14900,14901,14911,14918,14930,14941,14945,14955,14959,14963,14972,14976,14981,14985,14989,14994,14999,15004,15009,15014,15018,15022,15039,15046,15058,15067,15071,15085,15089,15094,15099,15103,15113,15120,15126,15130,15139,15146,15164,15179,15191,15200,15204,15209,15213,15218,15223,15227,15232,15236,15249,15254,15261,15269,15297,15303,15308,15315,15320,15347,15351,15355,15365,15369,15405,15410,15417,15424,15428,15432,15437,15441,15450,15473,15496,15519,15540,15571,15575,15579,15584,15588,15593,15604,15616,15632,15645,15650,15654,15660,15664,15669,15680,15686,15697,15711,15724,15736,15749,15772],{"__ignoreMap":5521},[5525,14902,14903,14905,14907,14909],{"class":5527,"line":5528},[5525,14904,6512],{"class":6091},[5525,14906,7608],{"class":6207},[5525,14908,7611],{"class":6091},[5525,14910,7614],{"class":5531},[5525,14912,14913,14915],{"class":5527,"line":5549},[5525,14914,6518],{"class":6091},[5525,14916,14917],{"class":5531}," logging\n",[5525,14919,14920,14922,14925,14927],{"class":5527,"line":5567},[5525,14921,6512],{"class":6091},[5525,14923,14924],{"class":5531}," types ",[5525,14926,6518],{"class":6091},[5525,14928,14929],{"class":5531}," TracebackType\n",[5525,14931,14932,14934,14936,14938],{"class":5527,"line":5816},[5525,14933,6512],{"class":6091},[5525,14935,11557],{"class":5531},[5525,14937,6518],{"class":6091},[5525,14939,14940],{"class":5531}," Type\n",[5525,14942,14943],{"class":5527,"line":5822},[5525,14944,5850],{"emptyLinePlaceholder":5849},[5525,14946,14947,14950,14953],{"class":5527,"line":5828},[5525,14948,14949],{"class":5531},"logger = logging.getLogger(",[5525,14951,14952],{"class":6207},"__name__",[5525,14954,6778],{"class":5531},[5525,14956,14957],{"class":5527,"line":5834},[5525,14958,5850],{"emptyLinePlaceholder":5849},[5525,14960,14961],{"class":5527,"line":5840},[5525,14962,5850],{"emptyLinePlaceholder":5849},[5525,14964,14965,14967,14970],{"class":5527,"line":5846},[5525,14966,6079],{"class":6078},[5525,14968,14969],{"class":6082}," ManagedTransaction",[5525,14971,6086],{"class":5531},[5525,14973,14974],{"class":5527,"line":5853},[5525,14975,11599],{"class":5555},[5525,14977,14978],{"class":5527,"line":5859},[5525,14979,14980],{"class":5555},"    Контекстний менеджер для транзакцій бази даних.\n",[5525,14982,14983],{"class":5527,"line":5865},[5525,14984,6544],{"class":5555},[5525,14986,14987],{"class":5527,"line":5871},[5525,14988,13828],{"class":5555},[5525,14990,14991],{"class":5527,"line":5877},[5525,14992,14993],{"class":5555},"        with ManagedTransaction(connection) as tx:\n",[5525,14995,14996],{"class":5527,"line":5883},[5525,14997,14998],{"class":5555},"            tx.execute(\"INSERT INTO ...\")\n",[5525,15000,15001],{"class":5527,"line":5889},[5525,15002,15003],{"class":5555},"            tx.execute(\"UPDATE ...\")\n",[5525,15005,15006],{"class":5527,"line":5895},[5525,15007,15008],{"class":5555},"        # При виході без виключення — COMMIT\n",[5525,15010,15011],{"class":5527,"line":5901},[5525,15012,15013],{"class":5555},"        # При виключенні — автоматичний ROLLBACK\n",[5525,15015,15016],{"class":5527,"line":5906},[5525,15017,11599],{"class":5555},[5525,15019,15020],{"class":5527,"line":5911},[5525,15021,6544],{"class":5531},[5525,15023,15024,15026,15028,15030,15032,15034,15037],{"class":5527,"line":5917},[5525,15025,6199],{"class":6078},[5525,15027,6551],{"class":6118},[5525,15029,6147],{"class":5531},[5525,15031,6208],{"class":6207},[5525,15033,5614],{"class":5531},[5525,15035,15036],{"class":6207},"connection",[5525,15038,6211],{"class":5531},[5525,15040,15041,15043],{"class":5527,"line":5923},[5525,15042,6596],{"class":6078},[5525,15044,15045],{"class":5531},"._conn = connection\n",[5525,15047,15048,15050,15053,15055],{"class":5527,"line":5929},[5525,15049,6596],{"class":6078},[5525,15051,15052],{"class":5531},"._operations: list[",[5525,15054,6565],{"class":6082},[5525,15056,15057],{"class":5531},"] = []\n",[5525,15059,15060,15062,15065],{"class":5527,"line":5935},[5525,15061,6596],{"class":6078},[5525,15063,15064],{"class":5531},"._committed = ",[5525,15066,14830],{"class":6078},[5525,15068,15069],{"class":5527,"line":5941},[5525,15070,6544],{"class":5531},[5525,15072,15073,15075,15078,15080,15082],{"class":5527,"line":5947},[5525,15074,6199],{"class":6078},[5525,15076,15077],{"class":6118}," __enter__",[5525,15079,6147],{"class":5531},[5525,15081,6208],{"class":6207},[5525,15083,15084],{"class":5531},") -> ManagedTransaction:\n",[5525,15086,15087],{"class":5527,"line":5953},[5525,15088,7191],{"class":5555},[5525,15090,15091],{"class":5527,"line":5959},[5525,15092,15093],{"class":5555},"        Починає транзакцію.\n",[5525,15095,15096],{"class":5527,"line":5964},[5525,15097,15098],{"class":5555},"        Повертає self — щоб блок `as tx` отримав об'єкт транзакції.\n",[5525,15100,15101],{"class":5527,"line":5969},[5525,15102,7191],{"class":5555},[5525,15104,15105,15108,15111],{"class":5527,"line":5975},[5525,15106,15107],{"class":5531},"        logger.debug(",[5525,15109,15110],{"class":5555},"\"Транзакція розпочата\"",[5525,15112,6778],{"class":5531},[5525,15114,15115,15117],{"class":5527,"line":5981},[5525,15116,6596],{"class":6078},[5525,15118,15119],{"class":5531},"._conn.begin()\n",[5525,15121,15122,15124],{"class":5527,"line":5987},[5525,15123,6216],{"class":6091},[5525,15125,10029],{"class":6078},[5525,15127,15128],{"class":5527,"line":5993},[5525,15129,6544],{"class":5531},[5525,15131,15132,15134,15137],{"class":5527,"line":5999},[5525,15133,6199],{"class":6078},[5525,15135,15136],{"class":6118}," __exit__",[5525,15138,12105],{"class":5531},[5525,15140,15141,15143],{"class":5527,"line":6005},[5525,15142,6596],{"class":6207},[5525,15144,15145],{"class":5531},",\n",[5525,15147,15148,15151,15154,15157,15160,15162],{"class":5527,"line":6011},[5525,15149,15150],{"class":6207},"        exc_type",[5525,15152,15153],{"class":5531},": Type[",[5525,15155,15156],{"class":6082},"BaseException",[5525,15158,15159],{"class":5531},"] | ",[5525,15161,6585],{"class":6078},[5525,15163,15145],{"class":5531},[5525,15165,15166,15169,15171,15173,15175,15177],{"class":5527,"line":6016},[5525,15167,15168],{"class":6207},"        exc_val",[5525,15170,6127],{"class":5531},[5525,15172,15156],{"class":6082},[5525,15174,6810],{"class":5531},[5525,15176,6585],{"class":6078},[5525,15178,15145],{"class":5531},[5525,15180,15181,15184,15187,15189],{"class":5527,"line":6022},[5525,15182,15183],{"class":6207},"        exc_tb",[5525,15185,15186],{"class":5531},": TracebackType | ",[5525,15188,6585],{"class":6078},[5525,15190,15145],{"class":5531},[5525,15192,15193,15196,15198],{"class":5527,"line":6028},[5525,15194,15195],{"class":5531},"    ) -> ",[5525,15197,7893],{"class":6082},[5525,15199,6086],{"class":5531},[5525,15201,15202],{"class":5527,"line":6034},[5525,15203,7191],{"class":5555},[5525,15205,15206],{"class":5527,"line":6040},[5525,15207,15208],{"class":5555},"        Завершує транзакцію.\n",[5525,15210,15211],{"class":5527,"line":6046},[5525,15212,12408],{"class":5555},[5525,15214,15215],{"class":5527,"line":8117},[5525,15216,15217],{"class":5555},"        exc_type is None → виконання пройшло успішно → COMMIT\n",[5525,15219,15220],{"class":5527,"line":8128},[5525,15221,15222],{"class":5555},"        exc_type is not None → виникло виключення → ROLLBACK\n",[5525,15224,15225],{"class":5527,"line":8135},[5525,15226,12408],{"class":5555},[5525,15228,15229],{"class":5527,"line":8145},[5525,15230,15231],{"class":5555},"        Повертаємо False → не пригнічуємо виключення.\n",[5525,15233,15234],{"class":5527,"line":8150},[5525,15235,7191],{"class":5555},[5525,15237,15238,15240,15243,15245,15247],{"class":5527,"line":8155},[5525,15239,7220],{"class":6091},[5525,15241,15242],{"class":5531}," exc_type ",[5525,15244,8427],{"class":6078},[5525,15246,13983],{"class":6078},[5525,15248,6086],{"class":5531},[5525,15250,15251],{"class":5527,"line":8176},[5525,15252,15253],{"class":5545},"            # Нормальний вихід: зберігаємо зміни\n",[5525,15255,15256,15258],{"class":5527,"line":8196},[5525,15257,12427],{"class":6078},[5525,15259,15260],{"class":5531},"._conn.commit()\n",[5525,15262,15263,15265,15267],{"class":5527,"line":8214},[5525,15264,12427],{"class":6078},[5525,15266,15064],{"class":5531},[5525,15268,14796],{"class":6078},[5525,15270,15271,15274,15276,15279,15281,15283,15285,15287,15290,15292,15295],{"class":5527,"line":8219},[5525,15272,15273],{"class":5531},"            logger.info(",[5525,15275,7333],{"class":6078},[5525,15277,15278],{"class":5555},"\"Транзакція закомічена (",[5525,15280,6791],{"class":6078},[5525,15282,6150],{"class":6118},[5525,15284,6147],{"class":5531},[5525,15286,6208],{"class":6078},[5525,15288,15289],{"class":5531},"._operations)",[5525,15291,6797],{"class":6078},[5525,15293,15294],{"class":5555}," операцій)\"",[5525,15296,6778],{"class":5531},[5525,15298,15299,15301],{"class":5527,"line":8230},[5525,15300,7283],{"class":6091},[5525,15302,6086],{"class":5531},[5525,15304,15305],{"class":5527,"line":8241},[5525,15306,15307],{"class":5545},"            # Виключення: відкатуємо всі зміни\n",[5525,15309,15310,15312],{"class":5527,"line":8251},[5525,15311,12427],{"class":6078},[5525,15313,15314],{"class":5531},"._conn.rollback()\n",[5525,15316,15317],{"class":5527,"line":8261},[5525,15318,15319],{"class":5531},"            logger.error(\n",[5525,15321,15322,15324,15327,15329,15332,15334,15336,15338,15340,15343,15345],{"class":5527,"line":8266},[5525,15323,12110],{"class":6078},[5525,15325,15326],{"class":5555},"\"Транзакція відкочена через ",[5525,15328,6791],{"class":6078},[5525,15330,15331],{"class":5531},"exc_type.",[5525,15333,14952],{"class":6207},[5525,15335,6797],{"class":6078},[5525,15337,6127],{"class":5555},[5525,15339,6791],{"class":6078},[5525,15341,15342],{"class":5531},"exc_val",[5525,15344,6797],{"class":6078},[5525,15346,6718],{"class":5555},[5525,15348,15349],{"class":5527,"line":8272},[5525,15350,12136],{"class":5531},[5525,15352,15353],{"class":5527,"line":8316},[5525,15354,12408],{"class":5531},[5525,15356,15357,15359,15362],{"class":5527,"line":8329},[5525,15358,6216],{"class":6091},[5525,15360,15361],{"class":6078}," False",[5525,15363,15364],{"class":5545},"  # не пригнічуємо виключення\n",[5525,15366,15367],{"class":5527,"line":10253},[5525,15368,6544],{"class":5531},[5525,15370,15371,15373,15376,15378,15380,15382,15385,15387,15389,15391,15394,15396,15398,15401,15403],{"class":5527,"line":10259},[5525,15372,6199],{"class":6078},[5525,15374,15375],{"class":6118}," execute",[5525,15377,6147],{"class":5531},[5525,15379,6208],{"class":6207},[5525,15381,5614],{"class":5531},[5525,15383,15384],{"class":6207},"sql",[5525,15386,6127],{"class":5531},[5525,15388,6565],{"class":6082},[5525,15390,5614],{"class":5531},[5525,15392,15393],{"class":6207},"params",[5525,15395,6127],{"class":5531},[5525,15397,9579],{"class":6082},[5525,15399,15400],{"class":5531}," = ()) -> ",[5525,15402,6585],{"class":6078},[5525,15404,6086],{"class":5531},[5525,15406,15407],{"class":5527,"line":10277},[5525,15408,15409],{"class":5555},"        \"\"\"Виконує SQL-запит у рамках транзакції.\"\"\"\n",[5525,15411,15412,15414],{"class":5527,"line":10303},[5525,15413,6596],{"class":6078},[5525,15415,15416],{"class":5531},"._operations.append(sql)\n",[5525,15418,15419,15421],{"class":5527,"line":10308},[5525,15420,6596],{"class":6078},[5525,15422,15423],{"class":5531},"._conn.execute(sql, params)\n",[5525,15425,15426],{"class":5527,"line":10314},[5525,15427,5850],{"emptyLinePlaceholder":5849},[5525,15429,15430],{"class":5527,"line":10332},[5525,15431,5850],{"emptyLinePlaceholder":5849},[5525,15433,15434],{"class":5527,"line":10353},[5525,15435,15436],{"class":5545},"# --- Симуляція з'єднання ---\n",[5525,15438,15439],{"class":5527,"line":10358},[5525,15440,5850],{"emptyLinePlaceholder":5849},[5525,15442,15443,15445,15448],{"class":5527,"line":10383},[5525,15444,6079],{"class":6078},[5525,15446,15447],{"class":6082}," FakeConnection",[5525,15449,6086],{"class":5531},[5525,15451,15452,15454,15457,15459,15461,15464,15466,15468,15471],{"class":5527,"line":10394},[5525,15453,6199],{"class":6078},[5525,15455,15456],{"class":6118}," begin",[5525,15458,6147],{"class":5531},[5525,15460,6208],{"class":6207},[5525,15462,15463],{"class":5531},"):    ",[5525,15465,6144],{"class":6118},[5525,15467,6147],{"class":5531},[5525,15469,15470],{"class":5555},"\"  [DB] BEGIN TRANSACTION\"",[5525,15472,6778],{"class":5531},[5525,15474,15475,15477,15480,15482,15484,15487,15489,15491,15494],{"class":5527,"line":10401},[5525,15476,6199],{"class":6078},[5525,15478,15479],{"class":6118}," commit",[5525,15481,6147],{"class":5531},[5525,15483,6208],{"class":6207},[5525,15485,15486],{"class":5531},"):   ",[5525,15488,6144],{"class":6118},[5525,15490,6147],{"class":5531},[5525,15492,15493],{"class":5555},"\"  [DB] COMMIT\"",[5525,15495,6778],{"class":5531},[5525,15497,15498,15500,15503,15505,15507,15510,15512,15514,15517],{"class":5527,"line":10416},[5525,15499,6199],{"class":6078},[5525,15501,15502],{"class":6118}," rollback",[5525,15504,6147],{"class":5531},[5525,15506,6208],{"class":6207},[5525,15508,15509],{"class":5531},"): ",[5525,15511,6144],{"class":6118},[5525,15513,6147],{"class":5531},[5525,15515,15516],{"class":5555},"\"  [DB] ROLLBACK\"",[5525,15518,6778],{"class":5531},[5525,15520,15521,15523,15525,15527,15529,15531,15533,15535,15537],{"class":5527,"line":10421},[5525,15522,6199],{"class":6078},[5525,15524,15375],{"class":6118},[5525,15526,6147],{"class":5531},[5525,15528,6208],{"class":6207},[5525,15530,5614],{"class":5531},[5525,15532,15384],{"class":6207},[5525,15534,5614],{"class":5531},[5525,15536,15393],{"class":6207},[5525,15538,15539],{"class":5531},"=()):\n",[5525,15541,15542,15545,15547,15549,15552,15554,15556,15558,15561,15563,15565,15567,15569],{"class":5527,"line":10426},[5525,15543,15544],{"class":6118},"        print",[5525,15546,6147],{"class":5531},[5525,15548,7333],{"class":6078},[5525,15550,15551],{"class":5555},"\"  [DB] EXECUTE: ",[5525,15553,6791],{"class":6078},[5525,15555,15384],{"class":5531},[5525,15557,6797],{"class":6078},[5525,15559,15560],{"class":5555}," | params=",[5525,15562,6791],{"class":6078},[5525,15564,15393],{"class":5531},[5525,15566,6797],{"class":6078},[5525,15568,7146],{"class":5555},[5525,15570,6778],{"class":5531},[5525,15572,15573],{"class":5527,"line":10432},[5525,15574,5850],{"emptyLinePlaceholder":5849},[5525,15576,15577],{"class":5527,"line":10446},[5525,15578,5850],{"emptyLinePlaceholder":5849},[5525,15580,15581],{"class":5527,"line":10461},[5525,15582,15583],{"class":5531},"conn = FakeConnection()\n",[5525,15585,15586],{"class":5527,"line":10466},[5525,15587,5850],{"emptyLinePlaceholder":5849},[5525,15589,15590],{"class":5527,"line":10477},[5525,15591,15592],{"class":5545},"# Сценарій 1: успішна транзакція\n",[5525,15594,15595,15597,15599,15602],{"class":5527,"line":10488},[5525,15596,6144],{"class":6118},[5525,15598,6147],{"class":5531},[5525,15600,15601],{"class":5555},"\"=== Сценарій 1: успіх ===\"",[5525,15603,6778],{"class":5531},[5525,15605,15606,15608,15611,15613],{"class":5527,"line":10505},[5525,15607,5680],{"class":6091},[5525,15609,15610],{"class":5531}," ManagedTransaction(conn) ",[5525,15612,14716],{"class":6091},[5525,15614,15615],{"class":5531}," tx:\n",[5525,15617,15618,15621,15624,15627,15629],{"class":5527,"line":10520},[5525,15619,15620],{"class":5531},"    tx.execute(",[5525,15622,15623],{"class":5555},"\"INSERT INTO orders (user_id) VALUES (?)\"",[5525,15625,15626],{"class":5531},", (",[5525,15628,5536],{"class":5535},[5525,15630,15631],{"class":5531},",))\n",[5525,15633,15634,15636,15639,15641,15643],{"class":5527,"line":10531},[5525,15635,15620],{"class":5531},[5525,15637,15638],{"class":5555},"\"UPDATE inventory SET qty = qty - 1 WHERE id = ?\"",[5525,15640,15626],{"class":5531},[5525,15642,11370],{"class":5535},[5525,15644,15631],{"class":5531},[5525,15646,15647],{"class":5527,"line":10547},[5525,15648,15649],{"class":5545},"# → автоматичний COMMIT\n",[5525,15651,15652],{"class":5527,"line":10572},[5525,15653,5850],{"emptyLinePlaceholder":5849},[5525,15655,15656,15658],{"class":5527,"line":10586},[5525,15657,6144],{"class":6118},[5525,15659,14788],{"class":5531},[5525,15661,15662],{"class":5527,"line":10591},[5525,15663,5850],{"emptyLinePlaceholder":5849},[5525,15665,15666],{"class":5527,"line":10597},[5525,15667,15668],{"class":5545},"# Сценарій 2: виключення всередині → автоматичний ROLLBACK\n",[5525,15670,15671,15673,15675,15678],{"class":5527,"line":10628},[5525,15672,6144],{"class":6118},[5525,15674,6147],{"class":5531},[5525,15676,15677],{"class":5555},"\"=== Сценарій 2: помилка ===\"",[5525,15679,6778],{"class":5531},[5525,15681,15682,15684],{"class":5527,"line":10643},[5525,15683,14801],{"class":6091},[5525,15685,6086],{"class":5531},[5525,15687,15688,15691,15693,15695],{"class":5527,"line":10654},[5525,15689,15690],{"class":6091},"    with",[5525,15692,15610],{"class":5531},[5525,15694,14716],{"class":6091},[5525,15696,15615],{"class":5531},[5525,15698,15699,15702,15704,15706,15709],{"class":5527,"line":10659},[5525,15700,15701],{"class":5531},"        tx.execute(",[5525,15703,15623],{"class":5555},[5525,15705,15626],{"class":5531},[5525,15707,15708],{"class":5535},"99",[5525,15710,15631],{"class":5531},[5525,15712,15713,15715,15717,15719,15722],{"class":5527,"line":10665},[5525,15714,14577],{"class":6091},[5525,15716,8672],{"class":6082},[5525,15718,6147],{"class":5531},[5525,15720,15721],{"class":5555},"\"Недостатньо коштів на рахунку\"",[5525,15723,6778],{"class":5531},[5525,15725,15726,15728,15730,15732,15734],{"class":5527,"line":10677},[5525,15727,15701],{"class":5531},[5525,15729,15638],{"class":5555},[5525,15731,15626],{"class":5531},[5525,15733,8171],{"class":5535},[5525,15735,15631],{"class":5531},[5525,15737,15738,15741,15743,15746],{"class":5527,"line":10691},[5525,15739,15740],{"class":6091},"except",[5525,15742,8672],{"class":6082},[5525,15744,15745],{"class":6091}," as",[5525,15747,15748],{"class":5531}," e:\n",[5525,15750,15751,15754,15756,15758,15761,15763,15766,15768,15770],{"class":5527,"line":10702},[5525,15752,15753],{"class":6118},"    print",[5525,15755,6147],{"class":5531},[5525,15757,7333],{"class":6078},[5525,15759,15760],{"class":5555},"\"Перехоплено: ",[5525,15762,6791],{"class":6078},[5525,15764,15765],{"class":5531},"e",[5525,15767,6797],{"class":6078},[5525,15769,7146],{"class":5555},[5525,15771,6778],{"class":5531},[5525,15773,15774],{"class":5527,"line":12563},[5525,15775,15776],{"class":5545},"# → автоматичний ROLLBACK, виключення продовжило розповсюджуватись\n",[7425,15778,15780,15788,15792,15800,15804,15808,15815,15818,15822,15828,15832,15839],{"title":15779},"python transaction.py",[7429,15781,15783,7437,15786],{"className":15782},[5527],[5525,15784,7436],{"className":15785},[7435],[5607,15787,15779],{},[7429,15789,15791],{"className":15790},[5527],"=== Сценарій 1: успіх ===",[7429,15793,15795,15796],{"className":15794},[5527],"  [DB] ",[5525,15797,15799],{"className":15798},[7463],"BEGIN TRANSACTION",[7429,15801,15803],{"className":15802},[5527],"  [DB] EXECUTE: INSERT INTO orders (user_id) VALUES (?) | params=(42,)",[7429,15805,15807],{"className":15806},[5527],"  [DB] EXECUTE: UPDATE inventory SET qty = qty - 1 WHERE id = ? | params=(7,)",[7429,15809,15795,15811],{"className":15810},[5527],[5525,15812,15814],{"className":15813},[8351],"COMMIT",[7429,15816],{"className":15817},[5527],[7429,15819,15821],{"className":15820},[5527],"=== Сценарій 2: помилка ===",[7429,15823,15795,15825],{"className":15824},[5527],[5525,15826,15799],{"className":15827},[7463],[7429,15829,15831],{"className":15830},[5527],"  [DB] EXECUTE: INSERT INTO orders (user_id) VALUES (?) | params=(99,)",[7429,15833,15795,15835],{"className":15834},[5527],[5525,15836,15838],{"className":15837},[10785],"ROLLBACK",[7429,15840,15842,15843],{"className":15841},[5527],"Перехоплено: ",[5525,15844,15846],{"className":15845},[10785],"Недостатньо коштів на рахунку",[5748,15848,15850,15851,8410,15853],{"id":15849},"пригнічення-виключень-коли-__exit__-повертає-true","Пригнічення виключень: коли ",[5507,15852,14698],{},[5507,15854,8352],{},[5512,15856,15857,15858,15861,15862,15864,15865,15868,15869,8978],{},"Є сценарії, де ви хочете ",[5607,15859,15860],{},"поглинути"," виключення всередині ",[5507,15863,5680],{}," — наприклад, клас ",[5507,15866,15867],{},"suppress"," з модуля ",[5507,15870,15871],{},"contextlib",[5516,15873,15875],{"className":5518,"code":15874,"language":5520,"meta":5521,"style":5521},"class Suppress:\n    \"\"\"\n    Контекстний менеджер: пригнічує вказані типи виключень.\n    Аналог contextlib.suppress з stdlib.\n    \n    Використання:\n        with Suppress(FileNotFoundError, PermissionError):\n            os.remove(\"\u002Ftmp\u002Fmaybe_exists.txt\")\n        # Якщо файл не існує — виключення просто ігнорується\n    \"\"\"\n    \n    def __init__(self, *exception_types: type[BaseException]):\n        self._types = exception_types\n    \n    def __enter__(self) -> Suppress:\n        return self\n    \n    def __exit__(\n        self,\n        exc_type: type[BaseException] | None,\n        exc_val: BaseException | None,\n        exc_tb,\n    ) -> bool:\n        # Якщо виключення є і воно одного з вказаних типів — пригнічуємо\n        if exc_type is not None and issubclass(exc_type, self._types):\n            return True   # ← True = виключення пригнічено\n        return False      # ← False = пропускаємо виключення далі\n\n\nimport os\n\nwith Suppress(FileNotFoundError):\n    os.remove(\"\u002Ftmp\u002Ffile_that_does_not_exist.txt\")\n\nprint(\"Продовжуємо роботу без зупинки\")  # виконається\n",[5507,15876,15877,15886,15890,15895,15900,15904,15908,15913,15918,15923,15927,15931,15954,15961,15965,15978,15984,15988,15996,16002,16016,16030,16036,16044,16049,16075,16085,16094,16098,16102,16109,16113,16125,16135,16139],{"__ignoreMap":5521},[5525,15878,15879,15881,15884],{"class":5527,"line":5528},[5525,15880,6079],{"class":6078},[5525,15882,15883],{"class":6082}," Suppress",[5525,15885,6086],{"class":5531},[5525,15887,15888],{"class":5527,"line":5549},[5525,15889,11599],{"class":5555},[5525,15891,15892],{"class":5527,"line":5567},[5525,15893,15894],{"class":5555},"    Контекстний менеджер: пригнічує вказані типи виключень.\n",[5525,15896,15897],{"class":5527,"line":5816},[5525,15898,15899],{"class":5555},"    Аналог contextlib.suppress з stdlib.\n",[5525,15901,15902],{"class":5527,"line":5822},[5525,15903,6544],{"class":5555},[5525,15905,15906],{"class":5527,"line":5828},[5525,15907,13828],{"class":5555},[5525,15909,15910],{"class":5527,"line":5834},[5525,15911,15912],{"class":5555},"        with Suppress(FileNotFoundError, PermissionError):\n",[5525,15914,15915],{"class":5527,"line":5840},[5525,15916,15917],{"class":5555},"            os.remove(\"\u002Ftmp\u002Fmaybe_exists.txt\")\n",[5525,15919,15920],{"class":5527,"line":5846},[5525,15921,15922],{"class":5555},"        # Якщо файл не існує — виключення просто ігнорується\n",[5525,15924,15925],{"class":5527,"line":5853},[5525,15926,11599],{"class":5555},[5525,15928,15929],{"class":5527,"line":5859},[5525,15930,6544],{"class":5531},[5525,15932,15933,15935,15937,15939,15941,15943,15946,15949,15951],{"class":5527,"line":5865},[5525,15934,6199],{"class":6078},[5525,15936,6551],{"class":6118},[5525,15938,6147],{"class":5531},[5525,15940,6208],{"class":6207},[5525,15942,13935],{"class":5531},[5525,15944,15945],{"class":6207},"exception_types",[5525,15947,15948],{"class":5531},": type[",[5525,15950,15156],{"class":6082},[5525,15952,15953],{"class":5531},"]):\n",[5525,15955,15956,15958],{"class":5527,"line":5871},[5525,15957,6596],{"class":6078},[5525,15959,15960],{"class":5531},"._types = exception_types\n",[5525,15962,15963],{"class":5527,"line":5877},[5525,15964,6544],{"class":5531},[5525,15966,15967,15969,15971,15973,15975],{"class":5527,"line":5883},[5525,15968,6199],{"class":6078},[5525,15970,15077],{"class":6118},[5525,15972,6147],{"class":5531},[5525,15974,6208],{"class":6207},[5525,15976,15977],{"class":5531},") -> Suppress:\n",[5525,15979,15980,15982],{"class":5527,"line":5889},[5525,15981,6216],{"class":6091},[5525,15983,10029],{"class":6078},[5525,15985,15986],{"class":5527,"line":5895},[5525,15987,6544],{"class":5531},[5525,15989,15990,15992,15994],{"class":5527,"line":5901},[5525,15991,6199],{"class":6078},[5525,15993,15136],{"class":6118},[5525,15995,12105],{"class":5531},[5525,15997,15998,16000],{"class":5527,"line":5906},[5525,15999,6596],{"class":6207},[5525,16001,15145],{"class":5531},[5525,16003,16004,16006,16008,16010,16012,16014],{"class":5527,"line":5911},[5525,16005,15150],{"class":6207},[5525,16007,15948],{"class":5531},[5525,16009,15156],{"class":6082},[5525,16011,15159],{"class":5531},[5525,16013,6585],{"class":6078},[5525,16015,15145],{"class":5531},[5525,16017,16018,16020,16022,16024,16026,16028],{"class":5527,"line":5917},[5525,16019,15168],{"class":6207},[5525,16021,6127],{"class":5531},[5525,16023,15156],{"class":6082},[5525,16025,6810],{"class":5531},[5525,16027,6585],{"class":6078},[5525,16029,15145],{"class":5531},[5525,16031,16032,16034],{"class":5527,"line":5923},[5525,16033,15183],{"class":6207},[5525,16035,15145],{"class":5531},[5525,16037,16038,16040,16042],{"class":5527,"line":5929},[5525,16039,15195],{"class":5531},[5525,16041,7893],{"class":6082},[5525,16043,6086],{"class":5531},[5525,16045,16046],{"class":5527,"line":5935},[5525,16047,16048],{"class":5545},"        # Якщо виключення є і воно одного з вказаних типів — пригнічуємо\n",[5525,16050,16051,16053,16055,16057,16059,16061,16064,16067,16070,16072],{"class":5527,"line":5941},[5525,16052,7220],{"class":6091},[5525,16054,15242],{"class":5531},[5525,16056,8427],{"class":6078},[5525,16058,7902],{"class":6078},[5525,16060,13983],{"class":6078},[5525,16062,16063],{"class":6078}," and",[5525,16065,16066],{"class":6118}," issubclass",[5525,16068,16069],{"class":5531},"(exc_type, ",[5525,16071,6208],{"class":6078},[5525,16073,16074],{"class":5531},"._types):\n",[5525,16076,16077,16079,16082],{"class":5527,"line":5947},[5525,16078,7233],{"class":6091},[5525,16080,16081],{"class":6078}," True",[5525,16083,16084],{"class":5545},"   # ← True = виключення пригнічено\n",[5525,16086,16087,16089,16091],{"class":5527,"line":5953},[5525,16088,6216],{"class":6091},[5525,16090,15361],{"class":6078},[5525,16092,16093],{"class":5545},"      # ← False = пропускаємо виключення далі\n",[5525,16095,16096],{"class":5527,"line":5959},[5525,16097,5850],{"emptyLinePlaceholder":5849},[5525,16099,16100],{"class":5527,"line":5964},[5525,16101,5850],{"emptyLinePlaceholder":5849},[5525,16103,16104,16106],{"class":5527,"line":5969},[5525,16105,6518],{"class":6091},[5525,16107,16108],{"class":5531}," os\n",[5525,16110,16111],{"class":5527,"line":5975},[5525,16112,5850],{"emptyLinePlaceholder":5849},[5525,16114,16115,16117,16120,16123],{"class":5527,"line":5981},[5525,16116,5680],{"class":6091},[5525,16118,16119],{"class":5531}," Suppress(",[5525,16121,16122],{"class":6082},"FileNotFoundError",[5525,16124,6211],{"class":5531},[5525,16126,16127,16130,16133],{"class":5527,"line":5987},[5525,16128,16129],{"class":5531},"    os.remove(",[5525,16131,16132],{"class":5555},"\"\u002Ftmp\u002Ffile_that_does_not_exist.txt\"",[5525,16134,6778],{"class":5531},[5525,16136,16137],{"class":5527,"line":5993},[5525,16138,5850],{"emptyLinePlaceholder":5849},[5525,16140,16141,16143,16145,16148,16150],{"class":5527,"line":5999},[5525,16142,6144],{"class":6118},[5525,16144,6147],{"class":5531},[5525,16146,16147],{"class":5555},"\"Продовжуємо роботу без зупинки\"",[5525,16149,7299],{"class":5531},[5525,16151,16152],{"class":5545},"# виконається\n",[5748,16154,16156,16159],{"id":16155},"contextlibcontextmanager-декораторний-спосіб",[5507,16157,16158],{},"contextlib.contextmanager",": декораторний спосіб",[5512,16161,16162,16163,5597,16165,16167,16168,16170],{},"Для простих випадків писати клас із ",[5507,16164,14695],{},[5507,16166,14698],{}," — зайво. ",[5507,16169,16158],{}," дозволяє створити контекстний менеджер з генераторної функції:",[5516,16172,16174],{"className":5518,"code":16173,"language":5520,"meta":5521,"style":5521},"from contextlib import contextmanager\nimport time\n\n@contextmanager\ndef timer(label: str):\n    \"\"\"\n    Контекстний менеджер для вимірювання часу виконання блоку.\n    \n    yield розділяє __enter__ (код до yield) та __exit__ (код після yield).\n    Значення після yield — це те, що прив'язується до 'as'.\n    \"\"\"\n    start = time.perf_counter()\n    results = {}\n    try:\n        yield results          # __enter__: передаємо словник для результатів\n    finally:\n        elapsed = time.perf_counter() - start\n        results['elapsed'] = elapsed\n        print(f\"[{label}] виконано за {elapsed:.4f}с\")\n\n\nwith timer(\"Сортування\") as info:\n    data = list(range(100_000, 0, -1))\n    data.sort()\n\nprint(f\"Деталі: {info}\")\n# [Сортування] виконано за 0.0089с\n# Деталі: {'elapsed': 0.0089...}\n",[5507,16175,16176,16188,16195,16199,16204,16222,16226,16231,16235,16240,16245,16249,16254,16259,16265,16276,16283,16288,16299,16331,16335,16339,16357,16385,16390,16394,16416,16421],{"__ignoreMap":5521},[5525,16177,16178,16180,16183,16185],{"class":5527,"line":5528},[5525,16179,6512],{"class":6091},[5525,16181,16182],{"class":5531}," contextlib ",[5525,16184,6518],{"class":6091},[5525,16186,16187],{"class":5531}," contextmanager\n",[5525,16189,16190,16192],{"class":5527,"line":5549},[5525,16191,6518],{"class":6091},[5525,16193,16194],{"class":5531}," time\n",[5525,16196,16197],{"class":5527,"line":5567},[5525,16198,5850],{"emptyLinePlaceholder":5849},[5525,16200,16201],{"class":5527,"line":5816},[5525,16202,16203],{"class":6118},"@contextmanager\n",[5525,16205,16206,16208,16211,16213,16216,16218,16220],{"class":5527,"line":5822},[5525,16207,14352],{"class":6078},[5525,16209,16210],{"class":6118}," timer",[5525,16212,6147],{"class":5531},[5525,16214,16215],{"class":6207},"label",[5525,16217,6127],{"class":5531},[5525,16219,6565],{"class":6082},[5525,16221,6211],{"class":5531},[5525,16223,16224],{"class":5527,"line":5828},[5525,16225,11599],{"class":5555},[5525,16227,16228],{"class":5527,"line":5834},[5525,16229,16230],{"class":5555},"    Контекстний менеджер для вимірювання часу виконання блоку.\n",[5525,16232,16233],{"class":5527,"line":5840},[5525,16234,6544],{"class":5555},[5525,16236,16237],{"class":5527,"line":5846},[5525,16238,16239],{"class":5555},"    yield розділяє __enter__ (код до yield) та __exit__ (код після yield).\n",[5525,16241,16242],{"class":5527,"line":5853},[5525,16243,16244],{"class":5555},"    Значення після yield — це те, що прив'язується до 'as'.\n",[5525,16246,16247],{"class":5527,"line":5859},[5525,16248,11599],{"class":5555},[5525,16250,16251],{"class":5527,"line":5865},[5525,16252,16253],{"class":5531},"    start = time.perf_counter()\n",[5525,16255,16256],{"class":5527,"line":5871},[5525,16257,16258],{"class":5531},"    results = {}\n",[5525,16260,16261,16263],{"class":5527,"line":5877},[5525,16262,14808],{"class":6091},[5525,16264,6086],{"class":5531},[5525,16266,16267,16270,16273],{"class":5527,"line":5883},[5525,16268,16269],{"class":6091},"        yield",[5525,16271,16272],{"class":5531}," results          ",[5525,16274,16275],{"class":5545},"# __enter__: передаємо словник для результатів\n",[5525,16277,16278,16281],{"class":5527,"line":5889},[5525,16279,16280],{"class":6091},"    finally",[5525,16282,6086],{"class":5531},[5525,16284,16285],{"class":5527,"line":5895},[5525,16286,16287],{"class":5531},"        elapsed = time.perf_counter() - start\n",[5525,16289,16290,16293,16296],{"class":5527,"line":5901},[5525,16291,16292],{"class":5531},"        results[",[5525,16294,16295],{"class":5555},"'elapsed'",[5525,16297,16298],{"class":5531},"] = elapsed\n",[5525,16300,16301,16303,16305,16307,16309,16311,16313,16315,16318,16320,16323,16326,16329],{"class":5527,"line":5906},[5525,16302,15544],{"class":6118},[5525,16304,6147],{"class":5531},[5525,16306,7333],{"class":6078},[5525,16308,6788],{"class":5555},[5525,16310,6791],{"class":6078},[5525,16312,16215],{"class":5531},[5525,16314,6797],{"class":6078},[5525,16316,16317],{"class":5555},"] виконано за ",[5525,16319,6791],{"class":6078},[5525,16321,16322],{"class":5531},"elapsed",[5525,16324,16325],{"class":6078},":.4f}",[5525,16327,16328],{"class":5555},"с\"",[5525,16330,6778],{"class":5531},[5525,16332,16333],{"class":5527,"line":5911},[5525,16334,5850],{"emptyLinePlaceholder":5849},[5525,16336,16337],{"class":5527,"line":5917},[5525,16338,5850],{"emptyLinePlaceholder":5849},[5525,16340,16341,16343,16346,16349,16352,16354],{"class":5527,"line":5923},[5525,16342,5680],{"class":6091},[5525,16344,16345],{"class":5531}," timer(",[5525,16347,16348],{"class":5555},"\"Сортування\"",[5525,16350,16351],{"class":5531},") ",[5525,16353,14716],{"class":6091},[5525,16355,16356],{"class":5531}," info:\n",[5525,16358,16359,16362,16364,16366,16369,16371,16374,16376,16378,16380,16382],{"class":5527,"line":5929},[5525,16360,16361],{"class":5531},"    data = ",[5525,16363,9575],{"class":6082},[5525,16365,6147],{"class":5531},[5525,16367,16368],{"class":6118},"range",[5525,16370,6147],{"class":5531},[5525,16372,16373],{"class":5535},"100_000",[5525,16375,5614],{"class":5531},[5525,16377,8191],{"class":5535},[5525,16379,12291],{"class":5531},[5525,16381,8161],{"class":5535},[5525,16383,16384],{"class":5531},"))\n",[5525,16386,16387],{"class":5527,"line":5935},[5525,16388,16389],{"class":5531},"    data.sort()\n",[5525,16391,16392],{"class":5527,"line":5941},[5525,16393,5850],{"emptyLinePlaceholder":5849},[5525,16395,16396,16398,16400,16402,16405,16407,16410,16412,16414],{"class":5527,"line":5947},[5525,16397,6144],{"class":6118},[5525,16399,6147],{"class":5531},[5525,16401,7333],{"class":6078},[5525,16403,16404],{"class":5555},"\"Деталі: ",[5525,16406,6791],{"class":6078},[5525,16408,16409],{"class":5531},"info",[5525,16411,6797],{"class":6078},[5525,16413,7146],{"class":5555},[5525,16415,6778],{"class":5531},[5525,16417,16418],{"class":5527,"line":5953},[5525,16419,16420],{"class":5545},"# [Сортування] виконано за 0.0089с\n",[5525,16422,16423],{"class":5527,"line":5959},[5525,16424,16425],{"class":5545},"# Деталі: {'elapsed': 0.0089...}\n",[6902,16427,16428,16429,7437,16432,9562,16434,16437,16438,16440,16441,7437,16444,16446,16447,16449,16450,16453,16454,16456,16457,16459],{},"Код ",[5607,16430,16431],{},"до",[5507,16433,13007],{},[5507,16435,16436],{},"contextmanager","-генераторі виконується як ",[5507,16439,14695],{},". Код ",[5607,16442,16443],{},"після",[5507,16445,13007],{}," — як ",[5507,16448,14698],{},". Блок ",[5507,16451,16452],{},"try\u002Ffinally"," навколо ",[5507,16455,13007],{}," гарантує виконання коду очищення навіть при виключенні всередині ",[5507,16458,5680],{},"-блоку.",[5741,16461],{},[5502,16463,16465],{"id":16464},"частина-viii-протокол-атрибутів","Частина VIII: Протокол атрибутів",[5748,16467,16469],{"id":16468},"перехоплення-доступу-до-атрибутів","Перехоплення доступу до атрибутів",[5512,16471,16472],{},"Python надає чотири методи для перехоплення операцій з атрибутами:",[6256,16474,16475,16488,16499,16515],{},[6259,16476,16479,16480,16483,16484,16487],{"name":16477,"type":16478},"__getattribute__(self, name: str)","Перехоплення БУДЬ-ЯКОГО читання","Викликається при кожному зверненні до атрибута: ",[5507,16481,16482],{},"obj.attr",". Перехоплює навіть атрибути, що існують. Перевизначення вимагає обережності — необхідно звертатись до ",[5507,16485,16486],{},"super().__getattribute__(name)",", щоб не потрапити у нескінченну рекурсію. Використовується рідко.",[6259,16489,11414,16492,16495,16496,16498],{"name":16490,"type":16491},"__getattr__(self, name: str)","Перехоплення ВІДСУТНЬОГО атрибута",[5607,16493,16494],{},"лише"," якщо атрибут не знайдено стандартним способом (не в ",[5507,16497,6063],{}," та не в класі). Ідеальний для lazy-завантаження, проксі-об'єктів та динамічних API.",[6259,16500,16503,16504,16507,16508,14734,16511,16514],{"name":16501,"type":16502},"__setattr__(self, name: str, value)","Перехоплення запису","Викликається при кожному ",[5507,16505,16506],{},"obj.attr = value",". Для збереження значення потрібно звертатись до ",[5507,16509,16510],{},"object.__setattr__(self, name, value)",[5507,16512,16513],{},"self.__dict__[name] = value",", щоб уникнути рекурсії.",[6259,16516,16519,16520,5659],{"name":16517,"type":16518},"__delattr__(self, name: str)","Перехоплення видалення","Викликається при ",[5507,16521,16522],{},"del obj.attr",[5748,16524,16526],{"id":16525},"практичний-сценарій-frozen-обєкт-незмінний-після-ініціалізації","Практичний сценарій: Frozen об'єкт (незмінний після ініціалізації)",[5516,16528,16530],{"className":5518,"code":16529,"language":5520,"meta":5521,"style":5521},"class FrozenObject:\n    \"\"\"\n    Об'єкт, атрибути якого можна встановити лише в __init__.\n    Після завершення ініціалізації будь-яка спроба змінити\n    або додати атрибут піднімає AttributeError.\n    \n    Досягається перехопленням __setattr__.\n    \"\"\"\n    \n    _is_initialized = False  # атрибут класу — не блокується __setattr__\n    \n    def __init__(self, **kwargs):\n        # Тимчасово дозволяємо запис для ініціалізації\n        for key, value in kwargs.items():\n            # Звертаємось до базового __setattr__ щоб уникнути рекурсії\n            object.__setattr__(self, key, value)\n        # Позначаємо: ініціалізація завершена\n        object.__setattr__(self, '_is_initialized', True)\n    \n    def __setattr__(self, name: str, value) -> None:\n        if self._is_initialized:\n            raise AttributeError(\n                f\"Об'єкт {type(self).__name__!r} є незмінним. \"\n                f\"Неможливо встановити '{name}'\"\n            )\n        object.__setattr__(self, name, value)\n    \n    def __delattr__(self, name: str) -> None:\n        raise AttributeError(\n            f\"Об'єкт {type(self).__name__!r} є незмінним. \"\n            f\"Неможливо видалити '{name}'\"\n        )\n    \n    def __repr__(self) -> str:\n        attrs = {k: v for k, v in self.__dict__.items() if not k.startswith('_')}\n        params = ', '.join(f\"{k}={v!r}\" for k, v in attrs.items())\n        return f\"{type(self).__name__}({params})\"\n\n\nconfig = FrozenObject(host=\"localhost\", port=5432, db=\"myapp\")\nprint(config)           # FrozenObject(host='localhost', port=5432, db='myapp')\nprint(config.host)      # localhost\n\ntry:\n    config.host = \"production.db\"   # AttributeError!\nexcept AttributeError as e:\n    print(f\"Помилка: {e}\")\n\ntry:\n    config.new_field = \"oops\"       # AttributeError!\nexcept AttributeError as e:\n    print(f\"Помилка: {e}\")\n",[5507,16531,16532,16541,16545,16550,16555,16560,16564,16569,16573,16577,16587,16591,16607,16612,16624,16629,16646,16651,16675,16679,16709,16718,16727,16751,16767,16771,16786,16790,16815,16823,16845,16860,16864,16868,16884,16919,16959,16991,16995,16999,17034,17044,17054,17058,17064,17075,17085,17106,17110,17116,17127,17137],{"__ignoreMap":5521},[5525,16533,16534,16536,16539],{"class":5527,"line":5528},[5525,16535,6079],{"class":6078},[5525,16537,16538],{"class":6082}," FrozenObject",[5525,16540,6086],{"class":5531},[5525,16542,16543],{"class":5527,"line":5549},[5525,16544,11599],{"class":5555},[5525,16546,16547],{"class":5527,"line":5567},[5525,16548,16549],{"class":5555},"    Об'єкт, атрибути якого можна встановити лише в __init__.\n",[5525,16551,16552],{"class":5527,"line":5816},[5525,16553,16554],{"class":5555},"    Після завершення ініціалізації будь-яка спроба змінити\n",[5525,16556,16557],{"class":5527,"line":5822},[5525,16558,16559],{"class":5555},"    або додати атрибут піднімає AttributeError.\n",[5525,16561,16562],{"class":5527,"line":5828},[5525,16563,6544],{"class":5555},[5525,16565,16566],{"class":5527,"line":5834},[5525,16567,16568],{"class":5555},"    Досягається перехопленням __setattr__.\n",[5525,16570,16571],{"class":5527,"line":5840},[5525,16572,11599],{"class":5555},[5525,16574,16575],{"class":5527,"line":5846},[5525,16576,6544],{"class":5531},[5525,16578,16579,16582,16584],{"class":5527,"line":5853},[5525,16580,16581],{"class":5531},"    _is_initialized = ",[5525,16583,8391],{"class":6078},[5525,16585,16586],{"class":5545},"  # атрибут класу — не блокується __setattr__\n",[5525,16588,16589],{"class":5527,"line":5859},[5525,16590,6544],{"class":5531},[5525,16592,16593,16595,16597,16599,16601,16603,16605],{"class":5527,"line":5865},[5525,16594,6199],{"class":6078},[5525,16596,6551],{"class":6118},[5525,16598,6147],{"class":5531},[5525,16600,6208],{"class":6207},[5525,16602,13941],{"class":5531},[5525,16604,13944],{"class":6207},[5525,16606,6211],{"class":5531},[5525,16608,16609],{"class":5527,"line":5871},[5525,16610,16611],{"class":5545},"        # Тимчасово дозволяємо запис для ініціалізації\n",[5525,16613,16614,16616,16619,16621],{"class":5527,"line":5877},[5525,16615,11999],{"class":6091},[5525,16617,16618],{"class":5531}," key, value ",[5525,16620,11475],{"class":6091},[5525,16622,16623],{"class":5531}," kwargs.items():\n",[5525,16625,16626],{"class":5527,"line":5883},[5525,16627,16628],{"class":5545},"            # Звертаємось до базового __setattr__ щоб уникнути рекурсії\n",[5525,16630,16631,16634,16636,16639,16641,16643],{"class":5527,"line":5889},[5525,16632,16633],{"class":6082},"            object",[5525,16635,5659],{"class":5531},[5525,16637,16638],{"class":6118},"__setattr__",[5525,16640,6147],{"class":5531},[5525,16642,6208],{"class":6078},[5525,16644,16645],{"class":5531},", key, value)\n",[5525,16647,16648],{"class":5527,"line":5895},[5525,16649,16650],{"class":5545},"        # Позначаємо: ініціалізація завершена\n",[5525,16652,16653,16656,16658,16660,16662,16664,16666,16669,16671,16673],{"class":5527,"line":5901},[5525,16654,16655],{"class":6082},"        object",[5525,16657,5659],{"class":5531},[5525,16659,16638],{"class":6118},[5525,16661,6147],{"class":5531},[5525,16663,6208],{"class":6078},[5525,16665,5614],{"class":5531},[5525,16667,16668],{"class":5555},"'_is_initialized'",[5525,16670,5614],{"class":5531},[5525,16672,8352],{"class":6078},[5525,16674,6778],{"class":5531},[5525,16676,16677],{"class":5527,"line":5906},[5525,16678,6544],{"class":5531},[5525,16680,16681,16683,16686,16688,16690,16692,16695,16697,16699,16701,16703,16705,16707],{"class":5527,"line":5911},[5525,16682,6199],{"class":6078},[5525,16684,16685],{"class":6118}," __setattr__",[5525,16687,6147],{"class":5531},[5525,16689,6208],{"class":6207},[5525,16691,5614],{"class":5531},[5525,16693,16694],{"class":6207},"name",[5525,16696,6127],{"class":5531},[5525,16698,6565],{"class":6082},[5525,16700,5614],{"class":5531},[5525,16702,13567],{"class":6207},[5525,16704,6637],{"class":5531},[5525,16706,6585],{"class":6078},[5525,16708,6086],{"class":5531},[5525,16710,16711,16713,16715],{"class":5527,"line":5917},[5525,16712,7220],{"class":6091},[5525,16714,7023],{"class":6078},[5525,16716,16717],{"class":5531},"._is_initialized:\n",[5525,16719,16720,16722,16725],{"class":5527,"line":5923},[5525,16721,8669],{"class":6091},[5525,16723,16724],{"class":6082}," AttributeError",[5525,16726,12105],{"class":5531},[5525,16728,16729,16731,16734,16736,16738,16740,16742,16744,16746,16748],{"class":5527,"line":5929},[5525,16730,12110],{"class":6078},[5525,16732,16733],{"class":5555},"\"Об'єкт ",[5525,16735,6791],{"class":6078},[5525,16737,14592],{"class":6082},[5525,16739,6147],{"class":5531},[5525,16741,6208],{"class":6078},[5525,16743,6178],{"class":5531},[5525,16745,14952],{"class":6207},[5525,16747,6682],{"class":6078},[5525,16749,16750],{"class":5555}," є незмінним. \"\n",[5525,16752,16753,16755,16758,16760,16762,16764],{"class":5527,"line":5935},[5525,16754,12110],{"class":6078},[5525,16756,16757],{"class":5555},"\"Неможливо встановити '",[5525,16759,6791],{"class":6078},[5525,16761,16694],{"class":5531},[5525,16763,6797],{"class":6078},[5525,16765,16766],{"class":5555},"'\"\n",[5525,16768,16769],{"class":5527,"line":5941},[5525,16770,12136],{"class":5531},[5525,16772,16773,16775,16777,16779,16781,16783],{"class":5527,"line":5947},[5525,16774,16655],{"class":6082},[5525,16776,5659],{"class":5531},[5525,16778,16638],{"class":6118},[5525,16780,6147],{"class":5531},[5525,16782,6208],{"class":6078},[5525,16784,16785],{"class":5531},", name, value)\n",[5525,16787,16788],{"class":5527,"line":5953},[5525,16789,6544],{"class":5531},[5525,16791,16792,16794,16797,16799,16801,16803,16805,16807,16809,16811,16813],{"class":5527,"line":5959},[5525,16793,6199],{"class":6078},[5525,16795,16796],{"class":6118}," __delattr__",[5525,16798,6147],{"class":5531},[5525,16800,6208],{"class":6207},[5525,16802,5614],{"class":5531},[5525,16804,16694],{"class":6207},[5525,16806,6127],{"class":5531},[5525,16808,6565],{"class":6082},[5525,16810,6637],{"class":5531},[5525,16812,6585],{"class":6078},[5525,16814,6086],{"class":5531},[5525,16816,16817,16819,16821],{"class":5527,"line":5964},[5525,16818,14577],{"class":6091},[5525,16820,16724],{"class":6082},[5525,16822,12105],{"class":5531},[5525,16824,16825,16827,16829,16831,16833,16835,16837,16839,16841,16843],{"class":5527,"line":5969},[5525,16826,6663],{"class":6078},[5525,16828,16733],{"class":5555},[5525,16830,6791],{"class":6078},[5525,16832,14592],{"class":6082},[5525,16834,6147],{"class":5531},[5525,16836,6208],{"class":6078},[5525,16838,6178],{"class":5531},[5525,16840,14952],{"class":6207},[5525,16842,6682],{"class":6078},[5525,16844,16750],{"class":5555},[5525,16846,16847,16849,16852,16854,16856,16858],{"class":5527,"line":5975},[5525,16848,6663],{"class":6078},[5525,16850,16851],{"class":5555},"\"Неможливо видалити '",[5525,16853,6791],{"class":6078},[5525,16855,16694],{"class":5531},[5525,16857,6797],{"class":6078},[5525,16859,16766],{"class":5555},[5525,16861,16862],{"class":5527,"line":5981},[5525,16863,6730],{"class":5531},[5525,16865,16866],{"class":5527,"line":5987},[5525,16867,6544],{"class":5531},[5525,16869,16870,16872,16874,16876,16878,16880,16882],{"class":5527,"line":5993},[5525,16871,6199],{"class":6078},[5525,16873,6630],{"class":6118},[5525,16875,6147],{"class":5531},[5525,16877,6208],{"class":6207},[5525,16879,6637],{"class":5531},[5525,16881,6565],{"class":6082},[5525,16883,6086],{"class":5531},[5525,16885,16886,16889,16891,16894,16896,16898,16900,16902,16905,16908,16910,16913,16916],{"class":5527,"line":5999},[5525,16887,16888],{"class":5531},"        attrs = {k: v ",[5525,16890,11866],{"class":6091},[5525,16892,16893],{"class":5531}," k, v ",[5525,16895,11475],{"class":6091},[5525,16897,7023],{"class":6078},[5525,16899,5659],{"class":5531},[5525,16901,6063],{"class":6207},[5525,16903,16904],{"class":5531},".items() ",[5525,16906,16907],{"class":6091},"if",[5525,16909,7902],{"class":6078},[5525,16911,16912],{"class":5531}," k.startswith(",[5525,16914,16915],{"class":5555},"'_'",[5525,16917,16918],{"class":5531},")}\n",[5525,16920,16921,16924,16926,16928,16930,16932,16934,16937,16939,16941,16943,16946,16948,16950,16952,16954,16956],{"class":5527,"line":6005},[5525,16922,16923],{"class":5531},"        params = ",[5525,16925,11855],{"class":5555},[5525,16927,11858],{"class":5531},[5525,16929,7333],{"class":6078},[5525,16931,7146],{"class":5555},[5525,16933,6791],{"class":6078},[5525,16935,16936],{"class":5531},"k",[5525,16938,6797],{"class":6078},[5525,16940,12617],{"class":5555},[5525,16942,6791],{"class":6078},[5525,16944,16945],{"class":5531},"v",[5525,16947,6682],{"class":6078},[5525,16949,7146],{"class":5555},[5525,16951,12840],{"class":6091},[5525,16953,16893],{"class":5531},[5525,16955,11475],{"class":6091},[5525,16957,16958],{"class":5531}," attrs.items())\n",[5525,16960,16961,16963,16965,16967,16969,16971,16973,16975,16977,16979,16981,16983,16985,16987,16989],{"class":5527,"line":6011},[5525,16962,6216],{"class":6091},[5525,16964,6785],{"class":6078},[5525,16966,7146],{"class":5555},[5525,16968,6791],{"class":6078},[5525,16970,14592],{"class":6082},[5525,16972,6147],{"class":5531},[5525,16974,6208],{"class":6078},[5525,16976,6178],{"class":5531},[5525,16978,14952],{"class":6207},[5525,16980,6797],{"class":6078},[5525,16982,6147],{"class":5555},[5525,16984,6791],{"class":6078},[5525,16986,15393],{"class":5531},[5525,16988,6797],{"class":6078},[5525,16990,7117],{"class":5555},[5525,16992,16993],{"class":5527,"line":6016},[5525,16994,5850],{"emptyLinePlaceholder":5849},[5525,16996,16997],{"class":5527,"line":6022},[5525,16998,5850],{"emptyLinePlaceholder":5849},[5525,17000,17001,17004,17007,17009,17012,17014,17017,17019,17022,17024,17027,17029,17032],{"class":5527,"line":6028},[5525,17002,17003],{"class":5531},"config = FrozenObject(",[5525,17005,17006],{"class":6207},"host",[5525,17008,12617],{"class":5531},[5525,17010,17011],{"class":5555},"\"localhost\"",[5525,17013,5614],{"class":5531},[5525,17015,17016],{"class":6207},"port",[5525,17018,12617],{"class":5531},[5525,17020,17021],{"class":5535},"5432",[5525,17023,5614],{"class":5531},[5525,17025,17026],{"class":6207},"db",[5525,17028,12617],{"class":5531},[5525,17030,17031],{"class":5555},"\"myapp\"",[5525,17033,6778],{"class":5531},[5525,17035,17036,17038,17041],{"class":5527,"line":6034},[5525,17037,6144],{"class":6118},[5525,17039,17040],{"class":5531},"(config)           ",[5525,17042,17043],{"class":5545},"# FrozenObject(host='localhost', port=5432, db='myapp')\n",[5525,17045,17046,17048,17051],{"class":5527,"line":6040},[5525,17047,6144],{"class":6118},[5525,17049,17050],{"class":5531},"(config.host)      ",[5525,17052,17053],{"class":5545},"# localhost\n",[5525,17055,17056],{"class":5527,"line":6046},[5525,17057,5850],{"emptyLinePlaceholder":5849},[5525,17059,17060,17062],{"class":5527,"line":8117},[5525,17061,14801],{"class":6091},[5525,17063,6086],{"class":5531},[5525,17065,17066,17069,17072],{"class":5527,"line":8128},[5525,17067,17068],{"class":5531},"    config.host = ",[5525,17070,17071],{"class":5555},"\"production.db\"",[5525,17073,17074],{"class":5545},"   # AttributeError!\n",[5525,17076,17077,17079,17081,17083],{"class":5527,"line":8135},[5525,17078,15740],{"class":6091},[5525,17080,16724],{"class":6082},[5525,17082,15745],{"class":6091},[5525,17084,15748],{"class":5531},[5525,17086,17087,17089,17091,17093,17096,17098,17100,17102,17104],{"class":5527,"line":8145},[5525,17088,15753],{"class":6118},[5525,17090,6147],{"class":5531},[5525,17092,7333],{"class":6078},[5525,17094,17095],{"class":5555},"\"Помилка: ",[5525,17097,6791],{"class":6078},[5525,17099,15765],{"class":5531},[5525,17101,6797],{"class":6078},[5525,17103,7146],{"class":5555},[5525,17105,6778],{"class":5531},[5525,17107,17108],{"class":5527,"line":8150},[5525,17109,5850],{"emptyLinePlaceholder":5849},[5525,17111,17112,17114],{"class":5527,"line":8155},[5525,17113,14801],{"class":6091},[5525,17115,6086],{"class":5531},[5525,17117,17118,17121,17124],{"class":5527,"line":8176},[5525,17119,17120],{"class":5531},"    config.new_field = ",[5525,17122,17123],{"class":5555},"\"oops\"",[5525,17125,17126],{"class":5545},"       # AttributeError!\n",[5525,17128,17129,17131,17133,17135],{"class":5527,"line":8196},[5525,17130,15740],{"class":6091},[5525,17132,16724],{"class":6082},[5525,17134,15745],{"class":6091},[5525,17136,15748],{"class":5531},[5525,17138,17139,17141,17143,17145,17147,17149,17151,17153,17155],{"class":5527,"line":8214},[5525,17140,15753],{"class":6118},[5525,17142,6147],{"class":5531},[5525,17144,7333],{"class":6078},[5525,17146,17095],{"class":5555},[5525,17148,6791],{"class":6078},[5525,17150,15765],{"class":5531},[5525,17152,6797],{"class":6078},[5525,17154,7146],{"class":5555},[5525,17156,6778],{"class":5531},[7425,17158,17160,17168,17177,17185,17193],{"title":17159},"python frozen.py",[7429,17161,17163,7437,17166],{"className":17162},[5527],[5525,17164,7436],{"className":17165},[7435],[5607,17167,17159],{},[7429,17169,17171,17172,17176],{"className":17170},[5527],"FrozenObject(",[5525,17173,17175],{"className":17174},[7463],"host='localhost', port=5432, db='myapp'",")",[7429,17178,17180,17181],{"className":17179},[5527],"config.host: ",[5525,17182,17184],{"className":17183},[8351],"localhost",[7429,17186,17188,17189],{"className":17187},[5527],"Помилка: ",[5525,17190,17192],{"className":17191},[10785],"Об'єкт 'FrozenObject' є незмінним. Неможливо встановити 'host'",[7429,17194,17188,17196],{"className":17195},[5527],[5525,17197,17199],{"className":17198},[10785],"Об'єкт 'FrozenObject' є незмінним. Неможливо встановити 'new_field'",[5748,17201,17203,17206],{"id":17202},"__getattr__-для-динамічних-проксі",[5507,17204,17205],{},"__getattr__"," для динамічних проксі",[5512,17208,17209,17211],{},[5507,17210,17205],{}," є ідеальним для побудови проксі-об'єктів та динамічних делегаторів:",[5516,17213,17215],{"className":5518,"code":17214,"language":5520,"meta":5521,"style":5521},"class LazyLoader:\n    \"\"\"\n    Проксі-об'єкт, що ліниво завантажує важкі атрибути\n    лише при першому зверненні до них.\n    \"\"\"\n    \n    def __init__(self):\n        self._cache: dict = {}\n    \n    def __getattr__(self, name: str):\n        # Цей метод викликається ЛИШЕ якщо 'name' не знайдено звичайним шляхом\n        if name in self._cache:\n            return self._cache[name]\n        \n        # Симуляція важкого обчислення\n        print(f\"[LazyLoader] Завантаження '{name}'...\")\n        import time; time.sleep(0.01)  # у реальності: читання файлу, запит до БД\n        \n        value = f\"\u003Cзначення для {name}>\"\n        self._cache[name] = value\n        # Зберігаємо в __dict__, щоб наступного разу __getattr__ не викликався\n        object.__setattr__(self, name, value)\n        return value\n\n\nloader = LazyLoader()\nprint(loader.config)    # [LazyLoader] Завантаження 'config'...  → \u003Cзначення для config>\nprint(loader.config)    # \u003Cзначення для config>  ← кеш, без завантаження\nprint(loader.schema)    # [LazyLoader] Завантаження 'schema'...  → \u003Cзначення для schema>\n",[5507,17216,17217,17226,17230,17235,17240,17244,17248,17260,17272,17276,17297,17302,17315,17324,17328,17333,17355,17371,17375,17393,17400,17405,17419,17425,17429,17433,17438,17448,17457],{"__ignoreMap":5521},[5525,17218,17219,17221,17224],{"class":5527,"line":5528},[5525,17220,6079],{"class":6078},[5525,17222,17223],{"class":6082}," LazyLoader",[5525,17225,6086],{"class":5531},[5525,17227,17228],{"class":5527,"line":5549},[5525,17229,11599],{"class":5555},[5525,17231,17232],{"class":5527,"line":5567},[5525,17233,17234],{"class":5555},"    Проксі-об'єкт, що ліниво завантажує важкі атрибути\n",[5525,17236,17237],{"class":5527,"line":5816},[5525,17238,17239],{"class":5555},"    лише при першому зверненні до них.\n",[5525,17241,17242],{"class":5527,"line":5822},[5525,17243,11599],{"class":5555},[5525,17245,17246],{"class":5527,"line":5828},[5525,17247,6544],{"class":5531},[5525,17249,17250,17252,17254,17256,17258],{"class":5527,"line":5834},[5525,17251,6199],{"class":6078},[5525,17253,6551],{"class":6118},[5525,17255,6147],{"class":5531},[5525,17257,6208],{"class":6207},[5525,17259,6211],{"class":5531},[5525,17261,17262,17264,17267,17269],{"class":5527,"line":5840},[5525,17263,6596],{"class":6078},[5525,17265,17266],{"class":5531},"._cache: ",[5525,17268,6319],{"class":6082},[5525,17270,17271],{"class":5531}," = {}\n",[5525,17273,17274],{"class":5527,"line":5846},[5525,17275,6544],{"class":5531},[5525,17277,17278,17280,17283,17285,17287,17289,17291,17293,17295],{"class":5527,"line":5853},[5525,17279,6199],{"class":6078},[5525,17281,17282],{"class":6118}," __getattr__",[5525,17284,6147],{"class":5531},[5525,17286,6208],{"class":6207},[5525,17288,5614],{"class":5531},[5525,17290,16694],{"class":6207},[5525,17292,6127],{"class":5531},[5525,17294,6565],{"class":6082},[5525,17296,6211],{"class":5531},[5525,17298,17299],{"class":5527,"line":5859},[5525,17300,17301],{"class":5545},"        # Цей метод викликається ЛИШЕ якщо 'name' не знайдено звичайним шляхом\n",[5525,17303,17304,17306,17309,17311,17313],{"class":5527,"line":5865},[5525,17305,7220],{"class":6091},[5525,17307,17308],{"class":5531}," name ",[5525,17310,11475],{"class":6078},[5525,17312,7023],{"class":6078},[5525,17314,14064],{"class":5531},[5525,17316,17317,17319,17321],{"class":5527,"line":5871},[5525,17318,7233],{"class":6091},[5525,17320,7023],{"class":6078},[5525,17322,17323],{"class":5531},"._cache[name]\n",[5525,17325,17326],{"class":5527,"line":5877},[5525,17327,12408],{"class":5531},[5525,17329,17330],{"class":5527,"line":5883},[5525,17331,17332],{"class":5545},"        # Симуляція важкого обчислення\n",[5525,17334,17335,17337,17339,17341,17344,17346,17348,17350,17353],{"class":5527,"line":5889},[5525,17336,15544],{"class":6118},[5525,17338,6147],{"class":5531},[5525,17340,7333],{"class":6078},[5525,17342,17343],{"class":5555},"\"[LazyLoader] Завантаження '",[5525,17345,6791],{"class":6078},[5525,17347,16694],{"class":5531},[5525,17349,6797],{"class":6078},[5525,17351,17352],{"class":5555},"'...\"",[5525,17354,6778],{"class":5531},[5525,17356,17357,17360,17363,17366,17368],{"class":5527,"line":5895},[5525,17358,17359],{"class":6091},"        import",[5525,17361,17362],{"class":5531}," time; time.sleep(",[5525,17364,17365],{"class":5535},"0.01",[5525,17367,7299],{"class":5531},[5525,17369,17370],{"class":5545},"# у реальності: читання файлу, запит до БД\n",[5525,17372,17373],{"class":5527,"line":5901},[5525,17374,12408],{"class":5531},[5525,17376,17377,17379,17381,17384,17386,17388,17390],{"class":5527,"line":5906},[5525,17378,13248],{"class":5531},[5525,17380,7333],{"class":6078},[5525,17382,17383],{"class":5555},"\"\u003Cзначення для ",[5525,17385,6791],{"class":6078},[5525,17387,16694],{"class":5531},[5525,17389,6797],{"class":6078},[5525,17391,17392],{"class":5555},">\"\n",[5525,17394,17395,17397],{"class":5527,"line":5911},[5525,17396,6596],{"class":6078},[5525,17398,17399],{"class":5531},"._cache[name] = value\n",[5525,17401,17402],{"class":5527,"line":5917},[5525,17403,17404],{"class":5545},"        # Зберігаємо в __dict__, щоб наступного разу __getattr__ не викликався\n",[5525,17406,17407,17409,17411,17413,17415,17417],{"class":5527,"line":5923},[5525,17408,16655],{"class":6082},[5525,17410,5659],{"class":5531},[5525,17412,16638],{"class":6118},[5525,17414,6147],{"class":5531},[5525,17416,6208],{"class":6078},[5525,17418,16785],{"class":5531},[5525,17420,17421,17423],{"class":5527,"line":5929},[5525,17422,6216],{"class":6091},[5525,17424,13269],{"class":5531},[5525,17426,17427],{"class":5527,"line":5935},[5525,17428,5850],{"emptyLinePlaceholder":5849},[5525,17430,17431],{"class":5527,"line":5941},[5525,17432,5850],{"emptyLinePlaceholder":5849},[5525,17434,17435],{"class":5527,"line":5947},[5525,17436,17437],{"class":5531},"loader = LazyLoader()\n",[5525,17439,17440,17442,17445],{"class":5527,"line":5953},[5525,17441,6144],{"class":6118},[5525,17443,17444],{"class":5531},"(loader.config)    ",[5525,17446,17447],{"class":5545},"# [LazyLoader] Завантаження 'config'...  → \u003Cзначення для config>\n",[5525,17449,17450,17452,17454],{"class":5527,"line":5959},[5525,17451,6144],{"class":6118},[5525,17453,17444],{"class":5531},[5525,17455,17456],{"class":5545},"# \u003Cзначення для config>  ← кеш, без завантаження\n",[5525,17458,17459,17461,17464],{"class":5527,"line":5964},[5525,17460,6144],{"class":6118},[5525,17462,17463],{"class":5531},"(loader.schema)    ",[5525,17465,17466],{"class":5545},"# [LazyLoader] Завантаження 'schema'...  → \u003Cзначення для schema>\n",[5741,17468],{},[5502,17470,17472],{"id":17471},"частина-ix-схема-прийняття-рішень-та-підводні-камені","Частина IX: Схема прийняття рішень та підводні камені",[5748,17474,17476],{"id":17475},"коли-що-визначати-алгоритм-вибору","Коли що визначати: алгоритм вибору",[5512,17478,17479],{},"Перш ніж реалізовувати dunder-метод, варто відповісти на кілька запитань:",[5790,17481,17482],{},[5516,17483,17485],{"className":5794,"code":17484,"language":5796,"meta":5521,"style":5521},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\nskinparam ArrowColor #6366f1\n\nstart\n\n:Додаєш dunder-метод до класу?;\n\nif (Клас представляє «значення» або\\nматематичну сутність?) then (Так)\n    :Визначи __repr__, __str__;\n    :Визначи __eq__;\n    if (Об'єкт незмінний?) then (Так)\n        :Визнач __hash__;\n        note right: Тепер можна використовувати\\nяк ключ dict і в set\n    else (Ні \u002F мутабельний)\n        :НЕ визначай __hash__;\n        note right: Мутабельні об'єкти\\nне повинні бути hashable\n    endif\n    if (Потрібна арифметика?) then (Так)\n        :Визнач __add__, __radd__;\n        if (Потрібна += оптимізація?) then (Так)\n            :Визнач __iadd__;\n        endif\n    endif\nendif\n\nif (Клас веде себе як колекція?) then (Так)\n    :Визнач __len__ та __getitem__;\n    if (Мутабельна колекція?) then (Так)\n        :Визнач __setitem__, __delitem__;\n    endif\n    if (Потрібна оптимізована перевірка 'in'?) then (Так)\n        :Визнач __contains__;\n    endif\nendif\n\nif (Клас керує ресурсом\\n(файл, lock, з'єднання)?) then (Так)\n    :Визнач __enter__ та __exit__;\nendif\n\nif (Клас може бути викликаний\\nяк функція?) then (Так)\n    :Визнач __call__;\nendif\n\nstop\n@enduml\n",[5507,17486,17487,17491,17495,17499,17503,17507,17511,17515,17520,17524,17529,17534,17539,17544,17549,17554,17559,17564,17569,17573,17578,17583,17588,17593,17598,17602,17606,17610,17615,17620,17625,17630,17634,17639,17644,17648,17652,17656,17661,17666,17670,17674,17679,17684,17688,17692,17697],{"__ignoreMap":5521},[5525,17488,17489],{"class":5527,"line":5528},[5525,17490,5803],{},[5525,17492,17493],{"class":5527,"line":5549},[5525,17494,5808],{},[5525,17496,17497],{"class":5527,"line":5567},[5525,17498,5813],{},[5525,17500,17501],{"class":5527,"line":5816},[5525,17502,5819],{},[5525,17504,17505],{"class":5527,"line":5822},[5525,17506,5850],{"emptyLinePlaceholder":5849},[5525,17508,17509],{"class":5527,"line":5828},[5525,17510,10860],{},[5525,17512,17513],{"class":5527,"line":5834},[5525,17514,5850],{"emptyLinePlaceholder":5849},[5525,17516,17517],{"class":5527,"line":5840},[5525,17518,17519],{},":Додаєш dunder-метод до класу?;\n",[5525,17521,17522],{"class":5527,"line":5846},[5525,17523,5850],{"emptyLinePlaceholder":5849},[5525,17525,17526],{"class":5527,"line":5853},[5525,17527,17528],{},"if (Клас представляє «значення» або\\nматематичну сутність?) then (Так)\n",[5525,17530,17531],{"class":5527,"line":5859},[5525,17532,17533],{},"    :Визначи __repr__, __str__;\n",[5525,17535,17536],{"class":5527,"line":5865},[5525,17537,17538],{},"    :Визначи __eq__;\n",[5525,17540,17541],{"class":5527,"line":5871},[5525,17542,17543],{},"    if (Об'єкт незмінний?) then (Так)\n",[5525,17545,17546],{"class":5527,"line":5877},[5525,17547,17548],{},"        :Визнач __hash__;\n",[5525,17550,17551],{"class":5527,"line":5883},[5525,17552,17553],{},"        note right: Тепер можна використовувати\\nяк ключ dict і в set\n",[5525,17555,17556],{"class":5527,"line":5889},[5525,17557,17558],{},"    else (Ні \u002F мутабельний)\n",[5525,17560,17561],{"class":5527,"line":5895},[5525,17562,17563],{},"        :НЕ визначай __hash__;\n",[5525,17565,17566],{"class":5527,"line":5901},[5525,17567,17568],{},"        note right: Мутабельні об'єкти\\nне повинні бути hashable\n",[5525,17570,17571],{"class":5527,"line":5906},[5525,17572,10903],{},[5525,17574,17575],{"class":5527,"line":5911},[5525,17576,17577],{},"    if (Потрібна арифметика?) then (Так)\n",[5525,17579,17580],{"class":5527,"line":5917},[5525,17581,17582],{},"        :Визнач __add__, __radd__;\n",[5525,17584,17585],{"class":5527,"line":5923},[5525,17586,17587],{},"        if (Потрібна += оптимізація?) then (Так)\n",[5525,17589,17590],{"class":5527,"line":5929},[5525,17591,17592],{},"            :Визнач __iadd__;\n",[5525,17594,17595],{"class":5527,"line":5935},[5525,17596,17597],{},"        endif\n",[5525,17599,17600],{"class":5527,"line":5941},[5525,17601,10903],{},[5525,17603,17604],{"class":5527,"line":5947},[5525,17605,10908],{},[5525,17607,17608],{"class":5527,"line":5953},[5525,17609,5850],{"emptyLinePlaceholder":5849},[5525,17611,17612],{"class":5527,"line":5959},[5525,17613,17614],{},"if (Клас веде себе як колекція?) then (Так)\n",[5525,17616,17617],{"class":5527,"line":5964},[5525,17618,17619],{},"    :Визнач __len__ та __getitem__;\n",[5525,17621,17622],{"class":5527,"line":5969},[5525,17623,17624],{},"    if (Мутабельна колекція?) then (Так)\n",[5525,17626,17627],{"class":5527,"line":5975},[5525,17628,17629],{},"        :Визнач __setitem__, __delitem__;\n",[5525,17631,17632],{"class":5527,"line":5981},[5525,17633,10903],{},[5525,17635,17636],{"class":5527,"line":5987},[5525,17637,17638],{},"    if (Потрібна оптимізована перевірка 'in'?) then (Так)\n",[5525,17640,17641],{"class":5527,"line":5993},[5525,17642,17643],{},"        :Визнач __contains__;\n",[5525,17645,17646],{"class":5527,"line":5999},[5525,17647,10903],{},[5525,17649,17650],{"class":5527,"line":6005},[5525,17651,10908],{},[5525,17653,17654],{"class":5527,"line":6011},[5525,17655,5850],{"emptyLinePlaceholder":5849},[5525,17657,17658],{"class":5527,"line":6016},[5525,17659,17660],{},"if (Клас керує ресурсом\\n(файл, lock, з'єднання)?) then (Так)\n",[5525,17662,17663],{"class":5527,"line":6022},[5525,17664,17665],{},"    :Визнач __enter__ та __exit__;\n",[5525,17667,17668],{"class":5527,"line":6028},[5525,17669,10908],{},[5525,17671,17672],{"class":5527,"line":6034},[5525,17673,5850],{"emptyLinePlaceholder":5849},[5525,17675,17676],{"class":5527,"line":6040},[5525,17677,17678],{},"if (Клас може бути викликаний\\nяк функція?) then (Так)\n",[5525,17680,17681],{"class":5527,"line":6046},[5525,17682,17683],{},"    :Визнач __call__;\n",[5525,17685,17686],{"class":5527,"line":8117},[5525,17687,10908],{},[5525,17689,17690],{"class":5527,"line":8128},[5525,17691,5850],{"emptyLinePlaceholder":5849},[5525,17693,17694],{"class":5527,"line":8135},[5525,17695,17696],{},"stop\n",[5525,17698,17699],{"class":5527,"line":8145},[5525,17700,6049],{},[5748,17702,17704],{"id":17703},"топ-5-підводних-каменів","Топ-5 підводних каменів",[6158,17706,17707,17714],{},[5512,17708,17709],{},[5607,17710,17711,17712],{},"Підводний камінь 1: Рекурсія у ",[5507,17713,16638],{},[5516,17715,17717],{"className":5518,"code":17716,"language":5520,"meta":5521,"style":5521},"class Bad:\n    def __setattr__(self, name, value):\n        self.name = value  # ← НЕСКІНЧЕННА РЕКУРСІЯ! self.name → __setattr__\n\nclass Good:\n    def __setattr__(self, name, value):\n        self.__dict__[name] = value  # ← пряма робота зі словником\n        # або: object.__setattr__(self, name, value)\n",[5507,17718,17719,17728,17748,17758,17762,17771,17791,17805],{"__ignoreMap":5521},[5525,17720,17721,17723,17726],{"class":5527,"line":5528},[5525,17722,6079],{"class":6078},[5525,17724,17725],{"class":6082}," Bad",[5525,17727,6086],{"class":5531},[5525,17729,17730,17732,17734,17736,17738,17740,17742,17744,17746],{"class":5527,"line":5549},[5525,17731,6199],{"class":6078},[5525,17733,16685],{"class":6118},[5525,17735,6147],{"class":5531},[5525,17737,6208],{"class":6207},[5525,17739,5614],{"class":5531},[5525,17741,16694],{"class":6207},[5525,17743,5614],{"class":5531},[5525,17745,13567],{"class":6207},[5525,17747,6211],{"class":5531},[5525,17749,17750,17752,17755],{"class":5527,"line":5567},[5525,17751,6596],{"class":6078},[5525,17753,17754],{"class":5531},".name = value  ",[5525,17756,17757],{"class":5545},"# ← НЕСКІНЧЕННА РЕКУРСІЯ! self.name → __setattr__\n",[5525,17759,17760],{"class":5527,"line":5816},[5525,17761,5850],{"emptyLinePlaceholder":5849},[5525,17763,17764,17766,17769],{"class":5527,"line":5822},[5525,17765,6079],{"class":6078},[5525,17767,17768],{"class":6082}," Good",[5525,17770,6086],{"class":5531},[5525,17772,17773,17775,17777,17779,17781,17783,17785,17787,17789],{"class":5527,"line":5828},[5525,17774,6199],{"class":6078},[5525,17776,16685],{"class":6118},[5525,17778,6147],{"class":5531},[5525,17780,6208],{"class":6207},[5525,17782,5614],{"class":5531},[5525,17784,16694],{"class":6207},[5525,17786,5614],{"class":5531},[5525,17788,13567],{"class":6207},[5525,17790,6211],{"class":5531},[5525,17792,17793,17795,17797,17799,17802],{"class":5527,"line":5834},[5525,17794,6596],{"class":6078},[5525,17796,5659],{"class":5531},[5525,17798,6063],{"class":6207},[5525,17800,17801],{"class":5531},"[name] = value  ",[5525,17803,17804],{"class":5545},"# ← пряма робота зі словником\n",[5525,17806,17807],{"class":5527,"line":5840},[5525,17808,17809],{"class":5545},"        # або: object.__setattr__(self, name, value)\n",[6158,17811,17812,17823],{},[5512,17813,17814],{},[5607,17815,17816,17817,17819,17820,17822],{},"Підводний камінь 2: ",[5507,17818,6310],{}," без ",[5507,17821,6315],{}," → нехешований об'єкт",[5512,17824,17825,17826,17828,17829,17831,17832,17834,17835,5659],{},"Якщо визначили ",[5507,17827,6310],{}," — Python автоматично обнулює ",[5507,17830,6315],{},". Якщо об'єкт має бути хешованим (ключ dict, елемент set), завжди визначайте ",[5507,17833,6315],{}," разом із ",[5507,17836,6310],{},[6158,17838,17839,17848],{},[5512,17840,17841],{},[5607,17842,17843,17844,11019,17846],{},"Підводний камінь 3: Повернення ",[5507,17845,8391],{},[5507,17847,8387],{},[5516,17849,17851],{"className":5518,"code":17850,"language":5520,"meta":5521,"style":5521},"# Погано:\ndef __add__(self, other):\n    if not isinstance(other, MyClass):\n        return False  # Зламає reflected operators!\n\n# Правильно:\ndef __add__(self, other):\n    if not isinstance(other, MyClass):\n        return NotImplemented  # Python спробує other.__radd__(self)\n",[5507,17852,17853,17858,17874,17885,17894,17898,17903,17919,17929],{"__ignoreMap":5521},[5525,17854,17855],{"class":5527,"line":5528},[5525,17856,17857],{"class":5545},"# Погано:\n",[5525,17859,17860,17862,17864,17866,17868,17870,17872],{"class":5527,"line":5549},[5525,17861,14352],{"class":6078},[5525,17863,9839],{"class":6118},[5525,17865,6147],{"class":5531},[5525,17867,6208],{"class":6207},[5525,17869,5614],{"class":5531},[5525,17871,7883],{"class":6207},[5525,17873,6211],{"class":5531},[5525,17875,17876,17878,17880,17882],{"class":5527,"line":5567},[5525,17877,14380],{"class":6091},[5525,17879,7902],{"class":6078},[5525,17881,7905],{"class":6118},[5525,17883,17884],{"class":5531},"(other, MyClass):\n",[5525,17886,17887,17889,17891],{"class":5527,"line":5816},[5525,17888,6216],{"class":6091},[5525,17890,15361],{"class":6078},[5525,17892,17893],{"class":5545},"  # Зламає reflected operators!\n",[5525,17895,17896],{"class":5527,"line":5822},[5525,17897,5850],{"emptyLinePlaceholder":5849},[5525,17899,17900],{"class":5527,"line":5828},[5525,17901,17902],{"class":5545},"# Правильно:\n",[5525,17904,17905,17907,17909,17911,17913,17915,17917],{"class":5527,"line":5834},[5525,17906,14352],{"class":6078},[5525,17908,9839],{"class":6118},[5525,17910,6147],{"class":5531},[5525,17912,6208],{"class":6207},[5525,17914,5614],{"class":5531},[5525,17916,7883],{"class":6207},[5525,17918,6211],{"class":5531},[5525,17920,17921,17923,17925,17927],{"class":5527,"line":5840},[5525,17922,14380],{"class":6091},[5525,17924,7902],{"class":6078},[5525,17926,7905],{"class":6118},[5525,17928,17884],{"class":5531},[5525,17930,17931,17933,17935],{"class":5527,"line":5846},[5525,17932,6216],{"class":6091},[5525,17934,7915],{"class":6078},[5525,17936,17937],{"class":5545},"  # Python спробує other.__radd__(self)\n",[6158,17939,17940,17950],{},[5512,17941,17942],{},[5607,17943,17944,17945,8410,17947,17949],{},"Підводний камінь 4: ",[5507,17946,14698],{},[5507,17948,8352],{}," без умови",[5516,17951,17953],{"className":5518,"code":17952,"language":5520,"meta":5521,"style":5521},"# Погано: пригнічує ВСІ виключення, включно з SystemExit і KeyboardInterrupt\ndef __exit__(self, exc_type, exc_val, exc_tb):\n    self.cleanup()\n    return True  # ← НІКОЛИ не робіть це без перевірки exc_type!\n\n# Правильно:\ndef __exit__(self, exc_type, exc_val, exc_tb):\n    self.cleanup()\n    return False  # дозволяємо виключенню поширюватись\n",[5507,17954,17955,17960,17986,17994,18003,18007,18011,18035,18041],{"__ignoreMap":5521},[5525,17956,17957],{"class":5527,"line":5528},[5525,17958,17959],{"class":5545},"# Погано: пригнічує ВСІ виключення, включно з SystemExit і KeyboardInterrupt\n",[5525,17961,17962,17964,17966,17968,17970,17972,17975,17977,17979,17981,17984],{"class":5527,"line":5549},[5525,17963,14352],{"class":6078},[5525,17965,15136],{"class":6118},[5525,17967,6147],{"class":5531},[5525,17969,6208],{"class":6207},[5525,17971,5614],{"class":5531},[5525,17973,17974],{"class":6207},"exc_type",[5525,17976,5614],{"class":5531},[5525,17978,15342],{"class":6207},[5525,17980,5614],{"class":5531},[5525,17982,17983],{"class":6207},"exc_tb",[5525,17985,6211],{"class":5531},[5525,17987,17988,17991],{"class":5527,"line":5567},[5525,17989,17990],{"class":6078},"    self",[5525,17992,17993],{"class":5531},".cleanup()\n",[5525,17995,17996,17998,18000],{"class":5527,"line":5816},[5525,17997,14399],{"class":6091},[5525,17999,16081],{"class":6078},[5525,18001,18002],{"class":5545},"  # ← НІКОЛИ не робіть це без перевірки exc_type!\n",[5525,18004,18005],{"class":5527,"line":5822},[5525,18006,5850],{"emptyLinePlaceholder":5849},[5525,18008,18009],{"class":5527,"line":5828},[5525,18010,17902],{"class":5545},[5525,18012,18013,18015,18017,18019,18021,18023,18025,18027,18029,18031,18033],{"class":5527,"line":5834},[5525,18014,14352],{"class":6078},[5525,18016,15136],{"class":6118},[5525,18018,6147],{"class":5531},[5525,18020,6208],{"class":6207},[5525,18022,5614],{"class":5531},[5525,18024,17974],{"class":6207},[5525,18026,5614],{"class":5531},[5525,18028,15342],{"class":6207},[5525,18030,5614],{"class":5531},[5525,18032,17983],{"class":6207},[5525,18034,6211],{"class":5531},[5525,18036,18037,18039],{"class":5527,"line":5840},[5525,18038,17990],{"class":6078},[5525,18040,17993],{"class":5531},[5525,18042,18043,18045,18047],{"class":5527,"line":5846},[5525,18044,14399],{"class":6091},[5525,18046,15361],{"class":6078},[5525,18048,18049],{"class":5545},"  # дозволяємо виключенню поширюватись\n",[6158,18051,18052,18060,18071],{},[5512,18053,18054],{},[5607,18055,18056,18057,18059],{},"Підводний камінь 5: ",[5507,18058,6275],{}," спричиняє виключення",[5512,18061,18062,18064,18065,18067,18068,18070],{},[5507,18063,6275],{}," часто викликається у відлагоджувачі та при логуванні — у контексті, де вже сталась помилка. Якщо ",[5507,18066,6275],{}," сам підіймає виключення, ви отримаєте безвихідну ситуацію. Завжди робіть ",[5507,18069,6275],{}," максимально захищеним:",[5516,18072,18074],{"className":5518,"code":18073,"language":5520,"meta":5521,"style":5521},"def __repr__(self) -> str:\n    try:\n        return f\"MyClass(x={self.x!r}, y={self.y!r})\"\n    except Exception:\n        return f\"\u003CMyClass: помилка представлення>\"\n",[5507,18075,18076,18092,18098,18124,18133],{"__ignoreMap":5521},[5525,18077,18078,18080,18082,18084,18086,18088,18090],{"class":5527,"line":5528},[5525,18079,14352],{"class":6078},[5525,18081,6630],{"class":6118},[5525,18083,6147],{"class":5531},[5525,18085,6208],{"class":6207},[5525,18087,6637],{"class":5531},[5525,18089,6565],{"class":6082},[5525,18091,6086],{"class":5531},[5525,18093,18094,18096],{"class":5527,"line":5549},[5525,18095,14808],{"class":6091},[5525,18097,6086],{"class":5531},[5525,18099,18100,18102,18104,18107,18109,18111,18113,18116,18118,18120,18122],{"class":5527,"line":5567},[5525,18101,6216],{"class":6091},[5525,18103,6785],{"class":6078},[5525,18105,18106],{"class":5555},"\"MyClass(x=",[5525,18108,6676],{"class":6078},[5525,18110,9251],{"class":5531},[5525,18112,6682],{"class":6078},[5525,18114,18115],{"class":5555},", y=",[5525,18117,6676],{"class":6078},[5525,18119,9260],{"class":5531},[5525,18121,6682],{"class":6078},[5525,18123,7117],{"class":5555},[5525,18125,18126,18128,18131],{"class":5527,"line":5816},[5525,18127,14820],{"class":6091},[5525,18129,18130],{"class":6082}," Exception",[5525,18132,6086],{"class":5531},[5525,18134,18135,18137,18139],{"class":5527,"line":5822},[5525,18136,6216],{"class":6091},[5525,18138,6785],{"class":6078},[5525,18140,18141],{"class":5555},"\"\u003CMyClass: помилка представлення>\"\n",[5741,18143],{},[5502,18145,18147],{"id":18146},"практичний-блок","Практичний блок",[5748,18149,18151,18152],{"id":18150},"рівень-1-базовий-клас-money","Рівень 1 (Базовий): Клас ",[5507,18153,18154],{},"Money",[5512,18156,18157],{},"Реалізуйте клас для роботи з грошовими сумами з підтримкою протоколів:",[5516,18159,18161],{"className":5518,"code":18160,"language":5520,"meta":5521,"style":5521},"from decimal import Decimal\n\nclass Money:\n    \"\"\"\n    Грошова сума з валютою.\n    \n    Вимоги:\n    - __repr__: Money(amount=Decimal('100.50'), currency='UAH')\n    - __str__: 100.50 UAH\n    - __add__, __sub__: складання\u002Fвіднімання одної валюти\n    - __mul__: множення на число (Money * 1.2)\n    - __eq__, __lt__, __le__: порівняння (лише однакова валюта)\n    - __hash__: хешування (Money є незмінним)\n    - __bool__: False якщо amount == 0\n    - При різних валютах підіймати ValueError\n    \"\"\"\n    \n    def __init__(self, amount: str | Decimal, currency: str):\n        self.amount = Decimal(str(amount))\n        self.currency = currency.upper()\n    \n    # ... ваша реалізація\n",[5507,18162,18163,18175,18179,18188,18192,18197,18201,18206,18211,18216,18221,18226,18231,18236,18241,18246,18250,18254,18285,18297,18304,18308],{"__ignoreMap":5521},[5525,18164,18165,18167,18170,18172],{"class":5527,"line":5528},[5525,18166,6512],{"class":6091},[5525,18168,18169],{"class":5531}," decimal ",[5525,18171,6518],{"class":6091},[5525,18173,18174],{"class":5531}," Decimal\n",[5525,18176,18177],{"class":5527,"line":5549},[5525,18178,5850],{"emptyLinePlaceholder":5849},[5525,18180,18181,18183,18186],{"class":5527,"line":5567},[5525,18182,6079],{"class":6078},[5525,18184,18185],{"class":6082}," Money",[5525,18187,6086],{"class":5531},[5525,18189,18190],{"class":5527,"line":5816},[5525,18191,11599],{"class":5555},[5525,18193,18194],{"class":5527,"line":5822},[5525,18195,18196],{"class":5555},"    Грошова сума з валютою.\n",[5525,18198,18199],{"class":5527,"line":5828},[5525,18200,6544],{"class":5555},[5525,18202,18203],{"class":5527,"line":5834},[5525,18204,18205],{"class":5555},"    Вимоги:\n",[5525,18207,18208],{"class":5527,"line":5840},[5525,18209,18210],{"class":5555},"    - __repr__: Money(amount=Decimal('100.50'), currency='UAH')\n",[5525,18212,18213],{"class":5527,"line":5846},[5525,18214,18215],{"class":5555},"    - __str__: 100.50 UAH\n",[5525,18217,18218],{"class":5527,"line":5853},[5525,18219,18220],{"class":5555},"    - __add__, __sub__: складання\u002Fвіднімання одної валюти\n",[5525,18222,18223],{"class":5527,"line":5859},[5525,18224,18225],{"class":5555},"    - __mul__: множення на число (Money * 1.2)\n",[5525,18227,18228],{"class":5527,"line":5865},[5525,18229,18230],{"class":5555},"    - __eq__, __lt__, __le__: порівняння (лише однакова валюта)\n",[5525,18232,18233],{"class":5527,"line":5871},[5525,18234,18235],{"class":5555},"    - __hash__: хешування (Money є незмінним)\n",[5525,18237,18238],{"class":5527,"line":5877},[5525,18239,18240],{"class":5555},"    - __bool__: False якщо amount == 0\n",[5525,18242,18243],{"class":5527,"line":5883},[5525,18244,18245],{"class":5555},"    - При різних валютах підіймати ValueError\n",[5525,18247,18248],{"class":5527,"line":5889},[5525,18249,11599],{"class":5555},[5525,18251,18252],{"class":5527,"line":5895},[5525,18253,6544],{"class":5531},[5525,18255,18256,18258,18260,18262,18264,18266,18269,18271,18273,18276,18279,18281,18283],{"class":5527,"line":5901},[5525,18257,6199],{"class":6078},[5525,18259,6551],{"class":6118},[5525,18261,6147],{"class":5531},[5525,18263,6208],{"class":6207},[5525,18265,5614],{"class":5531},[5525,18267,18268],{"class":6207},"amount",[5525,18270,6127],{"class":5531},[5525,18272,6565],{"class":6082},[5525,18274,18275],{"class":5531}," | Decimal, ",[5525,18277,18278],{"class":6207},"currency",[5525,18280,6127],{"class":5531},[5525,18282,6565],{"class":6082},[5525,18284,6211],{"class":5531},[5525,18286,18287,18289,18292,18294],{"class":5527,"line":5906},[5525,18288,6596],{"class":6078},[5525,18290,18291],{"class":5531},".amount = Decimal(",[5525,18293,6565],{"class":6082},[5525,18295,18296],{"class":5531},"(amount))\n",[5525,18298,18299,18301],{"class":5527,"line":5911},[5525,18300,6596],{"class":6078},[5525,18302,18303],{"class":5531},".currency = currency.upper()\n",[5525,18305,18306],{"class":5527,"line":5917},[5525,18307,6544],{"class":5531},[5525,18309,18310],{"class":5527,"line":5923},[5525,18311,18312],{"class":5545},"    # ... ваша реалізація\n",[5748,18314,18316,18317],{"id":18315},"рівень-2-середній-клас-timeseries","Рівень 2 (Середній): Клас ",[5507,18318,18319],{},"TimeSeries",[5512,18321,18322,18323,18325],{},"Реалізуйте клас ",[5507,18324,18319],{}," — контейнер для часових рядів (наприклад, ціни активів):",[5516,18327,18329],{"className":5518,"code":18328,"language":5520,"meta":5521,"style":5521},"from datetime import date\nfrom typing import Iterator\n\nclass TimeSeries:\n    \"\"\"\n    Часовий ряд: відображення дата → значення.\n    \n    Вимоги контейнерного протоколу:\n    - __len__: кількість точок\n    - __getitem__: доступ за датою (KeyError якщо немає) або за int-індексом\n    - __setitem__: додавання\u002Fоновлення точки\n    - __delitem__: видалення точки\n    - __contains__: перевірка наявності дати\n    - __iter__: ітерація по датах у хронологічному порядку\n    - __repr__, __str__\n    \n    Додаткові методи:\n    - .values() → ітератор значень у хронологічному порядку\n    - .items() → ітератор (дата, значення) у хронологічному порядку\n    - .between(start, end) → новий TimeSeries зі зрізом\n    - __add__(other: TimeSeries) → поелементне додавання (однакові дати)\n    \"\"\"\n    pass\n",[5507,18330,18331,18342,18353,18357,18366,18370,18375,18379,18384,18389,18394,18399,18404,18409,18414,18419,18423,18428,18433,18438,18443,18448,18452],{"__ignoreMap":5521},[5525,18332,18333,18335,18337,18339],{"class":5527,"line":5528},[5525,18334,6512],{"class":6091},[5525,18336,6515],{"class":5531},[5525,18338,6518],{"class":6091},[5525,18340,18341],{"class":5531}," date\n",[5525,18343,18344,18346,18348,18350],{"class":5527,"line":5549},[5525,18345,6512],{"class":6091},[5525,18347,11557],{"class":5531},[5525,18349,6518],{"class":6091},[5525,18351,18352],{"class":5531}," Iterator\n",[5525,18354,18355],{"class":5527,"line":5567},[5525,18356,5850],{"emptyLinePlaceholder":5849},[5525,18358,18359,18361,18364],{"class":5527,"line":5816},[5525,18360,6079],{"class":6078},[5525,18362,18363],{"class":6082}," TimeSeries",[5525,18365,6086],{"class":5531},[5525,18367,18368],{"class":5527,"line":5822},[5525,18369,11599],{"class":5555},[5525,18371,18372],{"class":5527,"line":5828},[5525,18373,18374],{"class":5555},"    Часовий ряд: відображення дата → значення.\n",[5525,18376,18377],{"class":5527,"line":5834},[5525,18378,6544],{"class":5555},[5525,18380,18381],{"class":5527,"line":5840},[5525,18382,18383],{"class":5555},"    Вимоги контейнерного протоколу:\n",[5525,18385,18386],{"class":5527,"line":5846},[5525,18387,18388],{"class":5555},"    - __len__: кількість точок\n",[5525,18390,18391],{"class":5527,"line":5853},[5525,18392,18393],{"class":5555},"    - __getitem__: доступ за датою (KeyError якщо немає) або за int-індексом\n",[5525,18395,18396],{"class":5527,"line":5859},[5525,18397,18398],{"class":5555},"    - __setitem__: додавання\u002Fоновлення точки\n",[5525,18400,18401],{"class":5527,"line":5865},[5525,18402,18403],{"class":5555},"    - __delitem__: видалення точки\n",[5525,18405,18406],{"class":5527,"line":5871},[5525,18407,18408],{"class":5555},"    - __contains__: перевірка наявності дати\n",[5525,18410,18411],{"class":5527,"line":5877},[5525,18412,18413],{"class":5555},"    - __iter__: ітерація по датах у хронологічному порядку\n",[5525,18415,18416],{"class":5527,"line":5883},[5525,18417,18418],{"class":5555},"    - __repr__, __str__\n",[5525,18420,18421],{"class":5527,"line":5889},[5525,18422,6544],{"class":5555},[5525,18424,18425],{"class":5527,"line":5895},[5525,18426,18427],{"class":5555},"    Додаткові методи:\n",[5525,18429,18430],{"class":5527,"line":5901},[5525,18431,18432],{"class":5555},"    - .values() → ітератор значень у хронологічному порядку\n",[5525,18434,18435],{"class":5527,"line":5906},[5525,18436,18437],{"class":5555},"    - .items() → ітератор (дата, значення) у хронологічному порядку\n",[5525,18439,18440],{"class":5527,"line":5911},[5525,18441,18442],{"class":5555},"    - .between(start, end) → новий TimeSeries зі зрізом\n",[5525,18444,18445],{"class":5527,"line":5917},[5525,18446,18447],{"class":5555},"    - __add__(other: TimeSeries) → поелементне додавання (однакові дати)\n",[5525,18449,18450],{"class":5527,"line":5923},[5525,18451,11599],{"class":5555},[5525,18453,18454],{"class":5527,"line":5929},[5525,18455,6092],{"class":6091},[5748,18457,18459,18460],{"id":18458},"рівень-3-advanced-валідуючий-дескриптор-через-__set_name__","Рівень 3 (Advanced): Валідуючий дескриптор через ",[5507,18461,18462],{},"__set_name__",[5512,18464,18322,18465,18468,18469,18471],{},[5507,18466,18467],{},"ValidatedModel"," — базовий клас для валідованих моделей даних, що використовує ",[5507,18470,16638],{}," для перехоплення запису та реєстру валідаторів:",[5516,18473,18475],{"className":5518,"code":18474,"language":5520,"meta":5521,"style":5521},"from typing import Any, Callable\n\nclass ValidatedModel:\n    \"\"\"\n    Базовий клас для моделей із декларативною валідацією.\n    \n    Використання:\n        class User(ValidatedModel):\n            name: str\n            age: int\n        \n        user = User(name=\"Олена\", age=25)\n        user.age = -5   # ValueError: age must be >= 0\n        user.name = 123 # TypeError: name must be str\n    \n    Вимоги:\n    - __init_subclass__: при успадкуванні збирає type hints\n      і реєструє базові валідатори за типом\n    - __setattr__: перед записом виконує валідатори для цього поля\n    - classmethod validate_field(name, validator): реєструє кастомний валідатор\n    - Валідатори — callable(value) → None або ValueError\n    - __repr__: автоматично генерується з полів\n    - __eq__: порівняння за значеннями всіх полів\n    \"\"\"\n    pass\n",[5507,18476,18477,18488,18492,18501,18505,18510,18514,18518,18523,18528,18533,18537,18542,18547,18552,18556,18560,18565,18570,18575,18580,18585,18590,18595,18599],{"__ignoreMap":5521},[5525,18478,18479,18481,18483,18485],{"class":5527,"line":5528},[5525,18480,6512],{"class":6091},[5525,18482,11557],{"class":5531},[5525,18484,6518],{"class":6091},[5525,18486,18487],{"class":5531}," Any, Callable\n",[5525,18489,18490],{"class":5527,"line":5549},[5525,18491,5850],{"emptyLinePlaceholder":5849},[5525,18493,18494,18496,18499],{"class":5527,"line":5567},[5525,18495,6079],{"class":6078},[5525,18497,18498],{"class":6082}," ValidatedModel",[5525,18500,6086],{"class":5531},[5525,18502,18503],{"class":5527,"line":5816},[5525,18504,11599],{"class":5555},[5525,18506,18507],{"class":5527,"line":5822},[5525,18508,18509],{"class":5555},"    Базовий клас для моделей із декларативною валідацією.\n",[5525,18511,18512],{"class":5527,"line":5828},[5525,18513,6544],{"class":5555},[5525,18515,18516],{"class":5527,"line":5834},[5525,18517,13828],{"class":5555},[5525,18519,18520],{"class":5527,"line":5840},[5525,18521,18522],{"class":5555},"        class User(ValidatedModel):\n",[5525,18524,18525],{"class":5527,"line":5846},[5525,18526,18527],{"class":5555},"            name: str\n",[5525,18529,18530],{"class":5527,"line":5853},[5525,18531,18532],{"class":5555},"            age: int\n",[5525,18534,18535],{"class":5527,"line":5859},[5525,18536,12408],{"class":5555},[5525,18538,18539],{"class":5527,"line":5865},[5525,18540,18541],{"class":5555},"        user = User(name=\"Олена\", age=25)\n",[5525,18543,18544],{"class":5527,"line":5871},[5525,18545,18546],{"class":5555},"        user.age = -5   # ValueError: age must be >= 0\n",[5525,18548,18549],{"class":5527,"line":5877},[5525,18550,18551],{"class":5555},"        user.name = 123 # TypeError: name must be str\n",[5525,18553,18554],{"class":5527,"line":5883},[5525,18555,6544],{"class":5555},[5525,18557,18558],{"class":5527,"line":5889},[5525,18559,18205],{"class":5555},[5525,18561,18562],{"class":5527,"line":5895},[5525,18563,18564],{"class":5555},"    - __init_subclass__: при успадкуванні збирає type hints\n",[5525,18566,18567],{"class":5527,"line":5901},[5525,18568,18569],{"class":5555},"      і реєструє базові валідатори за типом\n",[5525,18571,18572],{"class":5527,"line":5906},[5525,18573,18574],{"class":5555},"    - __setattr__: перед записом виконує валідатори для цього поля\n",[5525,18576,18577],{"class":5527,"line":5911},[5525,18578,18579],{"class":5555},"    - classmethod validate_field(name, validator): реєструє кастомний валідатор\n",[5525,18581,18582],{"class":5527,"line":5917},[5525,18583,18584],{"class":5555},"    - Валідатори — callable(value) → None або ValueError\n",[5525,18586,18587],{"class":5527,"line":5923},[5525,18588,18589],{"class":5555},"    - __repr__: автоматично генерується з полів\n",[5525,18591,18592],{"class":5527,"line":5929},[5525,18593,18594],{"class":5555},"    - __eq__: порівняння за значеннями всіх полів\n",[5525,18596,18597],{"class":5527,"line":5935},[5525,18598,11599],{"class":5555},[5525,18600,18601],{"class":5527,"line":5941},[5525,18602,6092],{"class":6091},[5741,18604],{},[5502,18606,18608],{"id":18607},"практичний-приклад-від-а-до-я-кошик-покупок","Практичний приклад від А до Я: Кошик покупок",[5512,18610,18611,18612,18615],{},"Щоб об'єднати всі вивчені протоколи в єдину картину, побудуємо повноцінний клас ",[5507,18613,18614],{},"ShoppingCart"," — кошик покупок інтернет-магазину. Кожен dunder-метод тут вирішує конкретну реальну задачу, а не існує заради демонстрації.",[5748,18617,18619],{"id":18618},"постановка-задачі","Постановка задачі",[5512,18621,18622],{},"Нам потрібен клас, який:",[18624,18625,18626,18629,18641,18644,18649,18656],"ol",{},[13016,18627,18628],{},"Зберігає товари з кількістю та ціною.",[13016,18630,18631,18632,5614,18635,5614,18638,5659],{},"Підтримує зручний синтаксис доступу: ",[5507,18633,18634],{},"cart[\"Ноутбук\"]",[5507,18636,18637],{},"del cart[\"Миша\"]",[5507,18639,18640],{},"\"Ноутбук\" in cart",[13016,18642,18643],{},"Виводиться як красива таблиця для користувача та як детальний рядок для логів\u002Fналагодження.",[13016,18645,18646,18647,5659],{},"Дозволяє об'єднувати два кошики через ",[5507,18648,5509],{},[13016,18650,18651,18652,18655],{},"Підтримує застосування знижки через виклик: ",[5507,18653,18654],{},"cart(0.1)"," — знижка 10%.",[13016,18657,18658],{},"Може використовуватись як контекстний менеджер: при вході фіксує стан, при виключенні — відкатує до нього.",[5748,18660,18662],{"id":18661},"архітектура-проекту","Архітектура проекту",[5516,18664,18669],{"className":18665,"code":18667,"language":18668},[18666],"language-text","shop\u002F\n  __init__.py\n  models.py      ← клас CartItem (один товар)\n  cart.py        ← клас ShoppingCart (весь кошик)\n  main.py        ← демонстрація роботи\n","text",[5507,18670,18667],{"__ignoreMap":5521},[18672,18673,18674,18949,20794,20849],"code-tree",{},[5516,18675,18678],{"className":5518,"code":18676,"filename":18677,"language":5520,"meta":5521,"style":5521},"from __future__ import annotations\nfrom dataclasses import dataclass\n\n\n@dataclass\nclass CartItem:\n    \"\"\"\n    Один рядок у кошику: товар із ціною та кількістю.\n    \n    dataclass автоматично генерує __init__, __repr__ та __eq__.\n    frozen=True робить об'єкт незмінним та автоматично додає __hash__.\n    \"\"\"\n    name: str\n    price: float      # ціна за одиницю, грн\n    quantity: int = 1\n\n    @property\n    def total(self) -> float:\n        \"\"\"Загальна вартість позиції.\"\"\"\n        return self.price * self.quantity\n\n    def with_quantity(self, qty: int) -> CartItem:\n        \"\"\"Повертає новий CartItem з оновленою кількістю (незмінний патерн).\"\"\"\n        return CartItem(name=self.name, price=self.price, quantity=qty)\n\n    def with_price(self, new_price: float) -> CartItem:\n        \"\"\"Повертає новий CartItem з оновленою ціною.\"\"\"\n        return CartItem(name=self.name, price=new_price, quantity=self.quantity)\n","shop\u002Fmodels.py",[5507,18679,18680,18690,18702,18706,18710,18715,18724,18728,18733,18737,18742,18747,18751,18759,18769,18780,18784,18790,18807,18812,18826,18830,18853,18858,18890,18894,18916,18921],{"__ignoreMap":5521},[5525,18681,18682,18684,18686,18688],{"class":5527,"line":5528},[5525,18683,6512],{"class":6091},[5525,18685,7608],{"class":6207},[5525,18687,7611],{"class":6091},[5525,18689,7614],{"class":5531},[5525,18691,18692,18694,18697,18699],{"class":5527,"line":5549},[5525,18693,6512],{"class":6091},[5525,18695,18696],{"class":5531}," dataclasses ",[5525,18698,6518],{"class":6091},[5525,18700,18701],{"class":5531}," dataclass\n",[5525,18703,18704],{"class":5527,"line":5567},[5525,18705,5850],{"emptyLinePlaceholder":5849},[5525,18707,18708],{"class":5527,"line":5816},[5525,18709,5850],{"emptyLinePlaceholder":5849},[5525,18711,18712],{"class":5527,"line":5822},[5525,18713,18714],{"class":6118},"@dataclass\n",[5525,18716,18717,18719,18722],{"class":5527,"line":5828},[5525,18718,6079],{"class":6078},[5525,18720,18721],{"class":6082}," CartItem",[5525,18723,6086],{"class":5531},[5525,18725,18726],{"class":5527,"line":5834},[5525,18727,11599],{"class":5555},[5525,18729,18730],{"class":5527,"line":5840},[5525,18731,18732],{"class":5555},"    Один рядок у кошику: товар із ціною та кількістю.\n",[5525,18734,18735],{"class":5527,"line":5846},[5525,18736,6544],{"class":5555},[5525,18738,18739],{"class":5527,"line":5853},[5525,18740,18741],{"class":5555},"    dataclass автоматично генерує __init__, __repr__ та __eq__.\n",[5525,18743,18744],{"class":5527,"line":5859},[5525,18745,18746],{"class":5555},"    frozen=True робить об'єкт незмінним та автоматично додає __hash__.\n",[5525,18748,18749],{"class":5527,"line":5865},[5525,18750,11599],{"class":5555},[5525,18752,18753,18756],{"class":5527,"line":5871},[5525,18754,18755],{"class":5531},"    name: ",[5525,18757,18758],{"class":6082},"str\n",[5525,18760,18761,18764,18766],{"class":5527,"line":5877},[5525,18762,18763],{"class":5531},"    price: ",[5525,18765,6978],{"class":6082},[5525,18767,18768],{"class":5545},"      # ціна за одиницю, грн\n",[5525,18770,18771,18774,18776,18778],{"class":5527,"line":5883},[5525,18772,18773],{"class":5531},"    quantity: ",[5525,18775,7656],{"class":6082},[5525,18777,6121],{"class":5531},[5525,18779,12433],{"class":5535},[5525,18781,18782],{"class":5527,"line":5889},[5525,18783,5850],{"emptyLinePlaceholder":5849},[5525,18785,18786,18788],{"class":5527,"line":5895},[5525,18787,6996],{"class":6118},[5525,18789,6999],{"class":6082},[5525,18791,18792,18794,18797,18799,18801,18803,18805],{"class":5527,"line":5901},[5525,18793,6199],{"class":6078},[5525,18795,18796],{"class":6118}," total",[5525,18798,6147],{"class":5531},[5525,18800,6208],{"class":6207},[5525,18802,6637],{"class":5531},[5525,18804,6978],{"class":6082},[5525,18806,6086],{"class":5531},[5525,18808,18809],{"class":5527,"line":5906},[5525,18810,18811],{"class":5555},"        \"\"\"Загальна вартість позиції.\"\"\"\n",[5525,18813,18814,18816,18818,18821,18823],{"class":5527,"line":5911},[5525,18815,6216],{"class":6091},[5525,18817,7023],{"class":6078},[5525,18819,18820],{"class":5531},".price * ",[5525,18822,6208],{"class":6078},[5525,18824,18825],{"class":5531},".quantity\n",[5525,18827,18828],{"class":5527,"line":5917},[5525,18829,5850],{"emptyLinePlaceholder":5849},[5525,18831,18832,18834,18837,18839,18841,18843,18846,18848,18850],{"class":5527,"line":5923},[5525,18833,6199],{"class":6078},[5525,18835,18836],{"class":6118}," with_quantity",[5525,18838,6147],{"class":5531},[5525,18840,6208],{"class":6207},[5525,18842,5614],{"class":5531},[5525,18844,18845],{"class":6207},"qty",[5525,18847,6127],{"class":5531},[5525,18849,7656],{"class":6082},[5525,18851,18852],{"class":5531},") -> CartItem:\n",[5525,18854,18855],{"class":5527,"line":5929},[5525,18856,18857],{"class":5555},"        \"\"\"Повертає новий CartItem з оновленою кількістю (незмінний патерн).\"\"\"\n",[5525,18859,18860,18862,18865,18867,18869,18871,18874,18877,18879,18881,18884,18887],{"class":5527,"line":5935},[5525,18861,6216],{"class":6091},[5525,18863,18864],{"class":5531}," CartItem(",[5525,18866,16694],{"class":6207},[5525,18868,12617],{"class":5531},[5525,18870,6208],{"class":6078},[5525,18872,18873],{"class":5531},".name, ",[5525,18875,18876],{"class":6207},"price",[5525,18878,12617],{"class":5531},[5525,18880,6208],{"class":6078},[5525,18882,18883],{"class":5531},".price, ",[5525,18885,18886],{"class":6207},"quantity",[5525,18888,18889],{"class":5531},"=qty)\n",[5525,18891,18892],{"class":5527,"line":5941},[5525,18893,5850],{"emptyLinePlaceholder":5849},[5525,18895,18896,18898,18901,18903,18905,18907,18910,18912,18914],{"class":5527,"line":5947},[5525,18897,6199],{"class":6078},[5525,18899,18900],{"class":6118}," with_price",[5525,18902,6147],{"class":5531},[5525,18904,6208],{"class":6207},[5525,18906,5614],{"class":5531},[5525,18908,18909],{"class":6207},"new_price",[5525,18911,6127],{"class":5531},[5525,18913,6978],{"class":6082},[5525,18915,18852],{"class":5531},[5525,18917,18918],{"class":5527,"line":5953},[5525,18919,18920],{"class":5555},"        \"\"\"Повертає новий CartItem з оновленою ціною.\"\"\"\n",[5525,18922,18923,18925,18927,18929,18931,18933,18935,18937,18940,18942,18944,18946],{"class":5527,"line":5959},[5525,18924,6216],{"class":6091},[5525,18926,18864],{"class":5531},[5525,18928,16694],{"class":6207},[5525,18930,12617],{"class":5531},[5525,18932,6208],{"class":6078},[5525,18934,18873],{"class":5531},[5525,18936,18876],{"class":6207},[5525,18938,18939],{"class":5531},"=new_price, ",[5525,18941,18886],{"class":6207},[5525,18943,12617],{"class":5531},[5525,18945,6208],{"class":6078},[5525,18947,18948],{"class":5531},".quantity)\n",[5516,18950,18953],{"className":5518,"code":18951,"filename":18952,"language":5520,"meta":5521,"style":5521},"from __future__ import annotations\nfrom types import TracebackType\nfrom typing import Iterator\nfrom .models import CartItem\n\n\nclass ShoppingCart:\n    \"\"\"\n    Кошик покупок із повною підтримкою протоколів Python.\n\n    Протоколи:\n      Представлення  → __repr__, __str__\n      Контейнер      → __len__, __bool__, __contains__,\n                       __getitem__, __setitem__, __delitem__, __iter__\n      Арифметика     → __add__, __iadd__\n      Порівняння     → __eq__\n      Виклик         → __call__  (застосувати знижку)\n      Контекст       → __enter__, __exit__  (транзакційне редагування)\n    \"\"\"\n\n    def __init__(self, owner: str = \"Гість\"):\n        self._owner = owner\n        # Внутрішнє сховище: ім'я товару → CartItem\n        self._items: dict[str, CartItem] = {}\n        # Збережений стан для відкату у __exit__\n        self._snapshot: dict[str, CartItem] | None = None\n\n    # ------------------------------------------------------------------ #\n    #  Протокол представлення                                              #\n    # ------------------------------------------------------------------ #\n\n    def __repr__(self) -> str:\n        \"\"\"Детальне представлення для розробника \u002F логів.\"\"\"\n        items_repr = \", \".join(repr(item) for item in self._items.values())\n        return f\"ShoppingCart(owner={self._owner!r}, items=[{items_repr}])\"\n\n    def __str__(self) -> str:\n        \"\"\"Форматована таблиця для відображення користувачу.\"\"\"\n        if not self._items:\n            return f\"Кошик [{self._owner}] порожній\"\n\n        lines = [f\"Кошик покупок: {self._owner}\", \"─\" * 44]\n        for item in self._items.values():\n            lines.append(\n                f\"  {item.name:\u003C20} {item.quantity:>3} шт × \"\n                f\"{item.price:>7.2f} = {item.total:>9.2f} грн\"\n            )\n        lines.append(\"─\" * 44)\n        lines.append(f\"  {'РАЗОМ:':\u003C34} {self.total:>9.2f} грн\")\n        return \"\\n\".join(lines)\n\n    # ------------------------------------------------------------------ #\n    #  Контейнерний протокол                                               #\n    # ------------------------------------------------------------------ #\n\n    def __len__(self) -> int:\n        \"\"\"Кількість унікальних позицій у кошику.\"\"\"\n        return len(self._items)\n\n    def __bool__(self) -> bool:\n        \"\"\"True якщо кошик не порожній.\"\"\"\n        return bool(self._items)\n\n    def __contains__(self, name: object) -> bool:\n        \"\"\"Перевірка наявності товару: 'Ноутбук' in cart.\"\"\"\n        return name in self._items\n\n    def __getitem__(self, name: str) -> CartItem:\n        \"\"\"\n        Доступ до позиції за назвою: cart['Ноутбук'].\n        Підіймає KeyError якщо товару немає.\n        \"\"\"\n        if name not in self._items:\n            raise KeyError(f\"Товар {name!r} відсутній у кошику\")\n        return self._items[name]\n\n    def __setitem__(self, name: str, item: CartItem) -> None:\n        \"\"\"\n        Додавання або оновлення позиції: cart['Ноутбук'] = CartItem(...).\n        Якщо товар вже є — кількості підсумовуються.\n        \"\"\"\n        if name in self._items:\n            existing = self._items[name]\n            self._items[name] = existing.with_quantity(\n                existing.quantity + item.quantity\n            )\n        else:\n            self._items[name] = item\n\n    def __delitem__(self, name: str) -> None:\n        \"\"\"Видалення позиції: del cart['Миша'].\"\"\"\n        if name not in self._items:\n            raise KeyError(f\"Товар {name!r} відсутній у кошику\")\n        del self._items[name]\n\n    def __iter__(self) -> Iterator[CartItem]:\n        \"\"\"Ітерація по позиціях: for item in cart.\"\"\"\n        return iter(self._items.values())\n\n    # ------------------------------------------------------------------ #\n    #  Арифметичний протокол                                               #\n    # ------------------------------------------------------------------ #\n\n    def __add__(self, other: ShoppingCart) -> ShoppingCart:\n        \"\"\"\n        Об'єднання двох кошиків: merged = cart1 + cart2.\n        Повертає НОВИЙ кошик — cart1 і cart2 не змінюються.\n        При збігу назв — кількості підсумовуються.\n        \"\"\"\n        if not isinstance(other, ShoppingCart):\n            return NotImplemented\n        merged = ShoppingCart(owner=f\"{self._owner}+{other._owner}\")\n        for item in self:\n            merged[item.name] = item\n        for item in other:\n            merged[item.name] = item\n        return merged\n\n    def __iadd__(self, other: ShoppingCart) -> ShoppingCart:\n        \"\"\"\n        In-place об'єднання: cart1 += cart2.\n        Мутує cart1, не створює новий об'єкт.\n        \"\"\"\n        if not isinstance(other, ShoppingCart):\n            return NotImplemented\n        for item in other:\n            self[item.name] = item\n        return self\n\n    # ------------------------------------------------------------------ #\n    #  Протокол порівняння                                                 #\n    # ------------------------------------------------------------------ #\n\n    def __eq__(self, other: object) -> bool:\n        \"\"\"\n        Два кошики рівні якщо містять однакові позиції\n        (незалежно від власника).\n        \"\"\"\n        if not isinstance(other, ShoppingCart):\n            return NotImplemented\n        return self._items == other._items\n\n    # ------------------------------------------------------------------ #\n    #  Протокол виклику                                                    #\n    # ------------------------------------------------------------------ #\n\n    def __call__(self, discount: float) -> ShoppingCart:\n        \"\"\"\n        Застосовує відсоткову знижку до всіх позицій.\n        \n        cart(0.1)  → знижка 10%\n        cart(0.25) → знижка 25%\n        \n        Повертає self для можливості ланцюгового виклику.\n        \"\"\"\n        if not (0 \u003C discount \u003C 1):\n            raise ValueError(f\"Знижка має бути у діапазоні (0, 1), отримано: {discount}\")\n        factor = 1 - discount\n        self._items = {\n            name: item.with_price(round(item.price * factor, 2))\n            for name, item in self._items.items()\n        }\n        return self\n\n    # ------------------------------------------------------------------ #\n    #  Протокол контекстного менеджера                                     #\n    # ------------------------------------------------------------------ #\n\n    def __enter__(self) -> ShoppingCart:\n        \"\"\"\n        Фіксує поточний стан кошика як знімок (snapshot).\n        При виключенні всередині блоку — стан буде відновлено.\n        \"\"\"\n        import copy\n        self._snapshot = copy.deepcopy(self._items)\n        return self\n\n    def __exit__(\n        self,\n        exc_type: type[BaseException] | None,\n        exc_val: BaseException | None,\n        exc_tb: TracebackType | None,\n    ) -> bool:\n        if exc_type is not None and self._snapshot is not None:\n            # Відновлюємо стан до моменту входу в блок with\n            self._items = self._snapshot\n        self._snapshot = None\n        return False  # не пригнічуємо виключення\n\n    # ------------------------------------------------------------------ #\n    #  Допоміжні властивості                                               #\n    # ------------------------------------------------------------------ #\n\n    @property\n    def total(self) -> float:\n        \"\"\"Загальна вартість усіх позицій у кошику.\"\"\"\n        return sum(item.total for item in self._items.values())\n\n    @property\n    def item_count(self) -> int:\n        \"\"\"Загальна кількість одиниць товару (не позицій).\"\"\"\n        return sum(item.quantity for item in self._items.values())\n","shop\u002Fcart.py",[5507,18954,18955,18965,18975,18985,18997,19001,19005,19014,19018,19023,19027,19032,19037,19042,19047,19052,19057,19062,19067,19071,19075,19101,19108,19113,19125,19130,19148,19152,19157,19162,19166,19170,19186,19191,19218,19247,19251,19267,19272,19283,19301,19305,19336,19349,19354,19381,19408,19412,19425,19454,19470,19474,19478,19483,19487,19491,19507,19512,19525,19529,19545,19550,19562,19566,19590,19595,19608,19612,19632,19636,19641,19646,19650,19664,19689,19698,19702,19732,19736,19741,19746,19750,19762,19771,19778,19783,19787,19793,19800,19804,19829,19834,19848,19870,19879,19883,19896,19901,19914,19918,19922,19927,19931,19935,19952,19956,19961,19966,19971,19975,19986,19992,20024,20036,20041,20052,20056,20063,20067,20083,20087,20092,20097,20101,20111,20117,20127,20134,20140,20144,20148,20153,20158,20163,20188,20193,20199,20205,20210,20221,20228,20238,20243,20248,20254,20259,20264,20287,20292,20298,20303,20309,20315,20320,20326,20331,20349,20373,20384,20392,20408,20424,20429,20436,20441,20446,20452,20457,20462,20475,20480,20486,20492,20497,20505,20517,20524,20529,20538,20545,20560,20575,20586,20595,20623,20629,20642,20652,20661,20666,20671,20677,20682,20687,20694,20711,20717,20738,20743,20750,20768,20774],{"__ignoreMap":5521},[5525,18956,18957,18959,18961,18963],{"class":5527,"line":5528},[5525,18958,6512],{"class":6091},[5525,18960,7608],{"class":6207},[5525,18962,7611],{"class":6091},[5525,18964,7614],{"class":5531},[5525,18966,18967,18969,18971,18973],{"class":5527,"line":5549},[5525,18968,6512],{"class":6091},[5525,18970,14924],{"class":5531},[5525,18972,6518],{"class":6091},[5525,18974,14929],{"class":5531},[5525,18976,18977,18979,18981,18983],{"class":5527,"line":5567},[5525,18978,6512],{"class":6091},[5525,18980,11557],{"class":5531},[5525,18982,6518],{"class":6091},[5525,18984,18352],{"class":5531},[5525,18986,18987,18989,18992,18994],{"class":5527,"line":5816},[5525,18988,6512],{"class":6091},[5525,18990,18991],{"class":5531}," .models ",[5525,18993,6518],{"class":6091},[5525,18995,18996],{"class":5531}," CartItem\n",[5525,18998,18999],{"class":5527,"line":5822},[5525,19000,5850],{"emptyLinePlaceholder":5849},[5525,19002,19003],{"class":5527,"line":5828},[5525,19004,5850],{"emptyLinePlaceholder":5849},[5525,19006,19007,19009,19012],{"class":5527,"line":5834},[5525,19008,6079],{"class":6078},[5525,19010,19011],{"class":6082}," ShoppingCart",[5525,19013,6086],{"class":5531},[5525,19015,19016],{"class":5527,"line":5840},[5525,19017,11599],{"class":5555},[5525,19019,19020],{"class":5527,"line":5846},[5525,19021,19022],{"class":5555},"    Кошик покупок із повною підтримкою протоколів Python.\n",[5525,19024,19025],{"class":5527,"line":5853},[5525,19026,5850],{"emptyLinePlaceholder":5849},[5525,19028,19029],{"class":5527,"line":5859},[5525,19030,19031],{"class":5555},"    Протоколи:\n",[5525,19033,19034],{"class":5527,"line":5865},[5525,19035,19036],{"class":5555},"      Представлення  → __repr__, __str__\n",[5525,19038,19039],{"class":5527,"line":5871},[5525,19040,19041],{"class":5555},"      Контейнер      → __len__, __bool__, __contains__,\n",[5525,19043,19044],{"class":5527,"line":5877},[5525,19045,19046],{"class":5555},"                       __getitem__, __setitem__, __delitem__, __iter__\n",[5525,19048,19049],{"class":5527,"line":5883},[5525,19050,19051],{"class":5555},"      Арифметика     → __add__, __iadd__\n",[5525,19053,19054],{"class":5527,"line":5889},[5525,19055,19056],{"class":5555},"      Порівняння     → __eq__\n",[5525,19058,19059],{"class":5527,"line":5895},[5525,19060,19061],{"class":5555},"      Виклик         → __call__  (застосувати знижку)\n",[5525,19063,19064],{"class":5527,"line":5901},[5525,19065,19066],{"class":5555},"      Контекст       → __enter__, __exit__  (транзакційне редагування)\n",[5525,19068,19069],{"class":5527,"line":5906},[5525,19070,11599],{"class":5555},[5525,19072,19073],{"class":5527,"line":5911},[5525,19074,5850],{"emptyLinePlaceholder":5849},[5525,19076,19077,19079,19081,19083,19085,19087,19090,19092,19094,19096,19099],{"class":5527,"line":5917},[5525,19078,6199],{"class":6078},[5525,19080,6551],{"class":6118},[5525,19082,6147],{"class":5531},[5525,19084,6208],{"class":6207},[5525,19086,5614],{"class":5531},[5525,19088,19089],{"class":6207},"owner",[5525,19091,6127],{"class":5531},[5525,19093,6565],{"class":6082},[5525,19095,6121],{"class":5531},[5525,19097,19098],{"class":5555},"\"Гість\"",[5525,19100,6211],{"class":5531},[5525,19102,19103,19105],{"class":5527,"line":5923},[5525,19104,6596],{"class":6078},[5525,19106,19107],{"class":5531},"._owner = owner\n",[5525,19109,19110],{"class":5527,"line":5929},[5525,19111,19112],{"class":5545},"        # Внутрішнє сховище: ім'я товару → CartItem\n",[5525,19114,19115,19117,19120,19122],{"class":5527,"line":5935},[5525,19116,6596],{"class":6078},[5525,19118,19119],{"class":5531},"._items: dict[",[5525,19121,6565],{"class":6082},[5525,19123,19124],{"class":5531},", CartItem] = {}\n",[5525,19126,19127],{"class":5527,"line":5941},[5525,19128,19129],{"class":5545},"        # Збережений стан для відкату у __exit__\n",[5525,19131,19132,19134,19137,19139,19142,19144,19146],{"class":5527,"line":5947},[5525,19133,6596],{"class":6078},[5525,19135,19136],{"class":5531},"._snapshot: dict[",[5525,19138,6565],{"class":6082},[5525,19140,19141],{"class":5531},", CartItem] | ",[5525,19143,6585],{"class":6078},[5525,19145,6121],{"class":5531},[5525,19147,13918],{"class":6078},[5525,19149,19150],{"class":5527,"line":5953},[5525,19151,5850],{"emptyLinePlaceholder":5849},[5525,19153,19154],{"class":5527,"line":5959},[5525,19155,19156],{"class":5545},"    # ------------------------------------------------------------------ #\n",[5525,19158,19159],{"class":5527,"line":5964},[5525,19160,19161],{"class":5545},"    #  Протокол представлення                                              #\n",[5525,19163,19164],{"class":5527,"line":5969},[5525,19165,19156],{"class":5545},[5525,19167,19168],{"class":5527,"line":5975},[5525,19169,5850],{"emptyLinePlaceholder":5849},[5525,19171,19172,19174,19176,19178,19180,19182,19184],{"class":5527,"line":5981},[5525,19173,6199],{"class":6078},[5525,19175,6630],{"class":6118},[5525,19177,6147],{"class":5531},[5525,19179,6208],{"class":6207},[5525,19181,6637],{"class":5531},[5525,19183,6565],{"class":6082},[5525,19185,6086],{"class":5531},[5525,19187,19188],{"class":5527,"line":5987},[5525,19189,19190],{"class":5555},"        \"\"\"Детальне представлення для розробника \u002F логів.\"\"\"\n",[5525,19192,19193,19196,19199,19201,19203,19206,19208,19211,19213,19215],{"class":5527,"line":5993},[5525,19194,19195],{"class":5531},"        items_repr = ",[5525,19197,19198],{"class":5555},"\", \"",[5525,19200,11858],{"class":5531},[5525,19202,6874],{"class":6118},[5525,19204,19205],{"class":5531},"(item) ",[5525,19207,11866],{"class":6091},[5525,19209,19210],{"class":5531}," item ",[5525,19212,11475],{"class":6091},[5525,19214,7023],{"class":6078},[5525,19216,19217],{"class":5531},"._items.values())\n",[5525,19219,19220,19222,19224,19227,19229,19232,19234,19237,19239,19242,19244],{"class":5527,"line":5999},[5525,19221,6216],{"class":6091},[5525,19223,6785],{"class":6078},[5525,19225,19226],{"class":5555},"\"ShoppingCart(owner=",[5525,19228,6676],{"class":6078},[5525,19230,19231],{"class":5531},"._owner",[5525,19233,6682],{"class":6078},[5525,19235,19236],{"class":5555},", items=[",[5525,19238,6791],{"class":6078},[5525,19240,19241],{"class":5531},"items_repr",[5525,19243,6797],{"class":6078},[5525,19245,19246],{"class":5555},"])\"\n",[5525,19248,19249],{"class":5527,"line":6005},[5525,19250,5850],{"emptyLinePlaceholder":5849},[5525,19252,19253,19255,19257,19259,19261,19263,19265],{"class":5527,"line":6011},[5525,19254,6199],{"class":6078},[5525,19256,6741],{"class":6118},[5525,19258,6147],{"class":5531},[5525,19260,6208],{"class":6207},[5525,19262,6637],{"class":5531},[5525,19264,6565],{"class":6082},[5525,19266,6086],{"class":5531},[5525,19268,19269],{"class":5527,"line":6016},[5525,19270,19271],{"class":5555},"        \"\"\"Форматована таблиця для відображення користувачу.\"\"\"\n",[5525,19273,19274,19276,19278,19280],{"class":5527,"line":6022},[5525,19275,7220],{"class":6091},[5525,19277,7902],{"class":6078},[5525,19279,7023],{"class":6078},[5525,19281,19282],{"class":5531},"._items:\n",[5525,19284,19285,19287,19289,19292,19294,19296,19298],{"class":5527,"line":6028},[5525,19286,7233],{"class":6091},[5525,19288,6785],{"class":6078},[5525,19290,19291],{"class":5555},"\"Кошик [",[5525,19293,6676],{"class":6078},[5525,19295,19231],{"class":5531},[5525,19297,6797],{"class":6078},[5525,19299,19300],{"class":5555},"] порожній\"\n",[5525,19302,19303],{"class":5527,"line":6034},[5525,19304,5850],{"emptyLinePlaceholder":5849},[5525,19306,19307,19310,19312,19315,19317,19319,19321,19323,19325,19328,19331,19334],{"class":5527,"line":6040},[5525,19308,19309],{"class":5531},"        lines = [",[5525,19311,7333],{"class":6078},[5525,19313,19314],{"class":5555},"\"Кошик покупок: ",[5525,19316,6676],{"class":6078},[5525,19318,19231],{"class":5531},[5525,19320,6797],{"class":6078},[5525,19322,7146],{"class":5555},[5525,19324,5614],{"class":5531},[5525,19326,19327],{"class":5555},"\"─\"",[5525,19329,19330],{"class":5531}," * ",[5525,19332,19333],{"class":5535},"44",[5525,19335,14000],{"class":5531},[5525,19337,19338,19340,19342,19344,19346],{"class":5527,"line":6046},[5525,19339,11999],{"class":6091},[5525,19341,19210],{"class":5531},[5525,19343,11475],{"class":6091},[5525,19345,7023],{"class":6078},[5525,19347,19348],{"class":5531},"._items.values():\n",[5525,19350,19351],{"class":5527,"line":8117},[5525,19352,19353],{"class":5531},"            lines.append(\n",[5525,19355,19356,19358,19361,19363,19366,19369,19372,19375,19378],{"class":5527,"line":8128},[5525,19357,12110],{"class":6078},[5525,19359,19360],{"class":5555},"\"  ",[5525,19362,6791],{"class":6078},[5525,19364,19365],{"class":5531},"item.name",[5525,19367,19368],{"class":6078},":\u003C20}",[5525,19370,19371],{"class":6078}," {",[5525,19373,19374],{"class":5531},"item.quantity",[5525,19376,19377],{"class":6078},":>3}",[5525,19379,19380],{"class":5555}," шт × \"\n",[5525,19382,19383,19385,19387,19389,19392,19395,19397,19399,19402,19405],{"class":5527,"line":8135},[5525,19384,12110],{"class":6078},[5525,19386,7146],{"class":5555},[5525,19388,6791],{"class":6078},[5525,19390,19391],{"class":5531},"item.price",[5525,19393,19394],{"class":6078},":>7.2f}",[5525,19396,6121],{"class":5555},[5525,19398,6791],{"class":6078},[5525,19400,19401],{"class":5531},"item.total",[5525,19403,19404],{"class":6078},":>9.2f}",[5525,19406,19407],{"class":5555}," грн\"\n",[5525,19409,19410],{"class":5527,"line":8145},[5525,19411,12136],{"class":5531},[5525,19413,19414,19417,19419,19421,19423],{"class":5527,"line":8150},[5525,19415,19416],{"class":5531},"        lines.append(",[5525,19418,19327],{"class":5555},[5525,19420,19330],{"class":5531},[5525,19422,19333],{"class":5535},[5525,19424,6778],{"class":5531},[5525,19426,19427,19429,19431,19433,19435,19438,19441,19444,19447,19449,19452],{"class":5527,"line":8155},[5525,19428,19416],{"class":5531},[5525,19430,7333],{"class":6078},[5525,19432,19360],{"class":5555},[5525,19434,6791],{"class":6078},[5525,19436,19437],{"class":5555},"'РАЗОМ:'",[5525,19439,19440],{"class":6078},":\u003C34}",[5525,19442,19443],{"class":6078}," {self",[5525,19445,19446],{"class":5531},".total",[5525,19448,19404],{"class":6078},[5525,19450,19451],{"class":5555}," грн\"",[5525,19453,6778],{"class":5531},[5525,19455,19456,19458,19461,19465,19467],{"class":5527,"line":8176},[5525,19457,6216],{"class":6091},[5525,19459,19460],{"class":5555}," \"",[5525,19462,19464],{"class":19463},"sjcCO","\\n",[5525,19466,7146],{"class":5555},[5525,19468,19469],{"class":5531},".join(lines)\n",[5525,19471,19472],{"class":5527,"line":8196},[5525,19473,5850],{"emptyLinePlaceholder":5849},[5525,19475,19476],{"class":5527,"line":8214},[5525,19477,19156],{"class":5545},[5525,19479,19480],{"class":5527,"line":8219},[5525,19481,19482],{"class":5545},"    #  Контейнерний протокол                                               #\n",[5525,19484,19485],{"class":5527,"line":8230},[5525,19486,19156],{"class":5545},[5525,19488,19489],{"class":5527,"line":8241},[5525,19490,5850],{"emptyLinePlaceholder":5849},[5525,19492,19493,19495,19497,19499,19501,19503,19505],{"class":5527,"line":8251},[5525,19494,6199],{"class":6078},[5525,19496,6202],{"class":6118},[5525,19498,6147],{"class":5531},[5525,19500,6208],{"class":6207},[5525,19502,6637],{"class":5531},[5525,19504,7656],{"class":6082},[5525,19506,6086],{"class":5531},[5525,19508,19509],{"class":5527,"line":8261},[5525,19510,19511],{"class":5555},"        \"\"\"Кількість унікальних позицій у кошику.\"\"\"\n",[5525,19513,19514,19516,19518,19520,19522],{"class":5527,"line":8266},[5525,19515,6216],{"class":6091},[5525,19517,14145],{"class":6118},[5525,19519,6147],{"class":5531},[5525,19521,6208],{"class":6078},[5525,19523,19524],{"class":5531},"._items)\n",[5525,19526,19527],{"class":5527,"line":8272},[5525,19528,5850],{"emptyLinePlaceholder":5849},[5525,19530,19531,19533,19535,19537,19539,19541,19543],{"class":5527,"line":8316},[5525,19532,6199],{"class":6078},[5525,19534,10319],{"class":6118},[5525,19536,6147],{"class":5531},[5525,19538,6208],{"class":6207},[5525,19540,6637],{"class":5531},[5525,19542,7893],{"class":6082},[5525,19544,6086],{"class":5531},[5525,19546,19547],{"class":5527,"line":8329},[5525,19548,19549],{"class":5555},"        \"\"\"True якщо кошик не порожній.\"\"\"\n",[5525,19551,19552,19554,19556,19558,19560],{"class":5527,"line":10253},[5525,19553,6216],{"class":6091},[5525,19555,10337],{"class":6082},[5525,19557,6147],{"class":5531},[5525,19559,6208],{"class":6078},[5525,19561,19524],{"class":5531},[5525,19563,19564],{"class":5527,"line":10259},[5525,19565,5850],{"emptyLinePlaceholder":5849},[5525,19567,19568,19570,19572,19574,19576,19578,19580,19582,19584,19586,19588],{"class":5527,"line":10277},[5525,19569,6199],{"class":6078},[5525,19571,11970],{"class":6118},[5525,19573,6147],{"class":5531},[5525,19575,6208],{"class":6207},[5525,19577,5614],{"class":5531},[5525,19579,16694],{"class":6207},[5525,19581,6127],{"class":5531},[5525,19583,7888],{"class":6082},[5525,19585,6637],{"class":5531},[5525,19587,7893],{"class":6082},[5525,19589,6086],{"class":5531},[5525,19591,19592],{"class":5527,"line":10303},[5525,19593,19594],{"class":5555},"        \"\"\"Перевірка наявності товару: 'Ноутбук' in cart.\"\"\"\n",[5525,19596,19597,19599,19601,19603,19605],{"class":5527,"line":10308},[5525,19598,6216],{"class":6091},[5525,19600,17308],{"class":5531},[5525,19602,11475],{"class":6078},[5525,19604,7023],{"class":6078},[5525,19606,19607],{"class":5531},"._items\n",[5525,19609,19610],{"class":5527,"line":10314},[5525,19611,5850],{"emptyLinePlaceholder":5849},[5525,19613,19614,19616,19618,19620,19622,19624,19626,19628,19630],{"class":5527,"line":10332},[5525,19615,6199],{"class":6078},[5525,19617,12042],{"class":6118},[5525,19619,6147],{"class":5531},[5525,19621,6208],{"class":6207},[5525,19623,5614],{"class":5531},[5525,19625,16694],{"class":6207},[5525,19627,6127],{"class":5531},[5525,19629,6565],{"class":6082},[5525,19631,18852],{"class":5531},[5525,19633,19634],{"class":5527,"line":10353},[5525,19635,7191],{"class":5555},[5525,19637,19638],{"class":5527,"line":10358},[5525,19639,19640],{"class":5555},"        Доступ до позиції за назвою: cart['Ноутбук'].\n",[5525,19642,19643],{"class":5527,"line":10383},[5525,19644,19645],{"class":5555},"        Підіймає KeyError якщо товару немає.\n",[5525,19647,19648],{"class":5527,"line":10394},[5525,19649,7191],{"class":5555},[5525,19651,19652,19654,19656,19658,19660,19662],{"class":5527,"line":10401},[5525,19653,7220],{"class":6091},[5525,19655,17308],{"class":5531},[5525,19657,8656],{"class":6078},[5525,19659,8659],{"class":6078},[5525,19661,7023],{"class":6078},[5525,19663,19282],{"class":5531},[5525,19665,19666,19668,19671,19673,19675,19678,19680,19682,19684,19687],{"class":5527,"line":10416},[5525,19667,8669],{"class":6091},[5525,19669,19670],{"class":6082}," KeyError",[5525,19672,6147],{"class":5531},[5525,19674,7333],{"class":6078},[5525,19676,19677],{"class":5555},"\"Товар ",[5525,19679,6791],{"class":6078},[5525,19681,16694],{"class":5531},[5525,19683,6682],{"class":6078},[5525,19685,19686],{"class":5555}," відсутній у кошику\"",[5525,19688,6778],{"class":5531},[5525,19690,19691,19693,19695],{"class":5527,"line":10421},[5525,19692,6216],{"class":6091},[5525,19694,7023],{"class":6078},[5525,19696,19697],{"class":5531},"._items[name]\n",[5525,19699,19700],{"class":5527,"line":10426},[5525,19701,5850],{"emptyLinePlaceholder":5849},[5525,19703,19704,19706,19709,19711,19713,19715,19717,19719,19721,19723,19725,19728,19730],{"class":5527,"line":10432},[5525,19705,6199],{"class":6078},[5525,19707,19708],{"class":6118}," __setitem__",[5525,19710,6147],{"class":5531},[5525,19712,6208],{"class":6207},[5525,19714,5614],{"class":5531},[5525,19716,16694],{"class":6207},[5525,19718,6127],{"class":5531},[5525,19720,6565],{"class":6082},[5525,19722,5614],{"class":5531},[5525,19724,11979],{"class":6207},[5525,19726,19727],{"class":5531},": CartItem) -> ",[5525,19729,6585],{"class":6078},[5525,19731,6086],{"class":5531},[5525,19733,19734],{"class":5527,"line":10446},[5525,19735,7191],{"class":5555},[5525,19737,19738],{"class":5527,"line":10461},[5525,19739,19740],{"class":5555},"        Додавання або оновлення позиції: cart['Ноутбук'] = CartItem(...).\n",[5525,19742,19743],{"class":5527,"line":10466},[5525,19744,19745],{"class":5555},"        Якщо товар вже є — кількості підсумовуються.\n",[5525,19747,19748],{"class":5527,"line":10477},[5525,19749,7191],{"class":5555},[5525,19751,19752,19754,19756,19758,19760],{"class":5527,"line":10488},[5525,19753,7220],{"class":6091},[5525,19755,17308],{"class":5531},[5525,19757,11475],{"class":6078},[5525,19759,7023],{"class":6078},[5525,19761,19282],{"class":5531},[5525,19763,19764,19767,19769],{"class":5527,"line":10505},[5525,19765,19766],{"class":5531},"            existing = ",[5525,19768,6208],{"class":6078},[5525,19770,19697],{"class":5531},[5525,19772,19773,19775],{"class":5527,"line":10520},[5525,19774,12427],{"class":6078},[5525,19776,19777],{"class":5531},"._items[name] = existing.with_quantity(\n",[5525,19779,19780],{"class":5527,"line":10531},[5525,19781,19782],{"class":5531},"                existing.quantity + item.quantity\n",[5525,19784,19785],{"class":5527,"line":10547},[5525,19786,12136],{"class":5531},[5525,19788,19789,19791],{"class":5527,"line":10572},[5525,19790,7283],{"class":6091},[5525,19792,6086],{"class":5531},[5525,19794,19795,19797],{"class":5527,"line":10586},[5525,19796,12427],{"class":6078},[5525,19798,19799],{"class":5531},"._items[name] = item\n",[5525,19801,19802],{"class":5527,"line":10591},[5525,19803,5850],{"emptyLinePlaceholder":5849},[5525,19805,19806,19808,19811,19813,19815,19817,19819,19821,19823,19825,19827],{"class":5527,"line":10597},[5525,19807,6199],{"class":6078},[5525,19809,19810],{"class":6118}," __delitem__",[5525,19812,6147],{"class":5531},[5525,19814,6208],{"class":6207},[5525,19816,5614],{"class":5531},[5525,19818,16694],{"class":6207},[5525,19820,6127],{"class":5531},[5525,19822,6565],{"class":6082},[5525,19824,6637],{"class":5531},[5525,19826,6585],{"class":6078},[5525,19828,6086],{"class":5531},[5525,19830,19831],{"class":5527,"line":10628},[5525,19832,19833],{"class":5555},"        \"\"\"Видалення позиції: del cart['Миша'].\"\"\"\n",[5525,19835,19836,19838,19840,19842,19844,19846],{"class":5527,"line":10643},[5525,19837,7220],{"class":6091},[5525,19839,17308],{"class":5531},[5525,19841,8656],{"class":6078},[5525,19843,8659],{"class":6078},[5525,19845,7023],{"class":6078},[5525,19847,19282],{"class":5531},[5525,19849,19850,19852,19854,19856,19858,19860,19862,19864,19866,19868],{"class":5527,"line":10654},[5525,19851,8669],{"class":6091},[5525,19853,19670],{"class":6082},[5525,19855,6147],{"class":5531},[5525,19857,7333],{"class":6078},[5525,19859,19677],{"class":5555},[5525,19861,6791],{"class":6078},[5525,19863,16694],{"class":5531},[5525,19865,6682],{"class":6078},[5525,19867,19686],{"class":5555},[5525,19869,6778],{"class":5531},[5525,19871,19872,19875,19877],{"class":5527,"line":10659},[5525,19873,19874],{"class":6091},"        del",[5525,19876,7023],{"class":6078},[5525,19878,19697],{"class":5531},[5525,19880,19881],{"class":5527,"line":10665},[5525,19882,5850],{"emptyLinePlaceholder":5849},[5525,19884,19885,19887,19889,19891,19893],{"class":5527,"line":10677},[5525,19886,6199],{"class":6078},[5525,19888,12194],{"class":6118},[5525,19890,6147],{"class":5531},[5525,19892,6208],{"class":6207},[5525,19894,19895],{"class":5531},") -> Iterator[CartItem]:\n",[5525,19897,19898],{"class":5527,"line":10691},[5525,19899,19900],{"class":5555},"        \"\"\"Ітерація по позиціях: for item in cart.\"\"\"\n",[5525,19902,19903,19905,19908,19910,19912],{"class":5527,"line":10702},[5525,19904,6216],{"class":6091},[5525,19906,19907],{"class":6118}," iter",[5525,19909,6147],{"class":5531},[5525,19911,6208],{"class":6078},[5525,19913,19217],{"class":5531},[5525,19915,19916],{"class":5527,"line":12563},[5525,19917,5850],{"emptyLinePlaceholder":5849},[5525,19919,19920],{"class":5527,"line":12573},[5525,19921,19156],{"class":5545},[5525,19923,19924],{"class":5527,"line":12583},[5525,19925,19926],{"class":5545},"    #  Арифметичний протокол                                               #\n",[5525,19928,19929],{"class":5527,"line":12588},[5525,19930,19156],{"class":5545},[5525,19932,19933],{"class":5527,"line":12593},[5525,19934,5850],{"emptyLinePlaceholder":5849},[5525,19936,19937,19939,19941,19943,19945,19947,19949],{"class":5527,"line":12599},[5525,19938,6199],{"class":6078},[5525,19940,9839],{"class":6118},[5525,19942,6147],{"class":5531},[5525,19944,6208],{"class":6207},[5525,19946,5614],{"class":5531},[5525,19948,7883],{"class":6207},[5525,19950,19951],{"class":5531},": ShoppingCart) -> ShoppingCart:\n",[5525,19953,19954],{"class":5527,"line":12604},[5525,19955,7191],{"class":5555},[5525,19957,19958],{"class":5527,"line":12624},[5525,19959,19960],{"class":5555},"        Об'єднання двох кошиків: merged = cart1 + cart2.\n",[5525,19962,19963],{"class":5527,"line":12629},[5525,19964,19965],{"class":5555},"        Повертає НОВИЙ кошик — cart1 і cart2 не змінюються.\n",[5525,19967,19968],{"class":5527,"line":12635},[5525,19969,19970],{"class":5555},"        При збігу назв — кількості підсумовуються.\n",[5525,19972,19973],{"class":5527,"line":12656},[5525,19974,7191],{"class":5555},[5525,19976,19977,19979,19981,19983],{"class":5527,"line":12662},[5525,19978,7220],{"class":6091},[5525,19980,7902],{"class":6078},[5525,19982,7905],{"class":6118},[5525,19984,19985],{"class":5531},"(other, ShoppingCart):\n",[5525,19987,19988,19990],{"class":5527,"line":12667},[5525,19989,7233],{"class":6091},[5525,19991,7970],{"class":6078},[5525,19993,19994,19997,19999,20001,20003,20005,20007,20009,20011,20013,20015,20018,20020,20022],{"class":5527,"line":12678},[5525,19995,19996],{"class":5531},"        merged = ShoppingCart(",[5525,19998,19089],{"class":6207},[5525,20000,12617],{"class":5531},[5525,20002,7333],{"class":6078},[5525,20004,7146],{"class":5555},[5525,20006,6676],{"class":6078},[5525,20008,19231],{"class":5531},[5525,20010,6797],{"class":6078},[5525,20012,5509],{"class":5555},[5525,20014,6791],{"class":6078},[5525,20016,20017],{"class":5531},"other._owner",[5525,20019,6797],{"class":6078},[5525,20021,7146],{"class":5555},[5525,20023,6778],{"class":5531},[5525,20025,20026,20028,20030,20032,20034],{"class":5527,"line":12693},[5525,20027,11999],{"class":6091},[5525,20029,19210],{"class":5531},[5525,20031,11475],{"class":6091},[5525,20033,7023],{"class":6078},[5525,20035,6086],{"class":5531},[5525,20037,20038],{"class":5527,"line":12709},[5525,20039,20040],{"class":5531},"            merged[item.name] = item\n",[5525,20042,20043,20045,20047,20049],{"class":5527,"line":12725},[5525,20044,11999],{"class":6091},[5525,20046,19210],{"class":5531},[5525,20048,11475],{"class":6091},[5525,20050,20051],{"class":5531}," other:\n",[5525,20053,20054],{"class":5527,"line":12741},[5525,20055,20040],{"class":5531},[5525,20057,20058,20060],{"class":5527,"line":12746},[5525,20059,6216],{"class":6091},[5525,20061,20062],{"class":5531}," merged\n",[5525,20064,20065],{"class":5527,"line":12752},[5525,20066,5850],{"emptyLinePlaceholder":5849},[5525,20068,20069,20071,20073,20075,20077,20079,20081],{"class":5527,"line":12766},[5525,20070,6199],{"class":6078},[5525,20072,9977],{"class":6118},[5525,20074,6147],{"class":5531},[5525,20076,6208],{"class":6207},[5525,20078,5614],{"class":5531},[5525,20080,7883],{"class":6207},[5525,20082,19951],{"class":5531},[5525,20084,20085],{"class":5527,"line":12778},[5525,20086,7191],{"class":5555},[5525,20088,20089],{"class":5527,"line":12788},[5525,20090,20091],{"class":5555},"        In-place об'єднання: cart1 += cart2.\n",[5525,20093,20094],{"class":5527,"line":12793},[5525,20095,20096],{"class":5555},"        Мутує cart1, не створює новий об'єкт.\n",[5525,20098,20099],{"class":5527,"line":12799},[5525,20100,7191],{"class":5555},[5525,20102,20103,20105,20107,20109],{"class":5527,"line":12819},[5525,20104,7220],{"class":6091},[5525,20106,7902],{"class":6078},[5525,20108,7905],{"class":6118},[5525,20110,19985],{"class":5531},[5525,20112,20113,20115],{"class":5527,"line":12824},[5525,20114,7233],{"class":6091},[5525,20116,7970],{"class":6078},[5525,20118,20119,20121,20123,20125],{"class":5527,"line":12830},[5525,20120,11999],{"class":6091},[5525,20122,19210],{"class":5531},[5525,20124,11475],{"class":6091},[5525,20126,20051],{"class":5531},[5525,20128,20129,20131],{"class":5527,"line":12853},[5525,20130,12427],{"class":6078},[5525,20132,20133],{"class":5531},"[item.name] = item\n",[5525,20135,20136,20138],{"class":5527,"line":12858},[5525,20137,6216],{"class":6091},[5525,20139,10029],{"class":6078},[5525,20141,20142],{"class":5527,"line":12864},[5525,20143,5850],{"emptyLinePlaceholder":5849},[5525,20145,20146],{"class":5527,"line":12870},[5525,20147,19156],{"class":5545},[5525,20149,20150],{"class":5527,"line":12903},[5525,20151,20152],{"class":5545},"    #  Протокол порівняння                                                 #\n",[5525,20154,20156],{"class":5527,"line":20155},132,[5525,20157,19156],{"class":5545},[5525,20159,20161],{"class":5527,"line":20160},133,[5525,20162,5850],{"emptyLinePlaceholder":5849},[5525,20164,20166,20168,20170,20172,20174,20176,20178,20180,20182,20184,20186],{"class":5527,"line":20165},134,[5525,20167,6199],{"class":6078},[5525,20169,7874],{"class":6118},[5525,20171,6147],{"class":5531},[5525,20173,6208],{"class":6207},[5525,20175,5614],{"class":5531},[5525,20177,7883],{"class":6207},[5525,20179,6127],{"class":5531},[5525,20181,7888],{"class":6082},[5525,20183,6637],{"class":5531},[5525,20185,7893],{"class":6082},[5525,20187,6086],{"class":5531},[5525,20189,20191],{"class":5527,"line":20190},135,[5525,20192,7191],{"class":5555},[5525,20194,20196],{"class":5527,"line":20195},136,[5525,20197,20198],{"class":5555},"        Два кошики рівні якщо містять однакові позиції\n",[5525,20200,20202],{"class":5527,"line":20201},137,[5525,20203,20204],{"class":5555},"        (незалежно від власника).\n",[5525,20206,20208],{"class":5527,"line":20207},138,[5525,20209,7191],{"class":5555},[5525,20211,20213,20215,20217,20219],{"class":5527,"line":20212},139,[5525,20214,7220],{"class":6091},[5525,20216,7902],{"class":6078},[5525,20218,7905],{"class":6118},[5525,20220,19985],{"class":5531},[5525,20222,20224,20226],{"class":5527,"line":20223},140,[5525,20225,7233],{"class":6091},[5525,20227,7970],{"class":6078},[5525,20229,20231,20233,20235],{"class":5527,"line":20230},141,[5525,20232,6216],{"class":6091},[5525,20234,7023],{"class":6078},[5525,20236,20237],{"class":5531},"._items == other._items\n",[5525,20239,20241],{"class":5527,"line":20240},142,[5525,20242,5850],{"emptyLinePlaceholder":5849},[5525,20244,20246],{"class":5527,"line":20245},143,[5525,20247,19156],{"class":5545},[5525,20249,20251],{"class":5527,"line":20250},144,[5525,20252,20253],{"class":5545},"    #  Протокол виклику                                                    #\n",[5525,20255,20257],{"class":5527,"line":20256},145,[5525,20258,19156],{"class":5545},[5525,20260,20262],{"class":5527,"line":20261},146,[5525,20263,5850],{"emptyLinePlaceholder":5849},[5525,20265,20267,20269,20271,20273,20275,20277,20280,20282,20284],{"class":5527,"line":20266},147,[5525,20268,6199],{"class":6078},[5525,20270,13558],{"class":6118},[5525,20272,6147],{"class":5531},[5525,20274,6208],{"class":6207},[5525,20276,5614],{"class":5531},[5525,20278,20279],{"class":6207},"discount",[5525,20281,6127],{"class":5531},[5525,20283,6978],{"class":6082},[5525,20285,20286],{"class":5531},") -> ShoppingCart:\n",[5525,20288,20290],{"class":5527,"line":20289},148,[5525,20291,7191],{"class":5555},[5525,20293,20295],{"class":5527,"line":20294},149,[5525,20296,20297],{"class":5555},"        Застосовує відсоткову знижку до всіх позицій.\n",[5525,20299,20301],{"class":5527,"line":20300},150,[5525,20302,12408],{"class":5555},[5525,20304,20306],{"class":5527,"line":20305},151,[5525,20307,20308],{"class":5555},"        cart(0.1)  → знижка 10%\n",[5525,20310,20312],{"class":5527,"line":20311},152,[5525,20313,20314],{"class":5555},"        cart(0.25) → знижка 25%\n",[5525,20316,20318],{"class":5527,"line":20317},153,[5525,20319,12408],{"class":5555},[5525,20321,20323],{"class":5527,"line":20322},154,[5525,20324,20325],{"class":5555},"        Повертає self для можливості ланцюгового виклику.\n",[5525,20327,20329],{"class":5527,"line":20328},155,[5525,20330,7191],{"class":5555},[5525,20332,20334,20336,20338,20340,20342,20345,20347],{"class":5527,"line":20333},156,[5525,20335,7220],{"class":6091},[5525,20337,7902],{"class":6078},[5525,20339,7848],{"class":5531},[5525,20341,8191],{"class":5535},[5525,20343,20344],{"class":5531}," \u003C discount \u003C ",[5525,20346,8161],{"class":5535},[5525,20348,6211],{"class":5531},[5525,20350,20352,20354,20356,20358,20360,20363,20365,20367,20369,20371],{"class":5527,"line":20351},157,[5525,20353,8669],{"class":6091},[5525,20355,8672],{"class":6082},[5525,20357,6147],{"class":5531},[5525,20359,7333],{"class":6078},[5525,20361,20362],{"class":5555},"\"Знижка має бути у діапазоні (0, 1), отримано: ",[5525,20364,6791],{"class":6078},[5525,20366,20279],{"class":5531},[5525,20368,6797],{"class":6078},[5525,20370,7146],{"class":5555},[5525,20372,6778],{"class":5531},[5525,20374,20376,20379,20381],{"class":5527,"line":20375},158,[5525,20377,20378],{"class":5531},"        factor = ",[5525,20380,8161],{"class":5535},[5525,20382,20383],{"class":5531}," - discount\n",[5525,20385,20387,20389],{"class":5527,"line":20386},159,[5525,20388,6596],{"class":6078},[5525,20390,20391],{"class":5531},"._items = {\n",[5525,20393,20395,20398,20401,20404,20406],{"class":5527,"line":20394},160,[5525,20396,20397],{"class":5531},"            name: item.with_price(",[5525,20399,20400],{"class":6118},"round",[5525,20402,20403],{"class":5531},"(item.price * factor, ",[5525,20405,8166],{"class":5535},[5525,20407,16384],{"class":5531},[5525,20409,20411,20414,20417,20419,20421],{"class":5527,"line":20410},161,[5525,20412,20413],{"class":6091},"            for",[5525,20415,20416],{"class":5531}," name, item ",[5525,20418,11475],{"class":6091},[5525,20420,7023],{"class":6078},[5525,20422,20423],{"class":5531},"._items.items()\n",[5525,20425,20427],{"class":5527,"line":20426},162,[5525,20428,14275],{"class":5531},[5525,20430,20432,20434],{"class":5527,"line":20431},163,[5525,20433,6216],{"class":6091},[5525,20435,10029],{"class":6078},[5525,20437,20439],{"class":5527,"line":20438},164,[5525,20440,5850],{"emptyLinePlaceholder":5849},[5525,20442,20444],{"class":5527,"line":20443},165,[5525,20445,19156],{"class":5545},[5525,20447,20449],{"class":5527,"line":20448},166,[5525,20450,20451],{"class":5545},"    #  Протокол контекстного менеджера                                     #\n",[5525,20453,20455],{"class":5527,"line":20454},167,[5525,20456,19156],{"class":5545},[5525,20458,20460],{"class":5527,"line":20459},168,[5525,20461,5850],{"emptyLinePlaceholder":5849},[5525,20463,20465,20467,20469,20471,20473],{"class":5527,"line":20464},169,[5525,20466,6199],{"class":6078},[5525,20468,15077],{"class":6118},[5525,20470,6147],{"class":5531},[5525,20472,6208],{"class":6207},[5525,20474,20286],{"class":5531},[5525,20476,20478],{"class":5527,"line":20477},170,[5525,20479,7191],{"class":5555},[5525,20481,20483],{"class":5527,"line":20482},171,[5525,20484,20485],{"class":5555},"        Фіксує поточний стан кошика як знімок (snapshot).\n",[5525,20487,20489],{"class":5527,"line":20488},172,[5525,20490,20491],{"class":5555},"        При виключенні всередині блоку — стан буде відновлено.\n",[5525,20493,20495],{"class":5527,"line":20494},173,[5525,20496,7191],{"class":5555},[5525,20498,20500,20502],{"class":5527,"line":20499},174,[5525,20501,17359],{"class":6091},[5525,20503,20504],{"class":5531}," copy\n",[5525,20506,20508,20510,20513,20515],{"class":5527,"line":20507},175,[5525,20509,6596],{"class":6078},[5525,20511,20512],{"class":5531},"._snapshot = copy.deepcopy(",[5525,20514,6208],{"class":6078},[5525,20516,19524],{"class":5531},[5525,20518,20520,20522],{"class":5527,"line":20519},176,[5525,20521,6216],{"class":6091},[5525,20523,10029],{"class":6078},[5525,20525,20527],{"class":5527,"line":20526},177,[5525,20528,5850],{"emptyLinePlaceholder":5849},[5525,20530,20532,20534,20536],{"class":5527,"line":20531},178,[5525,20533,6199],{"class":6078},[5525,20535,15136],{"class":6118},[5525,20537,12105],{"class":5531},[5525,20539,20541,20543],{"class":5527,"line":20540},179,[5525,20542,6596],{"class":6207},[5525,20544,15145],{"class":5531},[5525,20546,20548,20550,20552,20554,20556,20558],{"class":5527,"line":20547},180,[5525,20549,15150],{"class":6207},[5525,20551,15948],{"class":5531},[5525,20553,15156],{"class":6082},[5525,20555,15159],{"class":5531},[5525,20557,6585],{"class":6078},[5525,20559,15145],{"class":5531},[5525,20561,20563,20565,20567,20569,20571,20573],{"class":5527,"line":20562},181,[5525,20564,15168],{"class":6207},[5525,20566,6127],{"class":5531},[5525,20568,15156],{"class":6082},[5525,20570,6810],{"class":5531},[5525,20572,6585],{"class":6078},[5525,20574,15145],{"class":5531},[5525,20576,20578,20580,20582,20584],{"class":5527,"line":20577},182,[5525,20579,15183],{"class":6207},[5525,20581,15186],{"class":5531},[5525,20583,6585],{"class":6078},[5525,20585,15145],{"class":5531},[5525,20587,20589,20591,20593],{"class":5527,"line":20588},183,[5525,20590,15195],{"class":5531},[5525,20592,7893],{"class":6082},[5525,20594,6086],{"class":5531},[5525,20596,20598,20600,20602,20604,20606,20608,20610,20612,20615,20617,20619,20621],{"class":5527,"line":20597},184,[5525,20599,7220],{"class":6091},[5525,20601,15242],{"class":5531},[5525,20603,8427],{"class":6078},[5525,20605,7902],{"class":6078},[5525,20607,13983],{"class":6078},[5525,20609,16063],{"class":6078},[5525,20611,7023],{"class":6078},[5525,20613,20614],{"class":5531},"._snapshot ",[5525,20616,8427],{"class":6078},[5525,20618,7902],{"class":6078},[5525,20620,13983],{"class":6078},[5525,20622,6086],{"class":5531},[5525,20624,20626],{"class":5527,"line":20625},185,[5525,20627,20628],{"class":5545},"            # Відновлюємо стан до моменту входу в блок with\n",[5525,20630,20632,20634,20637,20639],{"class":5527,"line":20631},186,[5525,20633,12427],{"class":6078},[5525,20635,20636],{"class":5531},"._items = ",[5525,20638,6208],{"class":6078},[5525,20640,20641],{"class":5531},"._snapshot\n",[5525,20643,20645,20647,20650],{"class":5527,"line":20644},187,[5525,20646,6596],{"class":6078},[5525,20648,20649],{"class":5531},"._snapshot = ",[5525,20651,13918],{"class":6078},[5525,20653,20655,20657,20659],{"class":5527,"line":20654},188,[5525,20656,6216],{"class":6091},[5525,20658,15361],{"class":6078},[5525,20660,15364],{"class":5545},[5525,20662,20664],{"class":5527,"line":20663},189,[5525,20665,5850],{"emptyLinePlaceholder":5849},[5525,20667,20669],{"class":5527,"line":20668},190,[5525,20670,19156],{"class":5545},[5525,20672,20674],{"class":5527,"line":20673},191,[5525,20675,20676],{"class":5545},"    #  Допоміжні властивості                                               #\n",[5525,20678,20680],{"class":5527,"line":20679},192,[5525,20681,19156],{"class":5545},[5525,20683,20685],{"class":5527,"line":20684},193,[5525,20686,5850],{"emptyLinePlaceholder":5849},[5525,20688,20690,20692],{"class":5527,"line":20689},194,[5525,20691,6996],{"class":6118},[5525,20693,6999],{"class":6082},[5525,20695,20697,20699,20701,20703,20705,20707,20709],{"class":5527,"line":20696},195,[5525,20698,6199],{"class":6078},[5525,20700,18796],{"class":6118},[5525,20702,6147],{"class":5531},[5525,20704,6208],{"class":6207},[5525,20706,6637],{"class":5531},[5525,20708,6978],{"class":6082},[5525,20710,6086],{"class":5531},[5525,20712,20714],{"class":5527,"line":20713},196,[5525,20715,20716],{"class":5555},"        \"\"\"Загальна вартість усіх позицій у кошику.\"\"\"\n",[5525,20718,20720,20722,20725,20728,20730,20732,20734,20736],{"class":5527,"line":20719},197,[5525,20721,6216],{"class":6091},[5525,20723,20724],{"class":6118}," sum",[5525,20726,20727],{"class":5531},"(item.total ",[5525,20729,11866],{"class":6091},[5525,20731,19210],{"class":5531},[5525,20733,11475],{"class":6091},[5525,20735,7023],{"class":6078},[5525,20737,19217],{"class":5531},[5525,20739,20741],{"class":5527,"line":20740},198,[5525,20742,5850],{"emptyLinePlaceholder":5849},[5525,20744,20746,20748],{"class":5527,"line":20745},199,[5525,20747,6996],{"class":6118},[5525,20749,6999],{"class":6082},[5525,20751,20753,20755,20758,20760,20762,20764,20766],{"class":5527,"line":20752},200,[5525,20754,6199],{"class":6078},[5525,20756,20757],{"class":6118}," item_count",[5525,20759,6147],{"class":5531},[5525,20761,6208],{"class":6207},[5525,20763,6637],{"class":5531},[5525,20765,7656],{"class":6082},[5525,20767,6086],{"class":5531},[5525,20769,20771],{"class":5527,"line":20770},201,[5525,20772,20773],{"class":5555},"        \"\"\"Загальна кількість одиниць товару (не позицій).\"\"\"\n",[5525,20775,20777,20779,20781,20784,20786,20788,20790,20792],{"class":5527,"line":20776},202,[5525,20778,6216],{"class":6091},[5525,20780,20724],{"class":6118},[5525,20782,20783],{"class":5531},"(item.quantity ",[5525,20785,11866],{"class":6091},[5525,20787,19210],{"class":5531},[5525,20789,11475],{"class":6091},[5525,20791,7023],{"class":6078},[5525,20793,19217],{"class":5531},[5516,20795,20798],{"className":5518,"code":20796,"filename":20797,"language":5520,"meta":5521,"style":5521},"\"\"\"Пакет shop: демонстраційний інтернет-магазин.\"\"\"\nfrom .models import CartItem\nfrom .cart import ShoppingCart\n\n__all__ = [\"CartItem\", \"ShoppingCart\"]\n","shop\u002F__init__.py",[5507,20799,20800,20805,20815,20827,20831],{"__ignoreMap":5521},[5525,20801,20802],{"class":5527,"line":5528},[5525,20803,20804],{"class":5555},"\"\"\"Пакет shop: демонстраційний інтернет-магазин.\"\"\"\n",[5525,20806,20807,20809,20811,20813],{"class":5527,"line":5549},[5525,20808,6512],{"class":6091},[5525,20810,18991],{"class":5531},[5525,20812,6518],{"class":6091},[5525,20814,18996],{"class":5531},[5525,20816,20817,20819,20822,20824],{"class":5527,"line":5567},[5525,20818,6512],{"class":6091},[5525,20820,20821],{"class":5531}," .cart ",[5525,20823,6518],{"class":6091},[5525,20825,20826],{"class":5531}," ShoppingCart\n",[5525,20828,20829],{"class":5527,"line":5816},[5525,20830,5850],{"emptyLinePlaceholder":5849},[5525,20832,20833,20836,20839,20842,20844,20847],{"class":5527,"line":5822},[5525,20834,20835],{"class":6207},"__all__",[5525,20837,20838],{"class":5531}," = [",[5525,20840,20841],{"class":5555},"\"CartItem\"",[5525,20843,5614],{"class":5531},[5525,20845,20846],{"class":5555},"\"ShoppingCart\"",[5525,20848,14000],{"class":5531},[5516,20850,20853],{"className":5518,"code":20851,"filename":20852,"language":5520,"meta":5521,"style":5521},"import sys\nfrom shop import CartItem, ShoppingCart\n\n\ndef demonstrate_repr_str(cart: ShoppingCart) -> None:\n    print(\"=== __repr__ (для розробника \u002F логів) ===\")\n    print(repr(cart))\n    print()\n    print(\"=== __str__ (для користувача) ===\")\n    print(str(cart))\n\n\ndef demonstrate_container(cart: ShoppingCart) -> None:\n    print(\"\\n=== Контейнерний протокол ===\")\n    print(f\"len(cart)              → {len(cart)}\")\n    print(f\"bool(cart)             → {bool(cart)}\")\n    print(f\"'Ноутбук' in cart      → {'Ноутбук' in cart}\")\n    print(f\"'Планшет' in cart      → {'Планшет' in cart}\")\n    print(f\"cart['Миша']           → {cart['Миша']}\")\n\n    print(\"\\n[for item in cart]\")\n    for item in cart:\n        print(f\"  {item.name}: {item.quantity} шт × {item.price} грн\")\n\n    print(\"\\n[del cart['Кабель']]\")\n    del cart[\"Кабель\"]\n    print(f\"Після видалення: {len(cart)} позицій\")\n\n\ndef demonstrate_arithmetic(cart: ShoppingCart) -> None:\n    print(\"\\n=== Арифметичний протокол ===\")\n\n    cart2 = ShoppingCart(owner=\"Іван\")\n    cart2[\"Монітор\"] = CartItem(\"Монітор\", price=12000.00, quantity=1)\n    cart2[\"Миша\"]    = CartItem(\"Миша\",    price=850.00,   quantity=1)\n\n    merged = cart + cart2\n    print(f\"cart + cart2 → новий кошик {merged._owner!r} з {len(merged)} позиціями\")\n    print(f\"Миша у merged: кількість = {merged['Миша'].quantity}\")  # 1+1=2\n\n    cart += cart2   # in-place: cart мутується\n    print(f\"cart після +=: {len(cart)} позицій (той самий об'єкт? → не перевіряємо)\")\n\n\ndef demonstrate_call(cart: ShoppingCart) -> None:\n    print(\"\\n=== Протокол виклику: cart(0.1) — знижка 10% ===\")\n    total_before = cart.total\n    cart(0.1)\n    total_after = cart.total\n    print(f\"До знижки:     {total_before:,.2f} грн\")\n    print(f\"Після знижки:  {total_after:,.2f} грн\")\n    print(f\"Зекономлено:   {total_before - total_after:,.2f} грн\")\n\n\ndef demonstrate_context_manager(cart: ShoppingCart) -> None:\n    print(\"\\n=== Контекстний менеджер: відкат при помилці ===\")\n    total_before = cart.total\n    print(f\"Стан ДО блоку with: {len(cart)} позицій, {total_before:,.2f} грн\")\n\n    try:\n        with cart:\n            cart[\"Принтер\"] = CartItem(\"Принтер\", price=5000.00, quantity=1)\n            print(f\"  Всередині блоку: {len(cart)} позицій\")\n            raise RuntimeError(\"Платіж відхилено — недостатньо коштів\")\n    except RuntimeError as e:\n        print(f\"  Перехоплено: {e}\")\n\n    print(f\"Стан ПІСЛЯ відкату: {len(cart)} позицій, {cart.total:,.2f} грн\")\n    print(f\"'Принтер' in cart → {'Принтер' in cart}  (відкочено!)\")\n\n\ndef main() -> int:\n    # Наповнюємо кошик\n    cart = ShoppingCart(owner=\"Олена\")\n    cart[\"Ноутбук\"] = CartItem(\"Ноутбук\", price=35000.00, quantity=1)\n    cart[\"Миша\"]    = CartItem(\"Миша\",    price=850.00,   quantity=2)\n    cart[\"Кабель\"]  = CartItem(\"Кабель\",  price=120.00,   quantity=3)\n\n    demonstrate_repr_str(cart)\n    demonstrate_container(cart)\n    demonstrate_arithmetic(cart)\n    demonstrate_call(cart)\n    demonstrate_context_manager(cart)\n\n    print(\"\\n=== Фінальний стан кошика ===\")\n    print(cart)\n    return 0\n\n\nif __name__ == \"__main__\":\n    sys.exit(main())\n","shop\u002Fmain.py",[5507,20854,20855,20862,20874,20878,20882,20901,20912,20923,20929,20940,20950,20954,20958,20975,20990,21014,21037,21064,21090,21117,21121,21136,21148,21185,21189,21204,21217,21241,21245,21249,21266,21281,21285,21299,21331,21364,21368,21373,21407,21437,21441,21449,21473,21477,21481,21498,21513,21518,21528,21533,21556,21578,21600,21604,21608,21625,21640,21644,21676,21680,21686,21693,21724,21748,21762,21772,21793,21797,21829,21856,21860,21864,21878,21883,21897,21928,21956,21987,21991,21996,22001,22006,22011,22016,22020,22035,22042,22049,22053,22057,22072],{"__ignoreMap":5521},[5525,20856,20857,20859],{"class":5527,"line":5528},[5525,20858,6518],{"class":6091},[5525,20860,20861],{"class":5531}," sys\n",[5525,20863,20864,20866,20869,20871],{"class":5527,"line":5549},[5525,20865,6512],{"class":6091},[5525,20867,20868],{"class":5531}," shop ",[5525,20870,6518],{"class":6091},[5525,20872,20873],{"class":5531}," CartItem, ShoppingCart\n",[5525,20875,20876],{"class":5527,"line":5567},[5525,20877,5850],{"emptyLinePlaceholder":5849},[5525,20879,20880],{"class":5527,"line":5816},[5525,20881,5850],{"emptyLinePlaceholder":5849},[5525,20883,20884,20886,20889,20891,20894,20897,20899],{"class":5527,"line":5822},[5525,20885,14352],{"class":6078},[5525,20887,20888],{"class":6118}," demonstrate_repr_str",[5525,20890,6147],{"class":5531},[5525,20892,20893],{"class":6207},"cart",[5525,20895,20896],{"class":5531},": ShoppingCart) -> ",[5525,20898,6585],{"class":6078},[5525,20900,6086],{"class":5531},[5525,20902,20903,20905,20907,20910],{"class":5527,"line":5828},[5525,20904,15753],{"class":6118},[5525,20906,6147],{"class":5531},[5525,20908,20909],{"class":5555},"\"=== __repr__ (для розробника \u002F логів) ===\"",[5525,20911,6778],{"class":5531},[5525,20913,20914,20916,20918,20920],{"class":5527,"line":5834},[5525,20915,15753],{"class":6118},[5525,20917,6147],{"class":5531},[5525,20919,6874],{"class":6118},[5525,20921,20922],{"class":5531},"(cart))\n",[5525,20924,20925,20927],{"class":5527,"line":5840},[5525,20926,15753],{"class":6118},[5525,20928,14788],{"class":5531},[5525,20930,20931,20933,20935,20938],{"class":5527,"line":5846},[5525,20932,15753],{"class":6118},[5525,20934,6147],{"class":5531},[5525,20936,20937],{"class":5555},"\"=== __str__ (для користувача) ===\"",[5525,20939,6778],{"class":5531},[5525,20941,20942,20944,20946,20948],{"class":5527,"line":5853},[5525,20943,15753],{"class":6118},[5525,20945,6147],{"class":5531},[5525,20947,6565],{"class":6082},[5525,20949,20922],{"class":5531},[5525,20951,20952],{"class":5527,"line":5859},[5525,20953,5850],{"emptyLinePlaceholder":5849},[5525,20955,20956],{"class":5527,"line":5865},[5525,20957,5850],{"emptyLinePlaceholder":5849},[5525,20959,20960,20962,20965,20967,20969,20971,20973],{"class":5527,"line":5871},[5525,20961,14352],{"class":6078},[5525,20963,20964],{"class":6118}," demonstrate_container",[5525,20966,6147],{"class":5531},[5525,20968,20893],{"class":6207},[5525,20970,20896],{"class":5531},[5525,20972,6585],{"class":6078},[5525,20974,6086],{"class":5531},[5525,20976,20977,20979,20981,20983,20985,20988],{"class":5527,"line":5877},[5525,20978,15753],{"class":6118},[5525,20980,6147],{"class":5531},[5525,20982,7146],{"class":5555},[5525,20984,19464],{"class":19463},[5525,20986,20987],{"class":5555},"=== Контейнерний протокол ===\"",[5525,20989,6778],{"class":5531},[5525,20991,20992,20994,20996,20998,21001,21003,21005,21008,21010,21012],{"class":5527,"line":5883},[5525,20993,15753],{"class":6118},[5525,20995,6147],{"class":5531},[5525,20997,7333],{"class":6078},[5525,20999,21000],{"class":5555},"\"len(cart)              → ",[5525,21002,6791],{"class":6078},[5525,21004,6150],{"class":6118},[5525,21006,21007],{"class":5531},"(cart)",[5525,21009,6797],{"class":6078},[5525,21011,7146],{"class":5555},[5525,21013,6778],{"class":5531},[5525,21015,21016,21018,21020,21022,21025,21027,21029,21031,21033,21035],{"class":5527,"line":5889},[5525,21017,15753],{"class":6118},[5525,21019,6147],{"class":5531},[5525,21021,7333],{"class":6078},[5525,21023,21024],{"class":5555},"\"bool(cart)             → ",[5525,21026,6791],{"class":6078},[5525,21028,7893],{"class":6082},[5525,21030,21007],{"class":5531},[5525,21032,6797],{"class":6078},[5525,21034,7146],{"class":5555},[5525,21036,6778],{"class":5531},[5525,21038,21039,21041,21043,21045,21048,21050,21053,21055,21058,21060,21062],{"class":5527,"line":5895},[5525,21040,15753],{"class":6118},[5525,21042,6147],{"class":5531},[5525,21044,7333],{"class":6078},[5525,21046,21047],{"class":5555},"\"'Ноутбук' in cart      → ",[5525,21049,6791],{"class":6078},[5525,21051,21052],{"class":5555},"'Ноутбук'",[5525,21054,8659],{"class":6078},[5525,21056,21057],{"class":5531}," cart",[5525,21059,6797],{"class":6078},[5525,21061,7146],{"class":5555},[5525,21063,6778],{"class":5531},[5525,21065,21066,21068,21070,21072,21075,21077,21080,21082,21084,21086,21088],{"class":5527,"line":5901},[5525,21067,15753],{"class":6118},[5525,21069,6147],{"class":5531},[5525,21071,7333],{"class":6078},[5525,21073,21074],{"class":5555},"\"'Планшет' in cart      → ",[5525,21076,6791],{"class":6078},[5525,21078,21079],{"class":5555},"'Планшет'",[5525,21081,8659],{"class":6078},[5525,21083,21057],{"class":5531},[5525,21085,6797],{"class":6078},[5525,21087,7146],{"class":5555},[5525,21089,6778],{"class":5531},[5525,21091,21092,21094,21096,21098,21101,21103,21106,21109,21111,21113,21115],{"class":5527,"line":5906},[5525,21093,15753],{"class":6118},[5525,21095,6147],{"class":5531},[5525,21097,7333],{"class":6078},[5525,21099,21100],{"class":5555},"\"cart['Миша']           → ",[5525,21102,6791],{"class":6078},[5525,21104,21105],{"class":5531},"cart[",[5525,21107,21108],{"class":5555},"'Миша'",[5525,21110,12926],{"class":5531},[5525,21112,6797],{"class":6078},[5525,21114,7146],{"class":5555},[5525,21116,6778],{"class":5531},[5525,21118,21119],{"class":5527,"line":5911},[5525,21120,5850],{"emptyLinePlaceholder":5849},[5525,21122,21123,21125,21127,21129,21131,21134],{"class":5527,"line":5917},[5525,21124,15753],{"class":6118},[5525,21126,6147],{"class":5531},[5525,21128,7146],{"class":5555},[5525,21130,19464],{"class":19463},[5525,21132,21133],{"class":5555},"[for item in cart]\"",[5525,21135,6778],{"class":5531},[5525,21137,21138,21141,21143,21145],{"class":5527,"line":5923},[5525,21139,21140],{"class":6091},"    for",[5525,21142,19210],{"class":5531},[5525,21144,11475],{"class":6091},[5525,21146,21147],{"class":5531}," cart:\n",[5525,21149,21150,21152,21154,21156,21158,21160,21162,21164,21166,21168,21170,21172,21175,21177,21179,21181,21183],{"class":5527,"line":5929},[5525,21151,15544],{"class":6118},[5525,21153,6147],{"class":5531},[5525,21155,7333],{"class":6078},[5525,21157,19360],{"class":5555},[5525,21159,6791],{"class":6078},[5525,21161,19365],{"class":5531},[5525,21163,6797],{"class":6078},[5525,21165,6127],{"class":5555},[5525,21167,6791],{"class":6078},[5525,21169,19374],{"class":5531},[5525,21171,6797],{"class":6078},[5525,21173,21174],{"class":5555}," шт × ",[5525,21176,6791],{"class":6078},[5525,21178,19391],{"class":5531},[5525,21180,6797],{"class":6078},[5525,21182,19451],{"class":5555},[5525,21184,6778],{"class":5531},[5525,21186,21187],{"class":5527,"line":5935},[5525,21188,5850],{"emptyLinePlaceholder":5849},[5525,21190,21191,21193,21195,21197,21199,21202],{"class":5527,"line":5941},[5525,21192,15753],{"class":6118},[5525,21194,6147],{"class":5531},[5525,21196,7146],{"class":5555},[5525,21198,19464],{"class":19463},[5525,21200,21201],{"class":5555},"[del cart['Кабель']]\"",[5525,21203,6778],{"class":5531},[5525,21205,21206,21209,21212,21215],{"class":5527,"line":5947},[5525,21207,21208],{"class":6091},"    del",[5525,21210,21211],{"class":5531}," cart[",[5525,21213,21214],{"class":5555},"\"Кабель\"",[5525,21216,14000],{"class":5531},[5525,21218,21219,21221,21223,21225,21228,21230,21232,21234,21236,21239],{"class":5527,"line":5953},[5525,21220,15753],{"class":6118},[5525,21222,6147],{"class":5531},[5525,21224,7333],{"class":6078},[5525,21226,21227],{"class":5555},"\"Після видалення: ",[5525,21229,6791],{"class":6078},[5525,21231,6150],{"class":6118},[5525,21233,21007],{"class":5531},[5525,21235,6797],{"class":6078},[5525,21237,21238],{"class":5555}," позицій\"",[5525,21240,6778],{"class":5531},[5525,21242,21243],{"class":5527,"line":5959},[5525,21244,5850],{"emptyLinePlaceholder":5849},[5525,21246,21247],{"class":5527,"line":5964},[5525,21248,5850],{"emptyLinePlaceholder":5849},[5525,21250,21251,21253,21256,21258,21260,21262,21264],{"class":5527,"line":5969},[5525,21252,14352],{"class":6078},[5525,21254,21255],{"class":6118}," demonstrate_arithmetic",[5525,21257,6147],{"class":5531},[5525,21259,20893],{"class":6207},[5525,21261,20896],{"class":5531},[5525,21263,6585],{"class":6078},[5525,21265,6086],{"class":5531},[5525,21267,21268,21270,21272,21274,21276,21279],{"class":5527,"line":5975},[5525,21269,15753],{"class":6118},[5525,21271,6147],{"class":5531},[5525,21273,7146],{"class":5555},[5525,21275,19464],{"class":19463},[5525,21277,21278],{"class":5555},"=== Арифметичний протокол ===\"",[5525,21280,6778],{"class":5531},[5525,21282,21283],{"class":5527,"line":5981},[5525,21284,5850],{"emptyLinePlaceholder":5849},[5525,21286,21287,21290,21292,21294,21297],{"class":5527,"line":5987},[5525,21288,21289],{"class":5531},"    cart2 = ShoppingCart(",[5525,21291,19089],{"class":6207},[5525,21293,12617],{"class":5531},[5525,21295,21296],{"class":5555},"\"Іван\"",[5525,21298,6778],{"class":5531},[5525,21300,21301,21304,21307,21310,21312,21314,21316,21318,21321,21323,21325,21327,21329],{"class":5527,"line":5993},[5525,21302,21303],{"class":5531},"    cart2[",[5525,21305,21306],{"class":5555},"\"Монітор\"",[5525,21308,21309],{"class":5531},"] = CartItem(",[5525,21311,21306],{"class":5555},[5525,21313,5614],{"class":5531},[5525,21315,18876],{"class":6207},[5525,21317,12617],{"class":5531},[5525,21319,21320],{"class":5535},"12000.00",[5525,21322,5614],{"class":5531},[5525,21324,18886],{"class":6207},[5525,21326,12617],{"class":5531},[5525,21328,8161],{"class":5535},[5525,21330,6778],{"class":5531},[5525,21332,21333,21335,21338,21341,21343,21346,21348,21350,21353,21356,21358,21360,21362],{"class":5527,"line":5999},[5525,21334,21303],{"class":5531},[5525,21336,21337],{"class":5555},"\"Миша\"",[5525,21339,21340],{"class":5531},"]    = CartItem(",[5525,21342,21337],{"class":5555},[5525,21344,21345],{"class":5531},",    ",[5525,21347,18876],{"class":6207},[5525,21349,12617],{"class":5531},[5525,21351,21352],{"class":5535},"850.00",[5525,21354,21355],{"class":5531},",   ",[5525,21357,18886],{"class":6207},[5525,21359,12617],{"class":5531},[5525,21361,8161],{"class":5535},[5525,21363,6778],{"class":5531},[5525,21365,21366],{"class":5527,"line":6005},[5525,21367,5850],{"emptyLinePlaceholder":5849},[5525,21369,21370],{"class":5527,"line":6011},[5525,21371,21372],{"class":5531},"    merged = cart + cart2\n",[5525,21374,21375,21377,21379,21381,21384,21386,21389,21391,21393,21395,21397,21400,21402,21405],{"class":5527,"line":6016},[5525,21376,15753],{"class":6118},[5525,21378,6147],{"class":5531},[5525,21380,7333],{"class":6078},[5525,21382,21383],{"class":5555},"\"cart + cart2 → новий кошик ",[5525,21385,6791],{"class":6078},[5525,21387,21388],{"class":5531},"merged._owner",[5525,21390,6682],{"class":6078},[5525,21392,8524],{"class":5555},[5525,21394,6791],{"class":6078},[5525,21396,6150],{"class":6118},[5525,21398,21399],{"class":5531},"(merged)",[5525,21401,6797],{"class":6078},[5525,21403,21404],{"class":5555}," позиціями\"",[5525,21406,6778],{"class":5531},[5525,21408,21409,21411,21413,21415,21418,21420,21423,21425,21428,21430,21432,21434],{"class":5527,"line":6022},[5525,21410,15753],{"class":6118},[5525,21412,6147],{"class":5531},[5525,21414,7333],{"class":6078},[5525,21416,21417],{"class":5555},"\"Миша у merged: кількість = ",[5525,21419,6791],{"class":6078},[5525,21421,21422],{"class":5531},"merged[",[5525,21424,21108],{"class":5555},[5525,21426,21427],{"class":5531},"].quantity",[5525,21429,6797],{"class":6078},[5525,21431,7146],{"class":5555},[5525,21433,7299],{"class":5531},[5525,21435,21436],{"class":5545},"# 1+1=2\n",[5525,21438,21439],{"class":5527,"line":6028},[5525,21440,5850],{"emptyLinePlaceholder":5849},[5525,21442,21443,21446],{"class":5527,"line":6034},[5525,21444,21445],{"class":5531},"    cart += cart2   ",[5525,21447,21448],{"class":5545},"# in-place: cart мутується\n",[5525,21450,21451,21453,21455,21457,21460,21462,21464,21466,21468,21471],{"class":5527,"line":6040},[5525,21452,15753],{"class":6118},[5525,21454,6147],{"class":5531},[5525,21456,7333],{"class":6078},[5525,21458,21459],{"class":5555},"\"cart після +=: ",[5525,21461,6791],{"class":6078},[5525,21463,6150],{"class":6118},[5525,21465,21007],{"class":5531},[5525,21467,6797],{"class":6078},[5525,21469,21470],{"class":5555}," позицій (той самий об'єкт? → не перевіряємо)\"",[5525,21472,6778],{"class":5531},[5525,21474,21475],{"class":5527,"line":6046},[5525,21476,5850],{"emptyLinePlaceholder":5849},[5525,21478,21479],{"class":5527,"line":8117},[5525,21480,5850],{"emptyLinePlaceholder":5849},[5525,21482,21483,21485,21488,21490,21492,21494,21496],{"class":5527,"line":8128},[5525,21484,14352],{"class":6078},[5525,21486,21487],{"class":6118}," demonstrate_call",[5525,21489,6147],{"class":5531},[5525,21491,20893],{"class":6207},[5525,21493,20896],{"class":5531},[5525,21495,6585],{"class":6078},[5525,21497,6086],{"class":5531},[5525,21499,21500,21502,21504,21506,21508,21511],{"class":5527,"line":8135},[5525,21501,15753],{"class":6118},[5525,21503,6147],{"class":5531},[5525,21505,7146],{"class":5555},[5525,21507,19464],{"class":19463},[5525,21509,21510],{"class":5555},"=== Протокол виклику: cart(0.1) — знижка 10% ===\"",[5525,21512,6778],{"class":5531},[5525,21514,21515],{"class":5527,"line":8145},[5525,21516,21517],{"class":5531},"    total_before = cart.total\n",[5525,21519,21520,21523,21526],{"class":5527,"line":8150},[5525,21521,21522],{"class":5531},"    cart(",[5525,21524,21525],{"class":5535},"0.1",[5525,21527,6778],{"class":5531},[5525,21529,21530],{"class":5527,"line":8155},[5525,21531,21532],{"class":5531},"    total_after = cart.total\n",[5525,21534,21535,21537,21539,21541,21544,21546,21549,21552,21554],{"class":5527,"line":8176},[5525,21536,15753],{"class":6118},[5525,21538,6147],{"class":5531},[5525,21540,7333],{"class":6078},[5525,21542,21543],{"class":5555},"\"До знижки:     ",[5525,21545,6791],{"class":6078},[5525,21547,21548],{"class":5531},"total_before",[5525,21550,21551],{"class":6078},":,.2f}",[5525,21553,19451],{"class":5555},[5525,21555,6778],{"class":5531},[5525,21557,21558,21560,21562,21564,21567,21569,21572,21574,21576],{"class":5527,"line":8196},[5525,21559,15753],{"class":6118},[5525,21561,6147],{"class":5531},[5525,21563,7333],{"class":6078},[5525,21565,21566],{"class":5555},"\"Після знижки:  ",[5525,21568,6791],{"class":6078},[5525,21570,21571],{"class":5531},"total_after",[5525,21573,21551],{"class":6078},[5525,21575,19451],{"class":5555},[5525,21577,6778],{"class":5531},[5525,21579,21580,21582,21584,21586,21589,21591,21594,21596,21598],{"class":5527,"line":8214},[5525,21581,15753],{"class":6118},[5525,21583,6147],{"class":5531},[5525,21585,7333],{"class":6078},[5525,21587,21588],{"class":5555},"\"Зекономлено:   ",[5525,21590,6791],{"class":6078},[5525,21592,21593],{"class":5531},"total_before - total_after",[5525,21595,21551],{"class":6078},[5525,21597,19451],{"class":5555},[5525,21599,6778],{"class":5531},[5525,21601,21602],{"class":5527,"line":8219},[5525,21603,5850],{"emptyLinePlaceholder":5849},[5525,21605,21606],{"class":5527,"line":8230},[5525,21607,5850],{"emptyLinePlaceholder":5849},[5525,21609,21610,21612,21615,21617,21619,21621,21623],{"class":5527,"line":8241},[5525,21611,14352],{"class":6078},[5525,21613,21614],{"class":6118}," demonstrate_context_manager",[5525,21616,6147],{"class":5531},[5525,21618,20893],{"class":6207},[5525,21620,20896],{"class":5531},[5525,21622,6585],{"class":6078},[5525,21624,6086],{"class":5531},[5525,21626,21627,21629,21631,21633,21635,21638],{"class":5527,"line":8251},[5525,21628,15753],{"class":6118},[5525,21630,6147],{"class":5531},[5525,21632,7146],{"class":5555},[5525,21634,19464],{"class":19463},[5525,21636,21637],{"class":5555},"=== Контекстний менеджер: відкат при помилці ===\"",[5525,21639,6778],{"class":5531},[5525,21641,21642],{"class":5527,"line":8261},[5525,21643,21517],{"class":5531},[5525,21645,21646,21648,21650,21652,21655,21657,21659,21661,21663,21666,21668,21670,21672,21674],{"class":5527,"line":8266},[5525,21647,15753],{"class":6118},[5525,21649,6147],{"class":5531},[5525,21651,7333],{"class":6078},[5525,21653,21654],{"class":5555},"\"Стан ДО блоку with: ",[5525,21656,6791],{"class":6078},[5525,21658,6150],{"class":6118},[5525,21660,21007],{"class":5531},[5525,21662,6797],{"class":6078},[5525,21664,21665],{"class":5555}," позицій, ",[5525,21667,6791],{"class":6078},[5525,21669,21548],{"class":5531},[5525,21671,21551],{"class":6078},[5525,21673,19451],{"class":5555},[5525,21675,6778],{"class":5531},[5525,21677,21678],{"class":5527,"line":8272},[5525,21679,5850],{"emptyLinePlaceholder":5849},[5525,21681,21682,21684],{"class":5527,"line":8316},[5525,21683,14808],{"class":6091},[5525,21685,6086],{"class":5531},[5525,21687,21688,21691],{"class":5527,"line":8329},[5525,21689,21690],{"class":6091},"        with",[5525,21692,21147],{"class":5531},[5525,21694,21695,21698,21701,21703,21705,21707,21709,21711,21714,21716,21718,21720,21722],{"class":5527,"line":10253},[5525,21696,21697],{"class":5531},"            cart[",[5525,21699,21700],{"class":5555},"\"Принтер\"",[5525,21702,21309],{"class":5531},[5525,21704,21700],{"class":5555},[5525,21706,5614],{"class":5531},[5525,21708,18876],{"class":6207},[5525,21710,12617],{"class":5531},[5525,21712,21713],{"class":5535},"5000.00",[5525,21715,5614],{"class":5531},[5525,21717,18886],{"class":6207},[5525,21719,12617],{"class":5531},[5525,21721,8161],{"class":5535},[5525,21723,6778],{"class":5531},[5525,21725,21726,21729,21731,21733,21736,21738,21740,21742,21744,21746],{"class":5527,"line":10259},[5525,21727,21728],{"class":6118},"            print",[5525,21730,6147],{"class":5531},[5525,21732,7333],{"class":6078},[5525,21734,21735],{"class":5555},"\"  Всередині блоку: ",[5525,21737,6791],{"class":6078},[5525,21739,6150],{"class":6118},[5525,21741,21007],{"class":5531},[5525,21743,6797],{"class":6078},[5525,21745,21238],{"class":5555},[5525,21747,6778],{"class":5531},[5525,21749,21750,21752,21755,21757,21760],{"class":5527,"line":10277},[5525,21751,8669],{"class":6091},[5525,21753,21754],{"class":6082}," RuntimeError",[5525,21756,6147],{"class":5531},[5525,21758,21759],{"class":5555},"\"Платіж відхилено — недостатньо коштів\"",[5525,21761,6778],{"class":5531},[5525,21763,21764,21766,21768,21770],{"class":5527,"line":10303},[5525,21765,14820],{"class":6091},[5525,21767,21754],{"class":6082},[5525,21769,15745],{"class":6091},[5525,21771,15748],{"class":5531},[5525,21773,21774,21776,21778,21780,21783,21785,21787,21789,21791],{"class":5527,"line":10308},[5525,21775,15544],{"class":6118},[5525,21777,6147],{"class":5531},[5525,21779,7333],{"class":6078},[5525,21781,21782],{"class":5555},"\"  Перехоплено: ",[5525,21784,6791],{"class":6078},[5525,21786,15765],{"class":5531},[5525,21788,6797],{"class":6078},[5525,21790,7146],{"class":5555},[5525,21792,6778],{"class":5531},[5525,21794,21795],{"class":5527,"line":10314},[5525,21796,5850],{"emptyLinePlaceholder":5849},[5525,21798,21799,21801,21803,21805,21808,21810,21812,21814,21816,21818,21820,21823,21825,21827],{"class":5527,"line":10332},[5525,21800,15753],{"class":6118},[5525,21802,6147],{"class":5531},[5525,21804,7333],{"class":6078},[5525,21806,21807],{"class":5555},"\"Стан ПІСЛЯ відкату: ",[5525,21809,6791],{"class":6078},[5525,21811,6150],{"class":6118},[5525,21813,21007],{"class":5531},[5525,21815,6797],{"class":6078},[5525,21817,21665],{"class":5555},[5525,21819,6791],{"class":6078},[5525,21821,21822],{"class":5531},"cart.total",[5525,21824,21551],{"class":6078},[5525,21826,19451],{"class":5555},[5525,21828,6778],{"class":5531},[5525,21830,21831,21833,21835,21837,21840,21842,21845,21847,21849,21851,21854],{"class":5527,"line":10353},[5525,21832,15753],{"class":6118},[5525,21834,6147],{"class":5531},[5525,21836,7333],{"class":6078},[5525,21838,21839],{"class":5555},"\"'Принтер' in cart → ",[5525,21841,6791],{"class":6078},[5525,21843,21844],{"class":5555},"'Принтер'",[5525,21846,8659],{"class":6078},[5525,21848,21057],{"class":5531},[5525,21850,6797],{"class":6078},[5525,21852,21853],{"class":5555},"  (відкочено!)\"",[5525,21855,6778],{"class":5531},[5525,21857,21858],{"class":5527,"line":10358},[5525,21859,5850],{"emptyLinePlaceholder":5849},[5525,21861,21862],{"class":5527,"line":10383},[5525,21863,5850],{"emptyLinePlaceholder":5849},[5525,21865,21866,21868,21871,21874,21876],{"class":5527,"line":10394},[5525,21867,14352],{"class":6078},[5525,21869,21870],{"class":6118}," main",[5525,21872,21873],{"class":5531},"() -> ",[5525,21875,7656],{"class":6082},[5525,21877,6086],{"class":5531},[5525,21879,21880],{"class":5527,"line":10401},[5525,21881,21882],{"class":5545},"    # Наповнюємо кошик\n",[5525,21884,21885,21888,21890,21892,21895],{"class":5527,"line":10416},[5525,21886,21887],{"class":5531},"    cart = ShoppingCart(",[5525,21889,19089],{"class":6207},[5525,21891,12617],{"class":5531},[5525,21893,21894],{"class":5555},"\"Олена\"",[5525,21896,6778],{"class":5531},[5525,21898,21899,21902,21905,21907,21909,21911,21913,21915,21918,21920,21922,21924,21926],{"class":5527,"line":10421},[5525,21900,21901],{"class":5531},"    cart[",[5525,21903,21904],{"class":5555},"\"Ноутбук\"",[5525,21906,21309],{"class":5531},[5525,21908,21904],{"class":5555},[5525,21910,5614],{"class":5531},[5525,21912,18876],{"class":6207},[5525,21914,12617],{"class":5531},[5525,21916,21917],{"class":5535},"35000.00",[5525,21919,5614],{"class":5531},[5525,21921,18886],{"class":6207},[5525,21923,12617],{"class":5531},[5525,21925,8161],{"class":5535},[5525,21927,6778],{"class":5531},[5525,21929,21930,21932,21934,21936,21938,21940,21942,21944,21946,21948,21950,21952,21954],{"class":5527,"line":10426},[5525,21931,21901],{"class":5531},[5525,21933,21337],{"class":5555},[5525,21935,21340],{"class":5531},[5525,21937,21337],{"class":5555},[5525,21939,21345],{"class":5531},[5525,21941,18876],{"class":6207},[5525,21943,12617],{"class":5531},[5525,21945,21352],{"class":5535},[5525,21947,21355],{"class":5531},[5525,21949,18886],{"class":6207},[5525,21951,12617],{"class":5531},[5525,21953,8166],{"class":5535},[5525,21955,6778],{"class":5531},[5525,21957,21958,21960,21962,21965,21967,21970,21972,21974,21977,21979,21981,21983,21985],{"class":5527,"line":10432},[5525,21959,21901],{"class":5531},[5525,21961,21214],{"class":5555},[5525,21963,21964],{"class":5531},"]  = CartItem(",[5525,21966,21214],{"class":5555},[5525,21968,21969],{"class":5531},",  ",[5525,21971,18876],{"class":6207},[5525,21973,12617],{"class":5531},[5525,21975,21976],{"class":5535},"120.00",[5525,21978,21355],{"class":5531},[5525,21980,18886],{"class":6207},[5525,21982,12617],{"class":5531},[5525,21984,8171],{"class":5535},[5525,21986,6778],{"class":5531},[5525,21988,21989],{"class":5527,"line":10446},[5525,21990,5850],{"emptyLinePlaceholder":5849},[5525,21992,21993],{"class":5527,"line":10461},[5525,21994,21995],{"class":5531},"    demonstrate_repr_str(cart)\n",[5525,21997,21998],{"class":5527,"line":10466},[5525,21999,22000],{"class":5531},"    demonstrate_container(cart)\n",[5525,22002,22003],{"class":5527,"line":10477},[5525,22004,22005],{"class":5531},"    demonstrate_arithmetic(cart)\n",[5525,22007,22008],{"class":5527,"line":10488},[5525,22009,22010],{"class":5531},"    demonstrate_call(cart)\n",[5525,22012,22013],{"class":5527,"line":10505},[5525,22014,22015],{"class":5531},"    demonstrate_context_manager(cart)\n",[5525,22017,22018],{"class":5527,"line":10520},[5525,22019,5850],{"emptyLinePlaceholder":5849},[5525,22021,22022,22024,22026,22028,22030,22033],{"class":5527,"line":10531},[5525,22023,15753],{"class":6118},[5525,22025,6147],{"class":5531},[5525,22027,7146],{"class":5555},[5525,22029,19464],{"class":19463},[5525,22031,22032],{"class":5555},"=== Фінальний стан кошика ===\"",[5525,22034,6778],{"class":5531},[5525,22036,22037,22039],{"class":5527,"line":10547},[5525,22038,15753],{"class":6118},[5525,22040,22041],{"class":5531},"(cart)\n",[5525,22043,22044,22046],{"class":5527,"line":10572},[5525,22045,14399],{"class":6091},[5525,22047,22048],{"class":5535}," 0\n",[5525,22050,22051],{"class":5527,"line":10586},[5525,22052,5850],{"emptyLinePlaceholder":5849},[5525,22054,22055],{"class":5527,"line":10591},[5525,22056,5850],{"emptyLinePlaceholder":5849},[5525,22058,22059,22061,22064,22067,22070],{"class":5527,"line":10597},[5525,22060,16907],{"class":6091},[5525,22062,22063],{"class":6207}," __name__",[5525,22065,22066],{"class":5531}," == ",[5525,22068,22069],{"class":5555},"\"__main__\"",[5525,22071,6086],{"class":5531},[5525,22073,22074],{"class":5527,"line":10628},[5525,22075,22076],{"class":5531},"    sys.exit(main())\n",[5741,22078],{},[5748,22080,22082],{"id":22081},"покрокова-реалізація","Покрокова реалізація",[22084,22085,22086,22090,22093,22132,22136,22156,22160],"steps",{},[5748,22087,22089],{"id":22088},"створення-структури-проекту","Створення структури проекту",[5512,22091,22092],{},"Створимо директорії та порожні файли пакету:",[7425,22094,22096,22105,22114,22123],{"title":22095},"Ініціалізація структури",[7429,22097,22099,7437,22102],{"className":22098},[5527],[5525,22100,7436],{"className":22101},[7435],[5607,22103,22104],{},"mkdir -p my_shop\u002Fshop",[7429,22106,22108,7437,22111],{"className":22107},[5527],[5525,22109,7436],{"className":22110},[7435],[5607,22112,22113],{},"touch my_shop\u002Fshop\u002F__init__.py my_shop\u002Fshop\u002Fmodels.py",[7429,22115,22117,7437,22120],{"className":22116},[5527],[5525,22118,7436],{"className":22119},[7435],[5607,22121,22122],{},"touch my_shop\u002Fshop\u002Fcart.py my_shop\u002Fshop\u002Fmain.py",[7429,22124,22126,7437,22129],{"className":22125},[5527],[5525,22127,7436],{"className":22128},[7435],[5607,22130,22131],{},"cd my_shop",[5748,22133,22135],{"id":22134},"реалізація-файлів","Реалізація файлів",[5512,22137,22138,22139,22142,22143,22146,22147,22149,22150,22149,22153,5659],{},"Запишіть код кожного файлу відповідно до архітектури вище. Порядок важливий: спочатку ",[5507,22140,22141],{},"models.py"," (від нього залежить ",[5507,22144,22145],{},"cart.py","), потім ",[5507,22148,22145],{},", потім ",[5507,22151,22152],{},"__init__.py",[5507,22154,22155],{},"main.py",[5748,22157,22159],{"id":22158},"запуск-та-перевірка","Запуск та перевірка",[7425,22161,22163,22171,22175,22182,22185,22189,22193,22197,22212,22228,22243,22246,22254,22257,22261,22268,22275,22282,22289,22297,22300,22304,22308,22312,22316,22319,22323,22331,22334,22338,22350,22361,22368,22371,22375,22383,22391,22399,22402,22406,22413,22420,22428,22438],{"title":22162},"python -m shop.main",[7429,22164,22166,7437,22169],{"className":22165},[5527],[5525,22167,7436],{"className":22168},[7435],[5607,22170,22162],{},[7429,22172,22174],{"className":22173},[5527],"=== __repr__ (для розробника \u002F логів) ===",[7429,22176,22178],{"className":22177},[5527],[5525,22179,22181],{"className":22180},[7463],"ShoppingCart(owner='Олена', items=[CartItem(name='Ноутбук', price=35000.0, quantity=1), ...])",[7429,22183],{"className":22184},[5527],[7429,22186,22188],{"className":22187},[5527],"=== __str__ (для користувача) ===",[7429,22190,22192],{"className":22191},[5527],"Кошик покупок: Олена",[7429,22194,22196],{"className":22195},[5527],"────────────────────────────────────────────",[7429,22198,22200,22201,21174,22204,6121,22207,22211],{"className":22199},[5527],"  Ноутбук                 ",[5525,22202,8161],{"className":22203},[7447],[5525,22205,21917],{"className":22206},[8351],[5525,22208,22210],{"className":22209},[8351]," 35000.00"," грн",[7429,22213,22215,22216,22219,22220,22223,22224,22211],{"className":22214},[5527],"  Миша                    ",[5525,22217,8166],{"className":22218},[7447]," шт ×   ",[5525,22221,21352],{"className":22222},[8351]," =  ",[5525,22225,22227],{"className":22226},[8351]," 1700.00",[7429,22229,22231,22232,22219,22235,22238,22239,22211],{"className":22230},[5527],"  Кабель                  ",[5525,22233,8171],{"className":22234},[7447],[5525,22236,21976],{"className":22237},[8351]," =    ",[5525,22240,22242],{"className":22241},[8351],"360.00",[7429,22244,22196],{"className":22245},[5527],[7429,22247,22249,22250,22211],{"className":22248},[5527],"  РАЗОМ:                                 ",[5525,22251,22253],{"className":22252},[8351]," 37060.00",[7429,22255],{"className":22256},[5527],[7429,22258,22260],{"className":22259},[5527],"=== Контейнерний протокол ===",[7429,22262,22264,22265],{"className":22263},[5527],"len(cart)              → ",[5525,22266,8171],{"className":22267},[7447],[7429,22269,22271,22272],{"className":22270},[5527],"bool(cart)             → ",[5525,22273,8352],{"className":22274},[8351],[7429,22276,22278,22279],{"className":22277},[5527],"'Ноутбук' in cart      → ",[5525,22280,8352],{"className":22281},[8351],[7429,22283,22285,22286],{"className":22284},[5527],"'Планшет' in cart      → ",[5525,22287,8391],{"className":22288},[10785],[7429,22290,22292,22293],{"className":22291},[5527],"cart['Миша']           → ",[5525,22294,22296],{"className":22295},[7463],"CartItem(name='Миша', price=850.0, quantity=2)",[7429,22298],{"className":22299},[5527],[7429,22301,22303],{"className":22302},[5527],"[for item in cart]",[7429,22305,22307],{"className":22306},[5527],"  Ноутбук: 1 шт × 35000.0 грн",[7429,22309,22311],{"className":22310},[5527],"  Миша: 2 шт × 850.0 грн",[7429,22313,22315],{"className":22314},[5527],"  Кабель: 3 шт × 120.0 грн",[7429,22317],{"className":22318},[5527],[7429,22320,22322],{"className":22321},[5527],"[del cart['Кабель']]",[7429,22324,22326,22327,22330],{"className":22325},[5527],"Після видалення: ",[5525,22328,8166],{"className":22329},[7447]," позицій",[7429,22332],{"className":22333},[5527],[7429,22335,22337],{"className":22336},[5527],"=== Арифметичний протокол ===",[7429,22339,22341,22342,8524,22346,22349],{"className":22340},[5527],"cart + cart2 → новий кошик ",[5525,22343,22345],{"className":22344},[7463],"'Олена+Іван'",[5525,22347,8171],{"className":22348},[7447]," позиціями",[7429,22351,22353,22354,9535,22357],{"className":22352},[5527],"Миша у merged: кількість = ",[5525,22355,8166],{"className":22356},[7447],[5525,22358,22360],{"className":22359},[9539],"# 1 (Олена) + 1 (Іван)",[7429,22362,22364,22365,22330],{"className":22363},[5527],"cart після +=: ",[5525,22366,8171],{"className":22367},[7447],[7429,22369],{"className":22370},[5527],[7429,22372,22374],{"className":22373},[5527],"=== Протокол виклику: cart(0.1) — знижка 10% ===",[7429,22376,22378,22379,22211],{"className":22377},[5527],"До знижки:     ",[5525,22380,22382],{"className":22381},[7447],"49,060.00",[7429,22384,22386,22387,22211],{"className":22385},[5527],"Після знижки:  ",[5525,22388,22390],{"className":22389},[8351],"44,154.00",[7429,22392,22394,22395,22211],{"className":22393},[5527],"Зекономлено:   ",[5525,22396,22398],{"className":22397},[8351],"4,906.00",[7429,22400],{"className":22401},[5527],[7429,22403,22405],{"className":22404},[5527],"=== Контекстний менеджер: відкат при помилці ===",[7429,22407,22409,22410,22211],{"className":22408},[5527],"Стан ДО блоку with: 3 позицій, ",[5525,22411,22390],{"className":22412},[7447],[7429,22414,22416,22417,22330],{"className":22415},[5527],"  Всередині блоку: ",[5525,22418,10456],{"className":22419},[7447],[7429,22421,22423,22424],{"className":22422},[5527],"  Перехоплено: ",[5525,22425,22427],{"className":22426},[10785],"Платіж відхилено — недостатньо коштів",[7429,22429,22431,22432,21665,22435,22211],{"className":22430},[5527],"Стан ПІСЛЯ відкату: ",[5525,22433,8171],{"className":22434},[7447],[5525,22436,22390],{"className":22437},[8351],[7429,22439,22441,22442,9535,22445],{"className":22440},[5527],"'Принтер' in cart → ",[5525,22443,8391],{"className":22444},[10785],[5525,22446,22448],{"className":22447},[9539],"(відкочено!)",[5741,22450],{},[5748,22452,22454],{"id":22453},"зведена-таблиця-який-протокол-де-застосовується","Зведена таблиця: який протокол де застосовується",[6424,22456,22457,22472],{},[6427,22458,22459],{},[6430,22460,22461,22464,22467],{},[6433,22462,22463],{},"Dunder-метод",[6433,22465,22466],{},"Синтаксис",[6433,22468,22469,22470],{},"Що робить у ",[5507,22471,18614],{},[6446,22473,22474,22488,22502,22516,22532,22548,22566,22581,22597,22614,22628,22646,22660,22673,22687],{},[6430,22475,22476,22480,22485],{},[6451,22477,22478],{},[5507,22479,6275],{},[6451,22481,22482],{},[5507,22483,22484],{},"repr(cart)",[6451,22486,22487],{},"Повний рядок для логів з усіма полями",[6430,22489,22490,22494,22499],{},[6451,22491,22492],{},[5507,22493,6269],{},[6451,22495,22496],{},[5507,22497,22498],{},"print(cart)",[6451,22500,22501],{},"Форматована таблиця товарів для користувача",[6430,22503,22504,22508,22513],{},[6451,22505,22506],{},[5507,22507,5780],{},[6451,22509,22510],{},[5507,22511,22512],{},"len(cart)",[6451,22514,22515],{},"Кількість унікальних позицій",[6430,22517,22518,22522,22527],{},[6451,22519,22520],{},[5507,22521,11422],{},[6451,22523,22524],{},[5507,22525,22526],{},"if cart:",[6451,22528,22529,22531],{},[5507,22530,8391],{}," якщо кошик порожній",[6430,22533,22534,22539,22543],{},[6451,22535,22536],{},[5507,22537,22538],{},"__contains__",[6451,22540,22541],{},[5507,22542,18640],{},[6451,22544,22545,22546],{},"O(1) перевірка через ",[5507,22547,6319],{},[6430,22549,22550,22554,22558],{},[6451,22551,22552],{},[5507,22553,5784],{},[6451,22555,22556],{},[5507,22557,18634],{},[6451,22559,22560,22561,14734,22564],{},"Повертає ",[5507,22562,22563],{},"CartItem",[5507,22565,11451],{},[6430,22567,22568,22573,22578],{},[6451,22569,22570],{},[5507,22571,22572],{},"__setitem__",[6451,22574,22575],{},[5507,22576,22577],{},"cart[\"Ноутбук\"] = item",[6451,22579,22580],{},"Додає або накопичує кількість",[6430,22582,22583,22588,22592],{},[6451,22584,22585],{},[5507,22586,22587],{},"__delitem__",[6451,22589,22590],{},[5507,22591,18637],{},[6451,22593,22594,22595],{},"Видаляє позицію або ",[5507,22596,11451],{},[6430,22598,22599,22603,22608],{},[6451,22600,22601],{},[5507,22602,5772],{},[6451,22604,22605],{},[5507,22606,22607],{},"for item in cart",[6451,22609,22610,22611,22613],{},"Ітерація по ",[5507,22612,22563],{}," у порядку додавання",[6430,22615,22616,22620,22625],{},[6451,22617,22618],{},[5507,22619,9642],{},[6451,22621,22622],{},[5507,22623,22624],{},"cart1 + cart2",[6451,22626,22627],{},"Новий кошик зі злитими позиціями",[6430,22629,22630,22634,22639],{},[6451,22631,22632],{},[5507,22633,6345],{},[6451,22635,22636],{},[5507,22637,22638],{},"cart1 += cart2",[6451,22640,22641,22642,22645],{},"Мутує ",[5507,22643,22644],{},"cart1",", не створює новий об'єкт",[6430,22647,22648,22652,22657],{},[6451,22649,22650],{},[5507,22651,6310],{},[6451,22653,22654],{},[5507,22655,22656],{},"cart1 == cart2",[6451,22658,22659],{},"Порівняння позицій (без урахування власника)",[6430,22661,22662,22666,22670],{},[6451,22663,22664],{},[5507,22665,6379],{},[6451,22667,22668],{},[5507,22669,18654],{},[6451,22671,22672],{},"Застосовує знижку 10% до всіх цін",[6430,22674,22675,22679,22684],{},[6451,22676,22677],{},[5507,22678,14695],{},[6451,22680,22681],{},[5507,22682,22683],{},"with cart:",[6451,22685,22686],{},"Зберігає знімок стану",[6430,22688,22689,22693,22698],{},[6451,22690,22691],{},[5507,22692,14698],{},[6451,22694,22695,22696],{},"кінець ",[5507,22697,5680],{},[6451,22699,22700],{},"Відкатує стан при виключенні",[5741,22702],{},[5502,22704,22706],{"id":22705},"підсумок","Підсумок",[5512,22708,22709,22710,22713],{},"Dunder-методи — це не магія. Це ",[5607,22711,22712],{},"точно визначені протоколи",": набори методів, реалізація яких дозволяє вашому класу брати участь у синтаксисі мови. CPython транслює кожен оператор, вбудовану функцію та конструкцію у виклики конкретних методів на конкретних об'єктах.",[5512,22715,22716],{},"Ключові висновки цієї статті:",[13013,22718,22719,22732,22739,22748,22760,22770],{},[13016,22720,22721,5781,22723,22725,22726,22728,22729,22731],{},[5507,22722,6275],{},[5507,22724,6269],{}," мають різну аудиторію: розробник vs кінцевий користувач. ",[5507,22727,6275],{}," — резервний варіант, якщо ",[5507,22730,6269],{}," відсутній.",[13016,22733,22734,5781,22736,22738],{},[5507,22735,6310],{},[5507,22737,6315],{}," завжди йдуть разом. Мутабельні об'єкти не повинні бути хешованими.",[13016,22740,22741,22742,22744,22745,22747],{},"Повертайте ",[5507,22743,8387],{}," (не ",[5507,22746,8391],{},") при невідповідному типі — це дозволяє Python спробувати reflected operator на іншому операнді.",[13016,22749,22750,22751,22753,22754,22756,22757,22759],{},"In-place оператори (",[5507,22752,6345],{},") повинні мутувати ",[5507,22755,6208],{}," і повертати ",[5507,22758,6208],{},", а не новий об'єкт.",[13016,22761,22762,22764,22765,22767,22768,5659],{},[5507,22763,14698],{}," з поверненням ",[5507,22766,8352],{}," — виняток із суворою умовою. За замовчуванням повертайте ",[5507,22769,8391],{},[13016,22771,22772,22774,22775,22778,22779,22782,22783,5659],{},[5507,22773,16638],{}," перехоплює ",[5607,22776,22777],{},"всі"," записи, включно з ",[5507,22780,22781],{},"__init__",". Для виклику оригінального запису використовуйте ",[5507,22784,22785],{},"object.__setattr__",[5512,22787,22788,22789,6127,22792,5614,22795,22798],{},"Наступна стаття розглядає ",[5607,22790,22791],{},"декоратори та керування життєвим циклом методів",[5507,22793,22794],{},"@staticmethod",[5507,22796,22797],{},"@classmethod"," та клас-декоратори — тобто ще один рівень кастомізації поведінки Python-об'єктів.",[22800,22801,22802],"style",{},"html pre.shiki code .sHH4Y, html code.shiki .sHH4Y{--shiki-light:#000000;--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .sJj4R, html code.shiki .sJj4R{--shiki-light:#098658;--shiki-default:#B5CEA8;--shiki-dark:#B5CEA8}html pre.shiki code .spJ8K, html code.shiki .spJ8K{--shiki-light:#008000;--shiki-default:#6A9955;--shiki-dark:#6A9955}html pre.shiki code .sbdoH, html code.shiki .sbdoH{--shiki-light:#A31515;--shiki-default:#CE9178;--shiki-dark:#CE9178}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 .su1O8, html code.shiki .su1O8{--shiki-light:#0000FF;--shiki-default:#569CD6;--shiki-dark:#569CD6}html pre.shiki code .sN1BT, html code.shiki .sN1BT{--shiki-light:#267F99;--shiki-default:#4EC9B0;--shiki-dark:#4EC9B0}html pre.shiki code .s8xlr, html code.shiki .s8xlr{--shiki-light:#AF00DB;--shiki-default:#C586C0;--shiki-dark:#C586C0}html pre.shiki code .s8Opu, html code.shiki .s8Opu{--shiki-light:#795E26;--shiki-default:#DCDCAA;--shiki-dark:#DCDCAA}html pre.shiki code .siwwj, html code.shiki .siwwj{--shiki-light:#001080;--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}html pre.shiki code .sjcCO, html code.shiki .sjcCO{--shiki-light:#EE0000;--shiki-default:#D7BA7D;--shiki-dark:#D7BA7D}",{"title":5521,"searchDepth":5549,"depth":5549,"links":22804},[22805,22807,22812,22818,22827,22833,22839,22846,22855,22861,22865,22873,22882],{"id":5504,"depth":5549,"text":22806},"Проблема: чому + працює і з числами, і з рядками?",{"id":5745,"depth":5549,"text":5746,"children":22808},[22809,22810,22811],{"id":5750,"depth":5567,"text":5751},{"id":6052,"depth":5567,"text":6053},{"id":6246,"depth":5567,"text":6247},{"id":6406,"depth":5549,"text":6407,"children":22813},[22814,22816],{"id":6410,"depth":5567,"text":22815},"__repr__ проти __str__: два різних призначення",{"id":6921,"depth":5567,"text":22817},"Метод __format__: власний форматний рядок",{"id":7475,"depth":5549,"text":7476,"children":22819},[22820,22821,22823,22825],{"id":7479,"depth":5567,"text":7480},{"id":8384,"depth":5567,"text":22822},"NotImplemented vs False: критична різниця",{"id":8509,"depth":5567,"text":22824},"@functools.total_ordering: мінімальна реалізація",{"id":8936,"depth":5567,"text":22826},"__hash__ та контракт рівності",{"id":9591,"depth":5549,"text":9592,"children":22828},[22829,22830,22831],{"id":9595,"depth":5567,"text":9596},{"id":10818,"depth":5567,"text":10819},{"id":11004,"depth":5567,"text":22832},"Протокол матричного множення: __matmul__",{"id":11399,"depth":5549,"text":11400,"children":22834},[22835,22836,22837],{"id":11403,"depth":5567,"text":11404},{"id":11527,"depth":5567,"text":11528},{"id":12993,"depth":5567,"text":22838},"Ітератор як окремий об'єкт: __iter__ + __next__",{"id":13442,"depth":5549,"text":22840,"children":22841},"Частина VI: Протокол виклику — __call__",[22842,22843,22844],{"id":13448,"depth":5567,"text":13449},{"id":13709,"depth":5567,"text":13710},{"id":14517,"depth":5567,"text":22845},"__call__ та перевірка callable",{"id":14685,"depth":5549,"text":14686,"children":22847},[22848,22850,22851,22853],{"id":14689,"depth":5567,"text":22849},"with під капотом: __enter__ та __exit__",{"id":14887,"depth":5567,"text":14888},{"id":15849,"depth":5567,"text":22852},"Пригнічення виключень: коли __exit__ повертає True",{"id":16155,"depth":5567,"text":22854},"contextlib.contextmanager: декораторний спосіб",{"id":16464,"depth":5549,"text":16465,"children":22856},[22857,22858,22859],{"id":16468,"depth":5567,"text":16469},{"id":16525,"depth":5567,"text":16526},{"id":17202,"depth":5567,"text":22860},"__getattr__ для динамічних проксі",{"id":17471,"depth":5549,"text":17472,"children":22862},[22863,22864],{"id":17475,"depth":5567,"text":17476},{"id":17703,"depth":5567,"text":17704},{"id":18146,"depth":5549,"text":18147,"children":22866},[22867,22869,22871],{"id":18150,"depth":5567,"text":22868},"Рівень 1 (Базовий): Клас Money",{"id":18315,"depth":5567,"text":22870},"Рівень 2 (Середній): Клас TimeSeries",{"id":18458,"depth":5567,"text":22872},"Рівень 3 (Advanced): Валідуючий дескриптор через __set_name__",{"id":18607,"depth":5549,"text":18608,"children":22874},[22875,22876,22877,22878,22879,22880,22881],{"id":18618,"depth":5567,"text":18619},{"id":18661,"depth":5567,"text":18662},{"id":22081,"depth":5567,"text":22082},{"id":22088,"depth":5567,"text":22089},{"id":22134,"depth":5567,"text":22135},{"id":22158,"depth":5567,"text":22159},{"id":22453,"depth":5567,"text":22454},{"id":22705,"depth":5549,"text":22706},"Глибоке дослідження системи dunder-методів Python — від рядкового представлення та арифметики до контейнерних протоколів і контекстних менеджерів. Розуміння того, як Python реалізує оператори та вбудовані функції через спеціальні методи об'єктів.","md",null,{},{"title":2945,"description":22883},"PSdMPYoCLtHGu3DBmcq2HRuOibXFBvdI5WFas5H71gM",[22890,22892],{"title":2941,"path":2942,"stem":2943,"description":22891,"children":-1},"Глибокий аналіз двох підходів до абстракції в Python — формальних Abstract Base Classes (ABC) та структурних Protocols (PEP 544). Номінативна та структурна типізація, mypy, runtime-перевірки та вибір правильного інструменту для production-коду.",{"title":2949,"path":2950,"stem":2951,"description":22893,"children":-1},"Глибокий розбір декораторів у Python — від @staticmethod і @classmethod до декораторів класів і callable-екземплярів. Як декоратори трансформують методи, зберігають стан між викликами та дозволяють будувати гнучку авторизацію й кешування без зміни основного коду.",1794581915054]