[{"data":1,"prerenderedAt":23798},["ShallowReactive",2],{"navigation_docs":3,"-python-advanced-encapsulation":5492,"-python-advanced-encapsulation-surround":23793},[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":2933,"body":5494,"description":23787,"extension":23788,"links":23789,"meta":23790,"navigation":5564,"path":2934,"seo":23791,"stem":2935,"__hash__":23792},"docs\u002F05.python\u002F02.advanced\u002F02.encapsulation.md",{"type":5495,"value":5496,"toc":23727},"minimark",[5497,5502,5507,5520,5625,5633,5665,5668,5672,5677,5684,5696,5703,5802,5804,5808,5815,5822,5929,5936,5947,6250,6301,6343,6373,6375,6382,6389,6393,6404,6693,6754,6769,6771,6775,6778,7020,7064,7078,7080,7084,7191,7193,7201,7205,7216,7381,7393,7456,7458,7465,7474,7892,7942,7944,7948,7963,8470,8790,8873,8875,8879,8882,8994,9020,9032,9123,9125,9132,9453,9488,9493,9515,9517,9521,9525,9541,9587,9591,9605,9701,9868,9894,9898,10041,10048,10054,10760,10790,10800,10826,10976,11011,11017,11019,11023,11029,11032,11302,11308,11315,11318,11624,11632,12860,12956,12989,12991,12995,12999,13007,13877,13969,13971,13975,13981,16129,16238,16240,16244,16251,17884,17983,17985,17989,17996,18114,18118,18432,18436,23257,23638,23640,23644,23723],[5498,5499,5501],"h1",{"id":5500},"інкапсуляція-та-керування-доступом","Інкапсуляція та керування доступом",[5503,5504,5506],"h2",{"id":5505},"вступ-коли-відкритий-клас-стає-небезпечним","Вступ: коли «відкритий» клас стає небезпечним",[5508,5509,5510,5511,5515,5516,5519],"p",{},"Уявіть банківський сервіс. Клас ",[5512,5513,5514],"code",{},"Account"," зберігає баланс у публічному атрибуті ",[5512,5517,5518],{},"balance",". Перший день у production:",[5521,5522,5527],"pre",{"className":5523,"code":5524,"language":5525,"meta":5526,"style":5526},"language-python shiki shiki-themes light-plus dark-plus dark-plus","# ❌ Катастрофа в production\naccount = Account(\"Олена\", 50_000.0)\n\n# Хтось з команди вирішив «швидко» виправити баг:\naccount.balance = -999_999.0   # від'ємний баланс — фінансовий крах\naccount.balance = \"заморожено\"  # str замість float — AttributeError о 3 ночі\n\n# Або підрядник отримав доступ до внутрішнього кешу:\naccount._cache[\"approved_limit\"] = 10_000_000  # обхід перевірок!\n","python","",[5512,5528,5529,5538,5559,5566,5572,5584,5596,5601,5607],{"__ignoreMap":5526},[5530,5531,5534],"span",{"class":5532,"line":5533},"line",1,[5530,5535,5537],{"class":5536},"spJ8K","# ❌ Катастрофа в production\n",[5530,5539,5541,5545,5549,5552,5556],{"class":5532,"line":5540},2,[5530,5542,5544],{"class":5543},"sHH4Y","account = Account(",[5530,5546,5548],{"class":5547},"sbdoH","\"Олена\"",[5530,5550,5551],{"class":5543},", ",[5530,5553,5555],{"class":5554},"sJj4R","50_000.0",[5530,5557,5558],{"class":5543},")\n",[5530,5560,5562],{"class":5532,"line":5561},3,[5530,5563,5565],{"emptyLinePlaceholder":5564},true,"\n",[5530,5567,5569],{"class":5532,"line":5568},4,[5530,5570,5571],{"class":5536},"# Хтось з команди вирішив «швидко» виправити баг:\n",[5530,5573,5575,5578,5581],{"class":5532,"line":5574},5,[5530,5576,5577],{"class":5543},"account.balance = -",[5530,5579,5580],{"class":5554},"999_999.0",[5530,5582,5583],{"class":5536},"   # від'ємний баланс — фінансовий крах\n",[5530,5585,5587,5590,5593],{"class":5532,"line":5586},6,[5530,5588,5589],{"class":5543},"account.balance = ",[5530,5591,5592],{"class":5547},"\"заморожено\"",[5530,5594,5595],{"class":5536},"  # str замість float — AttributeError о 3 ночі\n",[5530,5597,5599],{"class":5532,"line":5598},7,[5530,5600,5565],{"emptyLinePlaceholder":5564},[5530,5602,5604],{"class":5532,"line":5603},8,[5530,5605,5606],{"class":5536},"# Або підрядник отримав доступ до внутрішнього кешу:\n",[5530,5608,5610,5613,5616,5619,5622],{"class":5532,"line":5609},9,[5530,5611,5612],{"class":5543},"account._cache[",[5530,5614,5615],{"class":5547},"\"approved_limit\"",[5530,5617,5618],{"class":5543},"] = ",[5530,5620,5621],{"class":5554},"10_000_000",[5530,5623,5624],{"class":5536},"  # обхід перевірок!\n",[5508,5626,5627,5628,5632],{},"Жодного з цих сценаріїв не було б, якби клас ",[5629,5630,5631],"strong",{},"контролював доступ до своїх даних",". Саме це і вирішує інкапсуляція.",[5634,5635,5636,5642,5655,5660],"card-group",{},[5637,5638,5641],"card",{"icon":5639,"title":5640},"i-heroicons-shield-check","Захист даних","Публічний інтерфейс (методи та властивості) контролює всі зміни внутрішнього стану. Невалідні значення відхиляються до того, як вони потраплять у пам'ять.",[5637,5643,5646,5647,5650,5651,5654],{"icon":5644,"title":5645},"i-heroicons-arrow-path","Стабільний API","Внутрішня реалізація може змінюватися — переїзд з ",[5512,5648,5649],{},"float"," до ",[5512,5652,5653],{},"Decimal",", зміна структури кешу. Зовнішній код цього не відчує, бо взаємодіє лише через публічний інтерфейс.",[5637,5656,5659],{"icon":5657,"title":5658},"i-heroicons-link-slash","Менше зв'язності","Коли код взаємодіє через чітко визначений API — зміна одного класу не ламає десятки інших. Зв'язність (coupling) мінімальна.",[5637,5661,5664],{"icon":5662,"title":5663},"i-heroicons-document-text","Самодокументованість","Один погляд на публічний інтерфейс класу — і зрозуміло, що він вміє. Приватні деталі приховані і не захаращують API.",[5666,5667],"hr",{},[5503,5669,5671],{"id":5670},"частина-i-філософія-доступу-в-python","Частина I: Філософія доступу в Python",[5673,5674,5676],"h3",{"id":5675},"ми-всі-тут-дорослі-люди","«Ми всі тут дорослі люди»",[5508,5678,5679,5680,5683],{},"У C++, Java, C# компілятор фізично забороняє доступ до ",[5512,5681,5682],{},"private","-членів — код просто не скомпілюється. Python обрав інший шлях. Творець мови Гвідо ван Россум сформулював принцип:",[5685,5686,5687],"blockquote",{},[5508,5688,5689,5692],{},[5629,5690,5691],{},"«We are all consenting adults here»",[5693,5694,5695],"em",{},"(«Ми всі тут дорослі люди, що діють за згодою»)",[5508,5697,5698,5699,5702],{},"Мова не ставить жорстких бар'єрів. Якщо розробник хоче залізти у внутрішні деталі класу — він може. Але відповідальність за зламаний код повністю на ньому. Замість заборон Python використовує ",[5629,5700,5701],{},"угоди про іменування (naming conventions)",".",[5704,5705,5706],"plant-uml",{},[5521,5707,5711],{"className":5708,"code":5709,"language":5710,"meta":5526,"style":5526},"language-plantuml shiki shiki-themes light-plus dark-plus dark-plus","@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\nskinparam ArrowColor #6366f1\n\npackage \"Об'єкт класу (Екземпляр)\" #f3f4f6 {\n    rectangle \"Внутрішній стан\\n[_balance, __secret, _cache]\\n(Деталі реалізації)\" as Internal #fee2e2\n    rectangle \"Публічний інтерфейс (API)\\n[deposit(), withdraw(), balance]\" as Public #d1fae5\n\n    Public -down-> Internal : \"безпечно модифікує\\nта зчитує\"\n}\n\nactor \"Зовнішній код\" as Client\n\nClient -right-> Public : \"1. Викликає методи ✅\"\nClient --x Internal : \"2. Прямий доступ ❌\\n(порушення угоди)\"\n@enduml\n","plantuml",[5512,5712,5713,5718,5723,5728,5733,5737,5742,5747,5752,5756,5762,5768,5773,5779,5784,5790,5796],{"__ignoreMap":5526},[5530,5714,5715],{"class":5532,"line":5533},[5530,5716,5717],{},"@startuml\n",[5530,5719,5720],{"class":5532,"line":5540},[5530,5721,5722],{},"skinparam style plain\n",[5530,5724,5725],{"class":5532,"line":5561},[5530,5726,5727],{},"skinparam backgroundColor #ffffff\n",[5530,5729,5730],{"class":5532,"line":5568},[5530,5731,5732],{},"skinparam ArrowColor #6366f1\n",[5530,5734,5735],{"class":5532,"line":5574},[5530,5736,5565],{"emptyLinePlaceholder":5564},[5530,5738,5739],{"class":5532,"line":5586},[5530,5740,5741],{},"package \"Об'єкт класу (Екземпляр)\" #f3f4f6 {\n",[5530,5743,5744],{"class":5532,"line":5598},[5530,5745,5746],{},"    rectangle \"Внутрішній стан\\n[_balance, __secret, _cache]\\n(Деталі реалізації)\" as Internal #fee2e2\n",[5530,5748,5749],{"class":5532,"line":5603},[5530,5750,5751],{},"    rectangle \"Публічний інтерфейс (API)\\n[deposit(), withdraw(), balance]\" as Public #d1fae5\n",[5530,5753,5754],{"class":5532,"line":5609},[5530,5755,5565],{"emptyLinePlaceholder":5564},[5530,5757,5759],{"class":5532,"line":5758},10,[5530,5760,5761],{},"    Public -down-> Internal : \"безпечно модифікує\\nта зчитує\"\n",[5530,5763,5765],{"class":5532,"line":5764},11,[5530,5766,5767],{},"}\n",[5530,5769,5771],{"class":5532,"line":5770},12,[5530,5772,5565],{"emptyLinePlaceholder":5564},[5530,5774,5776],{"class":5532,"line":5775},13,[5530,5777,5778],{},"actor \"Зовнішній код\" as Client\n",[5530,5780,5782],{"class":5532,"line":5781},14,[5530,5783,5565],{"emptyLinePlaceholder":5564},[5530,5785,5787],{"class":5532,"line":5786},15,[5530,5788,5789],{},"Client -right-> Public : \"1. Викликає методи ✅\"\n",[5530,5791,5793],{"class":5532,"line":5792},16,[5530,5794,5795],{},"Client --x Internal : \"2. Прямий доступ ❌\\n(порушення угоди)\"\n",[5530,5797,5799],{"class":5532,"line":5798},17,[5530,5800,5801],{},"@enduml\n",[5666,5803],{},[5503,5805,5807],{"id":5806},"частина-ii-публічні-захищені-та-приватні-атрибути","Частина II: Публічні, захищені та приватні атрибути",[5673,5809,5811,5814],{"id":5810},"public-за-замовчуванням",[5512,5812,5813],{},"public"," — за замовчуванням",[5508,5816,5817,5818,5821],{},"Усі імена в класі без підкреслень є ",[5629,5819,5820],{},"публічними",". Вони є частиною стабільного публічного API і можуть змінюватись ззовні.",[5521,5823,5825],{"className":5523,"code":5824,"language":5525,"meta":5526,"style":5526},"class Point:\n    def __init__(self, x: float, y: float):\n        self.x = x  # публічний — змінювати можна і потрібно\n        self.y = y  # публічний\n\np = Point(3.0, 4.0)\np.x = 10.0  # ✅ цілком нормально\n",[5512,5826,5827,5840,5878,5889,5899,5903,5918],{"__ignoreMap":5526},[5530,5828,5829,5833,5837],{"class":5532,"line":5533},[5530,5830,5832],{"class":5831},"su1O8","class",[5530,5834,5836],{"class":5835},"sN1BT"," Point",[5530,5838,5839],{"class":5543},":\n",[5530,5841,5842,5845,5849,5852,5856,5858,5861,5864,5866,5868,5871,5873,5875],{"class":5532,"line":5540},[5530,5843,5844],{"class":5831},"    def",[5530,5846,5848],{"class":5847},"s8Opu"," __init__",[5530,5850,5851],{"class":5543},"(",[5530,5853,5855],{"class":5854},"siwwj","self",[5530,5857,5551],{"class":5543},[5530,5859,5860],{"class":5854},"x",[5530,5862,5863],{"class":5543},": ",[5530,5865,5649],{"class":5835},[5530,5867,5551],{"class":5543},[5530,5869,5870],{"class":5854},"y",[5530,5872,5863],{"class":5543},[5530,5874,5649],{"class":5835},[5530,5876,5877],{"class":5543},"):\n",[5530,5879,5880,5883,5886],{"class":5532,"line":5561},[5530,5881,5882],{"class":5831},"        self",[5530,5884,5885],{"class":5543},".x = x  ",[5530,5887,5888],{"class":5536},"# публічний — змінювати можна і потрібно\n",[5530,5890,5891,5893,5896],{"class":5532,"line":5568},[5530,5892,5882],{"class":5831},[5530,5894,5895],{"class":5543},".y = y  ",[5530,5897,5898],{"class":5536},"# публічний\n",[5530,5900,5901],{"class":5532,"line":5574},[5530,5902,5565],{"emptyLinePlaceholder":5564},[5530,5904,5905,5908,5911,5913,5916],{"class":5532,"line":5586},[5530,5906,5907],{"class":5543},"p = Point(",[5530,5909,5910],{"class":5554},"3.0",[5530,5912,5551],{"class":5543},[5530,5914,5915],{"class":5554},"4.0",[5530,5917,5558],{"class":5543},[5530,5919,5920,5923,5926],{"class":5532,"line":5598},[5530,5921,5922],{"class":5543},"p.x = ",[5530,5924,5925],{"class":5554},"10.0",[5530,5927,5928],{"class":5536},"  # ✅ цілком нормально\n",[5673,5930,5932,5935],{"id":5931},"_protected-угода-про-внутрішнє-використання",[5512,5933,5934],{},"_protected"," — угода про внутрішнє використання",[5508,5937,5938,5939,5942,5943,5946],{},"Один символ підкреслення перед іменем — ",[5629,5940,5941],{},"сигнал",": «це деталь реалізації, не призначена для прямого використання ззовні». Python це ",[5629,5944,5945],{},"не забороняє",", але весь інструментарій — IDE, linters, рецензенти коду — реагує на це попередженням.",[5521,5948,5950],{"className":5523,"code":5949,"language":5525,"meta":5526,"style":5526},"# bank_account.py\n\nclass BankAccount:\n    def __init__(self, owner: str, initial_balance: float):\n        self.owner = owner               # публічний ✅\n        self._balance = initial_balance  # захищений — для внутрішнього використання\n        self._transaction_log: list = [] # захищений — деталь реалізації\n\n    def deposit(self, amount: float) -> None:\n        if amount \u003C= 0:\n            raise ValueError(\"Сума депозиту має бути додатною\")\n        self._balance += amount\n        self._transaction_log.append(f\"+{amount}\")\n\n    def withdraw(self, amount: float) -> None:\n        if amount > self._balance:\n            raise ValueError(\"Недостатньо коштів\")\n        self._balance -= amount\n        self._transaction_log.append(f\"-{amount}\")\n\n    def get_balance(self) -> float:\n        return self._balance\n",[5512,5951,5952,5957,5961,5970,6001,6011,6021,6037,6041,6069,6083,6098,6105,6131,6135,6160,6172,6185,6193,6215,6220,6238],{"__ignoreMap":5526},[5530,5953,5954],{"class":5532,"line":5533},[5530,5955,5956],{"class":5536},"# bank_account.py\n",[5530,5958,5959],{"class":5532,"line":5540},[5530,5960,5565],{"emptyLinePlaceholder":5564},[5530,5962,5963,5965,5968],{"class":5532,"line":5561},[5530,5964,5832],{"class":5831},[5530,5966,5967],{"class":5835}," BankAccount",[5530,5969,5839],{"class":5543},[5530,5971,5972,5974,5976,5978,5980,5982,5985,5987,5990,5992,5995,5997,5999],{"class":5532,"line":5568},[5530,5973,5844],{"class":5831},[5530,5975,5848],{"class":5847},[5530,5977,5851],{"class":5543},[5530,5979,5855],{"class":5854},[5530,5981,5551],{"class":5543},[5530,5983,5984],{"class":5854},"owner",[5530,5986,5863],{"class":5543},[5530,5988,5989],{"class":5835},"str",[5530,5991,5551],{"class":5543},[5530,5993,5994],{"class":5854},"initial_balance",[5530,5996,5863],{"class":5543},[5530,5998,5649],{"class":5835},[5530,6000,5877],{"class":5543},[5530,6002,6003,6005,6008],{"class":5532,"line":5574},[5530,6004,5882],{"class":5831},[5530,6006,6007],{"class":5543},".owner = owner               ",[5530,6009,6010],{"class":5536},"# публічний ✅\n",[5530,6012,6013,6015,6018],{"class":5532,"line":5586},[5530,6014,5882],{"class":5831},[5530,6016,6017],{"class":5543},"._balance = initial_balance  ",[5530,6019,6020],{"class":5536},"# захищений — для внутрішнього використання\n",[5530,6022,6023,6025,6028,6031,6034],{"class":5532,"line":5598},[5530,6024,5882],{"class":5831},[5530,6026,6027],{"class":5543},"._transaction_log: ",[5530,6029,6030],{"class":5835},"list",[5530,6032,6033],{"class":5543}," = [] ",[5530,6035,6036],{"class":5536},"# захищений — деталь реалізації\n",[5530,6038,6039],{"class":5532,"line":5603},[5530,6040,5565],{"emptyLinePlaceholder":5564},[5530,6042,6043,6045,6048,6050,6052,6054,6057,6059,6061,6064,6067],{"class":5532,"line":5609},[5530,6044,5844],{"class":5831},[5530,6046,6047],{"class":5847}," deposit",[5530,6049,5851],{"class":5543},[5530,6051,5855],{"class":5854},[5530,6053,5551],{"class":5543},[5530,6055,6056],{"class":5854},"amount",[5530,6058,5863],{"class":5543},[5530,6060,5649],{"class":5835},[5530,6062,6063],{"class":5543},") -> ",[5530,6065,6066],{"class":5831},"None",[5530,6068,5839],{"class":5543},[5530,6070,6071,6075,6078,6081],{"class":5532,"line":5758},[5530,6072,6074],{"class":6073},"s8xlr","        if",[5530,6076,6077],{"class":5543}," amount \u003C= ",[5530,6079,6080],{"class":5554},"0",[5530,6082,5839],{"class":5543},[5530,6084,6085,6088,6091,6093,6096],{"class":5532,"line":5764},[5530,6086,6087],{"class":6073},"            raise",[5530,6089,6090],{"class":5835}," ValueError",[5530,6092,5851],{"class":5543},[5530,6094,6095],{"class":5547},"\"Сума депозиту має бути додатною\"",[5530,6097,5558],{"class":5543},[5530,6099,6100,6102],{"class":5532,"line":5770},[5530,6101,5882],{"class":5831},[5530,6103,6104],{"class":5543},"._balance += amount\n",[5530,6106,6107,6109,6112,6115,6118,6121,6123,6126,6129],{"class":5532,"line":5775},[5530,6108,5882],{"class":5831},[5530,6110,6111],{"class":5543},"._transaction_log.append(",[5530,6113,6114],{"class":5831},"f",[5530,6116,6117],{"class":5547},"\"+",[5530,6119,6120],{"class":5831},"{",[5530,6122,6056],{"class":5543},[5530,6124,6125],{"class":5831},"}",[5530,6127,6128],{"class":5547},"\"",[5530,6130,5558],{"class":5543},[5530,6132,6133],{"class":5532,"line":5781},[5530,6134,5565],{"emptyLinePlaceholder":5564},[5530,6136,6137,6139,6142,6144,6146,6148,6150,6152,6154,6156,6158],{"class":5532,"line":5786},[5530,6138,5844],{"class":5831},[5530,6140,6141],{"class":5847}," withdraw",[5530,6143,5851],{"class":5543},[5530,6145,5855],{"class":5854},[5530,6147,5551],{"class":5543},[5530,6149,6056],{"class":5854},[5530,6151,5863],{"class":5543},[5530,6153,5649],{"class":5835},[5530,6155,6063],{"class":5543},[5530,6157,6066],{"class":5831},[5530,6159,5839],{"class":5543},[5530,6161,6162,6164,6167,6169],{"class":5532,"line":5792},[5530,6163,6074],{"class":6073},[5530,6165,6166],{"class":5543}," amount > ",[5530,6168,5855],{"class":5831},[5530,6170,6171],{"class":5543},"._balance:\n",[5530,6173,6174,6176,6178,6180,6183],{"class":5532,"line":5798},[5530,6175,6087],{"class":6073},[5530,6177,6090],{"class":5835},[5530,6179,5851],{"class":5543},[5530,6181,6182],{"class":5547},"\"Недостатньо коштів\"",[5530,6184,5558],{"class":5543},[5530,6186,6188,6190],{"class":5532,"line":6187},18,[5530,6189,5882],{"class":5831},[5530,6191,6192],{"class":5543},"._balance -= amount\n",[5530,6194,6196,6198,6200,6202,6205,6207,6209,6211,6213],{"class":5532,"line":6195},19,[5530,6197,5882],{"class":5831},[5530,6199,6111],{"class":5543},[5530,6201,6114],{"class":5831},[5530,6203,6204],{"class":5547},"\"-",[5530,6206,6120],{"class":5831},[5530,6208,6056],{"class":5543},[5530,6210,6125],{"class":5831},[5530,6212,6128],{"class":5547},[5530,6214,5558],{"class":5543},[5530,6216,6218],{"class":5532,"line":6217},20,[5530,6219,5565],{"emptyLinePlaceholder":5564},[5530,6221,6223,6225,6228,6230,6232,6234,6236],{"class":5532,"line":6222},21,[5530,6224,5844],{"class":5831},[5530,6226,6227],{"class":5847}," get_balance",[5530,6229,5851],{"class":5543},[5530,6231,5855],{"class":5854},[5530,6233,6063],{"class":5543},[5530,6235,5649],{"class":5835},[5530,6237,5839],{"class":5543},[5530,6239,6241,6244,6247],{"class":5532,"line":6240},22,[5530,6242,6243],{"class":6073},"        return",[5530,6245,6246],{"class":5831}," self",[5530,6248,6249],{"class":5543},"._balance\n",[5521,6251,6253],{"className":5523,"code":6252,"language":5525,"meta":5526,"style":5526},"account = BankAccount(\"Денис\", 1000.0)\n\n# ⚠️ Технічно працює, але порушує угоду!\nprint(account._balance)       # 1000.0 — IDE покаже попередження\naccount._balance = -9999.0    # Баланс зламано — без жодних перевірок!\n",[5512,6254,6255,6270,6274,6279,6290],{"__ignoreMap":5526},[5530,6256,6257,6260,6263,6265,6268],{"class":5532,"line":5533},[5530,6258,6259],{"class":5543},"account = BankAccount(",[5530,6261,6262],{"class":5547},"\"Денис\"",[5530,6264,5551],{"class":5543},[5530,6266,6267],{"class":5554},"1000.0",[5530,6269,5558],{"class":5543},[5530,6271,6272],{"class":5532,"line":5540},[5530,6273,5565],{"emptyLinePlaceholder":5564},[5530,6275,6276],{"class":5532,"line":5561},[5530,6277,6278],{"class":5536},"# ⚠️ Технічно працює, але порушує угоду!\n",[5530,6280,6281,6284,6287],{"class":5532,"line":5568},[5530,6282,6283],{"class":5847},"print",[5530,6285,6286],{"class":5543},"(account._balance)       ",[5530,6288,6289],{"class":5536},"# 1000.0 — IDE покаже попередження\n",[5530,6291,6292,6295,6298],{"class":5532,"line":5574},[5530,6293,6294],{"class":5543},"account._balance = -",[5530,6296,6297],{"class":5554},"9999.0",[5530,6299,6300],{"class":5536},"    # Баланс зламано — без жодних перевірок!\n",[6302,6303,6305,6318,6333],"terminal-preview",{"title":6304},"pylint bank_account.py",[6306,6307,6309,6314,6315],"div",{"className":6308},[5532],[5530,6310,6313],{"className":6311},[6312],"opacity-40","$"," ",[5629,6316,6317],{},"pylint --disable=all --enable=W0212 main.py",[6306,6319,6321,6322,6327,6328],{"className":6320},[5532],"main.py:8:6: ",[5530,6323,6326],{"className":6324},[6325],"text-yellow-400","W0212",": Access to a protected member _balance of a client class ",[5530,6329,6332],{"className":6330},[6331],"text-gray-400","(protected-access)",[6306,6334,6336,6337,6327,6340],{"className":6335},[5532],"main.py:9:0: ",[5530,6338,6326],{"className":6339},[6325],[5530,6341,6332],{"className":6342},[6331],[5634,6344,6345,6353,6365],{},[5637,6346,6349,6350,6352],{"icon":6347,"title":6348},"i-heroicons-code-bracket-square","Підтримка IDE","VS Code і PyCharm приховують ",[5512,6351,5934],{}," атрибути в автодоповненні або виділяють їх попередженням при зверненні ззовні класу.",[5637,6354,6357,6360,6361,6364],{"icon":6355,"title":6356},"i-heroicons-shield-exclamation","Статичні лінтери",[5512,6358,6359],{},"pylint"," (W0212), ",[5512,6362,6363],{},"flake8-bugbear"," та інші видають попередження при доступі до захищених членів ззовні їхньої ієрархії.",[5637,6366,6368,6369,6372],{"icon":5644,"title":6367},"Нестабільний API","Атрибут з ",[5512,6370,6371],{},"_"," може бути перейменований або видалений у будь-якому мінорному релізі бібліотеки. Використовуючи його — ви приймаєте ризик поломки при оновленні.",[5666,6374],{},[5673,6376,6378,6381],{"id":6377},"__private-name-mangling",[5512,6379,6380],{},"__private"," — Name Mangling",[5508,6383,6384,6385,6388],{},"Два підкреслення перед іменем активують механізм ",[5629,6386,6387],{},"викривлення імен (Name Mangling)",". Компілятор Python автоматично перейменовує такий атрибут за шаблоном:",[6390,6391,6392],"math-formula",{},"_ClassName__attribute",[5508,6394,6395,6396,6399,6400,6403],{},"Це ",[5629,6397,6398],{},"не шифрування"," і ",[5629,6401,6402],{},"не справжня приватність"," — це лише захист від випадкових колізій імен.",[5521,6405,6407],{"className":5523,"code":6406,"language":5525,"meta":5526,"style":5526},"# secure_wallet.py\n\nclass SecureWallet:\n    def __init__(self, owner: str, initial_funds: float):\n        self.owner = owner\n        self.__funds = initial_funds  # → _SecureWallet__funds у пам'яті\n\n    def add_funds(self, amount: float) -> None:\n        if amount > 0:\n            self.__funds += amount\n\n    def get_funds(self) -> float:\n        return self.__funds\n\n\nwallet = SecureWallet(\"Марія\", 500.0)\n\n# Прямий доступ — AttributeError\ntry:\n    print(wallet.__funds)\nexcept AttributeError as e:\n    print(f\"AttributeError: {e}\")\n\n# Досліджуємо __dict__ — бачимо викривлене ім'я\nprint(wallet.__dict__)\n\n# Доступ через викривлене ім'я — все ще можливий!\nprint(wallet._SecureWallet__funds)\nwallet._SecureWallet__funds = -1000.0\nprint(wallet.get_funds())\n",[5512,6408,6409,6414,6418,6427,6456,6463,6473,6477,6502,6512,6520,6524,6541,6550,6554,6558,6573,6577,6582,6589,6597,6611,6633,6638,6644,6657,6662,6668,6676,6685],{"__ignoreMap":5526},[5530,6410,6411],{"class":5532,"line":5533},[5530,6412,6413],{"class":5536},"# secure_wallet.py\n",[5530,6415,6416],{"class":5532,"line":5540},[5530,6417,5565],{"emptyLinePlaceholder":5564},[5530,6419,6420,6422,6425],{"class":5532,"line":5561},[5530,6421,5832],{"class":5831},[5530,6423,6424],{"class":5835}," SecureWallet",[5530,6426,5839],{"class":5543},[5530,6428,6429,6431,6433,6435,6437,6439,6441,6443,6445,6447,6450,6452,6454],{"class":5532,"line":5568},[5530,6430,5844],{"class":5831},[5530,6432,5848],{"class":5847},[5530,6434,5851],{"class":5543},[5530,6436,5855],{"class":5854},[5530,6438,5551],{"class":5543},[5530,6440,5984],{"class":5854},[5530,6442,5863],{"class":5543},[5530,6444,5989],{"class":5835},[5530,6446,5551],{"class":5543},[5530,6448,6449],{"class":5854},"initial_funds",[5530,6451,5863],{"class":5543},[5530,6453,5649],{"class":5835},[5530,6455,5877],{"class":5543},[5530,6457,6458,6460],{"class":5532,"line":5574},[5530,6459,5882],{"class":5831},[5530,6461,6462],{"class":5543},".owner = owner\n",[5530,6464,6465,6467,6470],{"class":5532,"line":5586},[5530,6466,5882],{"class":5831},[5530,6468,6469],{"class":5543},".__funds = initial_funds  ",[5530,6471,6472],{"class":5536},"# → _SecureWallet__funds у пам'яті\n",[5530,6474,6475],{"class":5532,"line":5598},[5530,6476,5565],{"emptyLinePlaceholder":5564},[5530,6478,6479,6481,6484,6486,6488,6490,6492,6494,6496,6498,6500],{"class":5532,"line":5603},[5530,6480,5844],{"class":5831},[5530,6482,6483],{"class":5847}," add_funds",[5530,6485,5851],{"class":5543},[5530,6487,5855],{"class":5854},[5530,6489,5551],{"class":5543},[5530,6491,6056],{"class":5854},[5530,6493,5863],{"class":5543},[5530,6495,5649],{"class":5835},[5530,6497,6063],{"class":5543},[5530,6499,6066],{"class":5831},[5530,6501,5839],{"class":5543},[5530,6503,6504,6506,6508,6510],{"class":5532,"line":5609},[5530,6505,6074],{"class":6073},[5530,6507,6166],{"class":5543},[5530,6509,6080],{"class":5554},[5530,6511,5839],{"class":5543},[5530,6513,6514,6517],{"class":5532,"line":5758},[5530,6515,6516],{"class":5831},"            self",[5530,6518,6519],{"class":5543},".__funds += amount\n",[5530,6521,6522],{"class":5532,"line":5764},[5530,6523,5565],{"emptyLinePlaceholder":5564},[5530,6525,6526,6528,6531,6533,6535,6537,6539],{"class":5532,"line":5770},[5530,6527,5844],{"class":5831},[5530,6529,6530],{"class":5847}," get_funds",[5530,6532,5851],{"class":5543},[5530,6534,5855],{"class":5854},[5530,6536,6063],{"class":5543},[5530,6538,5649],{"class":5835},[5530,6540,5839],{"class":5543},[5530,6542,6543,6545,6547],{"class":5532,"line":5775},[5530,6544,6243],{"class":6073},[5530,6546,6246],{"class":5831},[5530,6548,6549],{"class":5543},".__funds\n",[5530,6551,6552],{"class":5532,"line":5781},[5530,6553,5565],{"emptyLinePlaceholder":5564},[5530,6555,6556],{"class":5532,"line":5786},[5530,6557,5565],{"emptyLinePlaceholder":5564},[5530,6559,6560,6563,6566,6568,6571],{"class":5532,"line":5792},[5530,6561,6562],{"class":5543},"wallet = SecureWallet(",[5530,6564,6565],{"class":5547},"\"Марія\"",[5530,6567,5551],{"class":5543},[5530,6569,6570],{"class":5554},"500.0",[5530,6572,5558],{"class":5543},[5530,6574,6575],{"class":5532,"line":5798},[5530,6576,5565],{"emptyLinePlaceholder":5564},[5530,6578,6579],{"class":5532,"line":6187},[5530,6580,6581],{"class":5536},"# Прямий доступ — AttributeError\n",[5530,6583,6584,6587],{"class":5532,"line":6195},[5530,6585,6586],{"class":6073},"try",[5530,6588,5839],{"class":5543},[5530,6590,6591,6594],{"class":5532,"line":6217},[5530,6592,6593],{"class":5847},"    print",[5530,6595,6596],{"class":5543},"(wallet.__funds)\n",[5530,6598,6599,6602,6605,6608],{"class":5532,"line":6222},[5530,6600,6601],{"class":6073},"except",[5530,6603,6604],{"class":5835}," AttributeError",[5530,6606,6607],{"class":6073}," as",[5530,6609,6610],{"class":5543}," e:\n",[5530,6612,6613,6615,6617,6619,6622,6624,6627,6629,6631],{"class":5532,"line":6240},[5530,6614,6593],{"class":5847},[5530,6616,5851],{"class":5543},[5530,6618,6114],{"class":5831},[5530,6620,6621],{"class":5547},"\"AttributeError: ",[5530,6623,6120],{"class":5831},[5530,6625,6626],{"class":5543},"e",[5530,6628,6125],{"class":5831},[5530,6630,6128],{"class":5547},[5530,6632,5558],{"class":5543},[5530,6634,6636],{"class":5532,"line":6635},23,[5530,6637,5565],{"emptyLinePlaceholder":5564},[5530,6639,6641],{"class":5532,"line":6640},24,[5530,6642,6643],{"class":5536},"# Досліджуємо __dict__ — бачимо викривлене ім'я\n",[5530,6645,6647,6649,6652,6655],{"class":5532,"line":6646},25,[5530,6648,6283],{"class":5847},[5530,6650,6651],{"class":5543},"(wallet.",[5530,6653,6654],{"class":5854},"__dict__",[5530,6656,5558],{"class":5543},[5530,6658,6660],{"class":5532,"line":6659},26,[5530,6661,5565],{"emptyLinePlaceholder":5564},[5530,6663,6665],{"class":5532,"line":6664},27,[5530,6666,6667],{"class":5536},"# Доступ через викривлене ім'я — все ще можливий!\n",[5530,6669,6671,6673],{"class":5532,"line":6670},28,[5530,6672,6283],{"class":5847},[5530,6674,6675],{"class":5543},"(wallet._SecureWallet__funds)\n",[5530,6677,6679,6682],{"class":5532,"line":6678},29,[5530,6680,6681],{"class":5543},"wallet._SecureWallet__funds = -",[5530,6683,6684],{"class":5554},"1000.0\n",[5530,6686,6688,6690],{"class":5532,"line":6687},30,[5530,6689,6283],{"class":5847},[5530,6691,6692],{"class":5543},"(wallet.get_funds())\n",[6302,6694,6696,6704,6713,6731,6743],{"title":6695},"python secure_wallet.py",[6306,6697,6699,6314,6702],{"className":6698},[5532],[5530,6700,6313],{"className":6701},[6312],[5629,6703,6695],{},[6306,6705,6707,6708],{"className":6706},[5532],"AttributeError: ",[5530,6709,6712],{"className":6710},[6711],"text-rose-400","'SecureWallet' object has no attribute '__funds'",[6306,6714,6716,6717,6722,6723,6727,6728,6125],{"className":6715},[5532],"{'owner': ",[5530,6718,6721],{"className":6719},[6720],"text-green-400","'Марія'",", '",[5530,6724,6726],{"className":6725},[6325],"_SecureWallet__funds","': ",[5530,6729,6570],{"className":6730},[6720],[6306,6732,6734,6738,6739],{"className":6733},[5532],[5530,6735,6570],{"className":6736},[6737],"text-blue-400","  ",[5530,6740,6742],{"className":6741},[6331],"# доступ через викривлене ім'я — все ще працює!",[6306,6744,6746,6738,6750],{"className":6745},[5532],[5530,6747,6749],{"className":6748},[6711],"-1000.0",[5530,6751,6753],{"className":6752},[6331],"# успішно перезаписано через mangled name",[6755,6756,6757,6760,6761,6764,6765,6768],"warning",{},[5629,6758,6759],{},"Name Mangling — це не засіб безпеки."," Він не шифрує дані і не захищає їх у пам'яті. ",[5512,6762,6763],{},"wallet._SecureWallet__funds"," є абсолютно легальним Python-кодом. Механізм призначений виключно для ",[5629,6766,6767],{},"запобігання випадковим колізіям імен"," у ієрархіях наслідування, а не для захисту від навмисного злому.",[5666,6770],{},[5673,6772,6774],{"id":6773},"справжнє-призначення-name-mangling-захист-від-колізій-при-наслідуванні","Справжнє призначення Name Mangling: захист від колізій при наслідуванні",[5508,6776,6777],{},"Ось реальна проблема, яку вирішує подвійне підкреслення. Без Name Mangling підклас міг би випадково перезаписати внутрішній атрибут батьківського класу:",[5521,6779,6781],{"className":5523,"code":6780,"language":5525,"meta":5526,"style":5526},"# collision_demo.py\n\nclass BaseConnector:\n    def __init__(self):\n        self.__timeout = 30  # → _BaseConnector__timeout\n\n    def connect(self):\n        print(f\"Базовий таймаут: {self.__timeout}с\")\n\n\nclass CustomConnector(BaseConnector):\n    def __init__(self):\n        super().__init__()\n        self.__timeout = 90  # → _CustomConnector__timeout (інше поле!)\n\n    def show_custom(self):\n        print(f\"Кастомний таймаут: {self.__timeout}с\")\n\n\nconn = CustomConnector()\nconn.connect()      # Базовий таймаут: 30с  ✅ НЕ перезаписано!\nconn.show_custom()  # Кастомний таймаут: 90с ✅\n\n# Два окремих поля у __dict__:\nprint(conn.__dict__)\n# {'_BaseConnector__timeout': 30, '_CustomConnector__timeout': 90}\n",[5512,6782,6783,6788,6792,6801,6813,6826,6830,6843,6868,6872,6876,6890,6902,6916,6928,6932,6945,6966,6970,6974,6979,6987,6995,6999,7004,7015],{"__ignoreMap":5526},[5530,6784,6785],{"class":5532,"line":5533},[5530,6786,6787],{"class":5536},"# collision_demo.py\n",[5530,6789,6790],{"class":5532,"line":5540},[5530,6791,5565],{"emptyLinePlaceholder":5564},[5530,6793,6794,6796,6799],{"class":5532,"line":5561},[5530,6795,5832],{"class":5831},[5530,6797,6798],{"class":5835}," BaseConnector",[5530,6800,5839],{"class":5543},[5530,6802,6803,6805,6807,6809,6811],{"class":5532,"line":5568},[5530,6804,5844],{"class":5831},[5530,6806,5848],{"class":5847},[5530,6808,5851],{"class":5543},[5530,6810,5855],{"class":5854},[5530,6812,5877],{"class":5543},[5530,6814,6815,6817,6820,6823],{"class":5532,"line":5574},[5530,6816,5882],{"class":5831},[5530,6818,6819],{"class":5543},".__timeout = ",[5530,6821,6822],{"class":5554},"30",[5530,6824,6825],{"class":5536},"  # → _BaseConnector__timeout\n",[5530,6827,6828],{"class":5532,"line":5586},[5530,6829,5565],{"emptyLinePlaceholder":5564},[5530,6831,6832,6834,6837,6839,6841],{"class":5532,"line":5598},[5530,6833,5844],{"class":5831},[5530,6835,6836],{"class":5847}," connect",[5530,6838,5851],{"class":5543},[5530,6840,5855],{"class":5854},[5530,6842,5877],{"class":5543},[5530,6844,6845,6848,6850,6852,6855,6858,6861,6863,6866],{"class":5532,"line":5603},[5530,6846,6847],{"class":5847},"        print",[5530,6849,5851],{"class":5543},[5530,6851,6114],{"class":5831},[5530,6853,6854],{"class":5547},"\"Базовий таймаут: ",[5530,6856,6857],{"class":5831},"{self",[5530,6859,6860],{"class":5543},".__timeout",[5530,6862,6125],{"class":5831},[5530,6864,6865],{"class":5547},"с\"",[5530,6867,5558],{"class":5543},[5530,6869,6870],{"class":5532,"line":5609},[5530,6871,5565],{"emptyLinePlaceholder":5564},[5530,6873,6874],{"class":5532,"line":5758},[5530,6875,5565],{"emptyLinePlaceholder":5564},[5530,6877,6878,6880,6883,6885,6888],{"class":5532,"line":5764},[5530,6879,5832],{"class":5831},[5530,6881,6882],{"class":5835}," CustomConnector",[5530,6884,5851],{"class":5543},[5530,6886,6887],{"class":5835},"BaseConnector",[5530,6889,5877],{"class":5543},[5530,6891,6892,6894,6896,6898,6900],{"class":5532,"line":5770},[5530,6893,5844],{"class":5831},[5530,6895,5848],{"class":5847},[5530,6897,5851],{"class":5543},[5530,6899,5855],{"class":5854},[5530,6901,5877],{"class":5543},[5530,6903,6904,6907,6910,6913],{"class":5532,"line":5775},[5530,6905,6906],{"class":5835},"        super",[5530,6908,6909],{"class":5543},"().",[5530,6911,6912],{"class":5847},"__init__",[5530,6914,6915],{"class":5543},"()\n",[5530,6917,6918,6920,6922,6925],{"class":5532,"line":5781},[5530,6919,5882],{"class":5831},[5530,6921,6819],{"class":5543},[5530,6923,6924],{"class":5554},"90",[5530,6926,6927],{"class":5536},"  # → _CustomConnector__timeout (інше поле!)\n",[5530,6929,6930],{"class":5532,"line":5786},[5530,6931,5565],{"emptyLinePlaceholder":5564},[5530,6933,6934,6936,6939,6941,6943],{"class":5532,"line":5792},[5530,6935,5844],{"class":5831},[5530,6937,6938],{"class":5847}," show_custom",[5530,6940,5851],{"class":5543},[5530,6942,5855],{"class":5854},[5530,6944,5877],{"class":5543},[5530,6946,6947,6949,6951,6953,6956,6958,6960,6962,6964],{"class":5532,"line":5798},[5530,6948,6847],{"class":5847},[5530,6950,5851],{"class":5543},[5530,6952,6114],{"class":5831},[5530,6954,6955],{"class":5547},"\"Кастомний таймаут: ",[5530,6957,6857],{"class":5831},[5530,6959,6860],{"class":5543},[5530,6961,6125],{"class":5831},[5530,6963,6865],{"class":5547},[5530,6965,5558],{"class":5543},[5530,6967,6968],{"class":5532,"line":6187},[5530,6969,5565],{"emptyLinePlaceholder":5564},[5530,6971,6972],{"class":5532,"line":6195},[5530,6973,5565],{"emptyLinePlaceholder":5564},[5530,6975,6976],{"class":5532,"line":6217},[5530,6977,6978],{"class":5543},"conn = CustomConnector()\n",[5530,6980,6981,6984],{"class":5532,"line":6222},[5530,6982,6983],{"class":5543},"conn.connect()      ",[5530,6985,6986],{"class":5536},"# Базовий таймаут: 30с  ✅ НЕ перезаписано!\n",[5530,6988,6989,6992],{"class":5532,"line":6240},[5530,6990,6991],{"class":5543},"conn.show_custom()  ",[5530,6993,6994],{"class":5536},"# Кастомний таймаут: 90с ✅\n",[5530,6996,6997],{"class":5532,"line":6635},[5530,6998,5565],{"emptyLinePlaceholder":5564},[5530,7000,7001],{"class":5532,"line":6640},[5530,7002,7003],{"class":5536},"# Два окремих поля у __dict__:\n",[5530,7005,7006,7008,7011,7013],{"class":5532,"line":6646},[5530,7007,6283],{"class":5847},[5530,7009,7010],{"class":5543},"(conn.",[5530,7012,6654],{"class":5854},[5530,7014,5558],{"class":5543},[5530,7016,7017],{"class":5532,"line":6659},[5530,7018,7019],{"class":5536},"# {'_BaseConnector__timeout': 30, '_CustomConnector__timeout': 90}\n",[6302,7021,7023,7031,7043,7051],{"title":7022},"python collision_demo.py",[6306,7024,7026,6314,7029],{"className":7025},[5532],[5530,7027,6313],{"className":7028},[6312],[5629,7030,7022],{},[6306,7032,7034,7035,7038,7039],{"className":7033},[5532],"Базовий таймаут: ",[5530,7036,6822],{"className":7037},[6720],"с  ",[5530,7040,7042],{"className":7041},[6331],"# НЕ перезаписано підкласом!",[6306,7044,7046,7047,7050],{"className":7045},[5532],"Кастомний таймаут: ",[5530,7048,6924],{"className":7049},[6737],"с",[6306,7052,6120,7054,7058,7059,7063],{"className":7053},[5532],[5530,7055,7057],{"className":7056},[6325],"'_BaseConnector__timeout'",": 30, ",[5530,7060,7062],{"className":7061},[6325],"'_CustomConnector__timeout'",": 90}",[7065,7066,7067,7068,7070,7071,7074,7075,7077],"tip",{},"Використовуйте ",[5512,7069,6380],{}," (подвійне підкреслення) ",[5629,7072,7073],{},"тільки"," коли проектуєте базовий клас бібліотеки і хочете захистити критичні внутрішні атрибути від випадкового перезапису у підкласах. Для всіх інших ситуацій — ",[5512,7076,5934],{}," (одне підкреслення) є достатнім і кращим вибором.",[5666,7079],{},[5673,7081,7083],{"id":7082},"порівняльна-таблиця-рівнів-доступу","Порівняльна таблиця рівнів доступу",[7085,7086,7087,7109],"table",{},[7088,7089,7090],"thead",{},[7091,7092,7093,7097,7100,7103,7106],"tr",{},[7094,7095,7096],"th",{},"Конвенція",[7094,7098,7099],{},"Приклад",[7094,7101,7102],{},"Значення",[7094,7104,7105],{},"Доступ ззовні",[7094,7107,7108],{},"Name Mangling",[7110,7111,7112,7132,7150,7172],"tbody",{},[7091,7113,7114,7118,7123,7126,7129],{},[7115,7116,7117],"td",{},"Без підкреслення",[7115,7119,7120],{},[5512,7121,7122],{},"self.name",[7115,7124,7125],{},"Публічний API",[7115,7127,7128],{},"✅ Заохочується",[7115,7130,7131],{},"❌",[7091,7133,7134,7137,7142,7145,7148],{},[7115,7135,7136],{},"Одне підкреслення",[7115,7138,7139],{},[5512,7140,7141],{},"self._balance",[7115,7143,7144],{},"Деталь реалізації",[7115,7146,7147],{},"⚠️ Угода (не заборонено)",[7115,7149,7131],{},[7091,7151,7152,7155,7160,7163,7169],{},[7115,7153,7154],{},"Два підкреслення",[7115,7156,7157],{},[5512,7158,7159],{},"self.__secret",[7115,7161,7162],{},"Захист від колізій",[7115,7164,7165,7166],{},"🔒 Лише через ",[5512,7167,7168],{},"_Class__secret",[7115,7170,7171],{},"✅",[7091,7173,7174,7177,7182,7185,7188],{},[7115,7175,7176],{},"Dunder",[7115,7178,7179],{},[5512,7180,7181],{},"self.__init__",[7115,7183,7184],{},"Магічний метод",[7115,7186,7187],{},"✅ Частина протоколу",[7115,7189,7190],{},"❌ (виняток)",[5666,7192],{},[5503,7194,7196,7197,7200],{"id":7195},"частина-iii-property-pythonic-шлях-до-валідації","Частина III: ",[5512,7198,7199],{},"@property"," — Pythonic-шлях до валідації",[5673,7202,7204],{"id":7203},"проблема-java-style-геттерівсеттерів","Проблема Java-style геттерів\u002Fсеттерів",[5508,7206,7207,7208,7211,7212,7215],{},"Розробники, що прийшли з Java або C#, часто несуть звичку обгортати кожне поле парою ",[5512,7209,7210],{},"getX()"," \u002F ",[5512,7213,7214],{},"setX()",":",[5521,7217,7219],{"className":5523,"code":7218,"language":5525,"meta":5526,"style":5526},"# ❌ Антипатерн: Java-style у Python\nclass UnpythonicAccount:\n    def __init__(self, balance: float):\n        self._balance = balance\n\n    def get_balance(self) -> float:       # зайвий шум\n        return self._balance\n\n    def set_balance(self, value: float):  # зайвий шум\n        if value \u003C 0:\n            raise ValueError(\"Баланс не може бути від'ємним\")\n        self._balance = value\n\naccount = UnpythonicAccount(1000.0)\naccount.set_balance(account.get_balance() + 500)  # некрасиво!\n",[5512,7220,7221,7226,7235,7255,7262,7266,7286,7294,7298,7323,7334,7347,7354,7358,7367],{"__ignoreMap":5526},[5530,7222,7223],{"class":5532,"line":5533},[5530,7224,7225],{"class":5536},"# ❌ Антипатерн: Java-style у Python\n",[5530,7227,7228,7230,7233],{"class":5532,"line":5540},[5530,7229,5832],{"class":5831},[5530,7231,7232],{"class":5835}," UnpythonicAccount",[5530,7234,5839],{"class":5543},[5530,7236,7237,7239,7241,7243,7245,7247,7249,7251,7253],{"class":5532,"line":5561},[5530,7238,5844],{"class":5831},[5530,7240,5848],{"class":5847},[5530,7242,5851],{"class":5543},[5530,7244,5855],{"class":5854},[5530,7246,5551],{"class":5543},[5530,7248,5518],{"class":5854},[5530,7250,5863],{"class":5543},[5530,7252,5649],{"class":5835},[5530,7254,5877],{"class":5543},[5530,7256,7257,7259],{"class":5532,"line":5568},[5530,7258,5882],{"class":5831},[5530,7260,7261],{"class":5543},"._balance = balance\n",[5530,7263,7264],{"class":5532,"line":5574},[5530,7265,5565],{"emptyLinePlaceholder":5564},[5530,7267,7268,7270,7272,7274,7276,7278,7280,7283],{"class":5532,"line":5586},[5530,7269,5844],{"class":5831},[5530,7271,6227],{"class":5847},[5530,7273,5851],{"class":5543},[5530,7275,5855],{"class":5854},[5530,7277,6063],{"class":5543},[5530,7279,5649],{"class":5835},[5530,7281,7282],{"class":5543},":       ",[5530,7284,7285],{"class":5536},"# зайвий шум\n",[5530,7287,7288,7290,7292],{"class":5532,"line":5598},[5530,7289,6243],{"class":6073},[5530,7291,6246],{"class":5831},[5530,7293,6249],{"class":5543},[5530,7295,7296],{"class":5532,"line":5603},[5530,7297,5565],{"emptyLinePlaceholder":5564},[5530,7299,7300,7302,7305,7307,7309,7311,7314,7316,7318,7321],{"class":5532,"line":5609},[5530,7301,5844],{"class":5831},[5530,7303,7304],{"class":5847}," set_balance",[5530,7306,5851],{"class":5543},[5530,7308,5855],{"class":5854},[5530,7310,5551],{"class":5543},[5530,7312,7313],{"class":5854},"value",[5530,7315,5863],{"class":5543},[5530,7317,5649],{"class":5835},[5530,7319,7320],{"class":5543},"):  ",[5530,7322,7285],{"class":5536},[5530,7324,7325,7327,7330,7332],{"class":5532,"line":5758},[5530,7326,6074],{"class":6073},[5530,7328,7329],{"class":5543}," value \u003C ",[5530,7331,6080],{"class":5554},[5530,7333,5839],{"class":5543},[5530,7335,7336,7338,7340,7342,7345],{"class":5532,"line":5764},[5530,7337,6087],{"class":6073},[5530,7339,6090],{"class":5835},[5530,7341,5851],{"class":5543},[5530,7343,7344],{"class":5547},"\"Баланс не може бути від'ємним\"",[5530,7346,5558],{"class":5543},[5530,7348,7349,7351],{"class":5532,"line":5770},[5530,7350,5882],{"class":5831},[5530,7352,7353],{"class":5543},"._balance = value\n",[5530,7355,7356],{"class":5532,"line":5775},[5530,7357,5565],{"emptyLinePlaceholder":5564},[5530,7359,7360,7363,7365],{"class":5532,"line":5781},[5530,7361,7362],{"class":5543},"account = UnpythonicAccount(",[5530,7364,6267],{"class":5554},[5530,7366,5558],{"class":5543},[5530,7368,7369,7372,7375,7378],{"class":5532,"line":5786},[5530,7370,7371],{"class":5543},"account.set_balance(account.get_balance() + ",[5530,7373,7374],{"class":5554},"500",[5530,7376,7377],{"class":5543},")  ",[5530,7379,7380],{"class":5536},"# некрасиво!\n",[5508,7382,7383,7386,7387,7389,7390,7215],{},[5629,7384,7385],{},"Pythonic-підхід:"," починайте з простого публічного атрибута. Якщо пізніше знадобиться валідація — перетворіть його на ",[5512,7388,7199],{},". Зовнішній код при цьому ",[5629,7391,7392],{},"не потребує змін",[5521,7394,7396],{"className":5523,"code":7395,"language":5525,"meta":5526,"style":5526},"# ✅ Правильно: починаємо просто\nclass PythonicAccount:\n    def __init__(self, balance: float):\n        self.balance = balance  # просто публічний атрибут\n\n# Якщо згодом потрібна валідація — перетворюємо на @property.\n# account.balance = 1500 — цей зовнішній код НЕ ЗМІНИТЬСЯ!\n",[5512,7397,7398,7403,7412,7432,7442,7446,7451],{"__ignoreMap":5526},[5530,7399,7400],{"class":5532,"line":5533},[5530,7401,7402],{"class":5536},"# ✅ Правильно: починаємо просто\n",[5530,7404,7405,7407,7410],{"class":5532,"line":5540},[5530,7406,5832],{"class":5831},[5530,7408,7409],{"class":5835}," PythonicAccount",[5530,7411,5839],{"class":5543},[5530,7413,7414,7416,7418,7420,7422,7424,7426,7428,7430],{"class":5532,"line":5561},[5530,7415,5844],{"class":5831},[5530,7417,5848],{"class":5847},[5530,7419,5851],{"class":5543},[5530,7421,5855],{"class":5854},[5530,7423,5551],{"class":5543},[5530,7425,5518],{"class":5854},[5530,7427,5863],{"class":5543},[5530,7429,5649],{"class":5835},[5530,7431,5877],{"class":5543},[5530,7433,7434,7436,7439],{"class":5532,"line":5568},[5530,7435,5882],{"class":5831},[5530,7437,7438],{"class":5543},".balance = balance  ",[5530,7440,7441],{"class":5536},"# просто публічний атрибут\n",[5530,7443,7444],{"class":5532,"line":5574},[5530,7445,5565],{"emptyLinePlaceholder":5564},[5530,7447,7448],{"class":5532,"line":5586},[5530,7449,7450],{"class":5536},"# Якщо згодом потрібна валідація — перетворюємо на @property.\n",[5530,7452,7453],{"class":5532,"line":5598},[5530,7454,7455],{"class":5536},"# account.balance = 1500 — цей зовнішній код НЕ ЗМІНИТЬСЯ!\n",[5666,7457],{},[5673,7459,7461,7462,7464],{"id":7460},"декоратор-property-обчислювальні-властивості-read-only","Декоратор ",[5512,7463,7199],{},": обчислювальні властивості (read-only)",[5508,7466,7467,7469,7470,7473],{},[5512,7468,7199],{}," перетворює метод на атрибут — зчитування відбувається без дужок ",[5512,7471,7472],{},"()",". За замовчуванням властивість є лише для читання.",[5521,7475,7477],{"className":5523,"code":7476,"language":5525,"meta":5526,"style":5526},"# circle.py\nimport math\n\nclass Circle:\n    def __init__(self, radius: float):\n        if radius \u003C= 0:\n            raise ValueError(\"Радіус має бути додатним\")\n        self.radius = radius\n\n    @property\n    def area(self) -> float:\n        \"\"\"Площа кола — обчислюється з radius при кожному зверненні.\"\"\"\n        return math.pi * self.radius ** 2\n\n    @property\n    def circumference(self) -> float:\n        \"\"\"Довжина кола.\"\"\"\n        return 2 * math.pi * self.radius\n\n    @property\n    def diameter(self) -> float:\n        \"\"\"Діаметр — обчислюється з radius.\"\"\"\n        return self.radius * 2\n\n\nc = Circle(5.0)\n\n# Звертаємось як до атрибута — БЕЗ дужок!\nprint(f\"Площа:    {c.area:.4f}\")\nprint(f\"Периметр: {c.circumference:.4f}\")\nprint(f\"Діаметр:  {c.diameter:.4f}\")\n\n# Можна змінити radius — всі властивості автоматично оновляться\nc.radius = 10.0\nprint(f\"Нова площа: {c.area:.4f}\")\n\n# Спроба записати у read-only властивість:\ntry:\n    c.area = 999.0\nexcept AttributeError as e:\n    print(f\"AttributeError: {e}\")\n",[5512,7478,7479,7484,7492,7496,7505,7526,7537,7550,7557,7561,7569,7586,7591,7606,7610,7616,7633,7638,7653,7657,7663,7680,7685,7696,7700,7704,7714,7718,7723,7746,7768,7791,7796,7802,7811,7833,7838,7844,7851,7860,7871],{"__ignoreMap":5526},[5530,7480,7481],{"class":5532,"line":5533},[5530,7482,7483],{"class":5536},"# circle.py\n",[5530,7485,7486,7489],{"class":5532,"line":5540},[5530,7487,7488],{"class":6073},"import",[5530,7490,7491],{"class":5543}," math\n",[5530,7493,7494],{"class":5532,"line":5561},[5530,7495,5565],{"emptyLinePlaceholder":5564},[5530,7497,7498,7500,7503],{"class":5532,"line":5568},[5530,7499,5832],{"class":5831},[5530,7501,7502],{"class":5835}," Circle",[5530,7504,5839],{"class":5543},[5530,7506,7507,7509,7511,7513,7515,7517,7520,7522,7524],{"class":5532,"line":5574},[5530,7508,5844],{"class":5831},[5530,7510,5848],{"class":5847},[5530,7512,5851],{"class":5543},[5530,7514,5855],{"class":5854},[5530,7516,5551],{"class":5543},[5530,7518,7519],{"class":5854},"radius",[5530,7521,5863],{"class":5543},[5530,7523,5649],{"class":5835},[5530,7525,5877],{"class":5543},[5530,7527,7528,7530,7533,7535],{"class":5532,"line":5586},[5530,7529,6074],{"class":6073},[5530,7531,7532],{"class":5543}," radius \u003C= ",[5530,7534,6080],{"class":5554},[5530,7536,5839],{"class":5543},[5530,7538,7539,7541,7543,7545,7548],{"class":5532,"line":5598},[5530,7540,6087],{"class":6073},[5530,7542,6090],{"class":5835},[5530,7544,5851],{"class":5543},[5530,7546,7547],{"class":5547},"\"Радіус має бути додатним\"",[5530,7549,5558],{"class":5543},[5530,7551,7552,7554],{"class":5532,"line":5603},[5530,7553,5882],{"class":5831},[5530,7555,7556],{"class":5543},".radius = radius\n",[5530,7558,7559],{"class":5532,"line":5609},[5530,7560,5565],{"emptyLinePlaceholder":5564},[5530,7562,7563,7566],{"class":5532,"line":5758},[5530,7564,7565],{"class":5847},"    @",[5530,7567,7568],{"class":5835},"property\n",[5530,7570,7571,7573,7576,7578,7580,7582,7584],{"class":5532,"line":5764},[5530,7572,5844],{"class":5831},[5530,7574,7575],{"class":5847}," area",[5530,7577,5851],{"class":5543},[5530,7579,5855],{"class":5854},[5530,7581,6063],{"class":5543},[5530,7583,5649],{"class":5835},[5530,7585,5839],{"class":5543},[5530,7587,7588],{"class":5532,"line":5770},[5530,7589,7590],{"class":5547},"        \"\"\"Площа кола — обчислюється з radius при кожному зверненні.\"\"\"\n",[5530,7592,7593,7595,7598,7600,7603],{"class":5532,"line":5775},[5530,7594,6243],{"class":6073},[5530,7596,7597],{"class":5543}," math.pi * ",[5530,7599,5855],{"class":5831},[5530,7601,7602],{"class":5543},".radius ** ",[5530,7604,7605],{"class":5554},"2\n",[5530,7607,7608],{"class":5532,"line":5781},[5530,7609,5565],{"emptyLinePlaceholder":5564},[5530,7611,7612,7614],{"class":5532,"line":5786},[5530,7613,7565],{"class":5847},[5530,7615,7568],{"class":5835},[5530,7617,7618,7620,7623,7625,7627,7629,7631],{"class":5532,"line":5792},[5530,7619,5844],{"class":5831},[5530,7621,7622],{"class":5847}," circumference",[5530,7624,5851],{"class":5543},[5530,7626,5855],{"class":5854},[5530,7628,6063],{"class":5543},[5530,7630,5649],{"class":5835},[5530,7632,5839],{"class":5543},[5530,7634,7635],{"class":5532,"line":5798},[5530,7636,7637],{"class":5547},"        \"\"\"Довжина кола.\"\"\"\n",[5530,7639,7640,7642,7645,7648,7650],{"class":5532,"line":6187},[5530,7641,6243],{"class":6073},[5530,7643,7644],{"class":5554}," 2",[5530,7646,7647],{"class":5543}," * math.pi * ",[5530,7649,5855],{"class":5831},[5530,7651,7652],{"class":5543},".radius\n",[5530,7654,7655],{"class":5532,"line":6195},[5530,7656,5565],{"emptyLinePlaceholder":5564},[5530,7658,7659,7661],{"class":5532,"line":6217},[5530,7660,7565],{"class":5847},[5530,7662,7568],{"class":5835},[5530,7664,7665,7667,7670,7672,7674,7676,7678],{"class":5532,"line":6222},[5530,7666,5844],{"class":5831},[5530,7668,7669],{"class":5847}," diameter",[5530,7671,5851],{"class":5543},[5530,7673,5855],{"class":5854},[5530,7675,6063],{"class":5543},[5530,7677,5649],{"class":5835},[5530,7679,5839],{"class":5543},[5530,7681,7682],{"class":5532,"line":6240},[5530,7683,7684],{"class":5547},"        \"\"\"Діаметр — обчислюється з radius.\"\"\"\n",[5530,7686,7687,7689,7691,7694],{"class":5532,"line":6635},[5530,7688,6243],{"class":6073},[5530,7690,6246],{"class":5831},[5530,7692,7693],{"class":5543},".radius * ",[5530,7695,7605],{"class":5554},[5530,7697,7698],{"class":5532,"line":6640},[5530,7699,5565],{"emptyLinePlaceholder":5564},[5530,7701,7702],{"class":5532,"line":6646},[5530,7703,5565],{"emptyLinePlaceholder":5564},[5530,7705,7706,7709,7712],{"class":5532,"line":6659},[5530,7707,7708],{"class":5543},"c = Circle(",[5530,7710,7711],{"class":5554},"5.0",[5530,7713,5558],{"class":5543},[5530,7715,7716],{"class":5532,"line":6664},[5530,7717,5565],{"emptyLinePlaceholder":5564},[5530,7719,7720],{"class":5532,"line":6670},[5530,7721,7722],{"class":5536},"# Звертаємось як до атрибута — БЕЗ дужок!\n",[5530,7724,7725,7727,7729,7731,7734,7736,7739,7742,7744],{"class":5532,"line":6678},[5530,7726,6283],{"class":5847},[5530,7728,5851],{"class":5543},[5530,7730,6114],{"class":5831},[5530,7732,7733],{"class":5547},"\"Площа:    ",[5530,7735,6120],{"class":5831},[5530,7737,7738],{"class":5543},"c.area",[5530,7740,7741],{"class":5831},":.4f}",[5530,7743,6128],{"class":5547},[5530,7745,5558],{"class":5543},[5530,7747,7748,7750,7752,7754,7757,7759,7762,7764,7766],{"class":5532,"line":6687},[5530,7749,6283],{"class":5847},[5530,7751,5851],{"class":5543},[5530,7753,6114],{"class":5831},[5530,7755,7756],{"class":5547},"\"Периметр: ",[5530,7758,6120],{"class":5831},[5530,7760,7761],{"class":5543},"c.circumference",[5530,7763,7741],{"class":5831},[5530,7765,6128],{"class":5547},[5530,7767,5558],{"class":5543},[5530,7769,7771,7773,7775,7777,7780,7782,7785,7787,7789],{"class":5532,"line":7770},31,[5530,7772,6283],{"class":5847},[5530,7774,5851],{"class":5543},[5530,7776,6114],{"class":5831},[5530,7778,7779],{"class":5547},"\"Діаметр:  ",[5530,7781,6120],{"class":5831},[5530,7783,7784],{"class":5543},"c.diameter",[5530,7786,7741],{"class":5831},[5530,7788,6128],{"class":5547},[5530,7790,5558],{"class":5543},[5530,7792,7794],{"class":5532,"line":7793},32,[5530,7795,5565],{"emptyLinePlaceholder":5564},[5530,7797,7799],{"class":5532,"line":7798},33,[5530,7800,7801],{"class":5536},"# Можна змінити radius — всі властивості автоматично оновляться\n",[5530,7803,7805,7808],{"class":5532,"line":7804},34,[5530,7806,7807],{"class":5543},"c.radius = ",[5530,7809,7810],{"class":5554},"10.0\n",[5530,7812,7814,7816,7818,7820,7823,7825,7827,7829,7831],{"class":5532,"line":7813},35,[5530,7815,6283],{"class":5847},[5530,7817,5851],{"class":5543},[5530,7819,6114],{"class":5831},[5530,7821,7822],{"class":5547},"\"Нова площа: ",[5530,7824,6120],{"class":5831},[5530,7826,7738],{"class":5543},[5530,7828,7741],{"class":5831},[5530,7830,6128],{"class":5547},[5530,7832,5558],{"class":5543},[5530,7834,7836],{"class":5532,"line":7835},36,[5530,7837,5565],{"emptyLinePlaceholder":5564},[5530,7839,7841],{"class":5532,"line":7840},37,[5530,7842,7843],{"class":5536},"# Спроба записати у read-only властивість:\n",[5530,7845,7847,7849],{"class":5532,"line":7846},38,[5530,7848,6586],{"class":6073},[5530,7850,5839],{"class":5543},[5530,7852,7854,7857],{"class":5532,"line":7853},39,[5530,7855,7856],{"class":5543},"    c.area = ",[5530,7858,7859],{"class":5554},"999.0\n",[5530,7861,7863,7865,7867,7869],{"class":5532,"line":7862},40,[5530,7864,6601],{"class":6073},[5530,7866,6604],{"class":5835},[5530,7868,6607],{"class":6073},[5530,7870,6610],{"class":5543},[5530,7872,7874,7876,7878,7880,7882,7884,7886,7888,7890],{"class":5532,"line":7873},41,[5530,7875,6593],{"class":5847},[5530,7877,5851],{"class":5543},[5530,7879,6114],{"class":5831},[5530,7881,6621],{"class":5547},[5530,7883,6120],{"class":5831},[5530,7885,6626],{"class":5543},[5530,7887,6125],{"class":5831},[5530,7889,6128],{"class":5547},[5530,7891,5558],{"class":5543},[6302,7893,7895,7903,7911,7919,7927,7935],{"title":7894},"python circle.py",[6306,7896,7898,6314,7901],{"className":7897},[5532],[5530,7899,6313],{"className":7900},[6312],[5629,7902,7894],{},[6306,7904,7906,7907],{"className":7905},[5532],"Площа:    ",[5530,7908,7910],{"className":7909},[6720],"78.5398",[6306,7912,7914,7915],{"className":7913},[5532],"Периметр: ",[5530,7916,7918],{"className":7917},[6720],"31.4159",[6306,7920,7922,7923],{"className":7921},[5532],"Діаметр:  ",[5530,7924,7926],{"className":7925},[6720],"10.0000",[6306,7928,7930,7931],{"className":7929},[5532],"Нова площа: ",[5530,7932,7934],{"className":7933},[6737],"314.1593",[6306,7936,6707,7938],{"className":7937},[5532],[5530,7939,7941],{"className":7940},[6711],"property 'area' of 'Circle' object has no setter",[5666,7943],{},[5673,7945,7947],{"id":7946},"геттери-сеттери-та-делітери","Геттери, Сеттери та Делітери",[5508,7949,7950,7951,7954,7955,7958,7959,7962],{},"Для запису та видалення використовуються декоратори ",[5512,7952,7953],{},".setter"," та ",[5512,7956,7957],{},".deleter",". Ім'я методу ",[5629,7960,7961],{},"завжди збігається"," з іменем властивості.",[5521,7964,7966],{"className":5523,"code":7965,"language":5525,"meta":5526,"style":5526},"# temperature.py\n\nclass Temperature:\n    \"\"\"\n    Зберігає температуру в Цельсіях, але дозволяє\n    читати\u002Fписати через Фаренгейти з автоматичною конвертацією.\n    \"\"\"\n\n    def __init__(self, celsius: float):\n        self.celsius = celsius  # ← виклик сеттера (валідація вже тут!)\n\n    # ── Цельсій ───────────────────────────────────────────────────────────────\n\n    @property\n    def celsius(self) -> float:\n        \"\"\"Геттер: повертає температуру в Цельсіях.\"\"\"\n        return self._celsius\n\n    @celsius.setter\n    def celsius(self, value: float) -> None:\n        \"\"\"Сеттер: валідує діапазон перед збереженням.\"\"\"\n        if not isinstance(value, (int, float)):\n            raise TypeError(f\"Очікується число, отримано: {type(value).__name__}\")\n        if value \u003C -273.15:\n            raise ValueError(f\"Температура {value}°C нижча за абсолютний нуль (-273.15°C)!\")\n        self._celsius = float(value)\n\n    # ── Фаренгейт ─────────────────────────────────────────────────────────────\n\n    @property\n    def fahrenheit(self) -> float:\n        \"\"\"Геттер: конвертує Цельсій у Фаренгейт.\"\"\"\n        return (self._celsius * 9 \u002F 5) + 32\n\n    @fahrenheit.setter\n    def fahrenheit(self, value: float) -> None:\n        \"\"\"Сеттер: конвертує Фаренгейт у Цельсій і записує через celsius.setter.\"\"\"\n        self.celsius = (value - 32) * 5 \u002F 9  # ← делегуємо валідацію celsius.setter!\n\n    @fahrenheit.deleter\n    def fahrenheit(self) -> None:\n        \"\"\"Делітер: очищає внутрішній стан.\"\"\"\n        print(\"Видалення температурних даних...\")\n        del self._celsius\n\n    # ── Кельвін (read-only) ───────────────────────────────────────────────────\n\n    @property\n    def kelvin(self) -> float:\n        \"\"\"Кельвін — лише читання, конвертується з Цельсія.\"\"\"\n        return self._celsius + 273.15\n",[5512,7967,7968,7973,7977,7986,7991,7996,8001,8005,8009,8030,8040,8044,8049,8053,8059,8076,8081,8090,8094,8099,8123,8128,8151,8182,8194,8218,8230,8234,8239,8243,8249,8266,8271,8297,8301,8306,8330,8335,8357,8361,8366,8382,8388,8400,8410,8415,8421,8426,8433,8451,8457],{"__ignoreMap":5526},[5530,7969,7970],{"class":5532,"line":5533},[5530,7971,7972],{"class":5536},"# temperature.py\n",[5530,7974,7975],{"class":5532,"line":5540},[5530,7976,5565],{"emptyLinePlaceholder":5564},[5530,7978,7979,7981,7984],{"class":5532,"line":5561},[5530,7980,5832],{"class":5831},[5530,7982,7983],{"class":5835}," Temperature",[5530,7985,5839],{"class":5543},[5530,7987,7988],{"class":5532,"line":5568},[5530,7989,7990],{"class":5547},"    \"\"\"\n",[5530,7992,7993],{"class":5532,"line":5574},[5530,7994,7995],{"class":5547},"    Зберігає температуру в Цельсіях, але дозволяє\n",[5530,7997,7998],{"class":5532,"line":5586},[5530,7999,8000],{"class":5547},"    читати\u002Fписати через Фаренгейти з автоматичною конвертацією.\n",[5530,8002,8003],{"class":5532,"line":5598},[5530,8004,7990],{"class":5547},[5530,8006,8007],{"class":5532,"line":5603},[5530,8008,5565],{"emptyLinePlaceholder":5564},[5530,8010,8011,8013,8015,8017,8019,8021,8024,8026,8028],{"class":5532,"line":5609},[5530,8012,5844],{"class":5831},[5530,8014,5848],{"class":5847},[5530,8016,5851],{"class":5543},[5530,8018,5855],{"class":5854},[5530,8020,5551],{"class":5543},[5530,8022,8023],{"class":5854},"celsius",[5530,8025,5863],{"class":5543},[5530,8027,5649],{"class":5835},[5530,8029,5877],{"class":5543},[5530,8031,8032,8034,8037],{"class":5532,"line":5758},[5530,8033,5882],{"class":5831},[5530,8035,8036],{"class":5543},".celsius = celsius  ",[5530,8038,8039],{"class":5536},"# ← виклик сеттера (валідація вже тут!)\n",[5530,8041,8042],{"class":5532,"line":5764},[5530,8043,5565],{"emptyLinePlaceholder":5564},[5530,8045,8046],{"class":5532,"line":5770},[5530,8047,8048],{"class":5536},"    # ── Цельсій ───────────────────────────────────────────────────────────────\n",[5530,8050,8051],{"class":5532,"line":5775},[5530,8052,5565],{"emptyLinePlaceholder":5564},[5530,8054,8055,8057],{"class":5532,"line":5781},[5530,8056,7565],{"class":5847},[5530,8058,7568],{"class":5835},[5530,8060,8061,8063,8066,8068,8070,8072,8074],{"class":5532,"line":5786},[5530,8062,5844],{"class":5831},[5530,8064,8065],{"class":5847}," celsius",[5530,8067,5851],{"class":5543},[5530,8069,5855],{"class":5854},[5530,8071,6063],{"class":5543},[5530,8073,5649],{"class":5835},[5530,8075,5839],{"class":5543},[5530,8077,8078],{"class":5532,"line":5792},[5530,8079,8080],{"class":5547},"        \"\"\"Геттер: повертає температуру в Цельсіях.\"\"\"\n",[5530,8082,8083,8085,8087],{"class":5532,"line":5798},[5530,8084,6243],{"class":6073},[5530,8086,6246],{"class":5831},[5530,8088,8089],{"class":5543},"._celsius\n",[5530,8091,8092],{"class":5532,"line":6187},[5530,8093,5565],{"emptyLinePlaceholder":5564},[5530,8095,8096],{"class":5532,"line":6195},[5530,8097,8098],{"class":5847},"    @celsius.setter\n",[5530,8100,8101,8103,8105,8107,8109,8111,8113,8115,8117,8119,8121],{"class":5532,"line":6217},[5530,8102,5844],{"class":5831},[5530,8104,8065],{"class":5847},[5530,8106,5851],{"class":5543},[5530,8108,5855],{"class":5854},[5530,8110,5551],{"class":5543},[5530,8112,7313],{"class":5854},[5530,8114,5863],{"class":5543},[5530,8116,5649],{"class":5835},[5530,8118,6063],{"class":5543},[5530,8120,6066],{"class":5831},[5530,8122,5839],{"class":5543},[5530,8124,8125],{"class":5532,"line":6222},[5530,8126,8127],{"class":5547},"        \"\"\"Сеттер: валідує діапазон перед збереженням.\"\"\"\n",[5530,8129,8130,8132,8135,8138,8141,8144,8146,8148],{"class":5532,"line":6240},[5530,8131,6074],{"class":6073},[5530,8133,8134],{"class":5831}," not",[5530,8136,8137],{"class":5847}," isinstance",[5530,8139,8140],{"class":5543},"(value, (",[5530,8142,8143],{"class":5835},"int",[5530,8145,5551],{"class":5543},[5530,8147,5649],{"class":5835},[5530,8149,8150],{"class":5543},")):\n",[5530,8152,8153,8155,8158,8160,8162,8165,8167,8170,8173,8176,8178,8180],{"class":5532,"line":6635},[5530,8154,6087],{"class":6073},[5530,8156,8157],{"class":5835}," TypeError",[5530,8159,5851],{"class":5543},[5530,8161,6114],{"class":5831},[5530,8163,8164],{"class":5547},"\"Очікується число, отримано: ",[5530,8166,6120],{"class":5831},[5530,8168,8169],{"class":5835},"type",[5530,8171,8172],{"class":5543},"(value).",[5530,8174,8175],{"class":5854},"__name__",[5530,8177,6125],{"class":5831},[5530,8179,6128],{"class":5547},[5530,8181,5558],{"class":5543},[5530,8183,8184,8186,8189,8192],{"class":5532,"line":6640},[5530,8185,6074],{"class":6073},[5530,8187,8188],{"class":5543}," value \u003C -",[5530,8190,8191],{"class":5554},"273.15",[5530,8193,5839],{"class":5543},[5530,8195,8196,8198,8200,8202,8204,8207,8209,8211,8213,8216],{"class":5532,"line":6646},[5530,8197,6087],{"class":6073},[5530,8199,6090],{"class":5835},[5530,8201,5851],{"class":5543},[5530,8203,6114],{"class":5831},[5530,8205,8206],{"class":5547},"\"Температура ",[5530,8208,6120],{"class":5831},[5530,8210,7313],{"class":5543},[5530,8212,6125],{"class":5831},[5530,8214,8215],{"class":5547},"°C нижча за абсолютний нуль (-273.15°C)!\"",[5530,8217,5558],{"class":5543},[5530,8219,8220,8222,8225,8227],{"class":5532,"line":6659},[5530,8221,5882],{"class":5831},[5530,8223,8224],{"class":5543},"._celsius = ",[5530,8226,5649],{"class":5835},[5530,8228,8229],{"class":5543},"(value)\n",[5530,8231,8232],{"class":5532,"line":6664},[5530,8233,5565],{"emptyLinePlaceholder":5564},[5530,8235,8236],{"class":5532,"line":6670},[5530,8237,8238],{"class":5536},"    # ── Фаренгейт ─────────────────────────────────────────────────────────────\n",[5530,8240,8241],{"class":5532,"line":6678},[5530,8242,5565],{"emptyLinePlaceholder":5564},[5530,8244,8245,8247],{"class":5532,"line":6687},[5530,8246,7565],{"class":5847},[5530,8248,7568],{"class":5835},[5530,8250,8251,8253,8256,8258,8260,8262,8264],{"class":5532,"line":7770},[5530,8252,5844],{"class":5831},[5530,8254,8255],{"class":5847}," fahrenheit",[5530,8257,5851],{"class":5543},[5530,8259,5855],{"class":5854},[5530,8261,6063],{"class":5543},[5530,8263,5649],{"class":5835},[5530,8265,5839],{"class":5543},[5530,8267,8268],{"class":5532,"line":7793},[5530,8269,8270],{"class":5547},"        \"\"\"Геттер: конвертує Цельсій у Фаренгейт.\"\"\"\n",[5530,8272,8273,8275,8278,8280,8283,8286,8288,8291,8294],{"class":5532,"line":7798},[5530,8274,6243],{"class":6073},[5530,8276,8277],{"class":5543}," (",[5530,8279,5855],{"class":5831},[5530,8281,8282],{"class":5543},"._celsius * ",[5530,8284,8285],{"class":5554},"9",[5530,8287,7211],{"class":5543},[5530,8289,8290],{"class":5554},"5",[5530,8292,8293],{"class":5543},") + ",[5530,8295,8296],{"class":5554},"32\n",[5530,8298,8299],{"class":5532,"line":7804},[5530,8300,5565],{"emptyLinePlaceholder":5564},[5530,8302,8303],{"class":5532,"line":7813},[5530,8304,8305],{"class":5847},"    @fahrenheit.setter\n",[5530,8307,8308,8310,8312,8314,8316,8318,8320,8322,8324,8326,8328],{"class":5532,"line":7835},[5530,8309,5844],{"class":5831},[5530,8311,8255],{"class":5847},[5530,8313,5851],{"class":5543},[5530,8315,5855],{"class":5854},[5530,8317,5551],{"class":5543},[5530,8319,7313],{"class":5854},[5530,8321,5863],{"class":5543},[5530,8323,5649],{"class":5835},[5530,8325,6063],{"class":5543},[5530,8327,6066],{"class":5831},[5530,8329,5839],{"class":5543},[5530,8331,8332],{"class":5532,"line":7840},[5530,8333,8334],{"class":5547},"        \"\"\"Сеттер: конвертує Фаренгейт у Цельсій і записує через celsius.setter.\"\"\"\n",[5530,8336,8337,8339,8342,8345,8348,8350,8352,8354],{"class":5532,"line":7846},[5530,8338,5882],{"class":5831},[5530,8340,8341],{"class":5543},".celsius = (value - ",[5530,8343,8344],{"class":5554},"32",[5530,8346,8347],{"class":5543},") * ",[5530,8349,8290],{"class":5554},[5530,8351,7211],{"class":5543},[5530,8353,8285],{"class":5554},[5530,8355,8356],{"class":5536},"  # ← делегуємо валідацію celsius.setter!\n",[5530,8358,8359],{"class":5532,"line":7853},[5530,8360,5565],{"emptyLinePlaceholder":5564},[5530,8362,8363],{"class":5532,"line":7862},[5530,8364,8365],{"class":5847},"    @fahrenheit.deleter\n",[5530,8367,8368,8370,8372,8374,8376,8378,8380],{"class":5532,"line":7873},[5530,8369,5844],{"class":5831},[5530,8371,8255],{"class":5847},[5530,8373,5851],{"class":5543},[5530,8375,5855],{"class":5854},[5530,8377,6063],{"class":5543},[5530,8379,6066],{"class":5831},[5530,8381,5839],{"class":5543},[5530,8383,8385],{"class":5532,"line":8384},42,[5530,8386,8387],{"class":5547},"        \"\"\"Делітер: очищає внутрішній стан.\"\"\"\n",[5530,8389,8391,8393,8395,8398],{"class":5532,"line":8390},43,[5530,8392,6847],{"class":5847},[5530,8394,5851],{"class":5543},[5530,8396,8397],{"class":5547},"\"Видалення температурних даних...\"",[5530,8399,5558],{"class":5543},[5530,8401,8403,8406,8408],{"class":5532,"line":8402},44,[5530,8404,8405],{"class":6073},"        del",[5530,8407,6246],{"class":5831},[5530,8409,8089],{"class":5543},[5530,8411,8413],{"class":5532,"line":8412},45,[5530,8414,5565],{"emptyLinePlaceholder":5564},[5530,8416,8418],{"class":5532,"line":8417},46,[5530,8419,8420],{"class":5536},"    # ── Кельвін (read-only) ───────────────────────────────────────────────────\n",[5530,8422,8424],{"class":5532,"line":8423},47,[5530,8425,5565],{"emptyLinePlaceholder":5564},[5530,8427,8429,8431],{"class":5532,"line":8428},48,[5530,8430,7565],{"class":5847},[5530,8432,7568],{"class":5835},[5530,8434,8436,8438,8441,8443,8445,8447,8449],{"class":5532,"line":8435},49,[5530,8437,5844],{"class":5831},[5530,8439,8440],{"class":5847}," kelvin",[5530,8442,5851],{"class":5543},[5530,8444,5855],{"class":5854},[5530,8446,6063],{"class":5543},[5530,8448,5649],{"class":5835},[5530,8450,5839],{"class":5543},[5530,8452,8454],{"class":5532,"line":8453},50,[5530,8455,8456],{"class":5547},"        \"\"\"Кельвін — лише читання, конвертується з Цельсія.\"\"\"\n",[5530,8458,8460,8462,8464,8467],{"class":5532,"line":8459},51,[5530,8461,6243],{"class":6073},[5530,8463,6246],{"class":5831},[5530,8465,8466],{"class":5543},"._celsius + ",[5530,8468,8469],{"class":5554},"273.15\n",[5521,8471,8473],{"className":5523,"code":8472,"language":5525,"meta":5526,"style":5526},"# Демонстрація\nt = Temperature(25.0)\nprint(f\"Цельсій:    {t.celsius}°C\")\nprint(f\"Фаренгейт: {t.fahrenheit}°F\")\nprint(f\"Кельвін:   {t.kelvin}K\")\n\n# Зміна через Фаренгейт — автоматична конвертація\nt.fahrenheit = 32.0\nprint(f\"\\nПісля t.fahrenheit = 32.0:\")\nprint(f\"Цельсій:    {t.celsius}°C\")\n\n# Валідація — нижче абсолютного нуля\ntry:\n    t.celsius = -300.0\nexcept ValueError as e:\n    print(f\"\\nValueError: {e}\")\n\n# Валідація типу\ntry:\n    t.celsius = \"гаряче\"\nexcept TypeError as e:\n    print(f\"TypeError: {e}\")\n\n# Делітер\ndel t.fahrenheit\ntry:\n    _ = t.celsius\nexcept AttributeError as e:\n    print(f\"\\nAttributeError після del: {e}\")\n",[5512,8474,8475,8480,8490,8513,8536,8559,8563,8568,8576,8595,8615,8619,8624,8630,8638,8648,8673,8677,8682,8688,8696,8706,8727,8731,8736,8744,8750,8755,8765],{"__ignoreMap":5526},[5530,8476,8477],{"class":5532,"line":5533},[5530,8478,8479],{"class":5536},"# Демонстрація\n",[5530,8481,8482,8485,8488],{"class":5532,"line":5540},[5530,8483,8484],{"class":5543},"t = Temperature(",[5530,8486,8487],{"class":5554},"25.0",[5530,8489,5558],{"class":5543},[5530,8491,8492,8494,8496,8498,8501,8503,8506,8508,8511],{"class":5532,"line":5561},[5530,8493,6283],{"class":5847},[5530,8495,5851],{"class":5543},[5530,8497,6114],{"class":5831},[5530,8499,8500],{"class":5547},"\"Цельсій:    ",[5530,8502,6120],{"class":5831},[5530,8504,8505],{"class":5543},"t.celsius",[5530,8507,6125],{"class":5831},[5530,8509,8510],{"class":5547},"°C\"",[5530,8512,5558],{"class":5543},[5530,8514,8515,8517,8519,8521,8524,8526,8529,8531,8534],{"class":5532,"line":5568},[5530,8516,6283],{"class":5847},[5530,8518,5851],{"class":5543},[5530,8520,6114],{"class":5831},[5530,8522,8523],{"class":5547},"\"Фаренгейт: ",[5530,8525,6120],{"class":5831},[5530,8527,8528],{"class":5543},"t.fahrenheit",[5530,8530,6125],{"class":5831},[5530,8532,8533],{"class":5547},"°F\"",[5530,8535,5558],{"class":5543},[5530,8537,8538,8540,8542,8544,8547,8549,8552,8554,8557],{"class":5532,"line":5574},[5530,8539,6283],{"class":5847},[5530,8541,5851],{"class":5543},[5530,8543,6114],{"class":5831},[5530,8545,8546],{"class":5547},"\"Кельвін:   ",[5530,8548,6120],{"class":5831},[5530,8550,8551],{"class":5543},"t.kelvin",[5530,8553,6125],{"class":5831},[5530,8555,8556],{"class":5547},"K\"",[5530,8558,5558],{"class":5543},[5530,8560,8561],{"class":5532,"line":5586},[5530,8562,5565],{"emptyLinePlaceholder":5564},[5530,8564,8565],{"class":5532,"line":5598},[5530,8566,8567],{"class":5536},"# Зміна через Фаренгейт — автоматична конвертація\n",[5530,8569,8570,8573],{"class":5532,"line":5603},[5530,8571,8572],{"class":5543},"t.fahrenheit = ",[5530,8574,8575],{"class":5554},"32.0\n",[5530,8577,8578,8580,8582,8584,8586,8590,8593],{"class":5532,"line":5609},[5530,8579,6283],{"class":5847},[5530,8581,5851],{"class":5543},[5530,8583,6114],{"class":5831},[5530,8585,6128],{"class":5547},[5530,8587,8589],{"class":8588},"sjcCO","\\n",[5530,8591,8592],{"class":5547},"Після t.fahrenheit = 32.0:\"",[5530,8594,5558],{"class":5543},[5530,8596,8597,8599,8601,8603,8605,8607,8609,8611,8613],{"class":5532,"line":5758},[5530,8598,6283],{"class":5847},[5530,8600,5851],{"class":5543},[5530,8602,6114],{"class":5831},[5530,8604,8500],{"class":5547},[5530,8606,6120],{"class":5831},[5530,8608,8505],{"class":5543},[5530,8610,6125],{"class":5831},[5530,8612,8510],{"class":5547},[5530,8614,5558],{"class":5543},[5530,8616,8617],{"class":5532,"line":5764},[5530,8618,5565],{"emptyLinePlaceholder":5564},[5530,8620,8621],{"class":5532,"line":5770},[5530,8622,8623],{"class":5536},"# Валідація — нижче абсолютного нуля\n",[5530,8625,8626,8628],{"class":5532,"line":5775},[5530,8627,6586],{"class":6073},[5530,8629,5839],{"class":5543},[5530,8631,8632,8635],{"class":5532,"line":5781},[5530,8633,8634],{"class":5543},"    t.celsius = -",[5530,8636,8637],{"class":5554},"300.0\n",[5530,8639,8640,8642,8644,8646],{"class":5532,"line":5786},[5530,8641,6601],{"class":6073},[5530,8643,6090],{"class":5835},[5530,8645,6607],{"class":6073},[5530,8647,6610],{"class":5543},[5530,8649,8650,8652,8654,8656,8658,8660,8663,8665,8667,8669,8671],{"class":5532,"line":5792},[5530,8651,6593],{"class":5847},[5530,8653,5851],{"class":5543},[5530,8655,6114],{"class":5831},[5530,8657,6128],{"class":5547},[5530,8659,8589],{"class":8588},[5530,8661,8662],{"class":5547},"ValueError: ",[5530,8664,6120],{"class":5831},[5530,8666,6626],{"class":5543},[5530,8668,6125],{"class":5831},[5530,8670,6128],{"class":5547},[5530,8672,5558],{"class":5543},[5530,8674,8675],{"class":5532,"line":5798},[5530,8676,5565],{"emptyLinePlaceholder":5564},[5530,8678,8679],{"class":5532,"line":6187},[5530,8680,8681],{"class":5536},"# Валідація типу\n",[5530,8683,8684,8686],{"class":5532,"line":6195},[5530,8685,6586],{"class":6073},[5530,8687,5839],{"class":5543},[5530,8689,8690,8693],{"class":5532,"line":6217},[5530,8691,8692],{"class":5543},"    t.celsius = ",[5530,8694,8695],{"class":5547},"\"гаряче\"\n",[5530,8697,8698,8700,8702,8704],{"class":5532,"line":6222},[5530,8699,6601],{"class":6073},[5530,8701,8157],{"class":5835},[5530,8703,6607],{"class":6073},[5530,8705,6610],{"class":5543},[5530,8707,8708,8710,8712,8714,8717,8719,8721,8723,8725],{"class":5532,"line":6240},[5530,8709,6593],{"class":5847},[5530,8711,5851],{"class":5543},[5530,8713,6114],{"class":5831},[5530,8715,8716],{"class":5547},"\"TypeError: ",[5530,8718,6120],{"class":5831},[5530,8720,6626],{"class":5543},[5530,8722,6125],{"class":5831},[5530,8724,6128],{"class":5547},[5530,8726,5558],{"class":5543},[5530,8728,8729],{"class":5532,"line":6635},[5530,8730,5565],{"emptyLinePlaceholder":5564},[5530,8732,8733],{"class":5532,"line":6640},[5530,8734,8735],{"class":5536},"# Делітер\n",[5530,8737,8738,8741],{"class":5532,"line":6646},[5530,8739,8740],{"class":6073},"del",[5530,8742,8743],{"class":5543}," t.fahrenheit\n",[5530,8745,8746,8748],{"class":5532,"line":6659},[5530,8747,6586],{"class":6073},[5530,8749,5839],{"class":5543},[5530,8751,8752],{"class":5532,"line":6664},[5530,8753,8754],{"class":5543},"    _ = t.celsius\n",[5530,8756,8757,8759,8761,8763],{"class":5532,"line":6670},[5530,8758,6601],{"class":6073},[5530,8760,6604],{"class":5835},[5530,8762,6607],{"class":6073},[5530,8764,6610],{"class":5543},[5530,8766,8767,8769,8771,8773,8775,8777,8780,8782,8784,8786,8788],{"class":5532,"line":6678},[5530,8768,6593],{"class":5847},[5530,8770,5851],{"class":5543},[5530,8772,6114],{"class":5831},[5530,8774,6128],{"class":5547},[5530,8776,8589],{"class":8588},[5530,8778,8779],{"class":5547},"AttributeError після del: ",[5530,8781,6120],{"class":5831},[5530,8783,6626],{"class":5543},[5530,8785,6125],{"class":5831},[5530,8787,6128],{"class":5547},[5530,8789,5558],{"class":5543},[6302,8791,8793,8801,8809,8818,8827,8830,8834,8841,8844,8851,8859,8862,8866],{"title":8792},"python temperature.py",[6306,8794,8796,6314,8799],{"className":8795},[5532],[5530,8797,6313],{"className":8798},[6312],[5629,8800,8792],{},[6306,8802,8804,8805,8808],{"className":8803},[5532],"Цельсій:    ",[5530,8806,8487],{"className":8807},[6720],"°C",[6306,8810,8812,8813,8817],{"className":8811},[5532],"Фаренгейт: ",[5530,8814,8816],{"className":8815},[6720],"77.0","°F",[6306,8819,8821,8822,8826],{"className":8820},[5532],"Кельвін:   ",[5530,8823,8825],{"className":8824},[6720],"298.15","K",[6306,8828],{"className":8829},[5532],[6306,8831,8833],{"className":8832},[5532],"Після t.fahrenheit = 32.0:",[6306,8835,8804,8837,8808],{"className":8836},[5532],[5530,8838,8840],{"className":8839},[6737],"0.0",[6306,8842],{"className":8843},[5532],[6306,8845,8662,8847],{"className":8846},[5532],[5530,8848,8850],{"className":8849},[6711],"Температура -300.0°C нижча за абсолютний нуль (-273.15°C)!",[6306,8852,8854,8855],{"className":8853},[5532],"TypeError: ",[5530,8856,8858],{"className":8857},[6711],"Очікується число, отримано: str",[6306,8860],{"className":8861},[5532],[6306,8863,8865],{"className":8864},[5532],"Видалення температурних даних...",[6306,8867,8779,8869],{"className":8868},[5532],[5530,8870,8872],{"className":8871},[6711],"'Temperature' object has no attribute '_celsius'",[5666,8874],{},[5673,8876,8878],{"id":8877},"критична-пастка-нескінченна-рекурсія","Критична пастка: нескінченна рекурсія",[5508,8880,8881],{},"Найпоширеніша помилка при написанні властивостей — збіг імені атрибута та назви сеттера:",[5521,8883,8885],{"className":5523,"code":8884,"language":5525,"meta":5526,"style":5526},"# ❌ НІКОЛИ ТАК НЕ РОБІТЬ\nclass BadTemperature:\n    def __init__(self, celsius):\n        self.celsius = celsius   # викликає setter\n\n    @property\n    def celsius(self):\n        return self.celsius      # ← рекурсія! викликає сам себе\n\n    @celsius.setter\n    def celsius(self, value):\n        self.celsius = value     # ← рекурсія! викликає сам себе\n",[5512,8886,8887,8892,8901,8917,8927,8931,8937,8949,8961,8965,8969,8985],{"__ignoreMap":5526},[5530,8888,8889],{"class":5532,"line":5533},[5530,8890,8891],{"class":5536},"# ❌ НІКОЛИ ТАК НЕ РОБІТЬ\n",[5530,8893,8894,8896,8899],{"class":5532,"line":5540},[5530,8895,5832],{"class":5831},[5530,8897,8898],{"class":5835}," BadTemperature",[5530,8900,5839],{"class":5543},[5530,8902,8903,8905,8907,8909,8911,8913,8915],{"class":5532,"line":5561},[5530,8904,5844],{"class":5831},[5530,8906,5848],{"class":5847},[5530,8908,5851],{"class":5543},[5530,8910,5855],{"class":5854},[5530,8912,5551],{"class":5543},[5530,8914,8023],{"class":5854},[5530,8916,5877],{"class":5543},[5530,8918,8919,8921,8924],{"class":5532,"line":5568},[5530,8920,5882],{"class":5831},[5530,8922,8923],{"class":5543},".celsius = celsius   ",[5530,8925,8926],{"class":5536},"# викликає setter\n",[5530,8928,8929],{"class":5532,"line":5574},[5530,8930,5565],{"emptyLinePlaceholder":5564},[5530,8932,8933,8935],{"class":5532,"line":5586},[5530,8934,7565],{"class":5847},[5530,8936,7568],{"class":5835},[5530,8938,8939,8941,8943,8945,8947],{"class":5532,"line":5598},[5530,8940,5844],{"class":5831},[5530,8942,8065],{"class":5847},[5530,8944,5851],{"class":5543},[5530,8946,5855],{"class":5854},[5530,8948,5877],{"class":5543},[5530,8950,8951,8953,8955,8958],{"class":5532,"line":5603},[5530,8952,6243],{"class":6073},[5530,8954,6246],{"class":5831},[5530,8956,8957],{"class":5543},".celsius      ",[5530,8959,8960],{"class":5536},"# ← рекурсія! викликає сам себе\n",[5530,8962,8963],{"class":5532,"line":5609},[5530,8964,5565],{"emptyLinePlaceholder":5564},[5530,8966,8967],{"class":5532,"line":5758},[5530,8968,8098],{"class":5847},[5530,8970,8971,8973,8975,8977,8979,8981,8983],{"class":5532,"line":5764},[5530,8972,5844],{"class":5831},[5530,8974,8065],{"class":5847},[5530,8976,5851],{"class":5543},[5530,8978,5855],{"class":5854},[5530,8980,5551],{"class":5543},[5530,8982,7313],{"class":5854},[5530,8984,5877],{"class":5543},[5530,8986,8987,8989,8992],{"class":5532,"line":5770},[5530,8988,5882],{"class":5831},[5530,8990,8991],{"class":5543},".celsius = value     ",[5530,8993,8960],{"class":5536},[6302,8995,8997,9006,9013],{"title":8996},"Що станеться при запуску",[6306,8998,9000,6314,9003],{"className":8999},[5532],[5530,9001,6313],{"className":9002},[6312],[5629,9004,9005],{},"python bad_temperature.py",[6306,9007,9009],{"className":9008},[5532],[5530,9010,9012],{"className":9011},[6711],"RecursionError: maximum recursion depth exceeded while calling a Python object",[6306,9014,9016],{"className":9015},[5532],[5530,9017,9019],{"className":9018},[6331],"# Python вийде з ладу через ~1000 вкладених викликів",[5508,9021,9022,9025,9026,9029,9030,7215],{},[5629,9023,9024],{},"Правило:"," внутрішній атрибут для зберігання даних ",[5629,9027,9028],{},"завжди"," відрізняється від імені властивості префіксом ",[5512,9031,6371],{},[5521,9033,9035],{"className":5523,"code":9034,"language":5525,"meta":5526,"style":5526},"# ✅ Правильно: властивість celsius, сховище _celsius\n@property\ndef celsius(self) -> float:\n    return self._celsius        # читаємо з _celsius\n\n@celsius.setter\ndef celsius(self, value: float) -> None:\n    self._celsius = value       # пишемо у _celsius\n",[5512,9036,9037,9042,9049,9066,9079,9083,9088,9112],{"__ignoreMap":5526},[5530,9038,9039],{"class":5532,"line":5533},[5530,9040,9041],{"class":5536},"# ✅ Правильно: властивість celsius, сховище _celsius\n",[5530,9043,9044,9047],{"class":5532,"line":5540},[5530,9045,9046],{"class":5847},"@",[5530,9048,7568],{"class":5835},[5530,9050,9051,9054,9056,9058,9060,9062,9064],{"class":5532,"line":5561},[5530,9052,9053],{"class":5831},"def",[5530,9055,8065],{"class":5847},[5530,9057,5851],{"class":5543},[5530,9059,5855],{"class":5854},[5530,9061,6063],{"class":5543},[5530,9063,5649],{"class":5835},[5530,9065,5839],{"class":5543},[5530,9067,9068,9071,9073,9076],{"class":5532,"line":5568},[5530,9069,9070],{"class":6073},"    return",[5530,9072,6246],{"class":5831},[5530,9074,9075],{"class":5543},"._celsius        ",[5530,9077,9078],{"class":5536},"# читаємо з _celsius\n",[5530,9080,9081],{"class":5532,"line":5574},[5530,9082,5565],{"emptyLinePlaceholder":5564},[5530,9084,9085],{"class":5532,"line":5586},[5530,9086,9087],{"class":5847},"@celsius.setter\n",[5530,9089,9090,9092,9094,9096,9098,9100,9102,9104,9106,9108,9110],{"class":5532,"line":5598},[5530,9091,9053],{"class":5831},[5530,9093,8065],{"class":5847},[5530,9095,5851],{"class":5543},[5530,9097,5855],{"class":5854},[5530,9099,5551],{"class":5543},[5530,9101,7313],{"class":5854},[5530,9103,5863],{"class":5543},[5530,9105,5649],{"class":5835},[5530,9107,6063],{"class":5543},[5530,9109,6066],{"class":5831},[5530,9111,5839],{"class":5543},[5530,9113,9114,9117,9120],{"class":5532,"line":5603},[5530,9115,9116],{"class":5831},"    self",[5530,9118,9119],{"class":5543},"._celsius = value       ",[5530,9121,9122],{"class":5536},"# пишемо у _celsius\n",[5666,9124],{},[5673,9126,9128,9129],{"id":9127},"декоратори-vs-функція-property","Декоратори vs функція ",[5512,9130,9131],{},"property()",[9133,9134,9135,9280],"tabs",{},[9136,9137,9139],"tabs-item",{"label":9138},"Через декоратори (сучасний стиль)",[5521,9140,9142],{"className":5523,"code":9141,"language":5525,"meta":5526,"style":5526},"class ModernAccount:\n    def __init__(self, balance: float):\n        self._balance = balance\n\n    @property\n    def balance(self) -> float:\n        \"\"\"Поточний баланс.\"\"\"\n        return self._balance\n\n    @balance.setter\n    def balance(self, value: float) -> None:\n        if value \u003C 0:\n            raise ValueError(\"Баланс не може бути від'ємним\")\n        self._balance = value\n",[5512,9143,9144,9153,9173,9179,9183,9189,9206,9211,9219,9223,9228,9252,9262,9274],{"__ignoreMap":5526},[5530,9145,9146,9148,9151],{"class":5532,"line":5533},[5530,9147,5832],{"class":5831},[5530,9149,9150],{"class":5835}," ModernAccount",[5530,9152,5839],{"class":5543},[5530,9154,9155,9157,9159,9161,9163,9165,9167,9169,9171],{"class":5532,"line":5540},[5530,9156,5844],{"class":5831},[5530,9158,5848],{"class":5847},[5530,9160,5851],{"class":5543},[5530,9162,5855],{"class":5854},[5530,9164,5551],{"class":5543},[5530,9166,5518],{"class":5854},[5530,9168,5863],{"class":5543},[5530,9170,5649],{"class":5835},[5530,9172,5877],{"class":5543},[5530,9174,9175,9177],{"class":5532,"line":5561},[5530,9176,5882],{"class":5831},[5530,9178,7261],{"class":5543},[5530,9180,9181],{"class":5532,"line":5568},[5530,9182,5565],{"emptyLinePlaceholder":5564},[5530,9184,9185,9187],{"class":5532,"line":5574},[5530,9186,7565],{"class":5847},[5530,9188,7568],{"class":5835},[5530,9190,9191,9193,9196,9198,9200,9202,9204],{"class":5532,"line":5586},[5530,9192,5844],{"class":5831},[5530,9194,9195],{"class":5847}," balance",[5530,9197,5851],{"class":5543},[5530,9199,5855],{"class":5854},[5530,9201,6063],{"class":5543},[5530,9203,5649],{"class":5835},[5530,9205,5839],{"class":5543},[5530,9207,9208],{"class":5532,"line":5598},[5530,9209,9210],{"class":5547},"        \"\"\"Поточний баланс.\"\"\"\n",[5530,9212,9213,9215,9217],{"class":5532,"line":5603},[5530,9214,6243],{"class":6073},[5530,9216,6246],{"class":5831},[5530,9218,6249],{"class":5543},[5530,9220,9221],{"class":5532,"line":5609},[5530,9222,5565],{"emptyLinePlaceholder":5564},[5530,9224,9225],{"class":5532,"line":5758},[5530,9226,9227],{"class":5847},"    @balance.setter\n",[5530,9229,9230,9232,9234,9236,9238,9240,9242,9244,9246,9248,9250],{"class":5532,"line":5764},[5530,9231,5844],{"class":5831},[5530,9233,9195],{"class":5847},[5530,9235,5851],{"class":5543},[5530,9237,5855],{"class":5854},[5530,9239,5551],{"class":5543},[5530,9241,7313],{"class":5854},[5530,9243,5863],{"class":5543},[5530,9245,5649],{"class":5835},[5530,9247,6063],{"class":5543},[5530,9249,6066],{"class":5831},[5530,9251,5839],{"class":5543},[5530,9253,9254,9256,9258,9260],{"class":5532,"line":5770},[5530,9255,6074],{"class":6073},[5530,9257,7329],{"class":5543},[5530,9259,6080],{"class":5554},[5530,9261,5839],{"class":5543},[5530,9263,9264,9266,9268,9270,9272],{"class":5532,"line":5775},[5530,9265,6087],{"class":6073},[5530,9267,6090],{"class":5835},[5530,9269,5851],{"class":5543},[5530,9271,7344],{"class":5547},[5530,9273,5558],{"class":5543},[5530,9275,9276,9278],{"class":5532,"line":5781},[5530,9277,5882],{"class":5831},[5530,9279,7353],{"class":5543},[9136,9281,9283],{"label":9282},"Через функцію property() (класичний)",[5521,9284,9286],{"className":5523,"code":9285,"language":5525,"meta":5526,"style":5526},"class ClassicAccount:\n    def __init__(self, balance: float):\n        self._balance = balance\n\n    def _get_balance(self) -> float:\n        return self._balance\n\n    def _set_balance(self, value: float) -> None:\n        if value \u003C 0:\n            raise ValueError(\"Баланс не може бути від'ємним\")\n        self._balance = value\n\n    # Зайві методи залишаються у просторі імен класу!\n    balance = property(fget=_get_balance, fset=_set_balance,\n                       doc=\"Поточний баланс.\")\n",[5512,9287,9288,9297,9317,9323,9327,9344,9352,9356,9381,9391,9403,9409,9413,9418,9440],{"__ignoreMap":5526},[5530,9289,9290,9292,9295],{"class":5532,"line":5533},[5530,9291,5832],{"class":5831},[5530,9293,9294],{"class":5835}," ClassicAccount",[5530,9296,5839],{"class":5543},[5530,9298,9299,9301,9303,9305,9307,9309,9311,9313,9315],{"class":5532,"line":5540},[5530,9300,5844],{"class":5831},[5530,9302,5848],{"class":5847},[5530,9304,5851],{"class":5543},[5530,9306,5855],{"class":5854},[5530,9308,5551],{"class":5543},[5530,9310,5518],{"class":5854},[5530,9312,5863],{"class":5543},[5530,9314,5649],{"class":5835},[5530,9316,5877],{"class":5543},[5530,9318,9319,9321],{"class":5532,"line":5561},[5530,9320,5882],{"class":5831},[5530,9322,7261],{"class":5543},[5530,9324,9325],{"class":5532,"line":5568},[5530,9326,5565],{"emptyLinePlaceholder":5564},[5530,9328,9329,9331,9334,9336,9338,9340,9342],{"class":5532,"line":5574},[5530,9330,5844],{"class":5831},[5530,9332,9333],{"class":5847}," _get_balance",[5530,9335,5851],{"class":5543},[5530,9337,5855],{"class":5854},[5530,9339,6063],{"class":5543},[5530,9341,5649],{"class":5835},[5530,9343,5839],{"class":5543},[5530,9345,9346,9348,9350],{"class":5532,"line":5586},[5530,9347,6243],{"class":6073},[5530,9349,6246],{"class":5831},[5530,9351,6249],{"class":5543},[5530,9353,9354],{"class":5532,"line":5598},[5530,9355,5565],{"emptyLinePlaceholder":5564},[5530,9357,9358,9360,9363,9365,9367,9369,9371,9373,9375,9377,9379],{"class":5532,"line":5603},[5530,9359,5844],{"class":5831},[5530,9361,9362],{"class":5847}," _set_balance",[5530,9364,5851],{"class":5543},[5530,9366,5855],{"class":5854},[5530,9368,5551],{"class":5543},[5530,9370,7313],{"class":5854},[5530,9372,5863],{"class":5543},[5530,9374,5649],{"class":5835},[5530,9376,6063],{"class":5543},[5530,9378,6066],{"class":5831},[5530,9380,5839],{"class":5543},[5530,9382,9383,9385,9387,9389],{"class":5532,"line":5609},[5530,9384,6074],{"class":6073},[5530,9386,7329],{"class":5543},[5530,9388,6080],{"class":5554},[5530,9390,5839],{"class":5543},[5530,9392,9393,9395,9397,9399,9401],{"class":5532,"line":5758},[5530,9394,6087],{"class":6073},[5530,9396,6090],{"class":5835},[5530,9398,5851],{"class":5543},[5530,9400,7344],{"class":5547},[5530,9402,5558],{"class":5543},[5530,9404,9405,9407],{"class":5532,"line":5764},[5530,9406,5882],{"class":5831},[5530,9408,7353],{"class":5543},[5530,9410,9411],{"class":5532,"line":5770},[5530,9412,5565],{"emptyLinePlaceholder":5564},[5530,9414,9415],{"class":5532,"line":5775},[5530,9416,9417],{"class":5536},"    # Зайві методи залишаються у просторі імен класу!\n",[5530,9419,9420,9423,9426,9428,9431,9434,9437],{"class":5532,"line":5781},[5530,9421,9422],{"class":5543},"    balance = ",[5530,9424,9425],{"class":5835},"property",[5530,9427,5851],{"class":5543},[5530,9429,9430],{"class":5854},"fget",[5530,9432,9433],{"class":5543},"=_get_balance, ",[5530,9435,9436],{"class":5854},"fset",[5530,9438,9439],{"class":5543},"=_set_balance,\n",[5530,9441,9442,9445,9448,9451],{"class":5532,"line":5786},[5530,9443,9444],{"class":5854},"                       doc",[5530,9446,9447],{"class":5543},"=",[5530,9449,9450],{"class":5547},"\"Поточний баланс.\"",[5530,9452,5558],{"class":5543},[9454,9455,9456,9464,9470,9480],"field-group",{},[9457,9458,9460,9461,9463],"field",{"name":9430,"type":9459},"callable | None = None","Функція-геттер. Приймає лише ",[5512,9462,5855],{},", повертає значення властивості.",[9457,9465,9466,9467,9469],{"name":9436,"type":9459},"Функція-сеттер. Приймає ",[5512,9468,5855],{}," та нове значення. Якщо не вказано — властивість є read-only.",[9457,9471,9473,9474,9476,9477,5702],{"name":9472,"type":9459},"fdel","Функція-делітер. Приймає лише ",[5512,9475,5855],{},". Викликається при ",[5512,9478,9479],{},"del obj.prop",[9457,9481,9484,9485,5702],{"name":9482,"type":9483},"doc","str | None = None","Документаційний рядок. Якщо не вказано — береться з ",[5512,9486,9487],{},"fget.__doc__",[5508,9489,9490],{},[5629,9491,9492],{},"Чому декоратори кращі:",[9494,9495,9496,9506,9509],"ol",{},[9497,9498,9499,7954,9502,9505],"li",{},[5512,9500,9501],{},"_get_balance",[5512,9503,9504],{},"_set_balance"," не засмічують публічний інтерфейс класу",[9497,9507,9508],{},"Геттер і сеттер розташовані поряд — одразу зрозуміло, що вони пов'язані",[9497,9510,9511,9512,9514],{},"Документаційний рядок природно прикріплений до ",[5512,9513,7199],{},"-методу",[5666,9516],{},[5503,9518,9520],{"id":9519},"частина-iv-під-капотом-протокол-дескрипторів","Частина IV: Під капотом — Протокол Дескрипторів",[5673,9522,9524],{"id":9523},"що-таке-дескриптор","Що таке дескриптор",[5508,9526,9527,9529,9530,9533,9534,9536,9537,9540],{},[5512,9528,7199],{}," — це ",[5629,9531,9532],{},"не магія",". Це об'єкт класу ",[5512,9535,9425],{},", що реалізує ",[5629,9538,9539],{},"протокол дескрипторів"," — набір спеціальних методів для перехоплення доступу до атрибутів.",[9454,9542,9543,9562,9569,9578],{},[9457,9544,9547,9548,9551,9552,9555,9556,9558,9559,9561],{"name":9545,"type":9546},"__get__(self, instance, owner)","descriptor method","Викликається при ",[5629,9549,9550],{},"зчитуванні"," атрибута. ",[5512,9553,9554],{},"instance"," — об'єкт-власник (або ",[5512,9557,6066],{}," при зверненні через клас). ",[5512,9560,5984],{}," — клас-власник.",[9457,9563,9547,9565,9568],{"name":9564,"type":9546},"__set__(self, instance, value)",[5629,9566,9567],{},"записі"," значення в атрибут. Наявність цього методу робить дескриптор «data descriptor».",[9457,9570,9547,9572,9575,9576,5702],{"name":9571,"type":9546},"__delete__(self, instance)",[5629,9573,9574],{},"видаленні"," атрибута через ",[5512,9577,8740],{},[9457,9579,9582,9583,9586],{"name":9580,"type":9581},"__set_name__(self, owner, name)","descriptor method (Python 3.6+)","Викликається ",[5629,9584,9585],{},"один раз"," під час парсингу класу. Дозволяє дескриптору дізнатися ім'я атрибута, якому він призначений. Замінює необхідність вручну передавати ім'я у конструктор.",[5673,9588,9590],{"id":9589},"алгоритм-пошуку-атрибутів-attribute-lookup","Алгоритм пошуку атрибутів (Attribute Lookup)",[5508,9592,9593,9594,9597,9598,9604],{},"Коли Python виконує ",[5512,9595,9596],{},"obj.attr",", він ",[5629,9599,9600,9601],{},"не просто шукає у ",[5512,9602,9603],{},"obj.__dict__",". Алгоритм суворо визначений:",[9606,9607,9608,9612,9623,9627,9655,9661,9666,9670,9688,9695],"steps",{},[5673,9609,9611],{"id":9610},"крок-1-пошук-у-класі-та-mro","Крок 1: Пошук у класі та MRO",[5508,9613,9614,9615,9618,9619,9622],{},"Python шукає ",[5512,9616,9617],{},"attr"," у ",[5512,9620,9621],{},"type(obj).__dict__"," та класах по ланцюжку MRO.",[5673,9624,9626],{"id":9625},"крок-2-data-descriptor-має-найвищий-пріоритет","Крок 2: Data Descriptor має найвищий пріоритет",[5508,9628,9629,9630,6314,9633,6314,9636,9639,9640,9643,9644,9647,9648,9651,9652,9654],{},"Якщо знайдено атрибут, що реалізує ",[5512,9631,9632],{},"__get__",[5629,9634,9635],{},"та",[5512,9637,9638],{},"__set__"," (або ",[5512,9641,9642],{},"__delete__",") — це ",[5629,9645,9646],{},"data descriptor",". Викликається ",[5512,9649,9650],{},"descriptor.__get__(obj, type(obj))",". Значення в ",[5512,9653,9603],{}," повністю ігнорується.",[5673,9656,9658,9659],{"id":9657},"крок-3-пошук-у-obj__dict__","Крок 3: Пошук у ",[5512,9660,9603],{},[5508,9662,9663,9664,5702],{},"Якщо data descriptor не знайдено — шукаємо у власному словнику екземпляра ",[5512,9665,9603],{},[5673,9667,9669],{"id":9668},"крок-4-non-data-descriptor-або-атрибут-класу","Крок 4: Non-data Descriptor або атрибут класу",[5508,9671,9672,9673,9675,9676,9529,9678,9681,9682,9684,9685,9687],{},"Якщо знайдено атрибут з ",[5512,9674,9632],{}," але без ",[5512,9677,9638],{},[5629,9679,9680],{},"non-data descriptor"," (наприклад, звичайна функція). Викликається ",[5512,9683,9632],{},". Якщо ",[5512,9686,9632],{}," немає — повертається атрибут класу.",[5673,9689,9691,9692],{"id":9690},"крок-5-__getattr__","Крок 5: ",[5512,9693,9694],{},"__getattr__",[5508,9696,9697,9698,9700],{},"Якщо нічого не знайдено — викликається ",[5512,9699,9694],{},", якщо він визначений.",[5704,9702,9703],{},[5521,9704,9706],{"className":5708,"code":9705,"language":5710,"meta":5526,"style":5526},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\nskinparam ArrowColor #6366f1\n\nstart\n\n:obj.attr;\n\n:Пошук attr у type(obj).__mro__;\n\nif (Знайдено data descriptor\\n(__get__ + __set__)?) then (Так)\n    :Викликати descriptor.__get__(obj, type)\\n**найвищий пріоритет**;\n    stop\nelse (Ні)\n    if (Є в obj.__dict__?) then (Так)\n        :Повернути obj.__dict__['attr'];\n        stop\n    else (Ні)\n        if (Знайдено non-data descriptor\\n(тільки __get__)?) then (Так)\n            :Викликати descriptor.__get__(obj, type);\n            stop\n        else (Ні)\n            if (__getattr__ визначено?) then (Так)\n                :Викликати __getattr__(obj, 'attr');\n                stop\n            else (Ні)\n                :raise AttributeError;\n                stop\n            endif\n        endif\n    endif\nendif\n@enduml\n",[5512,9707,9708,9712,9716,9720,9724,9728,9733,9737,9742,9746,9751,9755,9760,9765,9770,9775,9780,9785,9790,9795,9800,9805,9810,9815,9820,9825,9830,9835,9840,9844,9849,9854,9859,9864],{"__ignoreMap":5526},[5530,9709,9710],{"class":5532,"line":5533},[5530,9711,5717],{},[5530,9713,9714],{"class":5532,"line":5540},[5530,9715,5722],{},[5530,9717,9718],{"class":5532,"line":5561},[5530,9719,5727],{},[5530,9721,9722],{"class":5532,"line":5568},[5530,9723,5732],{},[5530,9725,9726],{"class":5532,"line":5574},[5530,9727,5565],{"emptyLinePlaceholder":5564},[5530,9729,9730],{"class":5532,"line":5586},[5530,9731,9732],{},"start\n",[5530,9734,9735],{"class":5532,"line":5598},[5530,9736,5565],{"emptyLinePlaceholder":5564},[5530,9738,9739],{"class":5532,"line":5603},[5530,9740,9741],{},":obj.attr;\n",[5530,9743,9744],{"class":5532,"line":5609},[5530,9745,5565],{"emptyLinePlaceholder":5564},[5530,9747,9748],{"class":5532,"line":5758},[5530,9749,9750],{},":Пошук attr у type(obj).__mro__;\n",[5530,9752,9753],{"class":5532,"line":5764},[5530,9754,5565],{"emptyLinePlaceholder":5564},[5530,9756,9757],{"class":5532,"line":5770},[5530,9758,9759],{},"if (Знайдено data descriptor\\n(__get__ + __set__)?) then (Так)\n",[5530,9761,9762],{"class":5532,"line":5775},[5530,9763,9764],{},"    :Викликати descriptor.__get__(obj, type)\\n**найвищий пріоритет**;\n",[5530,9766,9767],{"class":5532,"line":5781},[5530,9768,9769],{},"    stop\n",[5530,9771,9772],{"class":5532,"line":5786},[5530,9773,9774],{},"else (Ні)\n",[5530,9776,9777],{"class":5532,"line":5792},[5530,9778,9779],{},"    if (Є в obj.__dict__?) then (Так)\n",[5530,9781,9782],{"class":5532,"line":5798},[5530,9783,9784],{},"        :Повернути obj.__dict__['attr'];\n",[5530,9786,9787],{"class":5532,"line":6187},[5530,9788,9789],{},"        stop\n",[5530,9791,9792],{"class":5532,"line":6195},[5530,9793,9794],{},"    else (Ні)\n",[5530,9796,9797],{"class":5532,"line":6217},[5530,9798,9799],{},"        if (Знайдено non-data descriptor\\n(тільки __get__)?) then (Так)\n",[5530,9801,9802],{"class":5532,"line":6222},[5530,9803,9804],{},"            :Викликати descriptor.__get__(obj, type);\n",[5530,9806,9807],{"class":5532,"line":6240},[5530,9808,9809],{},"            stop\n",[5530,9811,9812],{"class":5532,"line":6635},[5530,9813,9814],{},"        else (Ні)\n",[5530,9816,9817],{"class":5532,"line":6640},[5530,9818,9819],{},"            if (__getattr__ визначено?) then (Так)\n",[5530,9821,9822],{"class":5532,"line":6646},[5530,9823,9824],{},"                :Викликати __getattr__(obj, 'attr');\n",[5530,9826,9827],{"class":5532,"line":6659},[5530,9828,9829],{},"                stop\n",[5530,9831,9832],{"class":5532,"line":6664},[5530,9833,9834],{},"            else (Ні)\n",[5530,9836,9837],{"class":5532,"line":6670},[5530,9838,9839],{},"                :raise AttributeError;\n",[5530,9841,9842],{"class":5532,"line":6678},[5530,9843,9829],{},[5530,9845,9846],{"class":5532,"line":6687},[5530,9847,9848],{},"            endif\n",[5530,9850,9851],{"class":5532,"line":7770},[5530,9852,9853],{},"        endif\n",[5530,9855,9856],{"class":5532,"line":7793},[5530,9857,9858],{},"    endif\n",[5530,9860,9861],{"class":5532,"line":7798},[5530,9862,9863],{},"endif\n",[5530,9865,9866],{"class":5532,"line":7804},[5530,9867,5801],{},[5508,9869,9870,9871,9874,9875,9877,9878,9881,9882,9884,9885,9887,9888,9891,9892,5702],{},"Саме тому ",[5512,9872,9873],{},"obj.area = 100"," на read-only ",[5512,9876,7199],{}," кидає ",[5512,9879,9880],{},"AttributeError"," — ",[5512,9883,9425],{}," є data descriptor (має ",[5512,9886,9638],{},", що кидає помилку без сеттера), і він перехоплює запис ",[5629,9889,9890],{},"до"," того, як Python дивиться у ",[5512,9893,9603],{},[5673,9895,9897],{"id":9896},"sequence-diagram-читання-та-запис-через-дескриптор","Sequence Diagram: читання та запис через дескриптор",[5704,9899,9900],{},[5521,9901,9903],{"className":5708,"code":9902,"language":5710,"meta":5526,"style":5526},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\nskinparam ArrowColor #6366f1\nskinparam sequence {\n    ParticipantBackgroundColor #f3f4f6\n    ParticipantBorderColor #d1d5db\n}\n\nactor \"Клієнтський код\" as Client\ncontrol \"Python Runtime\\n(Attribute Lookup)\" as Runtime\nparticipant \"celsius : property\\n(Descriptor)\" as Descriptor\nentity \"instance : Temperature\" as Instance\n\n== Зчитування: instance.celsius ==\nClient -> Runtime : instance.celsius\nRuntime -> Descriptor : data descriptor знайдено!\\n__get__(instance, Temperature)\nDescriptor -> Instance : fget(instance) → читає _celsius\nInstance --> Descriptor : 25.0\nDescriptor --> Runtime : 25.0\nRuntime --> Client : 25.0\n\n== Запис: instance.celsius = -300 ==\nClient -> Runtime : instance.celsius = -300\nRuntime -> Descriptor : __set__(instance, -300)\nDescriptor -> Descriptor : Валідація: -300 \u003C -273.15 → True\nDescriptor --> Runtime : raise ValueError\nRuntime --> Client : ValueError!\n@enduml\n",[5512,9904,9905,9909,9913,9917,9921,9926,9931,9936,9940,9944,9949,9954,9959,9964,9968,9973,9978,9983,9988,9993,9998,10003,10007,10012,10017,10022,10027,10032,10037],{"__ignoreMap":5526},[5530,9906,9907],{"class":5532,"line":5533},[5530,9908,5717],{},[5530,9910,9911],{"class":5532,"line":5540},[5530,9912,5722],{},[5530,9914,9915],{"class":5532,"line":5561},[5530,9916,5727],{},[5530,9918,9919],{"class":5532,"line":5568},[5530,9920,5732],{},[5530,9922,9923],{"class":5532,"line":5574},[5530,9924,9925],{},"skinparam sequence {\n",[5530,9927,9928],{"class":5532,"line":5586},[5530,9929,9930],{},"    ParticipantBackgroundColor #f3f4f6\n",[5530,9932,9933],{"class":5532,"line":5598},[5530,9934,9935],{},"    ParticipantBorderColor #d1d5db\n",[5530,9937,9938],{"class":5532,"line":5603},[5530,9939,5767],{},[5530,9941,9942],{"class":5532,"line":5609},[5530,9943,5565],{"emptyLinePlaceholder":5564},[5530,9945,9946],{"class":5532,"line":5758},[5530,9947,9948],{},"actor \"Клієнтський код\" as Client\n",[5530,9950,9951],{"class":5532,"line":5764},[5530,9952,9953],{},"control \"Python Runtime\\n(Attribute Lookup)\" as Runtime\n",[5530,9955,9956],{"class":5532,"line":5770},[5530,9957,9958],{},"participant \"celsius : property\\n(Descriptor)\" as Descriptor\n",[5530,9960,9961],{"class":5532,"line":5775},[5530,9962,9963],{},"entity \"instance : Temperature\" as Instance\n",[5530,9965,9966],{"class":5532,"line":5781},[5530,9967,5565],{"emptyLinePlaceholder":5564},[5530,9969,9970],{"class":5532,"line":5786},[5530,9971,9972],{},"== Зчитування: instance.celsius ==\n",[5530,9974,9975],{"class":5532,"line":5792},[5530,9976,9977],{},"Client -> Runtime : instance.celsius\n",[5530,9979,9980],{"class":5532,"line":5798},[5530,9981,9982],{},"Runtime -> Descriptor : data descriptor знайдено!\\n__get__(instance, Temperature)\n",[5530,9984,9985],{"class":5532,"line":6187},[5530,9986,9987],{},"Descriptor -> Instance : fget(instance) → читає _celsius\n",[5530,9989,9990],{"class":5532,"line":6195},[5530,9991,9992],{},"Instance --> Descriptor : 25.0\n",[5530,9994,9995],{"class":5532,"line":6217},[5530,9996,9997],{},"Descriptor --> Runtime : 25.0\n",[5530,9999,10000],{"class":5532,"line":6222},[5530,10001,10002],{},"Runtime --> Client : 25.0\n",[5530,10004,10005],{"class":5532,"line":6240},[5530,10006,5565],{"emptyLinePlaceholder":5564},[5530,10008,10009],{"class":5532,"line":6635},[5530,10010,10011],{},"== Запис: instance.celsius = -300 ==\n",[5530,10013,10014],{"class":5532,"line":6640},[5530,10015,10016],{},"Client -> Runtime : instance.celsius = -300\n",[5530,10018,10019],{"class":5532,"line":6646},[5530,10020,10021],{},"Runtime -> Descriptor : __set__(instance, -300)\n",[5530,10023,10024],{"class":5532,"line":6659},[5530,10025,10026],{},"Descriptor -> Descriptor : Валідація: -300 \u003C -273.15 → True\n",[5530,10028,10029],{"class":5532,"line":6664},[5530,10030,10031],{},"Descriptor --> Runtime : raise ValueError\n",[5530,10033,10034],{"class":5532,"line":6670},[5530,10035,10036],{},"Runtime --> Client : ValueError!\n",[5530,10038,10039],{"class":5532,"line":6678},[5530,10040,5801],{},[5673,10042,10044,10045,10047],{"id":10043},"симуляція-property-на-чистому-python","Симуляція ",[5512,10046,9425],{}," на чистому Python",[5508,10049,10050,10051,10053],{},"Щоб остаточно демістифікувати ",[5512,10052,7199],{},", напишемо власну реалізацію:",[5521,10055,10057],{"className":5523,"code":10056,"language":5525,"meta":5526,"style":5526},"class SimplifiedProperty:\n    \"\"\"\n    Спрощена реалізація вбудованого property на чистому Python.\n    Демонструє протокол дескрипторів у дії.\n    \"\"\"\n\n    def __init__(self, fget=None, fset=None, fdel=None, doc=None):\n        self.fget = fget\n        self.fset = fset\n        self.fdel = fdel\n        self.__doc__ = doc or (fget.__doc__ if fget else None)\n\n    def __get__(self, instance, owner):\n        # Звернення через клас (наприклад, Temperature.celsius)\n        if instance is None:\n            return self\n        if self.fget is None:\n            raise AttributeError(\"Не можна зчитати: геттер не визначено\")\n        return self.fget(instance)\n\n    def __set__(self, instance, value):\n        if self.fset is None:\n            raise AttributeError(\"Не можна записати: це read-only властивість\")\n        self.fset(instance, value)\n\n    def __delete__(self, instance):\n        if self.fdel is None:\n            raise AttributeError(\"Не можна видалити: делітер не визначений\")\n        self.fdel(instance)\n\n    # Методи для підтримки синтаксису @prop.setter \u002F @prop.deleter\n    def setter(self, fset):\n        \"\"\"Повертає НОВИЙ об'єкт property з доданим сеттером.\"\"\"\n        return SimplifiedProperty(self.fget, fset, self.fdel, self.__doc__)\n\n    def deleter(self, fdel):\n        \"\"\"Повертає НОВИЙ об'єкт property з доданим делітером.\"\"\"\n        return SimplifiedProperty(self.fget, self.fset, fdel, self.__doc__)\n\n\n# Тест: використання нашого SimplifiedProperty замість вбудованого\nclass TemperatureCustom:\n    def __init__(self, celsius: float):\n        self._celsius = celsius\n\n    @SimplifiedProperty\n    def celsius(self) -> float:\n        \"\"\"Температура в Цельсіях.\"\"\"\n        return self._celsius\n\n    @celsius.setter\n    def celsius(self, value: float) -> None:\n        if value \u003C -273.15:\n            raise ValueError(\"Нижче абсолютного нуля!\")\n        self._celsius = value\n\n\nt = TemperatureCustom(100.0)\nprint(t.celsius)    # 100.0 ✅\nt.celsius = 25.0\nprint(t.celsius)    # 25.0 ✅\n\ntry:\n    t.celsius = -300\nexcept ValueError as e:\n    print(f\"ValueError: {e}\")  # ✅ валідація спрацювала\n",[5512,10058,10059,10068,10072,10077,10082,10086,10090,10134,10141,10148,10155,10189,10193,10214,10219,10233,10241,10256,10269,10278,10282,10303,10318,10331,10338,10342,10359,10374,10387,10394,10398,10403,10420,10425,10450,10454,10471,10476,10500,10504,10508,10513,10522,10542,10549,10553,10558,10574,10579,10587,10591,10595,10620,10631,10645,10653,10658,10663,10674,10685,10694,10704,10709,10716,10724,10735],{"__ignoreMap":5526},[5530,10060,10061,10063,10066],{"class":5532,"line":5533},[5530,10062,5832],{"class":5831},[5530,10064,10065],{"class":5835}," SimplifiedProperty",[5530,10067,5839],{"class":5543},[5530,10069,10070],{"class":5532,"line":5540},[5530,10071,7990],{"class":5547},[5530,10073,10074],{"class":5532,"line":5561},[5530,10075,10076],{"class":5547},"    Спрощена реалізація вбудованого property на чистому Python.\n",[5530,10078,10079],{"class":5532,"line":5568},[5530,10080,10081],{"class":5547},"    Демонструє протокол дескрипторів у дії.\n",[5530,10083,10084],{"class":5532,"line":5574},[5530,10085,7990],{"class":5547},[5530,10087,10088],{"class":5532,"line":5586},[5530,10089,5565],{"emptyLinePlaceholder":5564},[5530,10091,10092,10094,10096,10098,10100,10102,10104,10106,10108,10110,10112,10114,10116,10118,10120,10122,10124,10126,10128,10130,10132],{"class":5532,"line":5598},[5530,10093,5844],{"class":5831},[5530,10095,5848],{"class":5847},[5530,10097,5851],{"class":5543},[5530,10099,5855],{"class":5854},[5530,10101,5551],{"class":5543},[5530,10103,9430],{"class":5854},[5530,10105,9447],{"class":5543},[5530,10107,6066],{"class":5831},[5530,10109,5551],{"class":5543},[5530,10111,9436],{"class":5854},[5530,10113,9447],{"class":5543},[5530,10115,6066],{"class":5831},[5530,10117,5551],{"class":5543},[5530,10119,9472],{"class":5854},[5530,10121,9447],{"class":5543},[5530,10123,6066],{"class":5831},[5530,10125,5551],{"class":5543},[5530,10127,9482],{"class":5854},[5530,10129,9447],{"class":5543},[5530,10131,6066],{"class":5831},[5530,10133,5877],{"class":5543},[5530,10135,10136,10138],{"class":5532,"line":5603},[5530,10137,5882],{"class":5831},[5530,10139,10140],{"class":5543},".fget = fget\n",[5530,10142,10143,10145],{"class":5532,"line":5609},[5530,10144,5882],{"class":5831},[5530,10146,10147],{"class":5543},".fset = fset\n",[5530,10149,10150,10152],{"class":5532,"line":5758},[5530,10151,5882],{"class":5831},[5530,10153,10154],{"class":5543},".fdel = fdel\n",[5530,10156,10157,10159,10161,10164,10167,10170,10173,10175,10178,10181,10184,10187],{"class":5532,"line":5764},[5530,10158,5882],{"class":5831},[5530,10160,5702],{"class":5543},[5530,10162,10163],{"class":5854},"__doc__",[5530,10165,10166],{"class":5543}," = doc ",[5530,10168,10169],{"class":5831},"or",[5530,10171,10172],{"class":5543}," (fget.",[5530,10174,10163],{"class":5854},[5530,10176,10177],{"class":6073}," if",[5530,10179,10180],{"class":5543}," fget ",[5530,10182,10183],{"class":6073},"else",[5530,10185,10186],{"class":5831}," None",[5530,10188,5558],{"class":5543},[5530,10190,10191],{"class":5532,"line":5770},[5530,10192,5565],{"emptyLinePlaceholder":5564},[5530,10194,10195,10197,10200,10202,10204,10206,10208,10210,10212],{"class":5532,"line":5775},[5530,10196,5844],{"class":5831},[5530,10198,10199],{"class":5847}," __get__",[5530,10201,5851],{"class":5543},[5530,10203,5855],{"class":5854},[5530,10205,5551],{"class":5543},[5530,10207,9554],{"class":5854},[5530,10209,5551],{"class":5543},[5530,10211,5984],{"class":5854},[5530,10213,5877],{"class":5543},[5530,10215,10216],{"class":5532,"line":5781},[5530,10217,10218],{"class":5536},"        # Звернення через клас (наприклад, Temperature.celsius)\n",[5530,10220,10221,10223,10226,10229,10231],{"class":5532,"line":5786},[5530,10222,6074],{"class":6073},[5530,10224,10225],{"class":5543}," instance ",[5530,10227,10228],{"class":5831},"is",[5530,10230,10186],{"class":5831},[5530,10232,5839],{"class":5543},[5530,10234,10235,10238],{"class":5532,"line":5792},[5530,10236,10237],{"class":6073},"            return",[5530,10239,10240],{"class":5831}," self\n",[5530,10242,10243,10245,10247,10250,10252,10254],{"class":5532,"line":5798},[5530,10244,6074],{"class":6073},[5530,10246,6246],{"class":5831},[5530,10248,10249],{"class":5543},".fget ",[5530,10251,10228],{"class":5831},[5530,10253,10186],{"class":5831},[5530,10255,5839],{"class":5543},[5530,10257,10258,10260,10262,10264,10267],{"class":5532,"line":6187},[5530,10259,6087],{"class":6073},[5530,10261,6604],{"class":5835},[5530,10263,5851],{"class":5543},[5530,10265,10266],{"class":5547},"\"Не можна зчитати: геттер не визначено\"",[5530,10268,5558],{"class":5543},[5530,10270,10271,10273,10275],{"class":5532,"line":6195},[5530,10272,6243],{"class":6073},[5530,10274,6246],{"class":5831},[5530,10276,10277],{"class":5543},".fget(instance)\n",[5530,10279,10280],{"class":5532,"line":6217},[5530,10281,5565],{"emptyLinePlaceholder":5564},[5530,10283,10284,10286,10289,10291,10293,10295,10297,10299,10301],{"class":5532,"line":6222},[5530,10285,5844],{"class":5831},[5530,10287,10288],{"class":5847}," __set__",[5530,10290,5851],{"class":5543},[5530,10292,5855],{"class":5854},[5530,10294,5551],{"class":5543},[5530,10296,9554],{"class":5854},[5530,10298,5551],{"class":5543},[5530,10300,7313],{"class":5854},[5530,10302,5877],{"class":5543},[5530,10304,10305,10307,10309,10312,10314,10316],{"class":5532,"line":6240},[5530,10306,6074],{"class":6073},[5530,10308,6246],{"class":5831},[5530,10310,10311],{"class":5543},".fset ",[5530,10313,10228],{"class":5831},[5530,10315,10186],{"class":5831},[5530,10317,5839],{"class":5543},[5530,10319,10320,10322,10324,10326,10329],{"class":5532,"line":6635},[5530,10321,6087],{"class":6073},[5530,10323,6604],{"class":5835},[5530,10325,5851],{"class":5543},[5530,10327,10328],{"class":5547},"\"Не можна записати: це read-only властивість\"",[5530,10330,5558],{"class":5543},[5530,10332,10333,10335],{"class":5532,"line":6640},[5530,10334,5882],{"class":5831},[5530,10336,10337],{"class":5543},".fset(instance, value)\n",[5530,10339,10340],{"class":5532,"line":6646},[5530,10341,5565],{"emptyLinePlaceholder":5564},[5530,10343,10344,10346,10349,10351,10353,10355,10357],{"class":5532,"line":6659},[5530,10345,5844],{"class":5831},[5530,10347,10348],{"class":5847}," __delete__",[5530,10350,5851],{"class":5543},[5530,10352,5855],{"class":5854},[5530,10354,5551],{"class":5543},[5530,10356,9554],{"class":5854},[5530,10358,5877],{"class":5543},[5530,10360,10361,10363,10365,10368,10370,10372],{"class":5532,"line":6664},[5530,10362,6074],{"class":6073},[5530,10364,6246],{"class":5831},[5530,10366,10367],{"class":5543},".fdel ",[5530,10369,10228],{"class":5831},[5530,10371,10186],{"class":5831},[5530,10373,5839],{"class":5543},[5530,10375,10376,10378,10380,10382,10385],{"class":5532,"line":6670},[5530,10377,6087],{"class":6073},[5530,10379,6604],{"class":5835},[5530,10381,5851],{"class":5543},[5530,10383,10384],{"class":5547},"\"Не можна видалити: делітер не визначений\"",[5530,10386,5558],{"class":5543},[5530,10388,10389,10391],{"class":5532,"line":6678},[5530,10390,5882],{"class":5831},[5530,10392,10393],{"class":5543},".fdel(instance)\n",[5530,10395,10396],{"class":5532,"line":6687},[5530,10397,5565],{"emptyLinePlaceholder":5564},[5530,10399,10400],{"class":5532,"line":7770},[5530,10401,10402],{"class":5536},"    # Методи для підтримки синтаксису @prop.setter \u002F @prop.deleter\n",[5530,10404,10405,10407,10410,10412,10414,10416,10418],{"class":5532,"line":7793},[5530,10406,5844],{"class":5831},[5530,10408,10409],{"class":5847}," setter",[5530,10411,5851],{"class":5543},[5530,10413,5855],{"class":5854},[5530,10415,5551],{"class":5543},[5530,10417,9436],{"class":5854},[5530,10419,5877],{"class":5543},[5530,10421,10422],{"class":5532,"line":7798},[5530,10423,10424],{"class":5547},"        \"\"\"Повертає НОВИЙ об'єкт property з доданим сеттером.\"\"\"\n",[5530,10426,10427,10429,10432,10434,10437,10439,10442,10444,10446,10448],{"class":5532,"line":7804},[5530,10428,6243],{"class":6073},[5530,10430,10431],{"class":5543}," SimplifiedProperty(",[5530,10433,5855],{"class":5831},[5530,10435,10436],{"class":5543},".fget, fset, ",[5530,10438,5855],{"class":5831},[5530,10440,10441],{"class":5543},".fdel, ",[5530,10443,5855],{"class":5831},[5530,10445,5702],{"class":5543},[5530,10447,10163],{"class":5854},[5530,10449,5558],{"class":5543},[5530,10451,10452],{"class":5532,"line":7813},[5530,10453,5565],{"emptyLinePlaceholder":5564},[5530,10455,10456,10458,10461,10463,10465,10467,10469],{"class":5532,"line":7835},[5530,10457,5844],{"class":5831},[5530,10459,10460],{"class":5847}," deleter",[5530,10462,5851],{"class":5543},[5530,10464,5855],{"class":5854},[5530,10466,5551],{"class":5543},[5530,10468,9472],{"class":5854},[5530,10470,5877],{"class":5543},[5530,10472,10473],{"class":5532,"line":7840},[5530,10474,10475],{"class":5547},"        \"\"\"Повертає НОВИЙ об'єкт property з доданим делітером.\"\"\"\n",[5530,10477,10478,10480,10482,10484,10487,10489,10492,10494,10496,10498],{"class":5532,"line":7846},[5530,10479,6243],{"class":6073},[5530,10481,10431],{"class":5543},[5530,10483,5855],{"class":5831},[5530,10485,10486],{"class":5543},".fget, ",[5530,10488,5855],{"class":5831},[5530,10490,10491],{"class":5543},".fset, fdel, ",[5530,10493,5855],{"class":5831},[5530,10495,5702],{"class":5543},[5530,10497,10163],{"class":5854},[5530,10499,5558],{"class":5543},[5530,10501,10502],{"class":5532,"line":7853},[5530,10503,5565],{"emptyLinePlaceholder":5564},[5530,10505,10506],{"class":5532,"line":7862},[5530,10507,5565],{"emptyLinePlaceholder":5564},[5530,10509,10510],{"class":5532,"line":7873},[5530,10511,10512],{"class":5536},"# Тест: використання нашого SimplifiedProperty замість вбудованого\n",[5530,10514,10515,10517,10520],{"class":5532,"line":8384},[5530,10516,5832],{"class":5831},[5530,10518,10519],{"class":5835}," TemperatureCustom",[5530,10521,5839],{"class":5543},[5530,10523,10524,10526,10528,10530,10532,10534,10536,10538,10540],{"class":5532,"line":8390},[5530,10525,5844],{"class":5831},[5530,10527,5848],{"class":5847},[5530,10529,5851],{"class":5543},[5530,10531,5855],{"class":5854},[5530,10533,5551],{"class":5543},[5530,10535,8023],{"class":5854},[5530,10537,5863],{"class":5543},[5530,10539,5649],{"class":5835},[5530,10541,5877],{"class":5543},[5530,10543,10544,10546],{"class":5532,"line":8402},[5530,10545,5882],{"class":5831},[5530,10547,10548],{"class":5543},"._celsius = celsius\n",[5530,10550,10551],{"class":5532,"line":8412},[5530,10552,5565],{"emptyLinePlaceholder":5564},[5530,10554,10555],{"class":5532,"line":8417},[5530,10556,10557],{"class":5847},"    @SimplifiedProperty\n",[5530,10559,10560,10562,10564,10566,10568,10570,10572],{"class":5532,"line":8423},[5530,10561,5844],{"class":5831},[5530,10563,8065],{"class":5847},[5530,10565,5851],{"class":5543},[5530,10567,5855],{"class":5854},[5530,10569,6063],{"class":5543},[5530,10571,5649],{"class":5835},[5530,10573,5839],{"class":5543},[5530,10575,10576],{"class":5532,"line":8428},[5530,10577,10578],{"class":5547},"        \"\"\"Температура в Цельсіях.\"\"\"\n",[5530,10580,10581,10583,10585],{"class":5532,"line":8435},[5530,10582,6243],{"class":6073},[5530,10584,6246],{"class":5831},[5530,10586,8089],{"class":5543},[5530,10588,10589],{"class":5532,"line":8453},[5530,10590,5565],{"emptyLinePlaceholder":5564},[5530,10592,10593],{"class":5532,"line":8459},[5530,10594,8098],{"class":5847},[5530,10596,10598,10600,10602,10604,10606,10608,10610,10612,10614,10616,10618],{"class":5532,"line":10597},52,[5530,10599,5844],{"class":5831},[5530,10601,8065],{"class":5847},[5530,10603,5851],{"class":5543},[5530,10605,5855],{"class":5854},[5530,10607,5551],{"class":5543},[5530,10609,7313],{"class":5854},[5530,10611,5863],{"class":5543},[5530,10613,5649],{"class":5835},[5530,10615,6063],{"class":5543},[5530,10617,6066],{"class":5831},[5530,10619,5839],{"class":5543},[5530,10621,10623,10625,10627,10629],{"class":5532,"line":10622},53,[5530,10624,6074],{"class":6073},[5530,10626,8188],{"class":5543},[5530,10628,8191],{"class":5554},[5530,10630,5839],{"class":5543},[5530,10632,10634,10636,10638,10640,10643],{"class":5532,"line":10633},54,[5530,10635,6087],{"class":6073},[5530,10637,6090],{"class":5835},[5530,10639,5851],{"class":5543},[5530,10641,10642],{"class":5547},"\"Нижче абсолютного нуля!\"",[5530,10644,5558],{"class":5543},[5530,10646,10648,10650],{"class":5532,"line":10647},55,[5530,10649,5882],{"class":5831},[5530,10651,10652],{"class":5543},"._celsius = value\n",[5530,10654,10656],{"class":5532,"line":10655},56,[5530,10657,5565],{"emptyLinePlaceholder":5564},[5530,10659,10661],{"class":5532,"line":10660},57,[5530,10662,5565],{"emptyLinePlaceholder":5564},[5530,10664,10666,10669,10672],{"class":5532,"line":10665},58,[5530,10667,10668],{"class":5543},"t = TemperatureCustom(",[5530,10670,10671],{"class":5554},"100.0",[5530,10673,5558],{"class":5543},[5530,10675,10677,10679,10682],{"class":5532,"line":10676},59,[5530,10678,6283],{"class":5847},[5530,10680,10681],{"class":5543},"(t.celsius)    ",[5530,10683,10684],{"class":5536},"# 100.0 ✅\n",[5530,10686,10688,10691],{"class":5532,"line":10687},60,[5530,10689,10690],{"class":5543},"t.celsius = ",[5530,10692,10693],{"class":5554},"25.0\n",[5530,10695,10697,10699,10701],{"class":5532,"line":10696},61,[5530,10698,6283],{"class":5847},[5530,10700,10681],{"class":5543},[5530,10702,10703],{"class":5536},"# 25.0 ✅\n",[5530,10705,10707],{"class":5532,"line":10706},62,[5530,10708,5565],{"emptyLinePlaceholder":5564},[5530,10710,10712,10714],{"class":5532,"line":10711},63,[5530,10713,6586],{"class":6073},[5530,10715,5839],{"class":5543},[5530,10717,10719,10721],{"class":5532,"line":10718},64,[5530,10720,8634],{"class":5543},[5530,10722,10723],{"class":5554},"300\n",[5530,10725,10727,10729,10731,10733],{"class":5532,"line":10726},65,[5530,10728,6601],{"class":6073},[5530,10730,6090],{"class":5835},[5530,10732,6607],{"class":6073},[5530,10734,6610],{"class":5543},[5530,10736,10738,10740,10742,10744,10747,10749,10751,10753,10755,10757],{"class":5532,"line":10737},66,[5530,10739,6593],{"class":5847},[5530,10741,5851],{"class":5543},[5530,10743,6114],{"class":5831},[5530,10745,10746],{"class":5547},"\"ValueError: ",[5530,10748,6120],{"class":5831},[5530,10750,6626],{"class":5543},[5530,10752,6125],{"class":5831},[5530,10754,6128],{"class":5547},[5530,10756,7377],{"class":5543},[5530,10758,10759],{"class":5536},"# ✅ валідація спрацювала\n",[6302,10761,10763,10771,10777,10783],{"title":10762},"python simplified_property_demo.py",[6306,10764,10766,6314,10769],{"className":10765},[5532],[5530,10767,6313],{"className":10768},[6312],[5629,10770,10762],{},[6306,10772,10774],{"className":10773},[5532],[5530,10775,10671],{"className":10776},[6720],[6306,10778,10780],{"className":10779},[5532],[5530,10781,8487],{"className":10782},[6720],[6306,10784,8662,10786],{"className":10785},[5532],[5530,10787,10789],{"className":10788},[6711],"Нижче абсолютного нуля!",[5673,10791,10793,10794,10796,10797,10799],{"id":10792},"незмінність-обєктів-property-чому-setter-створює-новий-обєкт","Незмінність об'єктів ",[5512,10795,9425],{},": чому ",[5512,10798,7953],{}," створює новий об'єкт",[5508,10801,10802,10803,10805,10806,10809,10810,10813,10814,10817,10818,7954,10820,10822,10823,10825],{},"Об'єкт ",[5512,10804,9425],{}," є ",[5629,10807,10808],{},"immutable-like",": виклик ",[5512,10811,10812],{},".setter(func)"," не модифікує існуючий об'єкт, а повертає ",[5629,10815,10816],{},"новий"," з скопійованими ",[5512,10819,9430],{},[5512,10821,9472],{}," і доданим ",[5512,10824,9436],{},". Доведемо практично:",[5521,10827,10829],{"className":5523,"code":10828,"language":5525,"meta":5526,"style":5526},"class Demo:\n    @property\n    def value(self) -> int:\n        return self._value\n\n    print(f\"Після @property: id={id(value)}\")   # id об'єкта 1\n\n    @value.setter\n    def value(self, v: int) -> None:\n        self._value = v\n\n    print(f\"Після @value.setter: id={id(value)}\")  # id об'єкта 2 — інший!\n",[5512,10830,10831,10840,10846,10863,10872,10876,10905,10909,10914,10939,10946,10950],{"__ignoreMap":5526},[5530,10832,10833,10835,10838],{"class":5532,"line":5533},[5530,10834,5832],{"class":5831},[5530,10836,10837],{"class":5835}," Demo",[5530,10839,5839],{"class":5543},[5530,10841,10842,10844],{"class":5532,"line":5540},[5530,10843,7565],{"class":5847},[5530,10845,7568],{"class":5835},[5530,10847,10848,10850,10853,10855,10857,10859,10861],{"class":5532,"line":5561},[5530,10849,5844],{"class":5831},[5530,10851,10852],{"class":5847}," value",[5530,10854,5851],{"class":5543},[5530,10856,5855],{"class":5854},[5530,10858,6063],{"class":5543},[5530,10860,8143],{"class":5835},[5530,10862,5839],{"class":5543},[5530,10864,10865,10867,10869],{"class":5532,"line":5568},[5530,10866,6243],{"class":6073},[5530,10868,6246],{"class":5831},[5530,10870,10871],{"class":5543},"._value\n",[5530,10873,10874],{"class":5532,"line":5574},[5530,10875,5565],{"emptyLinePlaceholder":5564},[5530,10877,10878,10880,10882,10884,10887,10889,10892,10895,10897,10899,10902],{"class":5532,"line":5586},[5530,10879,6593],{"class":5847},[5530,10881,5851],{"class":5543},[5530,10883,6114],{"class":5831},[5530,10885,10886],{"class":5547},"\"Після @property: id=",[5530,10888,6120],{"class":5831},[5530,10890,10891],{"class":5847},"id",[5530,10893,10894],{"class":5543},"(value)",[5530,10896,6125],{"class":5831},[5530,10898,6128],{"class":5547},[5530,10900,10901],{"class":5543},")   ",[5530,10903,10904],{"class":5536},"# id об'єкта 1\n",[5530,10906,10907],{"class":5532,"line":5598},[5530,10908,5565],{"emptyLinePlaceholder":5564},[5530,10910,10911],{"class":5532,"line":5603},[5530,10912,10913],{"class":5847},"    @value.setter\n",[5530,10915,10916,10918,10920,10922,10924,10926,10929,10931,10933,10935,10937],{"class":5532,"line":5609},[5530,10917,5844],{"class":5831},[5530,10919,10852],{"class":5847},[5530,10921,5851],{"class":5543},[5530,10923,5855],{"class":5854},[5530,10925,5551],{"class":5543},[5530,10927,10928],{"class":5854},"v",[5530,10930,5863],{"class":5543},[5530,10932,8143],{"class":5835},[5530,10934,6063],{"class":5543},[5530,10936,6066],{"class":5831},[5530,10938,5839],{"class":5543},[5530,10940,10941,10943],{"class":5532,"line":5758},[5530,10942,5882],{"class":5831},[5530,10944,10945],{"class":5543},"._value = v\n",[5530,10947,10948],{"class":5532,"line":5764},[5530,10949,5565],{"emptyLinePlaceholder":5564},[5530,10951,10952,10954,10956,10958,10961,10963,10965,10967,10969,10971,10973],{"class":5532,"line":5770},[5530,10953,6593],{"class":5847},[5530,10955,5851],{"class":5543},[5530,10957,6114],{"class":5831},[5530,10959,10960],{"class":5547},"\"Після @value.setter: id=",[5530,10962,6120],{"class":5831},[5530,10964,10891],{"class":5847},[5530,10966,10894],{"class":5543},[5530,10968,6125],{"class":5831},[5530,10970,6128],{"class":5547},[5530,10972,7377],{"class":5543},[5530,10974,10975],{"class":5536},"# id об'єкта 2 — інший!\n",[6302,10977,10979,10987,10999],{"title":10978},"python property_immutability.py",[6306,10980,10982,6314,10985],{"className":10981},[5532],[5530,10983,6313],{"className":10984},[6312],[5629,10986,10978],{},[6306,10988,10990,10991,6738,10995],{"className":10989},[5532],"Після @property:       id=",[5530,10992,10994],{"className":10993},[6737],"4373777600",[5530,10996,10998],{"className":10997},[6331],"# перший об'єкт",[6306,11000,11002,11003,6738,11007],{"className":11001},[5532],"Після @value.setter:  id=",[5530,11004,11006],{"className":11005},[6720],"4373777680",[5530,11008,11010],{"className":11009},[6331],"# новий об'єкт! адреса відрізняється",[7065,11012,11013,11014,11016],{},"Ця незмінність є навмисним дизайнерським рішенням. Якщо б ",[5512,11015,7953],{}," мутував існуючий об'єкт — можна було б випадково «зіпсувати» геттер, що вже використовується де-інде у коді. Immutability гарантує безпечне ланцюгування.",[5666,11018],{},[5503,11020,11022],{"id":11021},"частина-v-кастомні-дескриптори-для-перевикористання-валідації","Частина V: Кастомні дескриптори для перевикористання валідації",[5673,11024,11026,11027],{"id":11025},"проблема-десятки-однакових-property","Проблема: десятки однакових ",[5512,11028,7199],{},[5508,11030,11031],{},"Уявіть ігровий клас з десятком числових атрибутів, кожен з яким потребує валідації діапазону:",[5521,11033,11035],{"className":5523,"code":11034,"language":5525,"meta":5526,"style":5526},"# ❌ Антипатерн: дублювання логіки у кожному @property\nclass Character:\n    @property\n    def health(self) -> int:\n        return self._health\n\n    @health.setter\n    def health(self, v: int) -> None:\n        if not isinstance(v, int): raise TypeError(...)\n        if not 0 \u003C= v \u003C= 100: raise ValueError(...)\n        self._health = v\n\n    @property\n    def mana(self) -> int:       # ← та сама логіка\n        return self._mana\n\n    @mana.setter\n    def mana(self, v: int) -> None:   # ← та сама логіка\n        if not isinstance(v, int): raise TypeError(...)\n        if not 0 \u003C= v \u003C= 50: raise ValueError(...)\n        self._mana = v\n\n    # ... ще 8 атрибутів з тією ж логікою\n",[5512,11036,11037,11042,11051,11057,11074,11083,11087,11092,11116,11140,11163,11170,11174,11180,11200,11209,11213,11218,11245,11265,11286,11293,11297],{"__ignoreMap":5526},[5530,11038,11039],{"class":5532,"line":5533},[5530,11040,11041],{"class":5536},"# ❌ Антипатерн: дублювання логіки у кожному @property\n",[5530,11043,11044,11046,11049],{"class":5532,"line":5540},[5530,11045,5832],{"class":5831},[5530,11047,11048],{"class":5835}," Character",[5530,11050,5839],{"class":5543},[5530,11052,11053,11055],{"class":5532,"line":5561},[5530,11054,7565],{"class":5847},[5530,11056,7568],{"class":5835},[5530,11058,11059,11061,11064,11066,11068,11070,11072],{"class":5532,"line":5568},[5530,11060,5844],{"class":5831},[5530,11062,11063],{"class":5847}," health",[5530,11065,5851],{"class":5543},[5530,11067,5855],{"class":5854},[5530,11069,6063],{"class":5543},[5530,11071,8143],{"class":5835},[5530,11073,5839],{"class":5543},[5530,11075,11076,11078,11080],{"class":5532,"line":5574},[5530,11077,6243],{"class":6073},[5530,11079,6246],{"class":5831},[5530,11081,11082],{"class":5543},"._health\n",[5530,11084,11085],{"class":5532,"line":5586},[5530,11086,5565],{"emptyLinePlaceholder":5564},[5530,11088,11089],{"class":5532,"line":5598},[5530,11090,11091],{"class":5847},"    @health.setter\n",[5530,11093,11094,11096,11098,11100,11102,11104,11106,11108,11110,11112,11114],{"class":5532,"line":5603},[5530,11095,5844],{"class":5831},[5530,11097,11063],{"class":5847},[5530,11099,5851],{"class":5543},[5530,11101,5855],{"class":5854},[5530,11103,5551],{"class":5543},[5530,11105,10928],{"class":5854},[5530,11107,5863],{"class":5543},[5530,11109,8143],{"class":5835},[5530,11111,6063],{"class":5543},[5530,11113,6066],{"class":5831},[5530,11115,5839],{"class":5543},[5530,11117,11118,11120,11122,11124,11127,11129,11132,11135,11137],{"class":5532,"line":5609},[5530,11119,6074],{"class":6073},[5530,11121,8134],{"class":5831},[5530,11123,8137],{"class":5847},[5530,11125,11126],{"class":5543},"(v, ",[5530,11128,8143],{"class":5835},[5530,11130,11131],{"class":5543},"): ",[5530,11133,11134],{"class":6073},"raise",[5530,11136,8157],{"class":5835},[5530,11138,11139],{"class":5543},"(...)\n",[5530,11141,11142,11144,11146,11149,11152,11155,11157,11159,11161],{"class":5532,"line":5758},[5530,11143,6074],{"class":6073},[5530,11145,8134],{"class":5831},[5530,11147,11148],{"class":5554}," 0",[5530,11150,11151],{"class":5543}," \u003C= v \u003C= ",[5530,11153,11154],{"class":5554},"100",[5530,11156,5863],{"class":5543},[5530,11158,11134],{"class":6073},[5530,11160,6090],{"class":5835},[5530,11162,11139],{"class":5543},[5530,11164,11165,11167],{"class":5532,"line":5764},[5530,11166,5882],{"class":5831},[5530,11168,11169],{"class":5543},"._health = v\n",[5530,11171,11172],{"class":5532,"line":5770},[5530,11173,5565],{"emptyLinePlaceholder":5564},[5530,11175,11176,11178],{"class":5532,"line":5775},[5530,11177,7565],{"class":5847},[5530,11179,7568],{"class":5835},[5530,11181,11182,11184,11187,11189,11191,11193,11195,11197],{"class":5532,"line":5781},[5530,11183,5844],{"class":5831},[5530,11185,11186],{"class":5847}," mana",[5530,11188,5851],{"class":5543},[5530,11190,5855],{"class":5854},[5530,11192,6063],{"class":5543},[5530,11194,8143],{"class":5835},[5530,11196,7282],{"class":5543},[5530,11198,11199],{"class":5536},"# ← та сама логіка\n",[5530,11201,11202,11204,11206],{"class":5532,"line":5786},[5530,11203,6243],{"class":6073},[5530,11205,6246],{"class":5831},[5530,11207,11208],{"class":5543},"._mana\n",[5530,11210,11211],{"class":5532,"line":5792},[5530,11212,5565],{"emptyLinePlaceholder":5564},[5530,11214,11215],{"class":5532,"line":5798},[5530,11216,11217],{"class":5847},"    @mana.setter\n",[5530,11219,11220,11222,11224,11226,11228,11230,11232,11234,11236,11238,11240,11243],{"class":5532,"line":6187},[5530,11221,5844],{"class":5831},[5530,11223,11186],{"class":5847},[5530,11225,5851],{"class":5543},[5530,11227,5855],{"class":5854},[5530,11229,5551],{"class":5543},[5530,11231,10928],{"class":5854},[5530,11233,5863],{"class":5543},[5530,11235,8143],{"class":5835},[5530,11237,6063],{"class":5543},[5530,11239,6066],{"class":5831},[5530,11241,11242],{"class":5543},":   ",[5530,11244,11199],{"class":5536},[5530,11246,11247,11249,11251,11253,11255,11257,11259,11261,11263],{"class":5532,"line":6195},[5530,11248,6074],{"class":6073},[5530,11250,8134],{"class":5831},[5530,11252,8137],{"class":5847},[5530,11254,11126],{"class":5543},[5530,11256,8143],{"class":5835},[5530,11258,11131],{"class":5543},[5530,11260,11134],{"class":6073},[5530,11262,8157],{"class":5835},[5530,11264,11139],{"class":5543},[5530,11266,11267,11269,11271,11273,11275,11278,11280,11282,11284],{"class":5532,"line":6217},[5530,11268,6074],{"class":6073},[5530,11270,8134],{"class":5831},[5530,11272,11148],{"class":5554},[5530,11274,11151],{"class":5543},[5530,11276,11277],{"class":5554},"50",[5530,11279,5863],{"class":5543},[5530,11281,11134],{"class":6073},[5530,11283,6090],{"class":5835},[5530,11285,11139],{"class":5543},[5530,11287,11288,11290],{"class":5532,"line":6222},[5530,11289,5882],{"class":5831},[5530,11291,11292],{"class":5543},"._mana = v\n",[5530,11294,11295],{"class":5532,"line":6240},[5530,11296,5565],{"emptyLinePlaceholder":5564},[5530,11298,11299],{"class":5532,"line":6635},[5530,11300,11301],{"class":5536},"    # ... ще 8 атрибутів з тією ж логікою\n",[5508,11303,11304,11307],{},[5629,11305,11306],{},"Рішення:"," власний клас-дескриптор, що реалізує логіку один раз і перевикористовується для всіх атрибутів.",[5673,11309,11311,11314],{"id":11310},"__set_name__-автоматичне-отримання-імені-атрибута-python-36",[5512,11312,11313],{},"__set_name__",": автоматичне отримання імені атрибута (Python 3.6+)",[5508,11316,11317],{},"До Python 3.6 дескриптор не знав, під яким ім'ям його збережено в класі. Треба було передавати ім'я вручну:",[9133,11319,11320,11455],{},[9136,11321,11323],{"label":11322},"До Python 3.6 (застарілий)",[5521,11324,11326],{"className":5523,"code":11325,"language":5525,"meta":5526,"style":5526},"class LegacyIntegerRange:\n    def __init__(self, storage_name: str, min_val: int, max_val: int):\n        self.storage_name = storage_name  # дублювання!\n        self.min_val = min_val\n        self.max_val = max_val\n\nclass LegacyCharacter:\n    # Жахливе дублювання: ім'я вказується двічі\n    health = LegacyIntegerRange(\"_health\", 0, 100)\n    mana   = LegacyIntegerRange(\"_mana\",   0, 50)\n",[5512,11327,11328,11337,11376,11386,11393,11400,11404,11413,11418,11436],{"__ignoreMap":5526},[5530,11329,11330,11332,11335],{"class":5532,"line":5533},[5530,11331,5832],{"class":5831},[5530,11333,11334],{"class":5835}," LegacyIntegerRange",[5530,11336,5839],{"class":5543},[5530,11338,11339,11341,11343,11345,11347,11349,11352,11354,11356,11358,11361,11363,11365,11367,11370,11372,11374],{"class":5532,"line":5540},[5530,11340,5844],{"class":5831},[5530,11342,5848],{"class":5847},[5530,11344,5851],{"class":5543},[5530,11346,5855],{"class":5854},[5530,11348,5551],{"class":5543},[5530,11350,11351],{"class":5854},"storage_name",[5530,11353,5863],{"class":5543},[5530,11355,5989],{"class":5835},[5530,11357,5551],{"class":5543},[5530,11359,11360],{"class":5854},"min_val",[5530,11362,5863],{"class":5543},[5530,11364,8143],{"class":5835},[5530,11366,5551],{"class":5543},[5530,11368,11369],{"class":5854},"max_val",[5530,11371,5863],{"class":5543},[5530,11373,8143],{"class":5835},[5530,11375,5877],{"class":5543},[5530,11377,11378,11380,11383],{"class":5532,"line":5561},[5530,11379,5882],{"class":5831},[5530,11381,11382],{"class":5543},".storage_name = storage_name  ",[5530,11384,11385],{"class":5536},"# дублювання!\n",[5530,11387,11388,11390],{"class":5532,"line":5568},[5530,11389,5882],{"class":5831},[5530,11391,11392],{"class":5543},".min_val = min_val\n",[5530,11394,11395,11397],{"class":5532,"line":5574},[5530,11396,5882],{"class":5831},[5530,11398,11399],{"class":5543},".max_val = max_val\n",[5530,11401,11402],{"class":5532,"line":5586},[5530,11403,5565],{"emptyLinePlaceholder":5564},[5530,11405,11406,11408,11411],{"class":5532,"line":5598},[5530,11407,5832],{"class":5831},[5530,11409,11410],{"class":5835}," LegacyCharacter",[5530,11412,5839],{"class":5543},[5530,11414,11415],{"class":5532,"line":5603},[5530,11416,11417],{"class":5536},"    # Жахливе дублювання: ім'я вказується двічі\n",[5530,11419,11420,11423,11426,11428,11430,11432,11434],{"class":5532,"line":5609},[5530,11421,11422],{"class":5543},"    health = LegacyIntegerRange(",[5530,11424,11425],{"class":5547},"\"_health\"",[5530,11427,5551],{"class":5543},[5530,11429,6080],{"class":5554},[5530,11431,5551],{"class":5543},[5530,11433,11154],{"class":5554},[5530,11435,5558],{"class":5543},[5530,11437,11438,11441,11444,11447,11449,11451,11453],{"class":5532,"line":5758},[5530,11439,11440],{"class":5543},"    mana   = LegacyIntegerRange(",[5530,11442,11443],{"class":5547},"\"_mana\"",[5530,11445,11446],{"class":5543},",   ",[5530,11448,6080],{"class":5554},[5530,11450,5551],{"class":5543},[5530,11452,11277],{"class":5554},[5530,11454,5558],{"class":5543},[9136,11456,11458],{"label":11457},"Python 3.6+ з __set_name__",[5521,11459,11461],{"className":5523,"code":11460,"language":5525,"meta":5526,"style":5526},"class IntegerRange:\n    def __init__(self, min_val: int, max_val: int):\n        self.min_val = min_val\n        self.max_val = max_val\n\n    def __set_name__(self, owner, name):\n        # Python сам повідомляє дескриптору його ім'я!\n        # owner = Character, name = \"health\"\n        self.public_name  = name          # \"health\"\n        self.private_name = f\"_{name}\"    # \"_health\"\n\nclass Character:\n    # Жодного дублювання!\n    health = IntegerRange(0, 100)\n    mana   = IntegerRange(0, 50)\n",[5512,11462,11463,11472,11500,11506,11512,11516,11538,11543,11548,11558,11581,11585,11593,11598,11611],{"__ignoreMap":5526},[5530,11464,11465,11467,11470],{"class":5532,"line":5533},[5530,11466,5832],{"class":5831},[5530,11468,11469],{"class":5835}," IntegerRange",[5530,11471,5839],{"class":5543},[5530,11473,11474,11476,11478,11480,11482,11484,11486,11488,11490,11492,11494,11496,11498],{"class":5532,"line":5540},[5530,11475,5844],{"class":5831},[5530,11477,5848],{"class":5847},[5530,11479,5851],{"class":5543},[5530,11481,5855],{"class":5854},[5530,11483,5551],{"class":5543},[5530,11485,11360],{"class":5854},[5530,11487,5863],{"class":5543},[5530,11489,8143],{"class":5835},[5530,11491,5551],{"class":5543},[5530,11493,11369],{"class":5854},[5530,11495,5863],{"class":5543},[5530,11497,8143],{"class":5835},[5530,11499,5877],{"class":5543},[5530,11501,11502,11504],{"class":5532,"line":5561},[5530,11503,5882],{"class":5831},[5530,11505,11392],{"class":5543},[5530,11507,11508,11510],{"class":5532,"line":5568},[5530,11509,5882],{"class":5831},[5530,11511,11399],{"class":5543},[5530,11513,11514],{"class":5532,"line":5574},[5530,11515,5565],{"emptyLinePlaceholder":5564},[5530,11517,11518,11520,11523,11525,11527,11529,11531,11533,11536],{"class":5532,"line":5586},[5530,11519,5844],{"class":5831},[5530,11521,11522],{"class":5847}," __set_name__",[5530,11524,5851],{"class":5543},[5530,11526,5855],{"class":5854},[5530,11528,5551],{"class":5543},[5530,11530,5984],{"class":5854},[5530,11532,5551],{"class":5543},[5530,11534,11535],{"class":5854},"name",[5530,11537,5877],{"class":5543},[5530,11539,11540],{"class":5532,"line":5598},[5530,11541,11542],{"class":5536},"        # Python сам повідомляє дескриптору його ім'я!\n",[5530,11544,11545],{"class":5532,"line":5603},[5530,11546,11547],{"class":5536},"        # owner = Character, name = \"health\"\n",[5530,11549,11550,11552,11555],{"class":5532,"line":5609},[5530,11551,5882],{"class":5831},[5530,11553,11554],{"class":5543},".public_name  = name          ",[5530,11556,11557],{"class":5536},"# \"health\"\n",[5530,11559,11560,11562,11565,11567,11570,11572,11574,11576,11578],{"class":5532,"line":5758},[5530,11561,5882],{"class":5831},[5530,11563,11564],{"class":5543},".private_name = ",[5530,11566,6114],{"class":5831},[5530,11568,11569],{"class":5547},"\"_",[5530,11571,6120],{"class":5831},[5530,11573,11535],{"class":5543},[5530,11575,6125],{"class":5831},[5530,11577,6128],{"class":5547},[5530,11579,11580],{"class":5536},"    # \"_health\"\n",[5530,11582,11583],{"class":5532,"line":5764},[5530,11584,5565],{"emptyLinePlaceholder":5564},[5530,11586,11587,11589,11591],{"class":5532,"line":5770},[5530,11588,5832],{"class":5831},[5530,11590,11048],{"class":5835},[5530,11592,5839],{"class":5543},[5530,11594,11595],{"class":5532,"line":5775},[5530,11596,11597],{"class":5536},"    # Жодного дублювання!\n",[5530,11599,11600,11603,11605,11607,11609],{"class":5532,"line":5781},[5530,11601,11602],{"class":5543},"    health = IntegerRange(",[5530,11604,6080],{"class":5554},[5530,11606,5551],{"class":5543},[5530,11608,11154],{"class":5554},[5530,11610,5558],{"class":5543},[5530,11612,11613,11616,11618,11620,11622],{"class":5532,"line":5786},[5530,11614,11615],{"class":5543},"    mana   = IntegerRange(",[5530,11617,6080],{"class":5554},[5530,11619,5551],{"class":5543},[5530,11621,11277],{"class":5554},[5530,11623,5558],{"class":5543},[5673,11625,11627,11628,11631],{"id":11626},"повна-реалізація-integerrange-дескриптора","Повна реалізація ",[5512,11629,11630],{},"IntegerRange"," дескриптора",[5521,11633,11635],{"className":5523,"code":11634,"language":5525,"meta":5526,"style":5526},"# descriptors_validation.py\n\nclass IntegerRange:\n    \"\"\"\n    Data Descriptor для валідації цілочислових атрибутів у діапазоні.\n    Автоматично отримує ім'я атрибута через __set_name__ (Python 3.6+).\n    \"\"\"\n\n    def __init__(self, min_value: int, max_value: int):\n        self.min_value = min_value\n        self.max_value = max_value\n        # Ці поля будуть заповнені __set_name__\n        self.public_name  = None\n        self.private_name = None\n\n    def __set_name__(self, owner: type, name: str) -> None:\n        \"\"\"Викликається Python при парсингу класу-власника.\"\"\"\n        self.public_name  = name\n        self.private_name = f\"_{name}\"\n\n    def __get__(self, instance, owner: type):\n        if instance is None:\n            return self   # доступ через клас → повертаємо дескриптор\n        return getattr(instance, self.private_name, 0)\n\n    def __set__(self, instance, value: int) -> None:\n        # 1. Перевірка типу\n        if not isinstance(value, int):\n            raise TypeError(\n                f\"'{self.public_name}' має бути int, \"\n                f\"отримано {type(value).__name__!r}\"\n            )\n        # 2. Перевірка діапазону\n        if not (self.min_value \u003C= value \u003C= self.max_value):\n            raise ValueError(\n                f\"'{self.public_name}' має бути у [{self.min_value}, {self.max_value}], \"\n                f\"отримано {value}\"\n            )\n        # 3. Запис у захищений атрибут екземпляра\n        setattr(instance, self.private_name, value)\n\n    def __repr__(self) -> str:\n        return (\n            f\"IntegerRange({self.min_value!r}, {self.max_value!r}) \"\n            f\"→ '{self.public_name}'\"\n        )\n\n\nclass Character:\n    \"\"\"Ігровий персонаж з валідованими атрибутами через дескриптори.\"\"\"\n\n    health = IntegerRange(0, 100)\n    mana   = IntegerRange(0, 50)\n    level  = IntegerRange(1, 80)\n    armor  = IntegerRange(0, 500)\n\n    def __init__(self, name: str, health: int, mana: int, level: int, armor: int = 0):\n        self.name   = name\n        self.health = health   # → IntegerRange.__set__ з валідацією\n        self.mana   = mana\n        self.level  = level\n        self.armor  = armor\n\n    def __repr__(self) -> str:\n        return (\n            f\"Character({self.name!r}, HP={self.health}, \"\n            f\"MP={self.mana}, LVL={self.level}, ARM={self.armor})\"\n        )\n\n\n# ── Тести ─────────────────────────────────────────────────────────────────────\nhero = Character(\"Арагорн\", 100, 30, 5)\nprint(hero)\n\nhero.health = 75\nprint(f\"HP після удару: {hero.health}\")\n\n# Дескриптори у __dict__ класу — не у __dict__ екземпляра!\nprint(f\"\\nCharacter.__dict__ keys: {[k for k in Character.__dict__ if not k.startswith('__')]}\")\nprint(f\"hero.__dict__: {hero.__dict__}\")\n\n# Метаінформація дескриптора\nprint(f\"\\nОпис health: {Character.health}\")\n\n# Помилки\ntests = [\n    (lambda: setattr(hero, 'health', 150),  \"health=150 (>100)\"),\n    (lambda: setattr(hero, 'mana', -1),     \"mana=-1 (\u003C0)\"),\n    (lambda: setattr(hero, 'level', \"max\"), \"level='max' (не int)\"),\n]\n\nfor fn, label in tests:\n    try:\n        fn()\n    except (ValueError, TypeError) as e:\n        print(f\"[{label}] {type(e).__name__}: {e}\")\n",[5512,11636,11637,11642,11646,11654,11658,11663,11668,11672,11676,11706,11713,11720,11725,11735,11743,11747,11779,11784,11791,11810,11814,11838,11850,11859,11878,11882,11910,11915,11930,11939,11957,11977,11982,11987,12005,12013,12047,12061,12065,12070,12082,12086,12103,12110,12135,12151,12156,12160,12164,12172,12177,12181,12193,12205,12220,12233,12237,12298,12305,12315,12322,12329,12336,12340,12356,12362,12389,12427,12432,12437,12442,12448,12471,12479,12484,12493,12516,12521,12527,12581,12606,12611,12617,12644,12649,12655,12661,12695,12724,12753,12759,12764,12777,12785,12791,12815],{"__ignoreMap":5526},[5530,11638,11639],{"class":5532,"line":5533},[5530,11640,11641],{"class":5536},"# descriptors_validation.py\n",[5530,11643,11644],{"class":5532,"line":5540},[5530,11645,5565],{"emptyLinePlaceholder":5564},[5530,11647,11648,11650,11652],{"class":5532,"line":5561},[5530,11649,5832],{"class":5831},[5530,11651,11469],{"class":5835},[5530,11653,5839],{"class":5543},[5530,11655,11656],{"class":5532,"line":5568},[5530,11657,7990],{"class":5547},[5530,11659,11660],{"class":5532,"line":5574},[5530,11661,11662],{"class":5547},"    Data Descriptor для валідації цілочислових атрибутів у діапазоні.\n",[5530,11664,11665],{"class":5532,"line":5586},[5530,11666,11667],{"class":5547},"    Автоматично отримує ім'я атрибута через __set_name__ (Python 3.6+).\n",[5530,11669,11670],{"class":5532,"line":5598},[5530,11671,7990],{"class":5547},[5530,11673,11674],{"class":5532,"line":5603},[5530,11675,5565],{"emptyLinePlaceholder":5564},[5530,11677,11678,11680,11682,11684,11686,11688,11691,11693,11695,11697,11700,11702,11704],{"class":5532,"line":5609},[5530,11679,5844],{"class":5831},[5530,11681,5848],{"class":5847},[5530,11683,5851],{"class":5543},[5530,11685,5855],{"class":5854},[5530,11687,5551],{"class":5543},[5530,11689,11690],{"class":5854},"min_value",[5530,11692,5863],{"class":5543},[5530,11694,8143],{"class":5835},[5530,11696,5551],{"class":5543},[5530,11698,11699],{"class":5854},"max_value",[5530,11701,5863],{"class":5543},[5530,11703,8143],{"class":5835},[5530,11705,5877],{"class":5543},[5530,11707,11708,11710],{"class":5532,"line":5758},[5530,11709,5882],{"class":5831},[5530,11711,11712],{"class":5543},".min_value = min_value\n",[5530,11714,11715,11717],{"class":5532,"line":5764},[5530,11716,5882],{"class":5831},[5530,11718,11719],{"class":5543},".max_value = max_value\n",[5530,11721,11722],{"class":5532,"line":5770},[5530,11723,11724],{"class":5536},"        # Ці поля будуть заповнені __set_name__\n",[5530,11726,11727,11729,11732],{"class":5532,"line":5775},[5530,11728,5882],{"class":5831},[5530,11730,11731],{"class":5543},".public_name  = ",[5530,11733,11734],{"class":5831},"None\n",[5530,11736,11737,11739,11741],{"class":5532,"line":5781},[5530,11738,5882],{"class":5831},[5530,11740,11564],{"class":5543},[5530,11742,11734],{"class":5831},[5530,11744,11745],{"class":5532,"line":5786},[5530,11746,5565],{"emptyLinePlaceholder":5564},[5530,11748,11749,11751,11753,11755,11757,11759,11761,11763,11765,11767,11769,11771,11773,11775,11777],{"class":5532,"line":5792},[5530,11750,5844],{"class":5831},[5530,11752,11522],{"class":5847},[5530,11754,5851],{"class":5543},[5530,11756,5855],{"class":5854},[5530,11758,5551],{"class":5543},[5530,11760,5984],{"class":5854},[5530,11762,5863],{"class":5543},[5530,11764,8169],{"class":5835},[5530,11766,5551],{"class":5543},[5530,11768,11535],{"class":5854},[5530,11770,5863],{"class":5543},[5530,11772,5989],{"class":5835},[5530,11774,6063],{"class":5543},[5530,11776,6066],{"class":5831},[5530,11778,5839],{"class":5543},[5530,11780,11781],{"class":5532,"line":5798},[5530,11782,11783],{"class":5547},"        \"\"\"Викликається Python при парсингу класу-власника.\"\"\"\n",[5530,11785,11786,11788],{"class":5532,"line":6187},[5530,11787,5882],{"class":5831},[5530,11789,11790],{"class":5543},".public_name  = name\n",[5530,11792,11793,11795,11797,11799,11801,11803,11805,11807],{"class":5532,"line":6195},[5530,11794,5882],{"class":5831},[5530,11796,11564],{"class":5543},[5530,11798,6114],{"class":5831},[5530,11800,11569],{"class":5547},[5530,11802,6120],{"class":5831},[5530,11804,11535],{"class":5543},[5530,11806,6125],{"class":5831},[5530,11808,11809],{"class":5547},"\"\n",[5530,11811,11812],{"class":5532,"line":6217},[5530,11813,5565],{"emptyLinePlaceholder":5564},[5530,11815,11816,11818,11820,11822,11824,11826,11828,11830,11832,11834,11836],{"class":5532,"line":6222},[5530,11817,5844],{"class":5831},[5530,11819,10199],{"class":5847},[5530,11821,5851],{"class":5543},[5530,11823,5855],{"class":5854},[5530,11825,5551],{"class":5543},[5530,11827,9554],{"class":5854},[5530,11829,5551],{"class":5543},[5530,11831,5984],{"class":5854},[5530,11833,5863],{"class":5543},[5530,11835,8169],{"class":5835},[5530,11837,5877],{"class":5543},[5530,11839,11840,11842,11844,11846,11848],{"class":5532,"line":6240},[5530,11841,6074],{"class":6073},[5530,11843,10225],{"class":5543},[5530,11845,10228],{"class":5831},[5530,11847,10186],{"class":5831},[5530,11849,5839],{"class":5543},[5530,11851,11852,11854,11856],{"class":5532,"line":6635},[5530,11853,10237],{"class":6073},[5530,11855,6246],{"class":5831},[5530,11857,11858],{"class":5536},"   # доступ через клас → повертаємо дескриптор\n",[5530,11860,11861,11863,11866,11869,11871,11874,11876],{"class":5532,"line":6640},[5530,11862,6243],{"class":6073},[5530,11864,11865],{"class":5847}," getattr",[5530,11867,11868],{"class":5543},"(instance, ",[5530,11870,5855],{"class":5831},[5530,11872,11873],{"class":5543},".private_name, ",[5530,11875,6080],{"class":5554},[5530,11877,5558],{"class":5543},[5530,11879,11880],{"class":5532,"line":6646},[5530,11881,5565],{"emptyLinePlaceholder":5564},[5530,11883,11884,11886,11888,11890,11892,11894,11896,11898,11900,11902,11904,11906,11908],{"class":5532,"line":6659},[5530,11885,5844],{"class":5831},[5530,11887,10288],{"class":5847},[5530,11889,5851],{"class":5543},[5530,11891,5855],{"class":5854},[5530,11893,5551],{"class":5543},[5530,11895,9554],{"class":5854},[5530,11897,5551],{"class":5543},[5530,11899,7313],{"class":5854},[5530,11901,5863],{"class":5543},[5530,11903,8143],{"class":5835},[5530,11905,6063],{"class":5543},[5530,11907,6066],{"class":5831},[5530,11909,5839],{"class":5543},[5530,11911,11912],{"class":5532,"line":6664},[5530,11913,11914],{"class":5536},"        # 1. Перевірка типу\n",[5530,11916,11917,11919,11921,11923,11926,11928],{"class":5532,"line":6670},[5530,11918,6074],{"class":6073},[5530,11920,8134],{"class":5831},[5530,11922,8137],{"class":5847},[5530,11924,11925],{"class":5543},"(value, ",[5530,11927,8143],{"class":5835},[5530,11929,5877],{"class":5543},[5530,11931,11932,11934,11936],{"class":5532,"line":6678},[5530,11933,6087],{"class":6073},[5530,11935,8157],{"class":5835},[5530,11937,11938],{"class":5543},"(\n",[5530,11940,11941,11944,11947,11949,11952,11954],{"class":5532,"line":6687},[5530,11942,11943],{"class":5831},"                f",[5530,11945,11946],{"class":5547},"\"'",[5530,11948,6857],{"class":5831},[5530,11950,11951],{"class":5543},".public_name",[5530,11953,6125],{"class":5831},[5530,11955,11956],{"class":5547},"' має бути int, \"\n",[5530,11958,11959,11961,11964,11966,11968,11970,11972,11975],{"class":5532,"line":7770},[5530,11960,11943],{"class":5831},[5530,11962,11963],{"class":5547},"\"отримано ",[5530,11965,6120],{"class":5831},[5530,11967,8169],{"class":5835},[5530,11969,8172],{"class":5543},[5530,11971,8175],{"class":5854},[5530,11973,11974],{"class":5831},"!r}",[5530,11976,11809],{"class":5547},[5530,11978,11979],{"class":5532,"line":7793},[5530,11980,11981],{"class":5543},"            )\n",[5530,11983,11984],{"class":5532,"line":7798},[5530,11985,11986],{"class":5536},"        # 2. Перевірка діапазону\n",[5530,11988,11989,11991,11993,11995,11997,12000,12002],{"class":5532,"line":7804},[5530,11990,6074],{"class":6073},[5530,11992,8134],{"class":5831},[5530,11994,8277],{"class":5543},[5530,11996,5855],{"class":5831},[5530,11998,11999],{"class":5543},".min_value \u003C= value \u003C= ",[5530,12001,5855],{"class":5831},[5530,12003,12004],{"class":5543},".max_value):\n",[5530,12006,12007,12009,12011],{"class":5532,"line":7813},[5530,12008,6087],{"class":6073},[5530,12010,6090],{"class":5835},[5530,12012,11938],{"class":5543},[5530,12014,12015,12017,12019,12021,12023,12025,12028,12030,12033,12035,12037,12039,12042,12044],{"class":5532,"line":7835},[5530,12016,11943],{"class":5831},[5530,12018,11946],{"class":5547},[5530,12020,6857],{"class":5831},[5530,12022,11951],{"class":5543},[5530,12024,6125],{"class":5831},[5530,12026,12027],{"class":5547},"' має бути у [",[5530,12029,6857],{"class":5831},[5530,12031,12032],{"class":5543},".min_value",[5530,12034,6125],{"class":5831},[5530,12036,5551],{"class":5547},[5530,12038,6857],{"class":5831},[5530,12040,12041],{"class":5543},".max_value",[5530,12043,6125],{"class":5831},[5530,12045,12046],{"class":5547},"], \"\n",[5530,12048,12049,12051,12053,12055,12057,12059],{"class":5532,"line":7840},[5530,12050,11943],{"class":5831},[5530,12052,11963],{"class":5547},[5530,12054,6120],{"class":5831},[5530,12056,7313],{"class":5543},[5530,12058,6125],{"class":5831},[5530,12060,11809],{"class":5547},[5530,12062,12063],{"class":5532,"line":7846},[5530,12064,11981],{"class":5543},[5530,12066,12067],{"class":5532,"line":7853},[5530,12068,12069],{"class":5536},"        # 3. Запис у захищений атрибут екземпляра\n",[5530,12071,12072,12075,12077,12079],{"class":5532,"line":7862},[5530,12073,12074],{"class":5847},"        setattr",[5530,12076,11868],{"class":5543},[5530,12078,5855],{"class":5831},[5530,12080,12081],{"class":5543},".private_name, value)\n",[5530,12083,12084],{"class":5532,"line":7873},[5530,12085,5565],{"emptyLinePlaceholder":5564},[5530,12087,12088,12090,12093,12095,12097,12099,12101],{"class":5532,"line":8384},[5530,12089,5844],{"class":5831},[5530,12091,12092],{"class":5847}," __repr__",[5530,12094,5851],{"class":5543},[5530,12096,5855],{"class":5854},[5530,12098,6063],{"class":5543},[5530,12100,5989],{"class":5835},[5530,12102,5839],{"class":5543},[5530,12104,12105,12107],{"class":5532,"line":8390},[5530,12106,6243],{"class":6073},[5530,12108,12109],{"class":5543}," (\n",[5530,12111,12112,12115,12118,12120,12122,12124,12126,12128,12130,12132],{"class":5532,"line":8402},[5530,12113,12114],{"class":5831},"            f",[5530,12116,12117],{"class":5547},"\"IntegerRange(",[5530,12119,6857],{"class":5831},[5530,12121,12032],{"class":5543},[5530,12123,11974],{"class":5831},[5530,12125,5551],{"class":5547},[5530,12127,6857],{"class":5831},[5530,12129,12041],{"class":5543},[5530,12131,11974],{"class":5831},[5530,12133,12134],{"class":5547},") \"\n",[5530,12136,12137,12139,12142,12144,12146,12148],{"class":5532,"line":8412},[5530,12138,12114],{"class":5831},[5530,12140,12141],{"class":5547},"\"→ '",[5530,12143,6857],{"class":5831},[5530,12145,11951],{"class":5543},[5530,12147,6125],{"class":5831},[5530,12149,12150],{"class":5547},"'\"\n",[5530,12152,12153],{"class":5532,"line":8417},[5530,12154,12155],{"class":5543},"        )\n",[5530,12157,12158],{"class":5532,"line":8423},[5530,12159,5565],{"emptyLinePlaceholder":5564},[5530,12161,12162],{"class":5532,"line":8428},[5530,12163,5565],{"emptyLinePlaceholder":5564},[5530,12165,12166,12168,12170],{"class":5532,"line":8435},[5530,12167,5832],{"class":5831},[5530,12169,11048],{"class":5835},[5530,12171,5839],{"class":5543},[5530,12173,12174],{"class":5532,"line":8453},[5530,12175,12176],{"class":5547},"    \"\"\"Ігровий персонаж з валідованими атрибутами через дескриптори.\"\"\"\n",[5530,12178,12179],{"class":5532,"line":8459},[5530,12180,5565],{"emptyLinePlaceholder":5564},[5530,12182,12183,12185,12187,12189,12191],{"class":5532,"line":10597},[5530,12184,11602],{"class":5543},[5530,12186,6080],{"class":5554},[5530,12188,5551],{"class":5543},[5530,12190,11154],{"class":5554},[5530,12192,5558],{"class":5543},[5530,12194,12195,12197,12199,12201,12203],{"class":5532,"line":10622},[5530,12196,11615],{"class":5543},[5530,12198,6080],{"class":5554},[5530,12200,5551],{"class":5543},[5530,12202,11277],{"class":5554},[5530,12204,5558],{"class":5543},[5530,12206,12207,12210,12213,12215,12218],{"class":5532,"line":10633},[5530,12208,12209],{"class":5543},"    level  = IntegerRange(",[5530,12211,12212],{"class":5554},"1",[5530,12214,5551],{"class":5543},[5530,12216,12217],{"class":5554},"80",[5530,12219,5558],{"class":5543},[5530,12221,12222,12225,12227,12229,12231],{"class":5532,"line":10647},[5530,12223,12224],{"class":5543},"    armor  = IntegerRange(",[5530,12226,6080],{"class":5554},[5530,12228,5551],{"class":5543},[5530,12230,7374],{"class":5554},[5530,12232,5558],{"class":5543},[5530,12234,12235],{"class":5532,"line":10655},[5530,12236,5565],{"emptyLinePlaceholder":5564},[5530,12238,12239,12241,12243,12245,12247,12249,12251,12253,12255,12257,12260,12262,12264,12266,12269,12271,12273,12275,12278,12280,12282,12284,12287,12289,12291,12294,12296],{"class":5532,"line":10660},[5530,12240,5844],{"class":5831},[5530,12242,5848],{"class":5847},[5530,12244,5851],{"class":5543},[5530,12246,5855],{"class":5854},[5530,12248,5551],{"class":5543},[5530,12250,11535],{"class":5854},[5530,12252,5863],{"class":5543},[5530,12254,5989],{"class":5835},[5530,12256,5551],{"class":5543},[5530,12258,12259],{"class":5854},"health",[5530,12261,5863],{"class":5543},[5530,12263,8143],{"class":5835},[5530,12265,5551],{"class":5543},[5530,12267,12268],{"class":5854},"mana",[5530,12270,5863],{"class":5543},[5530,12272,8143],{"class":5835},[5530,12274,5551],{"class":5543},[5530,12276,12277],{"class":5854},"level",[5530,12279,5863],{"class":5543},[5530,12281,8143],{"class":5835},[5530,12283,5551],{"class":5543},[5530,12285,12286],{"class":5854},"armor",[5530,12288,5863],{"class":5543},[5530,12290,8143],{"class":5835},[5530,12292,12293],{"class":5543}," = ",[5530,12295,6080],{"class":5554},[5530,12297,5877],{"class":5543},[5530,12299,12300,12302],{"class":5532,"line":10665},[5530,12301,5882],{"class":5831},[5530,12303,12304],{"class":5543},".name   = name\n",[5530,12306,12307,12309,12312],{"class":5532,"line":10676},[5530,12308,5882],{"class":5831},[5530,12310,12311],{"class":5543},".health = health   ",[5530,12313,12314],{"class":5536},"# → IntegerRange.__set__ з валідацією\n",[5530,12316,12317,12319],{"class":5532,"line":10687},[5530,12318,5882],{"class":5831},[5530,12320,12321],{"class":5543},".mana   = mana\n",[5530,12323,12324,12326],{"class":5532,"line":10696},[5530,12325,5882],{"class":5831},[5530,12327,12328],{"class":5543},".level  = level\n",[5530,12330,12331,12333],{"class":5532,"line":10706},[5530,12332,5882],{"class":5831},[5530,12334,12335],{"class":5543},".armor  = armor\n",[5530,12337,12338],{"class":5532,"line":10711},[5530,12339,5565],{"emptyLinePlaceholder":5564},[5530,12341,12342,12344,12346,12348,12350,12352,12354],{"class":5532,"line":10718},[5530,12343,5844],{"class":5831},[5530,12345,12092],{"class":5847},[5530,12347,5851],{"class":5543},[5530,12349,5855],{"class":5854},[5530,12351,6063],{"class":5543},[5530,12353,5989],{"class":5835},[5530,12355,5839],{"class":5543},[5530,12357,12358,12360],{"class":5532,"line":10726},[5530,12359,6243],{"class":6073},[5530,12361,12109],{"class":5543},[5530,12363,12364,12366,12369,12371,12374,12376,12379,12381,12384,12386],{"class":5532,"line":10737},[5530,12365,12114],{"class":5831},[5530,12367,12368],{"class":5547},"\"Character(",[5530,12370,6857],{"class":5831},[5530,12372,12373],{"class":5543},".name",[5530,12375,11974],{"class":5831},[5530,12377,12378],{"class":5547},", HP=",[5530,12380,6857],{"class":5831},[5530,12382,12383],{"class":5543},".health",[5530,12385,6125],{"class":5831},[5530,12387,12388],{"class":5547},", \"\n",[5530,12390,12392,12394,12397,12399,12402,12404,12407,12409,12412,12414,12417,12419,12422,12424],{"class":5532,"line":12391},67,[5530,12393,12114],{"class":5831},[5530,12395,12396],{"class":5547},"\"MP=",[5530,12398,6857],{"class":5831},[5530,12400,12401],{"class":5543},".mana",[5530,12403,6125],{"class":5831},[5530,12405,12406],{"class":5547},", LVL=",[5530,12408,6857],{"class":5831},[5530,12410,12411],{"class":5543},".level",[5530,12413,6125],{"class":5831},[5530,12415,12416],{"class":5547},", ARM=",[5530,12418,6857],{"class":5831},[5530,12420,12421],{"class":5543},".armor",[5530,12423,6125],{"class":5831},[5530,12425,12426],{"class":5547},")\"\n",[5530,12428,12430],{"class":5532,"line":12429},68,[5530,12431,12155],{"class":5543},[5530,12433,12435],{"class":5532,"line":12434},69,[5530,12436,5565],{"emptyLinePlaceholder":5564},[5530,12438,12440],{"class":5532,"line":12439},70,[5530,12441,5565],{"emptyLinePlaceholder":5564},[5530,12443,12445],{"class":5532,"line":12444},71,[5530,12446,12447],{"class":5536},"# ── Тести ─────────────────────────────────────────────────────────────────────\n",[5530,12449,12451,12454,12457,12459,12461,12463,12465,12467,12469],{"class":5532,"line":12450},72,[5530,12452,12453],{"class":5543},"hero = Character(",[5530,12455,12456],{"class":5547},"\"Арагорн\"",[5530,12458,5551],{"class":5543},[5530,12460,11154],{"class":5554},[5530,12462,5551],{"class":5543},[5530,12464,6822],{"class":5554},[5530,12466,5551],{"class":5543},[5530,12468,8290],{"class":5554},[5530,12470,5558],{"class":5543},[5530,12472,12474,12476],{"class":5532,"line":12473},73,[5530,12475,6283],{"class":5847},[5530,12477,12478],{"class":5543},"(hero)\n",[5530,12480,12482],{"class":5532,"line":12481},74,[5530,12483,5565],{"emptyLinePlaceholder":5564},[5530,12485,12487,12490],{"class":5532,"line":12486},75,[5530,12488,12489],{"class":5543},"hero.health = ",[5530,12491,12492],{"class":5554},"75\n",[5530,12494,12496,12498,12500,12502,12505,12507,12510,12512,12514],{"class":5532,"line":12495},76,[5530,12497,6283],{"class":5847},[5530,12499,5851],{"class":5543},[5530,12501,6114],{"class":5831},[5530,12503,12504],{"class":5547},"\"HP після удару: ",[5530,12506,6120],{"class":5831},[5530,12508,12509],{"class":5543},"hero.health",[5530,12511,6125],{"class":5831},[5530,12513,6128],{"class":5547},[5530,12515,5558],{"class":5543},[5530,12517,12519],{"class":5532,"line":12518},77,[5530,12520,5565],{"emptyLinePlaceholder":5564},[5530,12522,12524],{"class":5532,"line":12523},78,[5530,12525,12526],{"class":5536},"# Дескриптори у __dict__ класу — не у __dict__ екземпляра!\n",[5530,12528,12530,12532,12534,12536,12538,12540,12543,12545,12548,12551,12554,12557,12560,12562,12564,12566,12569,12572,12575,12577,12579],{"class":5532,"line":12529},79,[5530,12531,6283],{"class":5847},[5530,12533,5851],{"class":5543},[5530,12535,6114],{"class":5831},[5530,12537,6128],{"class":5547},[5530,12539,8589],{"class":8588},[5530,12541,12542],{"class":5547},"Character.__dict__ keys: ",[5530,12544,6120],{"class":5831},[5530,12546,12547],{"class":5543},"[k ",[5530,12549,12550],{"class":6073},"for",[5530,12552,12553],{"class":5543}," k ",[5530,12555,12556],{"class":6073},"in",[5530,12558,12559],{"class":5543}," Character.",[5530,12561,6654],{"class":5854},[5530,12563,10177],{"class":6073},[5530,12565,8134],{"class":5831},[5530,12567,12568],{"class":5543}," k.startswith(",[5530,12570,12571],{"class":5547},"'__'",[5530,12573,12574],{"class":5543},")]",[5530,12576,6125],{"class":5831},[5530,12578,6128],{"class":5547},[5530,12580,5558],{"class":5543},[5530,12582,12584,12586,12588,12590,12593,12595,12598,12600,12602,12604],{"class":5532,"line":12583},80,[5530,12585,6283],{"class":5847},[5530,12587,5851],{"class":5543},[5530,12589,6114],{"class":5831},[5530,12591,12592],{"class":5547},"\"hero.__dict__: ",[5530,12594,6120],{"class":5831},[5530,12596,12597],{"class":5543},"hero.",[5530,12599,6654],{"class":5854},[5530,12601,6125],{"class":5831},[5530,12603,6128],{"class":5547},[5530,12605,5558],{"class":5543},[5530,12607,12609],{"class":5532,"line":12608},81,[5530,12610,5565],{"emptyLinePlaceholder":5564},[5530,12612,12614],{"class":5532,"line":12613},82,[5530,12615,12616],{"class":5536},"# Метаінформація дескриптора\n",[5530,12618,12620,12622,12624,12626,12628,12630,12633,12635,12638,12640,12642],{"class":5532,"line":12619},83,[5530,12621,6283],{"class":5847},[5530,12623,5851],{"class":5543},[5530,12625,6114],{"class":5831},[5530,12627,6128],{"class":5547},[5530,12629,8589],{"class":8588},[5530,12631,12632],{"class":5547},"Опис health: ",[5530,12634,6120],{"class":5831},[5530,12636,12637],{"class":5543},"Character.health",[5530,12639,6125],{"class":5831},[5530,12641,6128],{"class":5547},[5530,12643,5558],{"class":5543},[5530,12645,12647],{"class":5532,"line":12646},84,[5530,12648,5565],{"emptyLinePlaceholder":5564},[5530,12650,12652],{"class":5532,"line":12651},85,[5530,12653,12654],{"class":5536},"# Помилки\n",[5530,12656,12658],{"class":5532,"line":12657},86,[5530,12659,12660],{"class":5543},"tests = [\n",[5530,12662,12664,12667,12670,12672,12675,12678,12681,12683,12686,12689,12692],{"class":5532,"line":12663},87,[5530,12665,12666],{"class":5543},"    (",[5530,12668,12669],{"class":5831},"lambda",[5530,12671,5863],{"class":5543},[5530,12673,12674],{"class":5847},"setattr",[5530,12676,12677],{"class":5543},"(hero, ",[5530,12679,12680],{"class":5547},"'health'",[5530,12682,5551],{"class":5543},[5530,12684,12685],{"class":5554},"150",[5530,12687,12688],{"class":5543},"),  ",[5530,12690,12691],{"class":5547},"\"health=150 (>100)\"",[5530,12693,12694],{"class":5543},"),\n",[5530,12696,12698,12700,12702,12704,12706,12708,12711,12714,12716,12719,12722],{"class":5532,"line":12697},88,[5530,12699,12666],{"class":5543},[5530,12701,12669],{"class":5831},[5530,12703,5863],{"class":5543},[5530,12705,12674],{"class":5847},[5530,12707,12677],{"class":5543},[5530,12709,12710],{"class":5547},"'mana'",[5530,12712,12713],{"class":5543},", -",[5530,12715,12212],{"class":5554},[5530,12717,12718],{"class":5543},"),     ",[5530,12720,12721],{"class":5547},"\"mana=-1 (\u003C0)\"",[5530,12723,12694],{"class":5543},[5530,12725,12727,12729,12731,12733,12735,12737,12740,12742,12745,12748,12751],{"class":5532,"line":12726},89,[5530,12728,12666],{"class":5543},[5530,12730,12669],{"class":5831},[5530,12732,5863],{"class":5543},[5530,12734,12674],{"class":5847},[5530,12736,12677],{"class":5543},[5530,12738,12739],{"class":5547},"'level'",[5530,12741,5551],{"class":5543},[5530,12743,12744],{"class":5547},"\"max\"",[5530,12746,12747],{"class":5543},"), ",[5530,12749,12750],{"class":5547},"\"level='max' (не int)\"",[5530,12752,12694],{"class":5543},[5530,12754,12756],{"class":5532,"line":12755},90,[5530,12757,12758],{"class":5543},"]\n",[5530,12760,12762],{"class":5532,"line":12761},91,[5530,12763,5565],{"emptyLinePlaceholder":5564},[5530,12765,12767,12769,12772,12774],{"class":5532,"line":12766},92,[5530,12768,12550],{"class":6073},[5530,12770,12771],{"class":5543}," fn, label ",[5530,12773,12556],{"class":6073},[5530,12775,12776],{"class":5543}," tests:\n",[5530,12778,12780,12783],{"class":5532,"line":12779},93,[5530,12781,12782],{"class":6073},"    try",[5530,12784,5839],{"class":5543},[5530,12786,12788],{"class":5532,"line":12787},94,[5530,12789,12790],{"class":5543},"        fn()\n",[5530,12792,12794,12797,12799,12802,12804,12807,12810,12813],{"class":5532,"line":12793},95,[5530,12795,12796],{"class":6073},"    except",[5530,12798,8277],{"class":5543},[5530,12800,12801],{"class":5835},"ValueError",[5530,12803,5551],{"class":5543},[5530,12805,12806],{"class":5835},"TypeError",[5530,12808,12809],{"class":5543},") ",[5530,12811,12812],{"class":6073},"as",[5530,12814,6610],{"class":5543},[5530,12816,12818,12820,12822,12824,12827,12829,12832,12834,12837,12839,12841,12844,12846,12848,12850,12852,12854,12856,12858],{"class":5532,"line":12817},96,[5530,12819,6847],{"class":5847},[5530,12821,5851],{"class":5543},[5530,12823,6114],{"class":5831},[5530,12825,12826],{"class":5547},"\"[",[5530,12828,6120],{"class":5831},[5530,12830,12831],{"class":5543},"label",[5530,12833,6125],{"class":5831},[5530,12835,12836],{"class":5547},"] ",[5530,12838,6120],{"class":5831},[5530,12840,8169],{"class":5835},[5530,12842,12843],{"class":5543},"(e).",[5530,12845,8175],{"class":5854},[5530,12847,6125],{"class":5831},[5530,12849,5863],{"class":5547},[5530,12851,6120],{"class":5831},[5530,12853,6626],{"class":5543},[5530,12855,6125],{"class":5831},[5530,12857,6128],{"class":5547},[5530,12859,5558],{"class":5543},[6302,12861,12863,12871,12889,12897,12900,12911,12919,12922,12929,12932,12940,12948],{"title":12862},"python descriptors_validation.py",[6306,12864,12866,6314,12869],{"className":12865},[5532],[5530,12867,6313],{"className":12868},[6312],[5629,12870,12862],{},[6306,12872,12874,12875,12878,12879,12406,12882,12416,12885,12888],{"className":12873},[5532],"Character('Арагорн', HP=",[5530,12876,11154],{"className":12877},[6720],", MP=",[5530,12880,6822],{"className":12881},[6720],[5530,12883,8290],{"className":12884},[6720],[5530,12886,6080],{"className":12887},[6720],")",[6306,12890,12892,12893],{"className":12891},[5532],"HP після удару: ",[5530,12894,12896],{"className":12895},[6325],"75",[6306,12898],{"className":12899},[5532],[6306,12901,12542,12903,6738,12907],{"className":12902},[5532],[5530,12904,12906],{"className":12905},[6737],"['health', 'mana', 'level', 'armor']",[5530,12908,12910],{"className":12909},[6331],"# дескриптори тут!",[6306,12912,12914,12915],{"className":12913},[5532],"hero.__dict__: ",[5530,12916,12918],{"className":12917},[6737],"{'name': 'Арагорн', '_health': 75, '_mana': 30, '_level': 5, '_armor': 0}",[6306,12920],{"className":12921},[5532],[6306,12923,12632,12925],{"className":12924},[5532],[5530,12926,12928],{"className":12927},[6331],"IntegerRange(0, 100) → 'health'",[6306,12930],{"className":12931},[5532],[6306,12933,12935,12936],{"className":12934},[5532],"[health=150 (>100)] ",[5530,12937,12939],{"className":12938},[6711],"ValueError: 'health' має бути у [0, 100], отримано 150",[6306,12941,12943,12944],{"className":12942},[5532],"[mana=-1 (\u003C0)]     ",[5530,12945,12947],{"className":12946},[6711],"ValueError: 'mana' має бути у [0, 50], отримано -1",[6306,12949,12951,12952],{"className":12950},[5532],"[level='max']       ",[5530,12953,12955],{"className":12954},[6711],"TypeError: 'level' має бути int, отримано 'str'",[7065,12957,12958,12959,12962,12963,8277,12965,5551,12968,12971,12972,5551,12974,5551,12976,5551,12978,12980,12981,12984,12985,12988],{},"Зверніть увагу на ",[5512,12960,12961],{},"hero.__dict__",": значення зберігаються з префіксом ",[5512,12964,6371],{},[5512,12966,12967],{},"_health",[5512,12969,12970],{},"_mana","), а не під іменем дескриптора. Самі дескриптори (",[5512,12973,12259],{},[5512,12975,12268],{},[5512,12977,12277],{},[5512,12979,12286],{},") зберігаються у ",[5512,12982,12983],{},"Character.__dict__"," — на рівні ",[5629,12986,12987],{},"класу",", а не екземпляра.",[5666,12990],{},[5503,12992,12994],{"id":12993},"частина-vi-практичні-завдання","Частина VI: Практичні завдання",[5673,12996,12998],{"id":12997},"рівень-1-базовий-прямокутник-з-властивостями","Рівень 1 (Базовий): Прямокутник з властивостями",[5508,13000,13001,13002,5551,13004,13006],{},"Закріпіть синтаксис ",[5512,13003,7199],{},[5512,13005,7953],{}," та захищених атрибутів.",[5521,13008,13010],{"className":5523,"code":13009,"language":5525,"meta":5526,"style":5526},"# rectangle.py\nclass Rectangle:\n    \"\"\"\n    Прямокутник з валідацією розмірів через @property.\n    Площа та периметр — обчислювальні властивості (read-only).\n    \"\"\"\n\n    def __init__(self, width: float, height: float):\n        # Ці виклики проходять через сеттери — валідація відбувається вже тут\n        self.width  = width\n        self.height = height\n\n    @property\n    def width(self) -> float:\n        return self._width\n\n    @width.setter\n    def width(self, value: float) -> None:\n        if not isinstance(value, (int, float)):\n            raise TypeError(f\"width: очікується число, отримано {type(value).__name__}\")\n        if value \u003C= 0:\n            raise ValueError(f\"width має бути > 0, отримано {value}\")\n        self._width = float(value)\n\n    @property\n    def height(self) -> float:\n        return self._height\n\n    @height.setter\n    def height(self, value: float) -> None:\n        if not isinstance(value, (int, float)):\n            raise TypeError(f\"height: очікується число, отримано {type(value).__name__}\")\n        if value \u003C= 0:\n            raise ValueError(f\"height має бути > 0, отримано {value}\")\n        self._height = float(value)\n\n    @property\n    def area(self) -> float:\n        \"\"\"Площа (read-only, обчислюється).\"\"\"\n        return self._width * self._height\n\n    @property\n    def perimeter(self) -> float:\n        \"\"\"Периметр (read-only, обчислюється).\"\"\"\n        return 2 * (self._width + self._height)\n\n    @property\n    def is_square(self) -> bool:\n        \"\"\"Чи є прямокутник квадратом.\"\"\"\n        return self._width == self._height\n\n    def __repr__(self) -> str:\n        return f\"Rectangle(width={self._width}, height={self._height})\"\n\n\n# Тести\nr = Rectangle(4, 6)\nprint(r)\nprint(f\"Площа:    {r.area}\")\nprint(f\"Периметр: {r.perimeter}\")\nprint(f\"Квадрат:  {r.is_square}\")\n\nr.width = 6.0\nprint(f\"\\nПісля width=6: {r}\")\nprint(f\"Квадрат тепер: {r.is_square}\")\n\nfor bad_value, label in [(-1, \"від'ємна\"), (0, \"нуль\"), (\"широко\", \"рядок\")]:\n    try:\n        r.width = bad_value\n    except (ValueError, TypeError) as e:\n        print(f\"[{label}] {type(e).__name__}: {e}\")\n",[5512,13011,13012,13017,13026,13030,13035,13040,13044,13048,13078,13083,13090,13097,13101,13107,13124,13133,13137,13142,13166,13184,13211,13222,13245,13256,13260,13266,13283,13292,13296,13301,13325,13343,13370,13380,13403,13414,13418,13424,13440,13445,13458,13462,13468,13485,13490,13509,13513,13519,13537,13542,13555,13559,13575,13604,13608,13612,13617,13632,13639,13660,13681,13703,13707,13715,13741,13762,13766,13808,13814,13819,13837],{"__ignoreMap":5526},[5530,13013,13014],{"class":5532,"line":5533},[5530,13015,13016],{"class":5536},"# rectangle.py\n",[5530,13018,13019,13021,13024],{"class":5532,"line":5540},[5530,13020,5832],{"class":5831},[5530,13022,13023],{"class":5835}," Rectangle",[5530,13025,5839],{"class":5543},[5530,13027,13028],{"class":5532,"line":5561},[5530,13029,7990],{"class":5547},[5530,13031,13032],{"class":5532,"line":5568},[5530,13033,13034],{"class":5547},"    Прямокутник з валідацією розмірів через @property.\n",[5530,13036,13037],{"class":5532,"line":5574},[5530,13038,13039],{"class":5547},"    Площа та периметр — обчислювальні властивості (read-only).\n",[5530,13041,13042],{"class":5532,"line":5586},[5530,13043,7990],{"class":5547},[5530,13045,13046],{"class":5532,"line":5598},[5530,13047,5565],{"emptyLinePlaceholder":5564},[5530,13049,13050,13052,13054,13056,13058,13060,13063,13065,13067,13069,13072,13074,13076],{"class":5532,"line":5603},[5530,13051,5844],{"class":5831},[5530,13053,5848],{"class":5847},[5530,13055,5851],{"class":5543},[5530,13057,5855],{"class":5854},[5530,13059,5551],{"class":5543},[5530,13061,13062],{"class":5854},"width",[5530,13064,5863],{"class":5543},[5530,13066,5649],{"class":5835},[5530,13068,5551],{"class":5543},[5530,13070,13071],{"class":5854},"height",[5530,13073,5863],{"class":5543},[5530,13075,5649],{"class":5835},[5530,13077,5877],{"class":5543},[5530,13079,13080],{"class":5532,"line":5609},[5530,13081,13082],{"class":5536},"        # Ці виклики проходять через сеттери — валідація відбувається вже тут\n",[5530,13084,13085,13087],{"class":5532,"line":5758},[5530,13086,5882],{"class":5831},[5530,13088,13089],{"class":5543},".width  = width\n",[5530,13091,13092,13094],{"class":5532,"line":5764},[5530,13093,5882],{"class":5831},[5530,13095,13096],{"class":5543},".height = height\n",[5530,13098,13099],{"class":5532,"line":5770},[5530,13100,5565],{"emptyLinePlaceholder":5564},[5530,13102,13103,13105],{"class":5532,"line":5775},[5530,13104,7565],{"class":5847},[5530,13106,7568],{"class":5835},[5530,13108,13109,13111,13114,13116,13118,13120,13122],{"class":5532,"line":5781},[5530,13110,5844],{"class":5831},[5530,13112,13113],{"class":5847}," width",[5530,13115,5851],{"class":5543},[5530,13117,5855],{"class":5854},[5530,13119,6063],{"class":5543},[5530,13121,5649],{"class":5835},[5530,13123,5839],{"class":5543},[5530,13125,13126,13128,13130],{"class":5532,"line":5786},[5530,13127,6243],{"class":6073},[5530,13129,6246],{"class":5831},[5530,13131,13132],{"class":5543},"._width\n",[5530,13134,13135],{"class":5532,"line":5792},[5530,13136,5565],{"emptyLinePlaceholder":5564},[5530,13138,13139],{"class":5532,"line":5798},[5530,13140,13141],{"class":5847},"    @width.setter\n",[5530,13143,13144,13146,13148,13150,13152,13154,13156,13158,13160,13162,13164],{"class":5532,"line":6187},[5530,13145,5844],{"class":5831},[5530,13147,13113],{"class":5847},[5530,13149,5851],{"class":5543},[5530,13151,5855],{"class":5854},[5530,13153,5551],{"class":5543},[5530,13155,7313],{"class":5854},[5530,13157,5863],{"class":5543},[5530,13159,5649],{"class":5835},[5530,13161,6063],{"class":5543},[5530,13163,6066],{"class":5831},[5530,13165,5839],{"class":5543},[5530,13167,13168,13170,13172,13174,13176,13178,13180,13182],{"class":5532,"line":6195},[5530,13169,6074],{"class":6073},[5530,13171,8134],{"class":5831},[5530,13173,8137],{"class":5847},[5530,13175,8140],{"class":5543},[5530,13177,8143],{"class":5835},[5530,13179,5551],{"class":5543},[5530,13181,5649],{"class":5835},[5530,13183,8150],{"class":5543},[5530,13185,13186,13188,13190,13192,13194,13197,13199,13201,13203,13205,13207,13209],{"class":5532,"line":6217},[5530,13187,6087],{"class":6073},[5530,13189,8157],{"class":5835},[5530,13191,5851],{"class":5543},[5530,13193,6114],{"class":5831},[5530,13195,13196],{"class":5547},"\"width: очікується число, отримано ",[5530,13198,6120],{"class":5831},[5530,13200,8169],{"class":5835},[5530,13202,8172],{"class":5543},[5530,13204,8175],{"class":5854},[5530,13206,6125],{"class":5831},[5530,13208,6128],{"class":5547},[5530,13210,5558],{"class":5543},[5530,13212,13213,13215,13218,13220],{"class":5532,"line":6222},[5530,13214,6074],{"class":6073},[5530,13216,13217],{"class":5543}," value \u003C= ",[5530,13219,6080],{"class":5554},[5530,13221,5839],{"class":5543},[5530,13223,13224,13226,13228,13230,13232,13235,13237,13239,13241,13243],{"class":5532,"line":6240},[5530,13225,6087],{"class":6073},[5530,13227,6090],{"class":5835},[5530,13229,5851],{"class":5543},[5530,13231,6114],{"class":5831},[5530,13233,13234],{"class":5547},"\"width має бути > 0, отримано ",[5530,13236,6120],{"class":5831},[5530,13238,7313],{"class":5543},[5530,13240,6125],{"class":5831},[5530,13242,6128],{"class":5547},[5530,13244,5558],{"class":5543},[5530,13246,13247,13249,13252,13254],{"class":5532,"line":6635},[5530,13248,5882],{"class":5831},[5530,13250,13251],{"class":5543},"._width = ",[5530,13253,5649],{"class":5835},[5530,13255,8229],{"class":5543},[5530,13257,13258],{"class":5532,"line":6640},[5530,13259,5565],{"emptyLinePlaceholder":5564},[5530,13261,13262,13264],{"class":5532,"line":6646},[5530,13263,7565],{"class":5847},[5530,13265,7568],{"class":5835},[5530,13267,13268,13270,13273,13275,13277,13279,13281],{"class":5532,"line":6659},[5530,13269,5844],{"class":5831},[5530,13271,13272],{"class":5847}," height",[5530,13274,5851],{"class":5543},[5530,13276,5855],{"class":5854},[5530,13278,6063],{"class":5543},[5530,13280,5649],{"class":5835},[5530,13282,5839],{"class":5543},[5530,13284,13285,13287,13289],{"class":5532,"line":6664},[5530,13286,6243],{"class":6073},[5530,13288,6246],{"class":5831},[5530,13290,13291],{"class":5543},"._height\n",[5530,13293,13294],{"class":5532,"line":6670},[5530,13295,5565],{"emptyLinePlaceholder":5564},[5530,13297,13298],{"class":5532,"line":6678},[5530,13299,13300],{"class":5847},"    @height.setter\n",[5530,13302,13303,13305,13307,13309,13311,13313,13315,13317,13319,13321,13323],{"class":5532,"line":6687},[5530,13304,5844],{"class":5831},[5530,13306,13272],{"class":5847},[5530,13308,5851],{"class":5543},[5530,13310,5855],{"class":5854},[5530,13312,5551],{"class":5543},[5530,13314,7313],{"class":5854},[5530,13316,5863],{"class":5543},[5530,13318,5649],{"class":5835},[5530,13320,6063],{"class":5543},[5530,13322,6066],{"class":5831},[5530,13324,5839],{"class":5543},[5530,13326,13327,13329,13331,13333,13335,13337,13339,13341],{"class":5532,"line":7770},[5530,13328,6074],{"class":6073},[5530,13330,8134],{"class":5831},[5530,13332,8137],{"class":5847},[5530,13334,8140],{"class":5543},[5530,13336,8143],{"class":5835},[5530,13338,5551],{"class":5543},[5530,13340,5649],{"class":5835},[5530,13342,8150],{"class":5543},[5530,13344,13345,13347,13349,13351,13353,13356,13358,13360,13362,13364,13366,13368],{"class":5532,"line":7793},[5530,13346,6087],{"class":6073},[5530,13348,8157],{"class":5835},[5530,13350,5851],{"class":5543},[5530,13352,6114],{"class":5831},[5530,13354,13355],{"class":5547},"\"height: очікується число, отримано ",[5530,13357,6120],{"class":5831},[5530,13359,8169],{"class":5835},[5530,13361,8172],{"class":5543},[5530,13363,8175],{"class":5854},[5530,13365,6125],{"class":5831},[5530,13367,6128],{"class":5547},[5530,13369,5558],{"class":5543},[5530,13371,13372,13374,13376,13378],{"class":5532,"line":7798},[5530,13373,6074],{"class":6073},[5530,13375,13217],{"class":5543},[5530,13377,6080],{"class":5554},[5530,13379,5839],{"class":5543},[5530,13381,13382,13384,13386,13388,13390,13393,13395,13397,13399,13401],{"class":5532,"line":7804},[5530,13383,6087],{"class":6073},[5530,13385,6090],{"class":5835},[5530,13387,5851],{"class":5543},[5530,13389,6114],{"class":5831},[5530,13391,13392],{"class":5547},"\"height має бути > 0, отримано ",[5530,13394,6120],{"class":5831},[5530,13396,7313],{"class":5543},[5530,13398,6125],{"class":5831},[5530,13400,6128],{"class":5547},[5530,13402,5558],{"class":5543},[5530,13404,13405,13407,13410,13412],{"class":5532,"line":7813},[5530,13406,5882],{"class":5831},[5530,13408,13409],{"class":5543},"._height = ",[5530,13411,5649],{"class":5835},[5530,13413,8229],{"class":5543},[5530,13415,13416],{"class":5532,"line":7835},[5530,13417,5565],{"emptyLinePlaceholder":5564},[5530,13419,13420,13422],{"class":5532,"line":7840},[5530,13421,7565],{"class":5847},[5530,13423,7568],{"class":5835},[5530,13425,13426,13428,13430,13432,13434,13436,13438],{"class":5532,"line":7846},[5530,13427,5844],{"class":5831},[5530,13429,7575],{"class":5847},[5530,13431,5851],{"class":5543},[5530,13433,5855],{"class":5854},[5530,13435,6063],{"class":5543},[5530,13437,5649],{"class":5835},[5530,13439,5839],{"class":5543},[5530,13441,13442],{"class":5532,"line":7853},[5530,13443,13444],{"class":5547},"        \"\"\"Площа (read-only, обчислюється).\"\"\"\n",[5530,13446,13447,13449,13451,13454,13456],{"class":5532,"line":7862},[5530,13448,6243],{"class":6073},[5530,13450,6246],{"class":5831},[5530,13452,13453],{"class":5543},"._width * ",[5530,13455,5855],{"class":5831},[5530,13457,13291],{"class":5543},[5530,13459,13460],{"class":5532,"line":7873},[5530,13461,5565],{"emptyLinePlaceholder":5564},[5530,13463,13464,13466],{"class":5532,"line":8384},[5530,13465,7565],{"class":5847},[5530,13467,7568],{"class":5835},[5530,13469,13470,13472,13475,13477,13479,13481,13483],{"class":5532,"line":8390},[5530,13471,5844],{"class":5831},[5530,13473,13474],{"class":5847}," perimeter",[5530,13476,5851],{"class":5543},[5530,13478,5855],{"class":5854},[5530,13480,6063],{"class":5543},[5530,13482,5649],{"class":5835},[5530,13484,5839],{"class":5543},[5530,13486,13487],{"class":5532,"line":8402},[5530,13488,13489],{"class":5547},"        \"\"\"Периметр (read-only, обчислюється).\"\"\"\n",[5530,13491,13492,13494,13496,13499,13501,13504,13506],{"class":5532,"line":8412},[5530,13493,6243],{"class":6073},[5530,13495,7644],{"class":5554},[5530,13497,13498],{"class":5543}," * (",[5530,13500,5855],{"class":5831},[5530,13502,13503],{"class":5543},"._width + ",[5530,13505,5855],{"class":5831},[5530,13507,13508],{"class":5543},"._height)\n",[5530,13510,13511],{"class":5532,"line":8417},[5530,13512,5565],{"emptyLinePlaceholder":5564},[5530,13514,13515,13517],{"class":5532,"line":8423},[5530,13516,7565],{"class":5847},[5530,13518,7568],{"class":5835},[5530,13520,13521,13523,13526,13528,13530,13532,13535],{"class":5532,"line":8428},[5530,13522,5844],{"class":5831},[5530,13524,13525],{"class":5847}," is_square",[5530,13527,5851],{"class":5543},[5530,13529,5855],{"class":5854},[5530,13531,6063],{"class":5543},[5530,13533,13534],{"class":5835},"bool",[5530,13536,5839],{"class":5543},[5530,13538,13539],{"class":5532,"line":8435},[5530,13540,13541],{"class":5547},"        \"\"\"Чи є прямокутник квадратом.\"\"\"\n",[5530,13543,13544,13546,13548,13551,13553],{"class":5532,"line":8453},[5530,13545,6243],{"class":6073},[5530,13547,6246],{"class":5831},[5530,13549,13550],{"class":5543},"._width == ",[5530,13552,5855],{"class":5831},[5530,13554,13291],{"class":5543},[5530,13556,13557],{"class":5532,"line":8459},[5530,13558,5565],{"emptyLinePlaceholder":5564},[5530,13560,13561,13563,13565,13567,13569,13571,13573],{"class":5532,"line":10597},[5530,13562,5844],{"class":5831},[5530,13564,12092],{"class":5847},[5530,13566,5851],{"class":5543},[5530,13568,5855],{"class":5854},[5530,13570,6063],{"class":5543},[5530,13572,5989],{"class":5835},[5530,13574,5839],{"class":5543},[5530,13576,13577,13579,13582,13585,13587,13590,13592,13595,13597,13600,13602],{"class":5532,"line":10622},[5530,13578,6243],{"class":6073},[5530,13580,13581],{"class":5831}," f",[5530,13583,13584],{"class":5547},"\"Rectangle(width=",[5530,13586,6857],{"class":5831},[5530,13588,13589],{"class":5543},"._width",[5530,13591,6125],{"class":5831},[5530,13593,13594],{"class":5547},", height=",[5530,13596,6857],{"class":5831},[5530,13598,13599],{"class":5543},"._height",[5530,13601,6125],{"class":5831},[5530,13603,12426],{"class":5547},[5530,13605,13606],{"class":5532,"line":10633},[5530,13607,5565],{"emptyLinePlaceholder":5564},[5530,13609,13610],{"class":5532,"line":10647},[5530,13611,5565],{"emptyLinePlaceholder":5564},[5530,13613,13614],{"class":5532,"line":10655},[5530,13615,13616],{"class":5536},"# Тести\n",[5530,13618,13619,13622,13625,13627,13630],{"class":5532,"line":10660},[5530,13620,13621],{"class":5543},"r = Rectangle(",[5530,13623,13624],{"class":5554},"4",[5530,13626,5551],{"class":5543},[5530,13628,13629],{"class":5554},"6",[5530,13631,5558],{"class":5543},[5530,13633,13634,13636],{"class":5532,"line":10665},[5530,13635,6283],{"class":5847},[5530,13637,13638],{"class":5543},"(r)\n",[5530,13640,13641,13643,13645,13647,13649,13651,13654,13656,13658],{"class":5532,"line":10676},[5530,13642,6283],{"class":5847},[5530,13644,5851],{"class":5543},[5530,13646,6114],{"class":5831},[5530,13648,7733],{"class":5547},[5530,13650,6120],{"class":5831},[5530,13652,13653],{"class":5543},"r.area",[5530,13655,6125],{"class":5831},[5530,13657,6128],{"class":5547},[5530,13659,5558],{"class":5543},[5530,13661,13662,13664,13666,13668,13670,13672,13675,13677,13679],{"class":5532,"line":10687},[5530,13663,6283],{"class":5847},[5530,13665,5851],{"class":5543},[5530,13667,6114],{"class":5831},[5530,13669,7756],{"class":5547},[5530,13671,6120],{"class":5831},[5530,13673,13674],{"class":5543},"r.perimeter",[5530,13676,6125],{"class":5831},[5530,13678,6128],{"class":5547},[5530,13680,5558],{"class":5543},[5530,13682,13683,13685,13687,13689,13692,13694,13697,13699,13701],{"class":5532,"line":10696},[5530,13684,6283],{"class":5847},[5530,13686,5851],{"class":5543},[5530,13688,6114],{"class":5831},[5530,13690,13691],{"class":5547},"\"Квадрат:  ",[5530,13693,6120],{"class":5831},[5530,13695,13696],{"class":5543},"r.is_square",[5530,13698,6125],{"class":5831},[5530,13700,6128],{"class":5547},[5530,13702,5558],{"class":5543},[5530,13704,13705],{"class":5532,"line":10706},[5530,13706,5565],{"emptyLinePlaceholder":5564},[5530,13708,13709,13712],{"class":5532,"line":10711},[5530,13710,13711],{"class":5543},"r.width = ",[5530,13713,13714],{"class":5554},"6.0\n",[5530,13716,13717,13719,13721,13723,13725,13727,13730,13732,13735,13737,13739],{"class":5532,"line":10718},[5530,13718,6283],{"class":5847},[5530,13720,5851],{"class":5543},[5530,13722,6114],{"class":5831},[5530,13724,6128],{"class":5547},[5530,13726,8589],{"class":8588},[5530,13728,13729],{"class":5547},"Після width=6: ",[5530,13731,6120],{"class":5831},[5530,13733,13734],{"class":5543},"r",[5530,13736,6125],{"class":5831},[5530,13738,6128],{"class":5547},[5530,13740,5558],{"class":5543},[5530,13742,13743,13745,13747,13749,13752,13754,13756,13758,13760],{"class":5532,"line":10726},[5530,13744,6283],{"class":5847},[5530,13746,5851],{"class":5543},[5530,13748,6114],{"class":5831},[5530,13750,13751],{"class":5547},"\"Квадрат тепер: ",[5530,13753,6120],{"class":5831},[5530,13755,13696],{"class":5543},[5530,13757,6125],{"class":5831},[5530,13759,6128],{"class":5547},[5530,13761,5558],{"class":5543},[5530,13763,13764],{"class":5532,"line":10737},[5530,13765,5565],{"emptyLinePlaceholder":5564},[5530,13767,13768,13770,13773,13775,13778,13780,13782,13785,13788,13790,13792,13795,13797,13800,13802,13805],{"class":5532,"line":12391},[5530,13769,12550],{"class":6073},[5530,13771,13772],{"class":5543}," bad_value, label ",[5530,13774,12556],{"class":6073},[5530,13776,13777],{"class":5543}," [(-",[5530,13779,12212],{"class":5554},[5530,13781,5551],{"class":5543},[5530,13783,13784],{"class":5547},"\"від'ємна\"",[5530,13786,13787],{"class":5543},"), (",[5530,13789,6080],{"class":5554},[5530,13791,5551],{"class":5543},[5530,13793,13794],{"class":5547},"\"нуль\"",[5530,13796,13787],{"class":5543},[5530,13798,13799],{"class":5547},"\"широко\"",[5530,13801,5551],{"class":5543},[5530,13803,13804],{"class":5547},"\"рядок\"",[5530,13806,13807],{"class":5543},")]:\n",[5530,13809,13810,13812],{"class":5532,"line":12429},[5530,13811,12782],{"class":6073},[5530,13813,5839],{"class":5543},[5530,13815,13816],{"class":5532,"line":12434},[5530,13817,13818],{"class":5543},"        r.width = bad_value\n",[5530,13820,13821,13823,13825,13827,13829,13831,13833,13835],{"class":5532,"line":12439},[5530,13822,12796],{"class":6073},[5530,13824,8277],{"class":5543},[5530,13826,12801],{"class":5835},[5530,13828,5551],{"class":5543},[5530,13830,12806],{"class":5835},[5530,13832,12809],{"class":5543},[5530,13834,12812],{"class":6073},[5530,13836,6610],{"class":5543},[5530,13838,13839,13841,13843,13845,13847,13849,13851,13853,13855,13857,13859,13861,13863,13865,13867,13869,13871,13873,13875],{"class":5532,"line":12444},[5530,13840,6847],{"class":5847},[5530,13842,5851],{"class":5543},[5530,13844,6114],{"class":5831},[5530,13846,12826],{"class":5547},[5530,13848,6120],{"class":5831},[5530,13850,12831],{"class":5543},[5530,13852,6125],{"class":5831},[5530,13854,12836],{"class":5547},[5530,13856,6120],{"class":5831},[5530,13858,8169],{"class":5835},[5530,13860,12843],{"class":5543},[5530,13862,8175],{"class":5854},[5530,13864,6125],{"class":5831},[5530,13866,5863],{"class":5547},[5530,13868,6120],{"class":5831},[5530,13870,6626],{"class":5543},[5530,13872,6125],{"class":5831},[5530,13874,6128],{"class":5547},[5530,13876,5558],{"class":5543},[6302,13878,13880,13888,13899,13906,13913,13921,13924,13934,13942,13945,13953,13961],{"title":13879},"python rectangle.py",[6306,13881,13883,6314,13886],{"className":13882},[5532],[5530,13884,6313],{"className":13885},[6312],[5629,13887,13879],{},[6306,13889,13891,13892,13594,13895,12888],{"className":13890},[5532],"Rectangle(width=",[5530,13893,5915],{"className":13894},[6720],[5530,13896,13898],{"className":13897},[6720],"6.0",[6306,13900,7906,13902],{"className":13901},[5532],[5530,13903,13905],{"className":13904},[6720],"24.0",[6306,13907,7914,13909],{"className":13908},[5532],[5530,13910,13912],{"className":13911},[6720],"20.0",[6306,13914,13916,13917],{"className":13915},[5532],"Квадрат:  ",[5530,13918,13920],{"className":13919},[6711],"False",[6306,13922],{"className":13923},[5532],[6306,13925,13927,13928,13594,13931,12888],{"className":13926},[5532],"Після width=6: Rectangle(width=",[5530,13929,13898],{"className":13930},[6720],[5530,13932,13898],{"className":13933},[6720],[6306,13935,13937,13938],{"className":13936},[5532],"Квадрат тепер: ",[5530,13939,13941],{"className":13940},[6720],"True",[6306,13943],{"className":13944},[5532],[6306,13946,13948,13949],{"className":13947},[5532],"[від'ємна] ",[5530,13950,13952],{"className":13951},[6711],"ValueError: width має бути > 0, отримано -1",[6306,13954,13956,13957],{"className":13955},[5532],"[нуль]     ",[5530,13958,13960],{"className":13959},[6711],"ValueError: width має бути > 0, отримано 0",[6306,13962,13964,13965],{"className":13963},[5532],"[рядок]    ",[5530,13966,13968],{"className":13967},[6711],"TypeError: width: очікується число, отримано str",[5666,13970],{},[5673,13972,13974],{"id":13973},"рівень-2-середній-система-профілів-користувачів","Рівень 2 (Середній): Система профілів користувачів",[5508,13976,13977,13978,13980],{},"Production-сценарій: комбінація ",[5512,13979,7199],{}," та перевикористовуваних дескрипторів.",[13982,13983,13984,15062,15699],"code-tree",{},[5521,13985,13988],{"className":5523,"code":13986,"filename":13987,"language":5525,"meta":5526,"style":5526},"# Перевикористовувані дескриптори-валідатори\n\nclass NonEmptyString:\n    \"\"\"Дескриптор: непорожній рядок з автоматичним trim.\"\"\"\n\n    def __set_name__(self, owner: type, name: str) -> None:\n        self.public_name  = name\n        self.private_name = f\"_{name}\"\n\n    def __get__(self, instance, owner):\n        if instance is None:\n            return self\n        return getattr(instance, self.private_name, \"\")\n\n    def __set__(self, instance, value: str) -> None:\n        if not isinstance(value, str):\n            raise TypeError(\n                f\"'{self.public_name}' має бути str, \"\n                f\"отримано {type(value).__name__!r}\"\n            )\n        cleaned = value.strip()\n        if not cleaned:\n            raise ValueError(f\"'{self.public_name}' не може бути порожнім\")\n        setattr(instance, self.private_name, cleaned)\n\n\nclass EmailAttribute:\n    \"\"\"Дескриптор: валідний email-адрес (normalize to lowercase).\"\"\"\n\n    def __set_name__(self, owner: type, name: str) -> None:\n        self.public_name  = name\n        self.private_name = f\"_{name}\"\n\n    def __get__(self, instance, owner):\n        if instance is None:\n            return self\n        return getattr(instance, self.private_name, \"\")\n\n    def __set__(self, instance, value: str) -> None:\n        if not isinstance(value, str):\n            raise TypeError(f\"'{self.public_name}' має бути str\")\n        normalized = value.strip().lower()\n        if normalized.count(\"@\") != 1:\n            raise ValueError(\n                f\"'{self.public_name}': email має містити рівно один '@'\"\n            )\n        local, domain = normalized.split(\"@\")\n        if not local:\n            raise ValueError(f\"'{self.public_name}': локальна частина порожня\")\n        if \".\" not in domain or domain.startswith(\".\") or domain.endswith(\".\"):\n            raise ValueError(\n                f\"'{self.public_name}': невалідна доменна частина '{domain}'\"\n            )\n        setattr(instance, self.private_name, normalized)\n\n\nclass PhoneNumber:\n    \"\"\"Дескриптор: номер телефону у форматі +XXXXXXXXXXX (10-15 цифр після +).\"\"\"\n\n    def __set_name__(self, owner: type, name: str) -> None:\n        self.public_name  = name\n        self.private_name = f\"_{name}\"\n\n    def __get__(self, instance, owner):\n        if instance is None:\n            return self\n        return getattr(instance, self.private_name, None)\n\n    def __set__(self, instance, value: str | None) -> None:\n        if value is None:\n            setattr(instance, self.private_name, None)\n            return\n        if not isinstance(value, str):\n            raise TypeError(f\"'{self.public_name}' має бути str або None\")\n        stripped = value.strip()\n        if not stripped.startswith(\"+\"):\n            raise ValueError(f\"'{self.public_name}': має починатися з '+'\")\n        digits = stripped[1:]\n        if not digits.isdigit():\n            raise ValueError(f\"'{self.public_name}': після '+' лише цифри\")\n        if not (10 \u003C= len(digits) \u003C= 15):\n            raise ValueError(\n                f\"'{self.public_name}': кількість цифр має бути 10–15, \"\n                f\"отримано {len(digits)}\"\n            )\n        setattr(instance, self.private_name, stripped)\n","validators.py",[5512,13989,13990,13995,13999,14008,14013,14017,14049,14055,14073,14077,14097,14109,14115,14132,14136,14164,14178,14186,14201,14219,14223,14228,14237,14260,14271,14275,14279,14288,14293,14297,14329,14335,14353,14357,14377,14389,14395,14411,14415,14443,14457,14480,14485,14502,14510,14525,14529,14538,14547,14570,14604,14612,14636,14640,14651,14655,14659,14668,14673,14677,14709,14715,14733,14737,14757,14769,14775,14791,14795,14828,14841,14856,14861,14875,14898,14903,14917,14940,14950,14959,14982,15007,15015,15030,15047,15051],{"__ignoreMap":5526},[5530,13991,13992],{"class":5532,"line":5533},[5530,13993,13994],{"class":5536},"# Перевикористовувані дескриптори-валідатори\n",[5530,13996,13997],{"class":5532,"line":5540},[5530,13998,5565],{"emptyLinePlaceholder":5564},[5530,14000,14001,14003,14006],{"class":5532,"line":5561},[5530,14002,5832],{"class":5831},[5530,14004,14005],{"class":5835}," NonEmptyString",[5530,14007,5839],{"class":5543},[5530,14009,14010],{"class":5532,"line":5568},[5530,14011,14012],{"class":5547},"    \"\"\"Дескриптор: непорожній рядок з автоматичним trim.\"\"\"\n",[5530,14014,14015],{"class":5532,"line":5574},[5530,14016,5565],{"emptyLinePlaceholder":5564},[5530,14018,14019,14021,14023,14025,14027,14029,14031,14033,14035,14037,14039,14041,14043,14045,14047],{"class":5532,"line":5586},[5530,14020,5844],{"class":5831},[5530,14022,11522],{"class":5847},[5530,14024,5851],{"class":5543},[5530,14026,5855],{"class":5854},[5530,14028,5551],{"class":5543},[5530,14030,5984],{"class":5854},[5530,14032,5863],{"class":5543},[5530,14034,8169],{"class":5835},[5530,14036,5551],{"class":5543},[5530,14038,11535],{"class":5854},[5530,14040,5863],{"class":5543},[5530,14042,5989],{"class":5835},[5530,14044,6063],{"class":5543},[5530,14046,6066],{"class":5831},[5530,14048,5839],{"class":5543},[5530,14050,14051,14053],{"class":5532,"line":5598},[5530,14052,5882],{"class":5831},[5530,14054,11790],{"class":5543},[5530,14056,14057,14059,14061,14063,14065,14067,14069,14071],{"class":5532,"line":5603},[5530,14058,5882],{"class":5831},[5530,14060,11564],{"class":5543},[5530,14062,6114],{"class":5831},[5530,14064,11569],{"class":5547},[5530,14066,6120],{"class":5831},[5530,14068,11535],{"class":5543},[5530,14070,6125],{"class":5831},[5530,14072,11809],{"class":5547},[5530,14074,14075],{"class":5532,"line":5609},[5530,14076,5565],{"emptyLinePlaceholder":5564},[5530,14078,14079,14081,14083,14085,14087,14089,14091,14093,14095],{"class":5532,"line":5758},[5530,14080,5844],{"class":5831},[5530,14082,10199],{"class":5847},[5530,14084,5851],{"class":5543},[5530,14086,5855],{"class":5854},[5530,14088,5551],{"class":5543},[5530,14090,9554],{"class":5854},[5530,14092,5551],{"class":5543},[5530,14094,5984],{"class":5854},[5530,14096,5877],{"class":5543},[5530,14098,14099,14101,14103,14105,14107],{"class":5532,"line":5764},[5530,14100,6074],{"class":6073},[5530,14102,10225],{"class":5543},[5530,14104,10228],{"class":5831},[5530,14106,10186],{"class":5831},[5530,14108,5839],{"class":5543},[5530,14110,14111,14113],{"class":5532,"line":5770},[5530,14112,10237],{"class":6073},[5530,14114,10240],{"class":5831},[5530,14116,14117,14119,14121,14123,14125,14127,14130],{"class":5532,"line":5775},[5530,14118,6243],{"class":6073},[5530,14120,11865],{"class":5847},[5530,14122,11868],{"class":5543},[5530,14124,5855],{"class":5831},[5530,14126,11873],{"class":5543},[5530,14128,14129],{"class":5547},"\"\"",[5530,14131,5558],{"class":5543},[5530,14133,14134],{"class":5532,"line":5781},[5530,14135,5565],{"emptyLinePlaceholder":5564},[5530,14137,14138,14140,14142,14144,14146,14148,14150,14152,14154,14156,14158,14160,14162],{"class":5532,"line":5786},[5530,14139,5844],{"class":5831},[5530,14141,10288],{"class":5847},[5530,14143,5851],{"class":5543},[5530,14145,5855],{"class":5854},[5530,14147,5551],{"class":5543},[5530,14149,9554],{"class":5854},[5530,14151,5551],{"class":5543},[5530,14153,7313],{"class":5854},[5530,14155,5863],{"class":5543},[5530,14157,5989],{"class":5835},[5530,14159,6063],{"class":5543},[5530,14161,6066],{"class":5831},[5530,14163,5839],{"class":5543},[5530,14165,14166,14168,14170,14172,14174,14176],{"class":5532,"line":5792},[5530,14167,6074],{"class":6073},[5530,14169,8134],{"class":5831},[5530,14171,8137],{"class":5847},[5530,14173,11925],{"class":5543},[5530,14175,5989],{"class":5835},[5530,14177,5877],{"class":5543},[5530,14179,14180,14182,14184],{"class":5532,"line":5798},[5530,14181,6087],{"class":6073},[5530,14183,8157],{"class":5835},[5530,14185,11938],{"class":5543},[5530,14187,14188,14190,14192,14194,14196,14198],{"class":5532,"line":6187},[5530,14189,11943],{"class":5831},[5530,14191,11946],{"class":5547},[5530,14193,6857],{"class":5831},[5530,14195,11951],{"class":5543},[5530,14197,6125],{"class":5831},[5530,14199,14200],{"class":5547},"' має бути str, \"\n",[5530,14202,14203,14205,14207,14209,14211,14213,14215,14217],{"class":5532,"line":6195},[5530,14204,11943],{"class":5831},[5530,14206,11963],{"class":5547},[5530,14208,6120],{"class":5831},[5530,14210,8169],{"class":5835},[5530,14212,8172],{"class":5543},[5530,14214,8175],{"class":5854},[5530,14216,11974],{"class":5831},[5530,14218,11809],{"class":5547},[5530,14220,14221],{"class":5532,"line":6217},[5530,14222,11981],{"class":5543},[5530,14224,14225],{"class":5532,"line":6222},[5530,14226,14227],{"class":5543},"        cleaned = value.strip()\n",[5530,14229,14230,14232,14234],{"class":5532,"line":6240},[5530,14231,6074],{"class":6073},[5530,14233,8134],{"class":5831},[5530,14235,14236],{"class":5543}," cleaned:\n",[5530,14238,14239,14241,14243,14245,14247,14249,14251,14253,14255,14258],{"class":5532,"line":6635},[5530,14240,6087],{"class":6073},[5530,14242,6090],{"class":5835},[5530,14244,5851],{"class":5543},[5530,14246,6114],{"class":5831},[5530,14248,11946],{"class":5547},[5530,14250,6857],{"class":5831},[5530,14252,11951],{"class":5543},[5530,14254,6125],{"class":5831},[5530,14256,14257],{"class":5547},"' не може бути порожнім\"",[5530,14259,5558],{"class":5543},[5530,14261,14262,14264,14266,14268],{"class":5532,"line":6640},[5530,14263,12074],{"class":5847},[5530,14265,11868],{"class":5543},[5530,14267,5855],{"class":5831},[5530,14269,14270],{"class":5543},".private_name, cleaned)\n",[5530,14272,14273],{"class":5532,"line":6646},[5530,14274,5565],{"emptyLinePlaceholder":5564},[5530,14276,14277],{"class":5532,"line":6659},[5530,14278,5565],{"emptyLinePlaceholder":5564},[5530,14280,14281,14283,14286],{"class":5532,"line":6664},[5530,14282,5832],{"class":5831},[5530,14284,14285],{"class":5835}," EmailAttribute",[5530,14287,5839],{"class":5543},[5530,14289,14290],{"class":5532,"line":6670},[5530,14291,14292],{"class":5547},"    \"\"\"Дескриптор: валідний email-адрес (normalize to lowercase).\"\"\"\n",[5530,14294,14295],{"class":5532,"line":6678},[5530,14296,5565],{"emptyLinePlaceholder":5564},[5530,14298,14299,14301,14303,14305,14307,14309,14311,14313,14315,14317,14319,14321,14323,14325,14327],{"class":5532,"line":6687},[5530,14300,5844],{"class":5831},[5530,14302,11522],{"class":5847},[5530,14304,5851],{"class":5543},[5530,14306,5855],{"class":5854},[5530,14308,5551],{"class":5543},[5530,14310,5984],{"class":5854},[5530,14312,5863],{"class":5543},[5530,14314,8169],{"class":5835},[5530,14316,5551],{"class":5543},[5530,14318,11535],{"class":5854},[5530,14320,5863],{"class":5543},[5530,14322,5989],{"class":5835},[5530,14324,6063],{"class":5543},[5530,14326,6066],{"class":5831},[5530,14328,5839],{"class":5543},[5530,14330,14331,14333],{"class":5532,"line":7770},[5530,14332,5882],{"class":5831},[5530,14334,11790],{"class":5543},[5530,14336,14337,14339,14341,14343,14345,14347,14349,14351],{"class":5532,"line":7793},[5530,14338,5882],{"class":5831},[5530,14340,11564],{"class":5543},[5530,14342,6114],{"class":5831},[5530,14344,11569],{"class":5547},[5530,14346,6120],{"class":5831},[5530,14348,11535],{"class":5543},[5530,14350,6125],{"class":5831},[5530,14352,11809],{"class":5547},[5530,14354,14355],{"class":5532,"line":7798},[5530,14356,5565],{"emptyLinePlaceholder":5564},[5530,14358,14359,14361,14363,14365,14367,14369,14371,14373,14375],{"class":5532,"line":7804},[5530,14360,5844],{"class":5831},[5530,14362,10199],{"class":5847},[5530,14364,5851],{"class":5543},[5530,14366,5855],{"class":5854},[5530,14368,5551],{"class":5543},[5530,14370,9554],{"class":5854},[5530,14372,5551],{"class":5543},[5530,14374,5984],{"class":5854},[5530,14376,5877],{"class":5543},[5530,14378,14379,14381,14383,14385,14387],{"class":5532,"line":7813},[5530,14380,6074],{"class":6073},[5530,14382,10225],{"class":5543},[5530,14384,10228],{"class":5831},[5530,14386,10186],{"class":5831},[5530,14388,5839],{"class":5543},[5530,14390,14391,14393],{"class":5532,"line":7835},[5530,14392,10237],{"class":6073},[5530,14394,10240],{"class":5831},[5530,14396,14397,14399,14401,14403,14405,14407,14409],{"class":5532,"line":7840},[5530,14398,6243],{"class":6073},[5530,14400,11865],{"class":5847},[5530,14402,11868],{"class":5543},[5530,14404,5855],{"class":5831},[5530,14406,11873],{"class":5543},[5530,14408,14129],{"class":5547},[5530,14410,5558],{"class":5543},[5530,14412,14413],{"class":5532,"line":7846},[5530,14414,5565],{"emptyLinePlaceholder":5564},[5530,14416,14417,14419,14421,14423,14425,14427,14429,14431,14433,14435,14437,14439,14441],{"class":5532,"line":7853},[5530,14418,5844],{"class":5831},[5530,14420,10288],{"class":5847},[5530,14422,5851],{"class":5543},[5530,14424,5855],{"class":5854},[5530,14426,5551],{"class":5543},[5530,14428,9554],{"class":5854},[5530,14430,5551],{"class":5543},[5530,14432,7313],{"class":5854},[5530,14434,5863],{"class":5543},[5530,14436,5989],{"class":5835},[5530,14438,6063],{"class":5543},[5530,14440,6066],{"class":5831},[5530,14442,5839],{"class":5543},[5530,14444,14445,14447,14449,14451,14453,14455],{"class":5532,"line":7862},[5530,14446,6074],{"class":6073},[5530,14448,8134],{"class":5831},[5530,14450,8137],{"class":5847},[5530,14452,11925],{"class":5543},[5530,14454,5989],{"class":5835},[5530,14456,5877],{"class":5543},[5530,14458,14459,14461,14463,14465,14467,14469,14471,14473,14475,14478],{"class":5532,"line":7873},[5530,14460,6087],{"class":6073},[5530,14462,8157],{"class":5835},[5530,14464,5851],{"class":5543},[5530,14466,6114],{"class":5831},[5530,14468,11946],{"class":5547},[5530,14470,6857],{"class":5831},[5530,14472,11951],{"class":5543},[5530,14474,6125],{"class":5831},[5530,14476,14477],{"class":5547},"' має бути str\"",[5530,14479,5558],{"class":5543},[5530,14481,14482],{"class":5532,"line":8384},[5530,14483,14484],{"class":5543},"        normalized = value.strip().lower()\n",[5530,14486,14487,14489,14492,14495,14498,14500],{"class":5532,"line":8390},[5530,14488,6074],{"class":6073},[5530,14490,14491],{"class":5543}," normalized.count(",[5530,14493,14494],{"class":5547},"\"@\"",[5530,14496,14497],{"class":5543},") != ",[5530,14499,12212],{"class":5554},[5530,14501,5839],{"class":5543},[5530,14503,14504,14506,14508],{"class":5532,"line":8402},[5530,14505,6087],{"class":6073},[5530,14507,6090],{"class":5835},[5530,14509,11938],{"class":5543},[5530,14511,14512,14514,14516,14518,14520,14522],{"class":5532,"line":8412},[5530,14513,11943],{"class":5831},[5530,14515,11946],{"class":5547},[5530,14517,6857],{"class":5831},[5530,14519,11951],{"class":5543},[5530,14521,6125],{"class":5831},[5530,14523,14524],{"class":5547},"': email має містити рівно один '@'\"\n",[5530,14526,14527],{"class":5532,"line":8417},[5530,14528,11981],{"class":5543},[5530,14530,14531,14534,14536],{"class":5532,"line":8423},[5530,14532,14533],{"class":5543},"        local, domain = normalized.split(",[5530,14535,14494],{"class":5547},[5530,14537,5558],{"class":5543},[5530,14539,14540,14542,14544],{"class":5532,"line":8428},[5530,14541,6074],{"class":6073},[5530,14543,8134],{"class":5831},[5530,14545,14546],{"class":5543}," local:\n",[5530,14548,14549,14551,14553,14555,14557,14559,14561,14563,14565,14568],{"class":5532,"line":8435},[5530,14550,6087],{"class":6073},[5530,14552,6090],{"class":5835},[5530,14554,5851],{"class":5543},[5530,14556,6114],{"class":5831},[5530,14558,11946],{"class":5547},[5530,14560,6857],{"class":5831},[5530,14562,11951],{"class":5543},[5530,14564,6125],{"class":5831},[5530,14566,14567],{"class":5547},"': локальна частина порожня\"",[5530,14569,5558],{"class":5543},[5530,14571,14572,14574,14577,14579,14582,14585,14587,14590,14593,14595,14597,14600,14602],{"class":5532,"line":8453},[5530,14573,6074],{"class":6073},[5530,14575,14576],{"class":5547}," \".\"",[5530,14578,8134],{"class":5831},[5530,14580,14581],{"class":5831}," in",[5530,14583,14584],{"class":5543}," domain ",[5530,14586,10169],{"class":5831},[5530,14588,14589],{"class":5543}," domain.startswith(",[5530,14591,14592],{"class":5547},"\".\"",[5530,14594,12809],{"class":5543},[5530,14596,10169],{"class":5831},[5530,14598,14599],{"class":5543}," domain.endswith(",[5530,14601,14592],{"class":5547},[5530,14603,5877],{"class":5543},[5530,14605,14606,14608,14610],{"class":5532,"line":8459},[5530,14607,6087],{"class":6073},[5530,14609,6090],{"class":5835},[5530,14611,11938],{"class":5543},[5530,14613,14614,14616,14618,14620,14622,14624,14627,14629,14632,14634],{"class":5532,"line":10597},[5530,14615,11943],{"class":5831},[5530,14617,11946],{"class":5547},[5530,14619,6857],{"class":5831},[5530,14621,11951],{"class":5543},[5530,14623,6125],{"class":5831},[5530,14625,14626],{"class":5547},"': невалідна доменна частина '",[5530,14628,6120],{"class":5831},[5530,14630,14631],{"class":5543},"domain",[5530,14633,6125],{"class":5831},[5530,14635,12150],{"class":5547},[5530,14637,14638],{"class":5532,"line":10622},[5530,14639,11981],{"class":5543},[5530,14641,14642,14644,14646,14648],{"class":5532,"line":10633},[5530,14643,12074],{"class":5847},[5530,14645,11868],{"class":5543},[5530,14647,5855],{"class":5831},[5530,14649,14650],{"class":5543},".private_name, normalized)\n",[5530,14652,14653],{"class":5532,"line":10647},[5530,14654,5565],{"emptyLinePlaceholder":5564},[5530,14656,14657],{"class":5532,"line":10655},[5530,14658,5565],{"emptyLinePlaceholder":5564},[5530,14660,14661,14663,14666],{"class":5532,"line":10660},[5530,14662,5832],{"class":5831},[5530,14664,14665],{"class":5835}," PhoneNumber",[5530,14667,5839],{"class":5543},[5530,14669,14670],{"class":5532,"line":10665},[5530,14671,14672],{"class":5547},"    \"\"\"Дескриптор: номер телефону у форматі +XXXXXXXXXXX (10-15 цифр після +).\"\"\"\n",[5530,14674,14675],{"class":5532,"line":10676},[5530,14676,5565],{"emptyLinePlaceholder":5564},[5530,14678,14679,14681,14683,14685,14687,14689,14691,14693,14695,14697,14699,14701,14703,14705,14707],{"class":5532,"line":10687},[5530,14680,5844],{"class":5831},[5530,14682,11522],{"class":5847},[5530,14684,5851],{"class":5543},[5530,14686,5855],{"class":5854},[5530,14688,5551],{"class":5543},[5530,14690,5984],{"class":5854},[5530,14692,5863],{"class":5543},[5530,14694,8169],{"class":5835},[5530,14696,5551],{"class":5543},[5530,14698,11535],{"class":5854},[5530,14700,5863],{"class":5543},[5530,14702,5989],{"class":5835},[5530,14704,6063],{"class":5543},[5530,14706,6066],{"class":5831},[5530,14708,5839],{"class":5543},[5530,14710,14711,14713],{"class":5532,"line":10696},[5530,14712,5882],{"class":5831},[5530,14714,11790],{"class":5543},[5530,14716,14717,14719,14721,14723,14725,14727,14729,14731],{"class":5532,"line":10706},[5530,14718,5882],{"class":5831},[5530,14720,11564],{"class":5543},[5530,14722,6114],{"class":5831},[5530,14724,11569],{"class":5547},[5530,14726,6120],{"class":5831},[5530,14728,11535],{"class":5543},[5530,14730,6125],{"class":5831},[5530,14732,11809],{"class":5547},[5530,14734,14735],{"class":5532,"line":10711},[5530,14736,5565],{"emptyLinePlaceholder":5564},[5530,14738,14739,14741,14743,14745,14747,14749,14751,14753,14755],{"class":5532,"line":10718},[5530,14740,5844],{"class":5831},[5530,14742,10199],{"class":5847},[5530,14744,5851],{"class":5543},[5530,14746,5855],{"class":5854},[5530,14748,5551],{"class":5543},[5530,14750,9554],{"class":5854},[5530,14752,5551],{"class":5543},[5530,14754,5984],{"class":5854},[5530,14756,5877],{"class":5543},[5530,14758,14759,14761,14763,14765,14767],{"class":5532,"line":10726},[5530,14760,6074],{"class":6073},[5530,14762,10225],{"class":5543},[5530,14764,10228],{"class":5831},[5530,14766,10186],{"class":5831},[5530,14768,5839],{"class":5543},[5530,14770,14771,14773],{"class":5532,"line":10737},[5530,14772,10237],{"class":6073},[5530,14774,10240],{"class":5831},[5530,14776,14777,14779,14781,14783,14785,14787,14789],{"class":5532,"line":12391},[5530,14778,6243],{"class":6073},[5530,14780,11865],{"class":5847},[5530,14782,11868],{"class":5543},[5530,14784,5855],{"class":5831},[5530,14786,11873],{"class":5543},[5530,14788,6066],{"class":5831},[5530,14790,5558],{"class":5543},[5530,14792,14793],{"class":5532,"line":12429},[5530,14794,5565],{"emptyLinePlaceholder":5564},[5530,14796,14797,14799,14801,14803,14805,14807,14809,14811,14813,14815,14817,14820,14822,14824,14826],{"class":5532,"line":12434},[5530,14798,5844],{"class":5831},[5530,14800,10288],{"class":5847},[5530,14802,5851],{"class":5543},[5530,14804,5855],{"class":5854},[5530,14806,5551],{"class":5543},[5530,14808,9554],{"class":5854},[5530,14810,5551],{"class":5543},[5530,14812,7313],{"class":5854},[5530,14814,5863],{"class":5543},[5530,14816,5989],{"class":5835},[5530,14818,14819],{"class":5543}," | ",[5530,14821,6066],{"class":5831},[5530,14823,6063],{"class":5543},[5530,14825,6066],{"class":5831},[5530,14827,5839],{"class":5543},[5530,14829,14830,14832,14835,14837,14839],{"class":5532,"line":12439},[5530,14831,6074],{"class":6073},[5530,14833,14834],{"class":5543}," value ",[5530,14836,10228],{"class":5831},[5530,14838,10186],{"class":5831},[5530,14840,5839],{"class":5543},[5530,14842,14843,14846,14848,14850,14852,14854],{"class":5532,"line":12444},[5530,14844,14845],{"class":5847},"            setattr",[5530,14847,11868],{"class":5543},[5530,14849,5855],{"class":5831},[5530,14851,11873],{"class":5543},[5530,14853,6066],{"class":5831},[5530,14855,5558],{"class":5543},[5530,14857,14858],{"class":5532,"line":12450},[5530,14859,14860],{"class":6073},"            return\n",[5530,14862,14863,14865,14867,14869,14871,14873],{"class":5532,"line":12473},[5530,14864,6074],{"class":6073},[5530,14866,8134],{"class":5831},[5530,14868,8137],{"class":5847},[5530,14870,11925],{"class":5543},[5530,14872,5989],{"class":5835},[5530,14874,5877],{"class":5543},[5530,14876,14877,14879,14881,14883,14885,14887,14889,14891,14893,14896],{"class":5532,"line":12481},[5530,14878,6087],{"class":6073},[5530,14880,8157],{"class":5835},[5530,14882,5851],{"class":5543},[5530,14884,6114],{"class":5831},[5530,14886,11946],{"class":5547},[5530,14888,6857],{"class":5831},[5530,14890,11951],{"class":5543},[5530,14892,6125],{"class":5831},[5530,14894,14895],{"class":5547},"' має бути str або None\"",[5530,14897,5558],{"class":5543},[5530,14899,14900],{"class":5532,"line":12486},[5530,14901,14902],{"class":5543},"        stripped = value.strip()\n",[5530,14904,14905,14907,14909,14912,14915],{"class":5532,"line":12495},[5530,14906,6074],{"class":6073},[5530,14908,8134],{"class":5831},[5530,14910,14911],{"class":5543}," stripped.startswith(",[5530,14913,14914],{"class":5547},"\"+\"",[5530,14916,5877],{"class":5543},[5530,14918,14919,14921,14923,14925,14927,14929,14931,14933,14935,14938],{"class":5532,"line":12518},[5530,14920,6087],{"class":6073},[5530,14922,6090],{"class":5835},[5530,14924,5851],{"class":5543},[5530,14926,6114],{"class":5831},[5530,14928,11946],{"class":5547},[5530,14930,6857],{"class":5831},[5530,14932,11951],{"class":5543},[5530,14934,6125],{"class":5831},[5530,14936,14937],{"class":5547},"': має починатися з '+'\"",[5530,14939,5558],{"class":5543},[5530,14941,14942,14945,14947],{"class":5532,"line":12523},[5530,14943,14944],{"class":5543},"        digits = stripped[",[5530,14946,12212],{"class":5554},[5530,14948,14949],{"class":5543},":]\n",[5530,14951,14952,14954,14956],{"class":5532,"line":12529},[5530,14953,6074],{"class":6073},[5530,14955,8134],{"class":5831},[5530,14957,14958],{"class":5543}," digits.isdigit():\n",[5530,14960,14961,14963,14965,14967,14969,14971,14973,14975,14977,14980],{"class":5532,"line":12583},[5530,14962,6087],{"class":6073},[5530,14964,6090],{"class":5835},[5530,14966,5851],{"class":5543},[5530,14968,6114],{"class":5831},[5530,14970,11946],{"class":5547},[5530,14972,6857],{"class":5831},[5530,14974,11951],{"class":5543},[5530,14976,6125],{"class":5831},[5530,14978,14979],{"class":5547},"': після '+' лише цифри\"",[5530,14981,5558],{"class":5543},[5530,14983,14984,14986,14988,14990,14993,14996,14999,15002,15005],{"class":5532,"line":12608},[5530,14985,6074],{"class":6073},[5530,14987,8134],{"class":5831},[5530,14989,8277],{"class":5543},[5530,14991,14992],{"class":5554},"10",[5530,14994,14995],{"class":5543}," \u003C= ",[5530,14997,14998],{"class":5847},"len",[5530,15000,15001],{"class":5543},"(digits) \u003C= ",[5530,15003,15004],{"class":5554},"15",[5530,15006,5877],{"class":5543},[5530,15008,15009,15011,15013],{"class":5532,"line":12613},[5530,15010,6087],{"class":6073},[5530,15012,6090],{"class":5835},[5530,15014,11938],{"class":5543},[5530,15016,15017,15019,15021,15023,15025,15027],{"class":5532,"line":12619},[5530,15018,11943],{"class":5831},[5530,15020,11946],{"class":5547},[5530,15022,6857],{"class":5831},[5530,15024,11951],{"class":5543},[5530,15026,6125],{"class":5831},[5530,15028,15029],{"class":5547},"': кількість цифр має бути 10–15, \"\n",[5530,15031,15032,15034,15036,15038,15040,15043,15045],{"class":5532,"line":12646},[5530,15033,11943],{"class":5831},[5530,15035,11963],{"class":5547},[5530,15037,6120],{"class":5831},[5530,15039,14998],{"class":5847},[5530,15041,15042],{"class":5543},"(digits)",[5530,15044,6125],{"class":5831},[5530,15046,11809],{"class":5547},[5530,15048,15049],{"class":5532,"line":12651},[5530,15050,11981],{"class":5543},[5530,15052,15053,15055,15057,15059],{"class":5532,"line":12657},[5530,15054,12074],{"class":5847},[5530,15056,11868],{"class":5543},[5530,15058,5855],{"class":5831},[5530,15060,15061],{"class":5543},".private_name, stripped)\n",[5521,15063,15066],{"className":5523,"code":15064,"filename":15065,"language":5525,"meta":5526,"style":5526},"from validators import NonEmptyString, EmailAttribute, PhoneNumber\n\nclass UserProfile:\n    \"\"\"\n    Профіль користувача з декларативною валідацією через дескриптори\n    та @property для обчислювальних полів.\n    \"\"\"\n\n    # Дескриптори (валідація автоматична при присвоєнні)\n    username   = NonEmptyString()\n    first_name = NonEmptyString()\n    last_name  = NonEmptyString()\n    email      = EmailAttribute()\n    phone      = PhoneNumber()   # може бути None\n\n    def __init__(\n        self,\n        username:   str,\n        first_name: str,\n        last_name:  str,\n        email:      str,\n        phone:      str | None = None,\n        balance:    float = 0.0,\n    ):\n        self.username   = username\n        self.first_name = first_name\n        self.last_name  = last_name\n        self.email      = email\n        self.phone      = phone\n        self.balance    = balance  # через @property.setter\n\n    # ── @property: баланс з валідацією ───────────────────────────────────────\n\n    @property\n    def balance(self) -> float:\n        return self._balance\n\n    @balance.setter\n    def balance(self, value: float) -> None:\n        if not isinstance(value, (int, float)):\n            raise TypeError(\"balance має бути числом\")\n        if value \u003C 0:\n            raise ValueError(f\"balance не може бути від'ємним, отримано {value}\")\n        self._balance = float(value)\n\n    # ── Обчислювальні властивості (read-only) ────────────────────────────────\n\n    @property\n    def full_name(self) -> str:\n        \"\"\"Повне ім'я: first_name + last_name.\"\"\"\n        return f\"{self.first_name} {self.last_name}\"\n\n    @property\n    def display_name(self) -> str:\n        \"\"\"Відображуване ім'я: 'First Last (@username)'.\"\"\"\n        return f\"{self.full_name} (@{self.username})\"\n\n    @property\n    def is_verified(self) -> bool:\n        \"\"\"Верифікований якщо є і email, і phone.\"\"\"\n        return bool(self.email and self.phone)\n\n    def __repr__(self) -> str:\n        return (\n            f\"UserProfile(username={self.username!r}, \"\n            f\"email={self.email!r}, balance={self._balance})\"\n        )\n","user_profile.py",[5512,15067,15068,15081,15085,15094,15098,15103,15108,15112,15116,15121,15126,15131,15136,15141,15149,15153,15161,15168,15179,15190,15202,15214,15233,15249,15254,15261,15268,15275,15282,15289,15299,15303,15308,15312,15318,15334,15342,15346,15350,15374,15392,15405,15415,15438,15449,15453,15458,15462,15468,15485,15490,15515,15519,15525,15542,15547,15574,15578,15584,15601,15606,15628,15632,15648,15654,15669,15695],{"__ignoreMap":5526},[5530,15069,15070,15073,15076,15078],{"class":5532,"line":5533},[5530,15071,15072],{"class":6073},"from",[5530,15074,15075],{"class":5543}," validators ",[5530,15077,7488],{"class":6073},[5530,15079,15080],{"class":5543}," NonEmptyString, EmailAttribute, PhoneNumber\n",[5530,15082,15083],{"class":5532,"line":5540},[5530,15084,5565],{"emptyLinePlaceholder":5564},[5530,15086,15087,15089,15092],{"class":5532,"line":5561},[5530,15088,5832],{"class":5831},[5530,15090,15091],{"class":5835}," UserProfile",[5530,15093,5839],{"class":5543},[5530,15095,15096],{"class":5532,"line":5568},[5530,15097,7990],{"class":5547},[5530,15099,15100],{"class":5532,"line":5574},[5530,15101,15102],{"class":5547},"    Профіль користувача з декларативною валідацією через дескриптори\n",[5530,15104,15105],{"class":5532,"line":5586},[5530,15106,15107],{"class":5547},"    та @property для обчислювальних полів.\n",[5530,15109,15110],{"class":5532,"line":5598},[5530,15111,7990],{"class":5547},[5530,15113,15114],{"class":5532,"line":5603},[5530,15115,5565],{"emptyLinePlaceholder":5564},[5530,15117,15118],{"class":5532,"line":5609},[5530,15119,15120],{"class":5536},"    # Дескриптори (валідація автоматична при присвоєнні)\n",[5530,15122,15123],{"class":5532,"line":5758},[5530,15124,15125],{"class":5543},"    username   = NonEmptyString()\n",[5530,15127,15128],{"class":5532,"line":5764},[5530,15129,15130],{"class":5543},"    first_name = NonEmptyString()\n",[5530,15132,15133],{"class":5532,"line":5770},[5530,15134,15135],{"class":5543},"    last_name  = NonEmptyString()\n",[5530,15137,15138],{"class":5532,"line":5775},[5530,15139,15140],{"class":5543},"    email      = EmailAttribute()\n",[5530,15142,15143,15146],{"class":5532,"line":5781},[5530,15144,15145],{"class":5543},"    phone      = PhoneNumber()   ",[5530,15147,15148],{"class":5536},"# може бути None\n",[5530,15150,15151],{"class":5532,"line":5786},[5530,15152,5565],{"emptyLinePlaceholder":5564},[5530,15154,15155,15157,15159],{"class":5532,"line":5792},[5530,15156,5844],{"class":5831},[5530,15158,5848],{"class":5847},[5530,15160,11938],{"class":5543},[5530,15162,15163,15165],{"class":5532,"line":5798},[5530,15164,5882],{"class":5854},[5530,15166,15167],{"class":5543},",\n",[5530,15169,15170,15173,15175,15177],{"class":5532,"line":6187},[5530,15171,15172],{"class":5854},"        username",[5530,15174,11242],{"class":5543},[5530,15176,5989],{"class":5835},[5530,15178,15167],{"class":5543},[5530,15180,15181,15184,15186,15188],{"class":5532,"line":6195},[5530,15182,15183],{"class":5854},"        first_name",[5530,15185,5863],{"class":5543},[5530,15187,5989],{"class":5835},[5530,15189,15167],{"class":5543},[5530,15191,15192,15195,15198,15200],{"class":5532,"line":6217},[5530,15193,15194],{"class":5854},"        last_name",[5530,15196,15197],{"class":5543},":  ",[5530,15199,5989],{"class":5835},[5530,15201,15167],{"class":5543},[5530,15203,15204,15207,15210,15212],{"class":5532,"line":6222},[5530,15205,15206],{"class":5854},"        email",[5530,15208,15209],{"class":5543},":      ",[5530,15211,5989],{"class":5835},[5530,15213,15167],{"class":5543},[5530,15215,15216,15219,15221,15223,15225,15227,15229,15231],{"class":5532,"line":6240},[5530,15217,15218],{"class":5854},"        phone",[5530,15220,15209],{"class":5543},[5530,15222,5989],{"class":5835},[5530,15224,14819],{"class":5543},[5530,15226,6066],{"class":5831},[5530,15228,12293],{"class":5543},[5530,15230,6066],{"class":5831},[5530,15232,15167],{"class":5543},[5530,15234,15235,15238,15241,15243,15245,15247],{"class":5532,"line":6635},[5530,15236,15237],{"class":5854},"        balance",[5530,15239,15240],{"class":5543},":    ",[5530,15242,5649],{"class":5835},[5530,15244,12293],{"class":5543},[5530,15246,8840],{"class":5554},[5530,15248,15167],{"class":5543},[5530,15250,15251],{"class":5532,"line":6640},[5530,15252,15253],{"class":5543},"    ):\n",[5530,15255,15256,15258],{"class":5532,"line":6646},[5530,15257,5882],{"class":5831},[5530,15259,15260],{"class":5543},".username   = username\n",[5530,15262,15263,15265],{"class":5532,"line":6659},[5530,15264,5882],{"class":5831},[5530,15266,15267],{"class":5543},".first_name = first_name\n",[5530,15269,15270,15272],{"class":5532,"line":6664},[5530,15271,5882],{"class":5831},[5530,15273,15274],{"class":5543},".last_name  = last_name\n",[5530,15276,15277,15279],{"class":5532,"line":6670},[5530,15278,5882],{"class":5831},[5530,15280,15281],{"class":5543},".email      = email\n",[5530,15283,15284,15286],{"class":5532,"line":6678},[5530,15285,5882],{"class":5831},[5530,15287,15288],{"class":5543},".phone      = phone\n",[5530,15290,15291,15293,15296],{"class":5532,"line":6687},[5530,15292,5882],{"class":5831},[5530,15294,15295],{"class":5543},".balance    = balance  ",[5530,15297,15298],{"class":5536},"# через @property.setter\n",[5530,15300,15301],{"class":5532,"line":7770},[5530,15302,5565],{"emptyLinePlaceholder":5564},[5530,15304,15305],{"class":5532,"line":7793},[5530,15306,15307],{"class":5536},"    # ── @property: баланс з валідацією ───────────────────────────────────────\n",[5530,15309,15310],{"class":5532,"line":7798},[5530,15311,5565],{"emptyLinePlaceholder":5564},[5530,15313,15314,15316],{"class":5532,"line":7804},[5530,15315,7565],{"class":5847},[5530,15317,7568],{"class":5835},[5530,15319,15320,15322,15324,15326,15328,15330,15332],{"class":5532,"line":7813},[5530,15321,5844],{"class":5831},[5530,15323,9195],{"class":5847},[5530,15325,5851],{"class":5543},[5530,15327,5855],{"class":5854},[5530,15329,6063],{"class":5543},[5530,15331,5649],{"class":5835},[5530,15333,5839],{"class":5543},[5530,15335,15336,15338,15340],{"class":5532,"line":7835},[5530,15337,6243],{"class":6073},[5530,15339,6246],{"class":5831},[5530,15341,6249],{"class":5543},[5530,15343,15344],{"class":5532,"line":7840},[5530,15345,5565],{"emptyLinePlaceholder":5564},[5530,15347,15348],{"class":5532,"line":7846},[5530,15349,9227],{"class":5847},[5530,15351,15352,15354,15356,15358,15360,15362,15364,15366,15368,15370,15372],{"class":5532,"line":7853},[5530,15353,5844],{"class":5831},[5530,15355,9195],{"class":5847},[5530,15357,5851],{"class":5543},[5530,15359,5855],{"class":5854},[5530,15361,5551],{"class":5543},[5530,15363,7313],{"class":5854},[5530,15365,5863],{"class":5543},[5530,15367,5649],{"class":5835},[5530,15369,6063],{"class":5543},[5530,15371,6066],{"class":5831},[5530,15373,5839],{"class":5543},[5530,15375,15376,15378,15380,15382,15384,15386,15388,15390],{"class":5532,"line":7862},[5530,15377,6074],{"class":6073},[5530,15379,8134],{"class":5831},[5530,15381,8137],{"class":5847},[5530,15383,8140],{"class":5543},[5530,15385,8143],{"class":5835},[5530,15387,5551],{"class":5543},[5530,15389,5649],{"class":5835},[5530,15391,8150],{"class":5543},[5530,15393,15394,15396,15398,15400,15403],{"class":5532,"line":7873},[5530,15395,6087],{"class":6073},[5530,15397,8157],{"class":5835},[5530,15399,5851],{"class":5543},[5530,15401,15402],{"class":5547},"\"balance має бути числом\"",[5530,15404,5558],{"class":5543},[5530,15406,15407,15409,15411,15413],{"class":5532,"line":8384},[5530,15408,6074],{"class":6073},[5530,15410,7329],{"class":5543},[5530,15412,6080],{"class":5554},[5530,15414,5839],{"class":5543},[5530,15416,15417,15419,15421,15423,15425,15428,15430,15432,15434,15436],{"class":5532,"line":8390},[5530,15418,6087],{"class":6073},[5530,15420,6090],{"class":5835},[5530,15422,5851],{"class":5543},[5530,15424,6114],{"class":5831},[5530,15426,15427],{"class":5547},"\"balance не може бути від'ємним, отримано ",[5530,15429,6120],{"class":5831},[5530,15431,7313],{"class":5543},[5530,15433,6125],{"class":5831},[5530,15435,6128],{"class":5547},[5530,15437,5558],{"class":5543},[5530,15439,15440,15442,15445,15447],{"class":5532,"line":8402},[5530,15441,5882],{"class":5831},[5530,15443,15444],{"class":5543},"._balance = ",[5530,15446,5649],{"class":5835},[5530,15448,8229],{"class":5543},[5530,15450,15451],{"class":5532,"line":8412},[5530,15452,5565],{"emptyLinePlaceholder":5564},[5530,15454,15455],{"class":5532,"line":8417},[5530,15456,15457],{"class":5536},"    # ── Обчислювальні властивості (read-only) ────────────────────────────────\n",[5530,15459,15460],{"class":5532,"line":8423},[5530,15461,5565],{"emptyLinePlaceholder":5564},[5530,15463,15464,15466],{"class":5532,"line":8428},[5530,15465,7565],{"class":5847},[5530,15467,7568],{"class":5835},[5530,15469,15470,15472,15475,15477,15479,15481,15483],{"class":5532,"line":8435},[5530,15471,5844],{"class":5831},[5530,15473,15474],{"class":5847}," full_name",[5530,15476,5851],{"class":5543},[5530,15478,5855],{"class":5854},[5530,15480,6063],{"class":5543},[5530,15482,5989],{"class":5835},[5530,15484,5839],{"class":5543},[5530,15486,15487],{"class":5532,"line":8453},[5530,15488,15489],{"class":5547},"        \"\"\"Повне ім'я: first_name + last_name.\"\"\"\n",[5530,15491,15492,15494,15496,15498,15500,15503,15505,15508,15511,15513],{"class":5532,"line":8459},[5530,15493,6243],{"class":6073},[5530,15495,13581],{"class":5831},[5530,15497,6128],{"class":5547},[5530,15499,6857],{"class":5831},[5530,15501,15502],{"class":5543},".first_name",[5530,15504,6125],{"class":5831},[5530,15506,15507],{"class":5831}," {self",[5530,15509,15510],{"class":5543},".last_name",[5530,15512,6125],{"class":5831},[5530,15514,11809],{"class":5547},[5530,15516,15517],{"class":5532,"line":10597},[5530,15518,5565],{"emptyLinePlaceholder":5564},[5530,15520,15521,15523],{"class":5532,"line":10622},[5530,15522,7565],{"class":5847},[5530,15524,7568],{"class":5835},[5530,15526,15527,15529,15532,15534,15536,15538,15540],{"class":5532,"line":10633},[5530,15528,5844],{"class":5831},[5530,15530,15531],{"class":5847}," display_name",[5530,15533,5851],{"class":5543},[5530,15535,5855],{"class":5854},[5530,15537,6063],{"class":5543},[5530,15539,5989],{"class":5835},[5530,15541,5839],{"class":5543},[5530,15543,15544],{"class":5532,"line":10647},[5530,15545,15546],{"class":5547},"        \"\"\"Відображуване ім'я: 'First Last (@username)'.\"\"\"\n",[5530,15548,15549,15551,15553,15555,15557,15560,15562,15565,15567,15570,15572],{"class":5532,"line":10655},[5530,15550,6243],{"class":6073},[5530,15552,13581],{"class":5831},[5530,15554,6128],{"class":5547},[5530,15556,6857],{"class":5831},[5530,15558,15559],{"class":5543},".full_name",[5530,15561,6125],{"class":5831},[5530,15563,15564],{"class":5547}," (@",[5530,15566,6857],{"class":5831},[5530,15568,15569],{"class":5543},".username",[5530,15571,6125],{"class":5831},[5530,15573,12426],{"class":5547},[5530,15575,15576],{"class":5532,"line":10660},[5530,15577,5565],{"emptyLinePlaceholder":5564},[5530,15579,15580,15582],{"class":5532,"line":10665},[5530,15581,7565],{"class":5847},[5530,15583,7568],{"class":5835},[5530,15585,15586,15588,15591,15593,15595,15597,15599],{"class":5532,"line":10676},[5530,15587,5844],{"class":5831},[5530,15589,15590],{"class":5847}," is_verified",[5530,15592,5851],{"class":5543},[5530,15594,5855],{"class":5854},[5530,15596,6063],{"class":5543},[5530,15598,13534],{"class":5835},[5530,15600,5839],{"class":5543},[5530,15602,15603],{"class":5532,"line":10687},[5530,15604,15605],{"class":5547},"        \"\"\"Верифікований якщо є і email, і phone.\"\"\"\n",[5530,15607,15608,15610,15613,15615,15617,15620,15623,15625],{"class":5532,"line":10696},[5530,15609,6243],{"class":6073},[5530,15611,15612],{"class":5835}," bool",[5530,15614,5851],{"class":5543},[5530,15616,5855],{"class":5831},[5530,15618,15619],{"class":5543},".email ",[5530,15621,15622],{"class":6073},"and",[5530,15624,6246],{"class":5831},[5530,15626,15627],{"class":5543},".phone)\n",[5530,15629,15630],{"class":5532,"line":10706},[5530,15631,5565],{"emptyLinePlaceholder":5564},[5530,15633,15634,15636,15638,15640,15642,15644,15646],{"class":5532,"line":10711},[5530,15635,5844],{"class":5831},[5530,15637,12092],{"class":5847},[5530,15639,5851],{"class":5543},[5530,15641,5855],{"class":5854},[5530,15643,6063],{"class":5543},[5530,15645,5989],{"class":5835},[5530,15647,5839],{"class":5543},[5530,15649,15650,15652],{"class":5532,"line":10718},[5530,15651,6243],{"class":6073},[5530,15653,12109],{"class":5543},[5530,15655,15656,15658,15661,15663,15665,15667],{"class":5532,"line":10726},[5530,15657,12114],{"class":5831},[5530,15659,15660],{"class":5547},"\"UserProfile(username=",[5530,15662,6857],{"class":5831},[5530,15664,15569],{"class":5543},[5530,15666,11974],{"class":5831},[5530,15668,12388],{"class":5547},[5530,15670,15671,15673,15676,15678,15681,15683,15686,15688,15691,15693],{"class":5532,"line":10737},[5530,15672,12114],{"class":5831},[5530,15674,15675],{"class":5547},"\"email=",[5530,15677,6857],{"class":5831},[5530,15679,15680],{"class":5543},".email",[5530,15682,11974],{"class":5831},[5530,15684,15685],{"class":5547},", balance=",[5530,15687,6857],{"class":5831},[5530,15689,15690],{"class":5543},"._balance",[5530,15692,6125],{"class":5831},[5530,15694,12426],{"class":5547},[5530,15696,15697],{"class":5532,"line":12391},[5530,15698,12155],{"class":5543},[5521,15700,15703],{"className":5523,"code":15701,"filename":15702,"language":5525,"meta":5526,"style":5526},"from user_profile import UserProfile\n\nprint(\"=== Створення валідного профілю ===\")\nuser = UserProfile(\n    username=\"arakviel\",\n    first_name=\"  Денис  \",   # зайві пробіли — автоматично прибираються\n    last_name=\"Арквіель\",\n    email=\"Denys@Example.COM\", # нормалізується до lowercase\n    phone=\"+380671234567\",\n    balance=150.50,\n)\nprint(user)\nprint(f\"display_name: {user.display_name}\")\nprint(f\"is_verified:  {user.is_verified}\")\nprint(f\"first_name (trimmed): {user.first_name!r}\")\nprint(f\"email (normalized):   {user.email!r}\")\n\nprint(\"\\n=== Перевірка валідації ===\")\ntests = [\n    (lambda: setattr(user, 'username', \"  \"),      \"username=пробіли\"),\n    (lambda: setattr(user, 'email', \"not-an-email\"),\"email=невалідний\"),\n    (lambda: setattr(user, 'phone', \"0671234567\"), \"phone без '+'\"),\n    (lambda: setattr(user, 'balance', -10.0),      \"balance=-10\"),\n]\nfor fn, label in tests:\n    try:\n        fn()\n    except (ValueError, TypeError) as e:\n        print(f\"[{label}] {type(e).__name__}: {e}\")\n","main.py",[5512,15704,15705,15717,15721,15732,15737,15749,15764,15776,15791,15803,15815,15819,15826,15848,15870,15892,15914,15918,15933,15937,15966,15994,16021,16047,16051,16061,16067,16071,16089],{"__ignoreMap":5526},[5530,15706,15707,15709,15712,15714],{"class":5532,"line":5533},[5530,15708,15072],{"class":6073},[5530,15710,15711],{"class":5543}," user_profile ",[5530,15713,7488],{"class":6073},[5530,15715,15716],{"class":5543}," UserProfile\n",[5530,15718,15719],{"class":5532,"line":5540},[5530,15720,5565],{"emptyLinePlaceholder":5564},[5530,15722,15723,15725,15727,15730],{"class":5532,"line":5561},[5530,15724,6283],{"class":5847},[5530,15726,5851],{"class":5543},[5530,15728,15729],{"class":5547},"\"=== Створення валідного профілю ===\"",[5530,15731,5558],{"class":5543},[5530,15733,15734],{"class":5532,"line":5568},[5530,15735,15736],{"class":5543},"user = UserProfile(\n",[5530,15738,15739,15742,15744,15747],{"class":5532,"line":5574},[5530,15740,15741],{"class":5854},"    username",[5530,15743,9447],{"class":5543},[5530,15745,15746],{"class":5547},"\"arakviel\"",[5530,15748,15167],{"class":5543},[5530,15750,15751,15754,15756,15759,15761],{"class":5532,"line":5586},[5530,15752,15753],{"class":5854},"    first_name",[5530,15755,9447],{"class":5543},[5530,15757,15758],{"class":5547},"\"  Денис  \"",[5530,15760,11446],{"class":5543},[5530,15762,15763],{"class":5536},"# зайві пробіли — автоматично прибираються\n",[5530,15765,15766,15769,15771,15774],{"class":5532,"line":5598},[5530,15767,15768],{"class":5854},"    last_name",[5530,15770,9447],{"class":5543},[5530,15772,15773],{"class":5547},"\"Арквіель\"",[5530,15775,15167],{"class":5543},[5530,15777,15778,15781,15783,15786,15788],{"class":5532,"line":5603},[5530,15779,15780],{"class":5854},"    email",[5530,15782,9447],{"class":5543},[5530,15784,15785],{"class":5547},"\"Denys@Example.COM\"",[5530,15787,5551],{"class":5543},[5530,15789,15790],{"class":5536},"# нормалізується до lowercase\n",[5530,15792,15793,15796,15798,15801],{"class":5532,"line":5609},[5530,15794,15795],{"class":5854},"    phone",[5530,15797,9447],{"class":5543},[5530,15799,15800],{"class":5547},"\"+380671234567\"",[5530,15802,15167],{"class":5543},[5530,15804,15805,15808,15810,15813],{"class":5532,"line":5758},[5530,15806,15807],{"class":5854},"    balance",[5530,15809,9447],{"class":5543},[5530,15811,15812],{"class":5554},"150.50",[5530,15814,15167],{"class":5543},[5530,15816,15817],{"class":5532,"line":5764},[5530,15818,5558],{"class":5543},[5530,15820,15821,15823],{"class":5532,"line":5770},[5530,15822,6283],{"class":5847},[5530,15824,15825],{"class":5543},"(user)\n",[5530,15827,15828,15830,15832,15834,15837,15839,15842,15844,15846],{"class":5532,"line":5775},[5530,15829,6283],{"class":5847},[5530,15831,5851],{"class":5543},[5530,15833,6114],{"class":5831},[5530,15835,15836],{"class":5547},"\"display_name: ",[5530,15838,6120],{"class":5831},[5530,15840,15841],{"class":5543},"user.display_name",[5530,15843,6125],{"class":5831},[5530,15845,6128],{"class":5547},[5530,15847,5558],{"class":5543},[5530,15849,15850,15852,15854,15856,15859,15861,15864,15866,15868],{"class":5532,"line":5781},[5530,15851,6283],{"class":5847},[5530,15853,5851],{"class":5543},[5530,15855,6114],{"class":5831},[5530,15857,15858],{"class":5547},"\"is_verified:  ",[5530,15860,6120],{"class":5831},[5530,15862,15863],{"class":5543},"user.is_verified",[5530,15865,6125],{"class":5831},[5530,15867,6128],{"class":5547},[5530,15869,5558],{"class":5543},[5530,15871,15872,15874,15876,15878,15881,15883,15886,15888,15890],{"class":5532,"line":5786},[5530,15873,6283],{"class":5847},[5530,15875,5851],{"class":5543},[5530,15877,6114],{"class":5831},[5530,15879,15880],{"class":5547},"\"first_name (trimmed): ",[5530,15882,6120],{"class":5831},[5530,15884,15885],{"class":5543},"user.first_name",[5530,15887,11974],{"class":5831},[5530,15889,6128],{"class":5547},[5530,15891,5558],{"class":5543},[5530,15893,15894,15896,15898,15900,15903,15905,15908,15910,15912],{"class":5532,"line":5792},[5530,15895,6283],{"class":5847},[5530,15897,5851],{"class":5543},[5530,15899,6114],{"class":5831},[5530,15901,15902],{"class":5547},"\"email (normalized):   ",[5530,15904,6120],{"class":5831},[5530,15906,15907],{"class":5543},"user.email",[5530,15909,11974],{"class":5831},[5530,15911,6128],{"class":5547},[5530,15913,5558],{"class":5543},[5530,15915,15916],{"class":5532,"line":5798},[5530,15917,5565],{"emptyLinePlaceholder":5564},[5530,15919,15920,15922,15924,15926,15928,15931],{"class":5532,"line":6187},[5530,15921,6283],{"class":5847},[5530,15923,5851],{"class":5543},[5530,15925,6128],{"class":5547},[5530,15927,8589],{"class":8588},[5530,15929,15930],{"class":5547},"=== Перевірка валідації ===\"",[5530,15932,5558],{"class":5543},[5530,15934,15935],{"class":5532,"line":6195},[5530,15936,12660],{"class":5543},[5530,15938,15939,15941,15943,15945,15947,15950,15953,15955,15958,15961,15964],{"class":5532,"line":6217},[5530,15940,12666],{"class":5543},[5530,15942,12669],{"class":5831},[5530,15944,5863],{"class":5543},[5530,15946,12674],{"class":5847},[5530,15948,15949],{"class":5543},"(user, ",[5530,15951,15952],{"class":5547},"'username'",[5530,15954,5551],{"class":5543},[5530,15956,15957],{"class":5547},"\"  \"",[5530,15959,15960],{"class":5543},"),      ",[5530,15962,15963],{"class":5547},"\"username=пробіли\"",[5530,15965,12694],{"class":5543},[5530,15967,15968,15970,15972,15974,15976,15978,15981,15983,15986,15989,15992],{"class":5532,"line":6222},[5530,15969,12666],{"class":5543},[5530,15971,12669],{"class":5831},[5530,15973,5863],{"class":5543},[5530,15975,12674],{"class":5847},[5530,15977,15949],{"class":5543},[5530,15979,15980],{"class":5547},"'email'",[5530,15982,5551],{"class":5543},[5530,15984,15985],{"class":5547},"\"not-an-email\"",[5530,15987,15988],{"class":5543},"),",[5530,15990,15991],{"class":5547},"\"email=невалідний\"",[5530,15993,12694],{"class":5543},[5530,15995,15996,15998,16000,16002,16004,16006,16009,16011,16014,16016,16019],{"class":5532,"line":6240},[5530,15997,12666],{"class":5543},[5530,15999,12669],{"class":5831},[5530,16001,5863],{"class":5543},[5530,16003,12674],{"class":5847},[5530,16005,15949],{"class":5543},[5530,16007,16008],{"class":5547},"'phone'",[5530,16010,5551],{"class":5543},[5530,16012,16013],{"class":5547},"\"0671234567\"",[5530,16015,12747],{"class":5543},[5530,16017,16018],{"class":5547},"\"phone без '+'\"",[5530,16020,12694],{"class":5543},[5530,16022,16023,16025,16027,16029,16031,16033,16036,16038,16040,16042,16045],{"class":5532,"line":6635},[5530,16024,12666],{"class":5543},[5530,16026,12669],{"class":5831},[5530,16028,5863],{"class":5543},[5530,16030,12674],{"class":5847},[5530,16032,15949],{"class":5543},[5530,16034,16035],{"class":5547},"'balance'",[5530,16037,12713],{"class":5543},[5530,16039,5925],{"class":5554},[5530,16041,15960],{"class":5543},[5530,16043,16044],{"class":5547},"\"balance=-10\"",[5530,16046,12694],{"class":5543},[5530,16048,16049],{"class":5532,"line":6640},[5530,16050,12758],{"class":5543},[5530,16052,16053,16055,16057,16059],{"class":5532,"line":6646},[5530,16054,12550],{"class":6073},[5530,16056,12771],{"class":5543},[5530,16058,12556],{"class":6073},[5530,16060,12776],{"class":5543},[5530,16062,16063,16065],{"class":5532,"line":6659},[5530,16064,12782],{"class":6073},[5530,16066,5839],{"class":5543},[5530,16068,16069],{"class":5532,"line":6664},[5530,16070,12790],{"class":5543},[5530,16072,16073,16075,16077,16079,16081,16083,16085,16087],{"class":5532,"line":6670},[5530,16074,12796],{"class":6073},[5530,16076,8277],{"class":5543},[5530,16078,12801],{"class":5835},[5530,16080,5551],{"class":5543},[5530,16082,12806],{"class":5835},[5530,16084,12809],{"class":5543},[5530,16086,12812],{"class":6073},[5530,16088,6610],{"class":5543},[5530,16090,16091,16093,16095,16097,16099,16101,16103,16105,16107,16109,16111,16113,16115,16117,16119,16121,16123,16125,16127],{"class":5532,"line":6678},[5530,16092,6847],{"class":5847},[5530,16094,5851],{"class":5543},[5530,16096,6114],{"class":5831},[5530,16098,12826],{"class":5547},[5530,16100,6120],{"class":5831},[5530,16102,12831],{"class":5543},[5530,16104,6125],{"class":5831},[5530,16106,12836],{"class":5547},[5530,16108,6120],{"class":5831},[5530,16110,8169],{"class":5835},[5530,16112,12843],{"class":5543},[5530,16114,8175],{"class":5854},[5530,16116,6125],{"class":5831},[5530,16118,5863],{"class":5547},[5530,16120,6120],{"class":5831},[5530,16122,6626],{"class":5543},[5530,16124,6125],{"class":5831},[5530,16126,6128],{"class":5547},[5530,16128,5558],{"class":5543},[6302,16130,16132,16140,16144,16161,16169,16176,16188,16199,16202,16206,16214,16222,16230],{"title":16131},"python main.py",[6306,16133,16135,6314,16138],{"className":16134},[5532],[5530,16136,6313],{"className":16137},[6312],[5629,16139,16131],{},[6306,16141,16143],{"className":16142},[5532],"=== Створення валідного профілю ===",[6306,16145,16147,16148,16152,16153,15685,16157,12888],{"className":16146},[5532],"UserProfile(username=",[5530,16149,16151],{"className":16150},[6720],"'arakviel'",", email=",[5530,16154,16156],{"className":16155},[6720],"'denys@example.com'",[5530,16158,16160],{"className":16159},[6720],"150.5",[6306,16162,16164,16165],{"className":16163},[5532],"display_name: ",[5530,16166,16168],{"className":16167},[6737],"Денис Арквіель (@arakviel)",[6306,16170,16172,16173],{"className":16171},[5532],"is_verified:  ",[5530,16174,13941],{"className":16175},[6720],[6306,16177,16179,16180,6738,16184],{"className":16178},[5532],"first_name (trimmed): ",[5530,16181,16183],{"className":16182},[6720],"'Денис'",[5530,16185,16187],{"className":16186},[6331],"# пробіли прибрані!",[6306,16189,16191,16192,6738,16195],{"className":16190},[5532],"email (normalized):   ",[5530,16193,16156],{"className":16194},[6720],[5530,16196,16198],{"className":16197},[6331],"# lowercase!",[6306,16200],{"className":16201},[5532],[6306,16203,16205],{"className":16204},[5532],"=== Перевірка валідації ===",[6306,16207,16209,16210],{"className":16208},[5532],"[username=пробіли]    ",[5530,16211,16213],{"className":16212},[6711],"ValueError: 'username' не може бути порожнім",[6306,16215,16217,16218],{"className":16216},[5532],"[email=невалідний]    ",[5530,16219,16221],{"className":16220},[6711],"ValueError: 'email': email має містити рівно один '@'",[6306,16223,16225,16226],{"className":16224},[5532],"[phone без '+']      ",[5530,16227,16229],{"className":16228},[6711],"ValueError: 'phone': має починатися з '+'",[6306,16231,16233,16234],{"className":16232},[5532],"[balance=-10]        ",[5530,16235,16237],{"className":16236},[6711],"ValueError: balance не може бути від'ємним, отримано -10.0",[5666,16239],{},[5673,16241,16243],{"id":16242},"рівень-3-advanced-універсальний-дескриптор-з-декларативними-правилами","Рівень 3 (Advanced): Універсальний дескриптор з декларативними правилами",[5508,16245,16246,16247,16250],{},"Реалізуйте ",[5512,16248,16249],{},"ValidatedField"," — дескриптор загального призначення, що приймає список функцій-валідаторів. Це архітектура, що використовується у спрощених ORM-системах (Django fields, SQLAlchemy columns).",[5521,16252,16254],{"className":5523,"code":16253,"language":5525,"meta":5526,"style":5526},"# validated_field.py\nfrom typing import Any, Callable\n\n\n# Тип: функція-валідатор повертає None (успіх) або рядок (повідомлення про помилку)\nValidator = Callable[[Any], str | None]\n\n\ndef min_value(minimum: float) -> Validator:\n    def validate(value) -> str | None:\n        if value \u003C minimum:\n            return f\"Значення {value} менше мінімуму {minimum}\"\n    return validate\n\ndef max_value(maximum: float) -> Validator:\n    def validate(value) -> str | None:\n        if value > maximum:\n            return f\"Значення {value} перевищує максимум {maximum}\"\n    return validate\n\ndef is_type(*types) -> Validator:\n    def validate(value) -> str | None:\n        if not isinstance(value, types):\n            names = \" | \".join(t.__name__ for t in types)\n            return f\"Очікується {names}, отримано {type(value).__name__}\"\n    return validate\n\ndef not_empty() -> Validator:\n    def validate(value) -> str | None:\n        if hasattr(value, '__len__') and len(value) == 0:\n            return \"Значення не може бути порожнім\"\n        if isinstance(value, str) and not value.strip():\n            return \"Рядок не може складатися лише з пробілів\"\n    return validate\n\ndef regex_match(pattern: str) -> Validator:\n    import re\n    compiled = re.compile(pattern)\n    def validate(value) -> str | None:\n        if not compiled.match(str(value)):\n            return f\"Значення '{value}' не відповідає шаблону '{pattern}'\"\n    return validate\n\n\nclass ValidatedField:\n    \"\"\"\n    Універсальний дескриптор з декларативними правилами валідації.\n    Приймає довільну кількість функцій-валідаторів.\n    \"\"\"\n\n    def __init__(self, *validators: Validator, default=None):\n        self.validators   = validators\n        self.default      = default\n        self.public_name  = None\n        self.private_name = None\n\n    def __set_name__(self, owner: type, name: str) -> None:\n        self.public_name  = name\n        self.private_name = f\"_{name}\"\n\n    def __get__(self, instance, owner):\n        if instance is None:\n            return self\n        return getattr(instance, self.private_name, self.default)\n\n    def __set__(self, instance, value) -> None:\n        errors = []\n        for validator in self.validators:\n            error = validator(value)\n            if error is not None:\n                errors.append(error)\n        if errors:\n            raise ValueError(\n                f\"Поле '{self.public_name}': \" + \"; \".join(errors)\n            )\n        setattr(instance, self.private_name, value)\n\n    def __repr__(self) -> str:\n        return (\n            f\"ValidatedField({len(self.validators)} validators\"\n            f\"{', default=' + repr(self.default) if self.default is not None else ''})\"\n        )\n\n\n# ── Застосування: декларативна модель продукту ────────────────────────────────\n\nclass Product:\n    name = ValidatedField(\n        is_type(str),\n        not_empty(),\n    )\n    price = ValidatedField(\n        is_type(int, float),\n        min_value(0.01),\n        max_value(1_000_000),\n    )\n    sku = ValidatedField(\n        is_type(str),\n        regex_match(r\"^[A-Z]{2,4}-\\d{4,8}$\"),\n    )\n    stock = ValidatedField(\n        is_type(int),\n        min_value(0),\n        default=0,\n    )\n\n    def __init__(self, name: str, price: float, sku: str, stock: int = 0):\n        self.name  = name\n        self.price = price\n        self.sku   = sku\n        self.stock = stock\n\n    def __repr__(self) -> str:\n        return f\"Product({self.name!r}, price={self.price}, sku={self.sku!r})\"\n\n\n# Тести\nprint(\"=== Валідний продукт ===\")\np = Product(\"MacBook Pro\", 89999.0, \"MBP-20242\", stock=5)\nprint(p)\nprint(f\"stock (default worked): {p.stock}\")\n\nprint(\"\\n=== Тести валідації ===\")\nerrors_tests = [\n    (lambda: setattr(p, 'price', -1),      \"price=-1\"),\n    (lambda: setattr(p, 'price', 2_000_000),\"price=2M (>max)\"),\n    (lambda: setattr(p, 'sku', \"invalid\"), \"sku='invalid'\"),\n    (lambda: setattr(p, 'stock', -5),      \"stock=-5\"),\n    (lambda: setattr(p, 'name', \"\"),       \"name=''\"),\n]\nfor fn, label in errors_tests:\n    try:\n        fn()\n    except ValueError as e:\n        print(f\"[{label}]\\n  {e}\")\n",[5512,16255,16256,16261,16273,16277,16281,16286,16299,16303,16307,16326,16347,16354,16380,16387,16391,16409,16429,16436,16461,16467,16471,16486,16506,16517,16541,16572,16578,16582,16592,16612,16638,16645,16664,16671,16677,16681,16699,16707,16712,16732,16746,16772,16778,16782,16786,16795,16799,16804,16809,16813,16817,16845,16852,16859,16867,16875,16879,16911,16917,16935,16939,16959,16971,16977,16994,16998,17022,17027,17042,17047,17063,17068,17075,17083,17108,17112,17122,17126,17142,17148,17171,17218,17222,17226,17230,17235,17239,17248,17253,17262,17267,17272,17277,17289,17299,17309,17313,17319,17328,17365,17370,17376,17385,17394,17406,17411,17416,17468,17476,17484,17492,17500,17505,17522,17560,17565,17570,17575,17587,17616,17624,17647,17652,17668,17674,17702,17729,17757,17784,17812,17817,17829,17836,17841,17852],{"__ignoreMap":5526},[5530,16257,16258],{"class":5532,"line":5533},[5530,16259,16260],{"class":5536},"# validated_field.py\n",[5530,16262,16263,16265,16268,16270],{"class":5532,"line":5540},[5530,16264,15072],{"class":6073},[5530,16266,16267],{"class":5543}," typing ",[5530,16269,7488],{"class":6073},[5530,16271,16272],{"class":5543}," Any, Callable\n",[5530,16274,16275],{"class":5532,"line":5561},[5530,16276,5565],{"emptyLinePlaceholder":5564},[5530,16278,16279],{"class":5532,"line":5568},[5530,16280,5565],{"emptyLinePlaceholder":5564},[5530,16282,16283],{"class":5532,"line":5574},[5530,16284,16285],{"class":5536},"# Тип: функція-валідатор повертає None (успіх) або рядок (повідомлення про помилку)\n",[5530,16287,16288,16291,16293,16295,16297],{"class":5532,"line":5586},[5530,16289,16290],{"class":5543},"Validator = Callable[[Any], ",[5530,16292,5989],{"class":5835},[5530,16294,14819],{"class":5543},[5530,16296,6066],{"class":5831},[5530,16298,12758],{"class":5543},[5530,16300,16301],{"class":5532,"line":5598},[5530,16302,5565],{"emptyLinePlaceholder":5564},[5530,16304,16305],{"class":5532,"line":5603},[5530,16306,5565],{"emptyLinePlaceholder":5564},[5530,16308,16309,16311,16314,16316,16319,16321,16323],{"class":5532,"line":5609},[5530,16310,9053],{"class":5831},[5530,16312,16313],{"class":5847}," min_value",[5530,16315,5851],{"class":5543},[5530,16317,16318],{"class":5854},"minimum",[5530,16320,5863],{"class":5543},[5530,16322,5649],{"class":5835},[5530,16324,16325],{"class":5543},") -> Validator:\n",[5530,16327,16328,16330,16333,16335,16337,16339,16341,16343,16345],{"class":5532,"line":5758},[5530,16329,5844],{"class":5831},[5530,16331,16332],{"class":5847}," validate",[5530,16334,5851],{"class":5543},[5530,16336,7313],{"class":5854},[5530,16338,6063],{"class":5543},[5530,16340,5989],{"class":5835},[5530,16342,14819],{"class":5543},[5530,16344,6066],{"class":5831},[5530,16346,5839],{"class":5543},[5530,16348,16349,16351],{"class":5532,"line":5764},[5530,16350,6074],{"class":6073},[5530,16352,16353],{"class":5543}," value \u003C minimum:\n",[5530,16355,16356,16358,16360,16363,16365,16367,16369,16372,16374,16376,16378],{"class":5532,"line":5770},[5530,16357,10237],{"class":6073},[5530,16359,13581],{"class":5831},[5530,16361,16362],{"class":5547},"\"Значення ",[5530,16364,6120],{"class":5831},[5530,16366,7313],{"class":5543},[5530,16368,6125],{"class":5831},[5530,16370,16371],{"class":5547}," менше мінімуму ",[5530,16373,6120],{"class":5831},[5530,16375,16318],{"class":5543},[5530,16377,6125],{"class":5831},[5530,16379,11809],{"class":5547},[5530,16381,16382,16384],{"class":5532,"line":5775},[5530,16383,9070],{"class":6073},[5530,16385,16386],{"class":5543}," validate\n",[5530,16388,16389],{"class":5532,"line":5781},[5530,16390,5565],{"emptyLinePlaceholder":5564},[5530,16392,16393,16395,16398,16400,16403,16405,16407],{"class":5532,"line":5786},[5530,16394,9053],{"class":5831},[5530,16396,16397],{"class":5847}," max_value",[5530,16399,5851],{"class":5543},[5530,16401,16402],{"class":5854},"maximum",[5530,16404,5863],{"class":5543},[5530,16406,5649],{"class":5835},[5530,16408,16325],{"class":5543},[5530,16410,16411,16413,16415,16417,16419,16421,16423,16425,16427],{"class":5532,"line":5792},[5530,16412,5844],{"class":5831},[5530,16414,16332],{"class":5847},[5530,16416,5851],{"class":5543},[5530,16418,7313],{"class":5854},[5530,16420,6063],{"class":5543},[5530,16422,5989],{"class":5835},[5530,16424,14819],{"class":5543},[5530,16426,6066],{"class":5831},[5530,16428,5839],{"class":5543},[5530,16430,16431,16433],{"class":5532,"line":5798},[5530,16432,6074],{"class":6073},[5530,16434,16435],{"class":5543}," value > maximum:\n",[5530,16437,16438,16440,16442,16444,16446,16448,16450,16453,16455,16457,16459],{"class":5532,"line":6187},[5530,16439,10237],{"class":6073},[5530,16441,13581],{"class":5831},[5530,16443,16362],{"class":5547},[5530,16445,6120],{"class":5831},[5530,16447,7313],{"class":5543},[5530,16449,6125],{"class":5831},[5530,16451,16452],{"class":5547}," перевищує максимум ",[5530,16454,6120],{"class":5831},[5530,16456,16402],{"class":5543},[5530,16458,6125],{"class":5831},[5530,16460,11809],{"class":5547},[5530,16462,16463,16465],{"class":5532,"line":6195},[5530,16464,9070],{"class":6073},[5530,16466,16386],{"class":5543},[5530,16468,16469],{"class":5532,"line":6217},[5530,16470,5565],{"emptyLinePlaceholder":5564},[5530,16472,16473,16475,16478,16481,16484],{"class":5532,"line":6222},[5530,16474,9053],{"class":5831},[5530,16476,16477],{"class":5847}," is_type",[5530,16479,16480],{"class":5543},"(*",[5530,16482,16483],{"class":5854},"types",[5530,16485,16325],{"class":5543},[5530,16487,16488,16490,16492,16494,16496,16498,16500,16502,16504],{"class":5532,"line":6240},[5530,16489,5844],{"class":5831},[5530,16491,16332],{"class":5847},[5530,16493,5851],{"class":5543},[5530,16495,7313],{"class":5854},[5530,16497,6063],{"class":5543},[5530,16499,5989],{"class":5835},[5530,16501,14819],{"class":5543},[5530,16503,6066],{"class":5831},[5530,16505,5839],{"class":5543},[5530,16507,16508,16510,16512,16514],{"class":5532,"line":6635},[5530,16509,6074],{"class":6073},[5530,16511,8134],{"class":5831},[5530,16513,8137],{"class":5847},[5530,16515,16516],{"class":5543},"(value, types):\n",[5530,16518,16519,16522,16525,16528,16530,16533,16536,16538],{"class":5532,"line":6640},[5530,16520,16521],{"class":5543},"            names = ",[5530,16523,16524],{"class":5547},"\" | \"",[5530,16526,16527],{"class":5543},".join(t.",[5530,16529,8175],{"class":5854},[5530,16531,16532],{"class":6073}," for",[5530,16534,16535],{"class":5543}," t ",[5530,16537,12556],{"class":6073},[5530,16539,16540],{"class":5543}," types)\n",[5530,16542,16543,16545,16547,16550,16552,16555,16557,16560,16562,16564,16566,16568,16570],{"class":5532,"line":6646},[5530,16544,10237],{"class":6073},[5530,16546,13581],{"class":5831},[5530,16548,16549],{"class":5547},"\"Очікується ",[5530,16551,6120],{"class":5831},[5530,16553,16554],{"class":5543},"names",[5530,16556,6125],{"class":5831},[5530,16558,16559],{"class":5547},", отримано ",[5530,16561,6120],{"class":5831},[5530,16563,8169],{"class":5835},[5530,16565,8172],{"class":5543},[5530,16567,8175],{"class":5854},[5530,16569,6125],{"class":5831},[5530,16571,11809],{"class":5547},[5530,16573,16574,16576],{"class":5532,"line":6659},[5530,16575,9070],{"class":6073},[5530,16577,16386],{"class":5543},[5530,16579,16580],{"class":5532,"line":6664},[5530,16581,5565],{"emptyLinePlaceholder":5564},[5530,16583,16584,16586,16589],{"class":5532,"line":6670},[5530,16585,9053],{"class":5831},[5530,16587,16588],{"class":5847}," not_empty",[5530,16590,16591],{"class":5543},"() -> Validator:\n",[5530,16593,16594,16596,16598,16600,16602,16604,16606,16608,16610],{"class":5532,"line":6678},[5530,16595,5844],{"class":5831},[5530,16597,16332],{"class":5847},[5530,16599,5851],{"class":5543},[5530,16601,7313],{"class":5854},[5530,16603,6063],{"class":5543},[5530,16605,5989],{"class":5835},[5530,16607,14819],{"class":5543},[5530,16609,6066],{"class":5831},[5530,16611,5839],{"class":5543},[5530,16613,16614,16616,16619,16621,16624,16626,16628,16631,16634,16636],{"class":5532,"line":6687},[5530,16615,6074],{"class":6073},[5530,16617,16618],{"class":5847}," hasattr",[5530,16620,11925],{"class":5543},[5530,16622,16623],{"class":5547},"'__len__'",[5530,16625,12809],{"class":5543},[5530,16627,15622],{"class":5831},[5530,16629,16630],{"class":5847}," len",[5530,16632,16633],{"class":5543},"(value) == ",[5530,16635,6080],{"class":5554},[5530,16637,5839],{"class":5543},[5530,16639,16640,16642],{"class":5532,"line":7770},[5530,16641,10237],{"class":6073},[5530,16643,16644],{"class":5547}," \"Значення не може бути порожнім\"\n",[5530,16646,16647,16649,16651,16653,16655,16657,16659,16661],{"class":5532,"line":7793},[5530,16648,6074],{"class":6073},[5530,16650,8137],{"class":5847},[5530,16652,11925],{"class":5543},[5530,16654,5989],{"class":5835},[5530,16656,12809],{"class":5543},[5530,16658,15622],{"class":5831},[5530,16660,8134],{"class":5831},[5530,16662,16663],{"class":5543}," value.strip():\n",[5530,16665,16666,16668],{"class":5532,"line":7798},[5530,16667,10237],{"class":6073},[5530,16669,16670],{"class":5547}," \"Рядок не може складатися лише з пробілів\"\n",[5530,16672,16673,16675],{"class":5532,"line":7804},[5530,16674,9070],{"class":6073},[5530,16676,16386],{"class":5543},[5530,16678,16679],{"class":5532,"line":7813},[5530,16680,5565],{"emptyLinePlaceholder":5564},[5530,16682,16683,16685,16688,16690,16693,16695,16697],{"class":5532,"line":7835},[5530,16684,9053],{"class":5831},[5530,16686,16687],{"class":5847}," regex_match",[5530,16689,5851],{"class":5543},[5530,16691,16692],{"class":5854},"pattern",[5530,16694,5863],{"class":5543},[5530,16696,5989],{"class":5835},[5530,16698,16325],{"class":5543},[5530,16700,16701,16704],{"class":5532,"line":7840},[5530,16702,16703],{"class":6073},"    import",[5530,16705,16706],{"class":5543}," re\n",[5530,16708,16709],{"class":5532,"line":7846},[5530,16710,16711],{"class":5543},"    compiled = re.compile(pattern)\n",[5530,16713,16714,16716,16718,16720,16722,16724,16726,16728,16730],{"class":5532,"line":7853},[5530,16715,5844],{"class":5831},[5530,16717,16332],{"class":5847},[5530,16719,5851],{"class":5543},[5530,16721,7313],{"class":5854},[5530,16723,6063],{"class":5543},[5530,16725,5989],{"class":5835},[5530,16727,14819],{"class":5543},[5530,16729,6066],{"class":5831},[5530,16731,5839],{"class":5543},[5530,16733,16734,16736,16738,16741,16743],{"class":5532,"line":7862},[5530,16735,6074],{"class":6073},[5530,16737,8134],{"class":5831},[5530,16739,16740],{"class":5543}," compiled.match(",[5530,16742,5989],{"class":5835},[5530,16744,16745],{"class":5543},"(value)):\n",[5530,16747,16748,16750,16752,16755,16757,16759,16761,16764,16766,16768,16770],{"class":5532,"line":7873},[5530,16749,10237],{"class":6073},[5530,16751,13581],{"class":5831},[5530,16753,16754],{"class":5547},"\"Значення '",[5530,16756,6120],{"class":5831},[5530,16758,7313],{"class":5543},[5530,16760,6125],{"class":5831},[5530,16762,16763],{"class":5547},"' не відповідає шаблону '",[5530,16765,6120],{"class":5831},[5530,16767,16692],{"class":5543},[5530,16769,6125],{"class":5831},[5530,16771,12150],{"class":5547},[5530,16773,16774,16776],{"class":5532,"line":8384},[5530,16775,9070],{"class":6073},[5530,16777,16386],{"class":5543},[5530,16779,16780],{"class":5532,"line":8390},[5530,16781,5565],{"emptyLinePlaceholder":5564},[5530,16783,16784],{"class":5532,"line":8402},[5530,16785,5565],{"emptyLinePlaceholder":5564},[5530,16787,16788,16790,16793],{"class":5532,"line":8412},[5530,16789,5832],{"class":5831},[5530,16791,16792],{"class":5835}," ValidatedField",[5530,16794,5839],{"class":5543},[5530,16796,16797],{"class":5532,"line":8417},[5530,16798,7990],{"class":5547},[5530,16800,16801],{"class":5532,"line":8423},[5530,16802,16803],{"class":5547},"    Універсальний дескриптор з декларативними правилами валідації.\n",[5530,16805,16806],{"class":5532,"line":8428},[5530,16807,16808],{"class":5547},"    Приймає довільну кількість функцій-валідаторів.\n",[5530,16810,16811],{"class":5532,"line":8435},[5530,16812,7990],{"class":5547},[5530,16814,16815],{"class":5532,"line":8453},[5530,16816,5565],{"emptyLinePlaceholder":5564},[5530,16818,16819,16821,16823,16825,16827,16830,16833,16836,16839,16841,16843],{"class":5532,"line":8459},[5530,16820,5844],{"class":5831},[5530,16822,5848],{"class":5847},[5530,16824,5851],{"class":5543},[5530,16826,5855],{"class":5854},[5530,16828,16829],{"class":5543},", *",[5530,16831,16832],{"class":5854},"validators",[5530,16834,16835],{"class":5543},": Validator, ",[5530,16837,16838],{"class":5854},"default",[5530,16840,9447],{"class":5543},[5530,16842,6066],{"class":5831},[5530,16844,5877],{"class":5543},[5530,16846,16847,16849],{"class":5532,"line":10597},[5530,16848,5882],{"class":5831},[5530,16850,16851],{"class":5543},".validators   = validators\n",[5530,16853,16854,16856],{"class":5532,"line":10622},[5530,16855,5882],{"class":5831},[5530,16857,16858],{"class":5543},".default      = default\n",[5530,16860,16861,16863,16865],{"class":5532,"line":10633},[5530,16862,5882],{"class":5831},[5530,16864,11731],{"class":5543},[5530,16866,11734],{"class":5831},[5530,16868,16869,16871,16873],{"class":5532,"line":10647},[5530,16870,5882],{"class":5831},[5530,16872,11564],{"class":5543},[5530,16874,11734],{"class":5831},[5530,16876,16877],{"class":5532,"line":10655},[5530,16878,5565],{"emptyLinePlaceholder":5564},[5530,16880,16881,16883,16885,16887,16889,16891,16893,16895,16897,16899,16901,16903,16905,16907,16909],{"class":5532,"line":10660},[5530,16882,5844],{"class":5831},[5530,16884,11522],{"class":5847},[5530,16886,5851],{"class":5543},[5530,16888,5855],{"class":5854},[5530,16890,5551],{"class":5543},[5530,16892,5984],{"class":5854},[5530,16894,5863],{"class":5543},[5530,16896,8169],{"class":5835},[5530,16898,5551],{"class":5543},[5530,16900,11535],{"class":5854},[5530,16902,5863],{"class":5543},[5530,16904,5989],{"class":5835},[5530,16906,6063],{"class":5543},[5530,16908,6066],{"class":5831},[5530,16910,5839],{"class":5543},[5530,16912,16913,16915],{"class":5532,"line":10665},[5530,16914,5882],{"class":5831},[5530,16916,11790],{"class":5543},[5530,16918,16919,16921,16923,16925,16927,16929,16931,16933],{"class":5532,"line":10676},[5530,16920,5882],{"class":5831},[5530,16922,11564],{"class":5543},[5530,16924,6114],{"class":5831},[5530,16926,11569],{"class":5547},[5530,16928,6120],{"class":5831},[5530,16930,11535],{"class":5543},[5530,16932,6125],{"class":5831},[5530,16934,11809],{"class":5547},[5530,16936,16937],{"class":5532,"line":10687},[5530,16938,5565],{"emptyLinePlaceholder":5564},[5530,16940,16941,16943,16945,16947,16949,16951,16953,16955,16957],{"class":5532,"line":10696},[5530,16942,5844],{"class":5831},[5530,16944,10199],{"class":5847},[5530,16946,5851],{"class":5543},[5530,16948,5855],{"class":5854},[5530,16950,5551],{"class":5543},[5530,16952,9554],{"class":5854},[5530,16954,5551],{"class":5543},[5530,16956,5984],{"class":5854},[5530,16958,5877],{"class":5543},[5530,16960,16961,16963,16965,16967,16969],{"class":5532,"line":10706},[5530,16962,6074],{"class":6073},[5530,16964,10225],{"class":5543},[5530,16966,10228],{"class":5831},[5530,16968,10186],{"class":5831},[5530,16970,5839],{"class":5543},[5530,16972,16973,16975],{"class":5532,"line":10711},[5530,16974,10237],{"class":6073},[5530,16976,10240],{"class":5831},[5530,16978,16979,16981,16983,16985,16987,16989,16991],{"class":5532,"line":10718},[5530,16980,6243],{"class":6073},[5530,16982,11865],{"class":5847},[5530,16984,11868],{"class":5543},[5530,16986,5855],{"class":5831},[5530,16988,11873],{"class":5543},[5530,16990,5855],{"class":5831},[5530,16992,16993],{"class":5543},".default)\n",[5530,16995,16996],{"class":5532,"line":10726},[5530,16997,5565],{"emptyLinePlaceholder":5564},[5530,16999,17000,17002,17004,17006,17008,17010,17012,17014,17016,17018,17020],{"class":5532,"line":10737},[5530,17001,5844],{"class":5831},[5530,17003,10288],{"class":5847},[5530,17005,5851],{"class":5543},[5530,17007,5855],{"class":5854},[5530,17009,5551],{"class":5543},[5530,17011,9554],{"class":5854},[5530,17013,5551],{"class":5543},[5530,17015,7313],{"class":5854},[5530,17017,6063],{"class":5543},[5530,17019,6066],{"class":5831},[5530,17021,5839],{"class":5543},[5530,17023,17024],{"class":5532,"line":12391},[5530,17025,17026],{"class":5543},"        errors = []\n",[5530,17028,17029,17032,17035,17037,17039],{"class":5532,"line":12429},[5530,17030,17031],{"class":6073},"        for",[5530,17033,17034],{"class":5543}," validator ",[5530,17036,12556],{"class":6073},[5530,17038,6246],{"class":5831},[5530,17040,17041],{"class":5543},".validators:\n",[5530,17043,17044],{"class":5532,"line":12434},[5530,17045,17046],{"class":5543},"            error = validator(value)\n",[5530,17048,17049,17052,17055,17057,17059,17061],{"class":5532,"line":12439},[5530,17050,17051],{"class":6073},"            if",[5530,17053,17054],{"class":5543}," error ",[5530,17056,10228],{"class":5831},[5530,17058,8134],{"class":5831},[5530,17060,10186],{"class":5831},[5530,17062,5839],{"class":5543},[5530,17064,17065],{"class":5532,"line":12444},[5530,17066,17067],{"class":5543},"                errors.append(error)\n",[5530,17069,17070,17072],{"class":5532,"line":12450},[5530,17071,6074],{"class":6073},[5530,17073,17074],{"class":5543}," errors:\n",[5530,17076,17077,17079,17081],{"class":5532,"line":12473},[5530,17078,6087],{"class":6073},[5530,17080,6090],{"class":5835},[5530,17082,11938],{"class":5543},[5530,17084,17085,17087,17090,17092,17094,17096,17099,17102,17105],{"class":5532,"line":12481},[5530,17086,11943],{"class":5831},[5530,17088,17089],{"class":5547},"\"Поле '",[5530,17091,6857],{"class":5831},[5530,17093,11951],{"class":5543},[5530,17095,6125],{"class":5831},[5530,17097,17098],{"class":5547},"': \"",[5530,17100,17101],{"class":5543}," + ",[5530,17103,17104],{"class":5547},"\"; \"",[5530,17106,17107],{"class":5543},".join(errors)\n",[5530,17109,17110],{"class":5532,"line":12486},[5530,17111,11981],{"class":5543},[5530,17113,17114,17116,17118,17120],{"class":5532,"line":12495},[5530,17115,12074],{"class":5847},[5530,17117,11868],{"class":5543},[5530,17119,5855],{"class":5831},[5530,17121,12081],{"class":5543},[5530,17123,17124],{"class":5532,"line":12518},[5530,17125,5565],{"emptyLinePlaceholder":5564},[5530,17127,17128,17130,17132,17134,17136,17138,17140],{"class":5532,"line":12523},[5530,17129,5844],{"class":5831},[5530,17131,12092],{"class":5847},[5530,17133,5851],{"class":5543},[5530,17135,5855],{"class":5854},[5530,17137,6063],{"class":5543},[5530,17139,5989],{"class":5835},[5530,17141,5839],{"class":5543},[5530,17143,17144,17146],{"class":5532,"line":12529},[5530,17145,6243],{"class":6073},[5530,17147,12109],{"class":5543},[5530,17149,17150,17152,17155,17157,17159,17161,17163,17166,17168],{"class":5532,"line":12583},[5530,17151,12114],{"class":5831},[5530,17153,17154],{"class":5547},"\"ValidatedField(",[5530,17156,6120],{"class":5831},[5530,17158,14998],{"class":5847},[5530,17160,5851],{"class":5543},[5530,17162,5855],{"class":5831},[5530,17164,17165],{"class":5543},".validators)",[5530,17167,6125],{"class":5831},[5530,17169,17170],{"class":5547}," validators\"\n",[5530,17172,17173,17175,17177,17179,17182,17184,17187,17189,17191,17194,17197,17199,17202,17204,17206,17208,17211,17214,17216],{"class":5532,"line":12608},[5530,17174,12114],{"class":5831},[5530,17176,6128],{"class":5547},[5530,17178,6120],{"class":5831},[5530,17180,17181],{"class":5547},"', default='",[5530,17183,17101],{"class":5543},[5530,17185,17186],{"class":5847},"repr",[5530,17188,5851],{"class":5543},[5530,17190,5855],{"class":5831},[5530,17192,17193],{"class":5543},".default) ",[5530,17195,17196],{"class":6073},"if",[5530,17198,6246],{"class":5831},[5530,17200,17201],{"class":5543},".default ",[5530,17203,10228],{"class":5831},[5530,17205,8134],{"class":5831},[5530,17207,10186],{"class":5831},[5530,17209,17210],{"class":6073}," else",[5530,17212,17213],{"class":5547}," ''",[5530,17215,6125],{"class":5831},[5530,17217,12426],{"class":5547},[5530,17219,17220],{"class":5532,"line":12613},[5530,17221,12155],{"class":5543},[5530,17223,17224],{"class":5532,"line":12619},[5530,17225,5565],{"emptyLinePlaceholder":5564},[5530,17227,17228],{"class":5532,"line":12646},[5530,17229,5565],{"emptyLinePlaceholder":5564},[5530,17231,17232],{"class":5532,"line":12651},[5530,17233,17234],{"class":5536},"# ── Застосування: декларативна модель продукту ────────────────────────────────\n",[5530,17236,17237],{"class":5532,"line":12657},[5530,17238,5565],{"emptyLinePlaceholder":5564},[5530,17240,17241,17243,17246],{"class":5532,"line":12663},[5530,17242,5832],{"class":5831},[5530,17244,17245],{"class":5835}," Product",[5530,17247,5839],{"class":5543},[5530,17249,17250],{"class":5532,"line":12697},[5530,17251,17252],{"class":5543},"    name = ValidatedField(\n",[5530,17254,17255,17258,17260],{"class":5532,"line":12726},[5530,17256,17257],{"class":5543},"        is_type(",[5530,17259,5989],{"class":5835},[5530,17261,12694],{"class":5543},[5530,17263,17264],{"class":5532,"line":12755},[5530,17265,17266],{"class":5543},"        not_empty(),\n",[5530,17268,17269],{"class":5532,"line":12761},[5530,17270,17271],{"class":5543},"    )\n",[5530,17273,17274],{"class":5532,"line":12766},[5530,17275,17276],{"class":5543},"    price = ValidatedField(\n",[5530,17278,17279,17281,17283,17285,17287],{"class":5532,"line":12779},[5530,17280,17257],{"class":5543},[5530,17282,8143],{"class":5835},[5530,17284,5551],{"class":5543},[5530,17286,5649],{"class":5835},[5530,17288,12694],{"class":5543},[5530,17290,17291,17294,17297],{"class":5532,"line":12787},[5530,17292,17293],{"class":5543},"        min_value(",[5530,17295,17296],{"class":5554},"0.01",[5530,17298,12694],{"class":5543},[5530,17300,17301,17304,17307],{"class":5532,"line":12793},[5530,17302,17303],{"class":5543},"        max_value(",[5530,17305,17306],{"class":5554},"1_000_000",[5530,17308,12694],{"class":5543},[5530,17310,17311],{"class":5532,"line":12817},[5530,17312,17271],{"class":5543},[5530,17314,17316],{"class":5532,"line":17315},97,[5530,17317,17318],{"class":5543},"    sku = ValidatedField(\n",[5530,17320,17322,17324,17326],{"class":5532,"line":17321},98,[5530,17323,17257],{"class":5543},[5530,17325,5989],{"class":5835},[5530,17327,12694],{"class":5543},[5530,17329,17331,17334,17336,17340,17344,17347,17350,17354,17357,17360,17363],{"class":5532,"line":17330},99,[5530,17332,17333],{"class":5543},"        regex_match(",[5530,17335,13734],{"class":5831},[5530,17337,17339],{"class":17338},"shsrj","\"^",[5530,17341,17343],{"class":17342},"sAV2Q","[",[5530,17345,17346],{"class":17338},"A-Z",[5530,17348,17349],{"class":17342},"]",[5530,17351,17353],{"class":17352},"sYsli","{2,4}",[5530,17355,17356],{"class":17338},"-\\d",[5530,17358,17359],{"class":17352},"{4,8}",[5530,17361,17362],{"class":17338},"$\"",[5530,17364,12694],{"class":5543},[5530,17366,17368],{"class":5532,"line":17367},100,[5530,17369,17271],{"class":5543},[5530,17371,17373],{"class":5532,"line":17372},101,[5530,17374,17375],{"class":5543},"    stock = ValidatedField(\n",[5530,17377,17379,17381,17383],{"class":5532,"line":17378},102,[5530,17380,17257],{"class":5543},[5530,17382,8143],{"class":5835},[5530,17384,12694],{"class":5543},[5530,17386,17388,17390,17392],{"class":5532,"line":17387},103,[5530,17389,17293],{"class":5543},[5530,17391,6080],{"class":5554},[5530,17393,12694],{"class":5543},[5530,17395,17397,17400,17402,17404],{"class":5532,"line":17396},104,[5530,17398,17399],{"class":5854},"        default",[5530,17401,9447],{"class":5543},[5530,17403,6080],{"class":5554},[5530,17405,15167],{"class":5543},[5530,17407,17409],{"class":5532,"line":17408},105,[5530,17410,17271],{"class":5543},[5530,17412,17414],{"class":5532,"line":17413},106,[5530,17415,5565],{"emptyLinePlaceholder":5564},[5530,17417,17419,17421,17423,17425,17427,17429,17431,17433,17435,17437,17440,17442,17444,17446,17449,17451,17453,17455,17458,17460,17462,17464,17466],{"class":5532,"line":17418},107,[5530,17420,5844],{"class":5831},[5530,17422,5848],{"class":5847},[5530,17424,5851],{"class":5543},[5530,17426,5855],{"class":5854},[5530,17428,5551],{"class":5543},[5530,17430,11535],{"class":5854},[5530,17432,5863],{"class":5543},[5530,17434,5989],{"class":5835},[5530,17436,5551],{"class":5543},[5530,17438,17439],{"class":5854},"price",[5530,17441,5863],{"class":5543},[5530,17443,5649],{"class":5835},[5530,17445,5551],{"class":5543},[5530,17447,17448],{"class":5854},"sku",[5530,17450,5863],{"class":5543},[5530,17452,5989],{"class":5835},[5530,17454,5551],{"class":5543},[5530,17456,17457],{"class":5854},"stock",[5530,17459,5863],{"class":5543},[5530,17461,8143],{"class":5835},[5530,17463,12293],{"class":5543},[5530,17465,6080],{"class":5554},[5530,17467,5877],{"class":5543},[5530,17469,17471,17473],{"class":5532,"line":17470},108,[5530,17472,5882],{"class":5831},[5530,17474,17475],{"class":5543},".name  = name\n",[5530,17477,17479,17481],{"class":5532,"line":17478},109,[5530,17480,5882],{"class":5831},[5530,17482,17483],{"class":5543},".price = price\n",[5530,17485,17487,17489],{"class":5532,"line":17486},110,[5530,17488,5882],{"class":5831},[5530,17490,17491],{"class":5543},".sku   = sku\n",[5530,17493,17495,17497],{"class":5532,"line":17494},111,[5530,17496,5882],{"class":5831},[5530,17498,17499],{"class":5543},".stock = stock\n",[5530,17501,17503],{"class":5532,"line":17502},112,[5530,17504,5565],{"emptyLinePlaceholder":5564},[5530,17506,17508,17510,17512,17514,17516,17518,17520],{"class":5532,"line":17507},113,[5530,17509,5844],{"class":5831},[5530,17511,12092],{"class":5847},[5530,17513,5851],{"class":5543},[5530,17515,5855],{"class":5854},[5530,17517,6063],{"class":5543},[5530,17519,5989],{"class":5835},[5530,17521,5839],{"class":5543},[5530,17523,17525,17527,17529,17532,17534,17536,17538,17541,17543,17546,17548,17551,17553,17556,17558],{"class":5532,"line":17524},114,[5530,17526,6243],{"class":6073},[5530,17528,13581],{"class":5831},[5530,17530,17531],{"class":5547},"\"Product(",[5530,17533,6857],{"class":5831},[5530,17535,12373],{"class":5543},[5530,17537,11974],{"class":5831},[5530,17539,17540],{"class":5547},", price=",[5530,17542,6857],{"class":5831},[5530,17544,17545],{"class":5543},".price",[5530,17547,6125],{"class":5831},[5530,17549,17550],{"class":5547},", sku=",[5530,17552,6857],{"class":5831},[5530,17554,17555],{"class":5543},".sku",[5530,17557,11974],{"class":5831},[5530,17559,12426],{"class":5547},[5530,17561,17563],{"class":5532,"line":17562},115,[5530,17564,5565],{"emptyLinePlaceholder":5564},[5530,17566,17568],{"class":5532,"line":17567},116,[5530,17569,5565],{"emptyLinePlaceholder":5564},[5530,17571,17573],{"class":5532,"line":17572},117,[5530,17574,13616],{"class":5536},[5530,17576,17578,17580,17582,17585],{"class":5532,"line":17577},118,[5530,17579,6283],{"class":5847},[5530,17581,5851],{"class":5543},[5530,17583,17584],{"class":5547},"\"=== Валідний продукт ===\"",[5530,17586,5558],{"class":5543},[5530,17588,17590,17593,17596,17598,17601,17603,17606,17608,17610,17612,17614],{"class":5532,"line":17589},119,[5530,17591,17592],{"class":5543},"p = Product(",[5530,17594,17595],{"class":5547},"\"MacBook Pro\"",[5530,17597,5551],{"class":5543},[5530,17599,17600],{"class":5554},"89999.0",[5530,17602,5551],{"class":5543},[5530,17604,17605],{"class":5547},"\"MBP-20242\"",[5530,17607,5551],{"class":5543},[5530,17609,17457],{"class":5854},[5530,17611,9447],{"class":5543},[5530,17613,8290],{"class":5554},[5530,17615,5558],{"class":5543},[5530,17617,17619,17621],{"class":5532,"line":17618},120,[5530,17620,6283],{"class":5847},[5530,17622,17623],{"class":5543},"(p)\n",[5530,17625,17627,17629,17631,17633,17636,17638,17641,17643,17645],{"class":5532,"line":17626},121,[5530,17628,6283],{"class":5847},[5530,17630,5851],{"class":5543},[5530,17632,6114],{"class":5831},[5530,17634,17635],{"class":5547},"\"stock (default worked): ",[5530,17637,6120],{"class":5831},[5530,17639,17640],{"class":5543},"p.stock",[5530,17642,6125],{"class":5831},[5530,17644,6128],{"class":5547},[5530,17646,5558],{"class":5543},[5530,17648,17650],{"class":5532,"line":17649},122,[5530,17651,5565],{"emptyLinePlaceholder":5564},[5530,17653,17655,17657,17659,17661,17663,17666],{"class":5532,"line":17654},123,[5530,17656,6283],{"class":5847},[5530,17658,5851],{"class":5543},[5530,17660,6128],{"class":5547},[5530,17662,8589],{"class":8588},[5530,17664,17665],{"class":5547},"=== Тести валідації ===\"",[5530,17667,5558],{"class":5543},[5530,17669,17671],{"class":5532,"line":17670},124,[5530,17672,17673],{"class":5543},"errors_tests = [\n",[5530,17675,17677,17679,17681,17683,17685,17688,17691,17693,17695,17697,17700],{"class":5532,"line":17676},125,[5530,17678,12666],{"class":5543},[5530,17680,12669],{"class":5831},[5530,17682,5863],{"class":5543},[5530,17684,12674],{"class":5847},[5530,17686,17687],{"class":5543},"(p, ",[5530,17689,17690],{"class":5547},"'price'",[5530,17692,12713],{"class":5543},[5530,17694,12212],{"class":5554},[5530,17696,15960],{"class":5543},[5530,17698,17699],{"class":5547},"\"price=-1\"",[5530,17701,12694],{"class":5543},[5530,17703,17705,17707,17709,17711,17713,17715,17717,17719,17722,17724,17727],{"class":5532,"line":17704},126,[5530,17706,12666],{"class":5543},[5530,17708,12669],{"class":5831},[5530,17710,5863],{"class":5543},[5530,17712,12674],{"class":5847},[5530,17714,17687],{"class":5543},[5530,17716,17690],{"class":5547},[5530,17718,5551],{"class":5543},[5530,17720,17721],{"class":5554},"2_000_000",[5530,17723,15988],{"class":5543},[5530,17725,17726],{"class":5547},"\"price=2M (>max)\"",[5530,17728,12694],{"class":5543},[5530,17730,17732,17734,17736,17738,17740,17742,17745,17747,17750,17752,17755],{"class":5532,"line":17731},127,[5530,17733,12666],{"class":5543},[5530,17735,12669],{"class":5831},[5530,17737,5863],{"class":5543},[5530,17739,12674],{"class":5847},[5530,17741,17687],{"class":5543},[5530,17743,17744],{"class":5547},"'sku'",[5530,17746,5551],{"class":5543},[5530,17748,17749],{"class":5547},"\"invalid\"",[5530,17751,12747],{"class":5543},[5530,17753,17754],{"class":5547},"\"sku='invalid'\"",[5530,17756,12694],{"class":5543},[5530,17758,17760,17762,17764,17766,17768,17770,17773,17775,17777,17779,17782],{"class":5532,"line":17759},128,[5530,17761,12666],{"class":5543},[5530,17763,12669],{"class":5831},[5530,17765,5863],{"class":5543},[5530,17767,12674],{"class":5847},[5530,17769,17687],{"class":5543},[5530,17771,17772],{"class":5547},"'stock'",[5530,17774,12713],{"class":5543},[5530,17776,8290],{"class":5554},[5530,17778,15960],{"class":5543},[5530,17780,17781],{"class":5547},"\"stock=-5\"",[5530,17783,12694],{"class":5543},[5530,17785,17787,17789,17791,17793,17795,17797,17800,17802,17804,17807,17810],{"class":5532,"line":17786},129,[5530,17788,12666],{"class":5543},[5530,17790,12669],{"class":5831},[5530,17792,5863],{"class":5543},[5530,17794,12674],{"class":5847},[5530,17796,17687],{"class":5543},[5530,17798,17799],{"class":5547},"'name'",[5530,17801,5551],{"class":5543},[5530,17803,14129],{"class":5547},[5530,17805,17806],{"class":5543},"),       ",[5530,17808,17809],{"class":5547},"\"name=''\"",[5530,17811,12694],{"class":5543},[5530,17813,17815],{"class":5532,"line":17814},130,[5530,17816,12758],{"class":5543},[5530,17818,17820,17822,17824,17826],{"class":5532,"line":17819},131,[5530,17821,12550],{"class":6073},[5530,17823,12771],{"class":5543},[5530,17825,12556],{"class":6073},[5530,17827,17828],{"class":5543}," errors_tests:\n",[5530,17830,17832,17834],{"class":5532,"line":17831},132,[5530,17833,12782],{"class":6073},[5530,17835,5839],{"class":5543},[5530,17837,17839],{"class":5532,"line":17838},133,[5530,17840,12790],{"class":5543},[5530,17842,17844,17846,17848,17850],{"class":5532,"line":17843},134,[5530,17845,12796],{"class":6073},[5530,17847,6090],{"class":5835},[5530,17849,6607],{"class":6073},[5530,17851,6610],{"class":5543},[5530,17853,17855,17857,17859,17861,17863,17865,17867,17869,17871,17873,17876,17878,17880,17882],{"class":5532,"line":17854},135,[5530,17856,6847],{"class":5847},[5530,17858,5851],{"class":5543},[5530,17860,6114],{"class":5831},[5530,17862,12826],{"class":5547},[5530,17864,6120],{"class":5831},[5530,17866,12831],{"class":5543},[5530,17868,6125],{"class":5831},[5530,17870,17349],{"class":5547},[5530,17872,8589],{"class":8588},[5530,17874,17875],{"class":5831},"  {",[5530,17877,6626],{"class":5543},[5530,17879,6125],{"class":5831},[5530,17881,6128],{"class":5547},[5530,17883,5558],{"class":5543},[6302,17885,17887,17895,17899,17914,17921,17924,17928,17932,17939,17943,17950,17954,17961,17965,17972,17976],{"title":17886},"python validated_field.py",[6306,17888,17890,6314,17893],{"className":17889},[5532],[5530,17891,6313],{"className":17892},[6312],[5629,17894,17886],{},[6306,17896,17898],{"className":17897},[5532],"=== Валідний продукт ===",[6306,17900,17902,17903,17540,17907,17550,17910,12888],{"className":17901},[5532],"Product(",[5530,17904,17906],{"className":17905},[6720],"'MacBook Pro'",[5530,17908,17600],{"className":17909},[6720],[5530,17911,17913],{"className":17912},[6720],"'MBP-20242'",[6306,17915,17917,17918],{"className":17916},[5532],"stock (default worked): ",[5530,17919,8290],{"className":17920},[6720],[6306,17922],{"className":17923},[5532],[6306,17925,17927],{"className":17926},[5532],"=== Тести валідації ===",[6306,17929,17931],{"className":17930},[5532],"[price=-1]",[6306,17933,6738,17935],{"className":17934},[5532],[5530,17936,17938],{"className":17937},[6711],"Поле 'price': Значення -1 менше мінімуму 0.01",[6306,17940,17942],{"className":17941},[5532],"[price=2M (>max)]",[6306,17944,6738,17946],{"className":17945},[5532],[5530,17947,17949],{"className":17948},[6711],"Поле 'price': Значення 2000000 перевищує максимум 1000000",[6306,17951,17953],{"className":17952},[5532],"[sku='invalid']",[6306,17955,6738,17957],{"className":17956},[5532],[5530,17958,17960],{"className":17959},[6711],"Поле 'sku': Значення 'invalid' не відповідає шаблону '^[A-Z]{2,4}-\\d{4,8}$'",[6306,17962,17964],{"className":17963},[5532],"[stock=-5]",[6306,17966,6738,17968],{"className":17967},[5532],[5530,17969,17971],{"className":17970},[6711],"Поле 'stock': Значення -5 менше мінімуму 0",[6306,17973,17975],{"className":17974},[5532],"[name='']",[6306,17977,6738,17979],{"className":17978},[5532],[5530,17980,17982],{"className":17981},[6711],"Поле 'name': Рядок не може складатися лише з пробілів",[5666,17984],{},[5503,17986,17988],{"id":17987},"практична-лабораторія-e-commerce-кошик-від-а-до-я","Практична лабораторія: E-Commerce кошик від А до Я",[5508,17990,17991,17992,17995],{},"Це комплексний приклад, що поєднує ",[5629,17993,17994],{},"всі концепції статті"," в одній системі:",[7085,17997,17998,18008],{},[7088,17999,18000],{},[7091,18001,18002,18005],{},[7094,18003,18004],{},"Концепція",[7094,18006,18007],{},"Де застосовано",[7110,18009,18010,18025,18038,18057,18073,18086,18100],{},[7091,18011,18012,18016],{},[7115,18013,18014],{},[5512,18015,5934],{},[7115,18017,18018,5551,18021,18024],{},[5512,18019,18020],{},"Product._stock",[5512,18022,18023],{},"Cart._items"," — внутрішні деталі",[7091,18026,18027,18032],{},[7115,18028,18029,18031],{},[5512,18030,6380],{}," (Name Mangling)",[7115,18033,18034,18037],{},[5512,18035,18036],{},"Cart.__discount_code"," — захист від колізій у підкласах",[7091,18039,18040,18045],{},[7115,18041,18042,18044],{},[5512,18043,7199],{}," (геттер)",[7115,18046,18047,5551,18050,5551,18053,18056],{},[5512,18048,18049],{},"Cart.total",[5512,18051,18052],{},"Cart.tax",[5512,18054,18055],{},"Cart.final_price"," — обчислювальні",[7091,18058,18059,18064],{},[7115,18060,18061,18063],{},[5512,18062,7199],{}," (сеттер + валідація)",[7115,18065,18066,5551,18069,18072],{},[5512,18067,18068],{},"Product.price",[5512,18070,18071],{},"Product.stock"," — захищений запис",[7091,18074,18075,18080],{},[7115,18076,18077,18079],{},[5512,18078,7199],{}," (делітер)",[7115,18081,18082,18085],{},[5512,18083,18084],{},"Cart.coupon"," — очищення знижки",[7091,18087,18088,18091],{},[7115,18089,18090],{},"Кастомний дескриптор",[7115,18092,18093,5551,18096,18099],{},[5512,18094,18095],{},"PositiveFloat",[5512,18097,18098],{},"NonNegativeInt"," — перевикористання валідації",[7091,18101,18102,18105],{},[7115,18103,18104],{},"Name Mangling при наслідуванні",[7115,18106,18107,9881,18110,18113],{},[5512,18108,18109],{},"PremiumCart",[5512,18111,18112],{},"__discount_code"," не конфліктує",[5673,18115,18117],{"id":18116},"архітектура-системи","Архітектура системи",[5704,18119,18120],{},[5521,18121,18123],{"className":5708,"code":18122,"language":5710,"meta":5526,"style":5526},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\nskinparam ArrowColor #6366f1\nskinparam class {\n    BackgroundColor #f3f4f6\n    BorderColor #d1d5db\n}\n\nclass PositiveFloat {\n    + __set_name__(owner, name)\n    + __get__(instance, owner)\n    + __set__(instance, value)\n}\n\nclass NonNegativeInt {\n    + __set_name__(owner, name)\n    + __get__(instance, owner)\n    + __set__(instance, value)\n}\n\nclass Product {\n    + name : str\n    + price : float \u003C\u003CPositiveFloat>>\n    + stock : int \u003C\u003CNonNegativeInt>>\n    - _category : str\n    + is_available : bool \u003C\u003Cproperty>>\n    + reserve(qty) : void\n    + release(qty) : void\n}\n\nclass Cart {\n    - _items : dict\n    - __discount_code : str | None\n    - __discount_percent : float\n    + subtotal : float \u003C\u003Cproperty>>\n    + tax : float \u003C\u003Cproperty>>\n    + discount_amount : float \u003C\u003Cproperty>>\n    + total : float \u003C\u003Cproperty>>\n    + coupon : str | None \u003C\u003Cproperty>>\n    + add(product, qty) : void\n    + remove(product) : void\n    + checkout() : Receipt\n}\n\nclass PremiumCart {\n    - __discount_code : str | None\n    + loyalty_discount : float \u003C\u003Cproperty>>\n    + total : float \u003C\u003Cproperty, override>>\n}\n\nclass Receipt {\n    + items : list\n    + subtotal : float\n    + tax : float\n    + discount : float\n    + total : float\n    + to_text() : str\n}\n\nProduct \"1\" --o \"0..*\" Cart : contains\nCart \u003C|-- PremiumCart\nCart --> Receipt : creates\nPositiveFloat ..> Product : validates price\nNonNegativeInt ..> Product : validates stock\n@enduml\n",[5512,18124,18125,18129,18133,18137,18141,18146,18151,18156,18160,18164,18169,18174,18179,18184,18188,18192,18197,18201,18205,18209,18213,18217,18222,18227,18232,18237,18242,18247,18252,18257,18261,18265,18270,18275,18280,18285,18290,18295,18300,18305,18310,18315,18320,18325,18329,18333,18338,18342,18347,18352,18356,18360,18365,18370,18375,18380,18385,18390,18395,18399,18403,18408,18413,18418,18423,18428],{"__ignoreMap":5526},[5530,18126,18127],{"class":5532,"line":5533},[5530,18128,5717],{},[5530,18130,18131],{"class":5532,"line":5540},[5530,18132,5722],{},[5530,18134,18135],{"class":5532,"line":5561},[5530,18136,5727],{},[5530,18138,18139],{"class":5532,"line":5568},[5530,18140,5732],{},[5530,18142,18143],{"class":5532,"line":5574},[5530,18144,18145],{},"skinparam class {\n",[5530,18147,18148],{"class":5532,"line":5586},[5530,18149,18150],{},"    BackgroundColor #f3f4f6\n",[5530,18152,18153],{"class":5532,"line":5598},[5530,18154,18155],{},"    BorderColor #d1d5db\n",[5530,18157,18158],{"class":5532,"line":5603},[5530,18159,5767],{},[5530,18161,18162],{"class":5532,"line":5609},[5530,18163,5565],{"emptyLinePlaceholder":5564},[5530,18165,18166],{"class":5532,"line":5758},[5530,18167,18168],{},"class PositiveFloat {\n",[5530,18170,18171],{"class":5532,"line":5764},[5530,18172,18173],{},"    + __set_name__(owner, name)\n",[5530,18175,18176],{"class":5532,"line":5770},[5530,18177,18178],{},"    + __get__(instance, owner)\n",[5530,18180,18181],{"class":5532,"line":5775},[5530,18182,18183],{},"    + __set__(instance, value)\n",[5530,18185,18186],{"class":5532,"line":5781},[5530,18187,5767],{},[5530,18189,18190],{"class":5532,"line":5786},[5530,18191,5565],{"emptyLinePlaceholder":5564},[5530,18193,18194],{"class":5532,"line":5792},[5530,18195,18196],{},"class NonNegativeInt {\n",[5530,18198,18199],{"class":5532,"line":5798},[5530,18200,18173],{},[5530,18202,18203],{"class":5532,"line":6187},[5530,18204,18178],{},[5530,18206,18207],{"class":5532,"line":6195},[5530,18208,18183],{},[5530,18210,18211],{"class":5532,"line":6217},[5530,18212,5767],{},[5530,18214,18215],{"class":5532,"line":6222},[5530,18216,5565],{"emptyLinePlaceholder":5564},[5530,18218,18219],{"class":5532,"line":6240},[5530,18220,18221],{},"class Product {\n",[5530,18223,18224],{"class":5532,"line":6635},[5530,18225,18226],{},"    + name : str\n",[5530,18228,18229],{"class":5532,"line":6640},[5530,18230,18231],{},"    + price : float \u003C\u003CPositiveFloat>>\n",[5530,18233,18234],{"class":5532,"line":6646},[5530,18235,18236],{},"    + stock : int \u003C\u003CNonNegativeInt>>\n",[5530,18238,18239],{"class":5532,"line":6659},[5530,18240,18241],{},"    - _category : str\n",[5530,18243,18244],{"class":5532,"line":6664},[5530,18245,18246],{},"    + is_available : bool \u003C\u003Cproperty>>\n",[5530,18248,18249],{"class":5532,"line":6670},[5530,18250,18251],{},"    + reserve(qty) : void\n",[5530,18253,18254],{"class":5532,"line":6678},[5530,18255,18256],{},"    + release(qty) : void\n",[5530,18258,18259],{"class":5532,"line":6687},[5530,18260,5767],{},[5530,18262,18263],{"class":5532,"line":7770},[5530,18264,5565],{"emptyLinePlaceholder":5564},[5530,18266,18267],{"class":5532,"line":7793},[5530,18268,18269],{},"class Cart {\n",[5530,18271,18272],{"class":5532,"line":7798},[5530,18273,18274],{},"    - _items : dict\n",[5530,18276,18277],{"class":5532,"line":7804},[5530,18278,18279],{},"    - __discount_code : str | None\n",[5530,18281,18282],{"class":5532,"line":7813},[5530,18283,18284],{},"    - __discount_percent : float\n",[5530,18286,18287],{"class":5532,"line":7835},[5530,18288,18289],{},"    + subtotal : float \u003C\u003Cproperty>>\n",[5530,18291,18292],{"class":5532,"line":7840},[5530,18293,18294],{},"    + tax : float \u003C\u003Cproperty>>\n",[5530,18296,18297],{"class":5532,"line":7846},[5530,18298,18299],{},"    + discount_amount : float \u003C\u003Cproperty>>\n",[5530,18301,18302],{"class":5532,"line":7853},[5530,18303,18304],{},"    + total : float \u003C\u003Cproperty>>\n",[5530,18306,18307],{"class":5532,"line":7862},[5530,18308,18309],{},"    + coupon : str | None \u003C\u003Cproperty>>\n",[5530,18311,18312],{"class":5532,"line":7873},[5530,18313,18314],{},"    + add(product, qty) : void\n",[5530,18316,18317],{"class":5532,"line":8384},[5530,18318,18319],{},"    + remove(product) : void\n",[5530,18321,18322],{"class":5532,"line":8390},[5530,18323,18324],{},"    + checkout() : Receipt\n",[5530,18326,18327],{"class":5532,"line":8402},[5530,18328,5767],{},[5530,18330,18331],{"class":5532,"line":8412},[5530,18332,5565],{"emptyLinePlaceholder":5564},[5530,18334,18335],{"class":5532,"line":8417},[5530,18336,18337],{},"class PremiumCart {\n",[5530,18339,18340],{"class":5532,"line":8423},[5530,18341,18279],{},[5530,18343,18344],{"class":5532,"line":8428},[5530,18345,18346],{},"    + loyalty_discount : float \u003C\u003Cproperty>>\n",[5530,18348,18349],{"class":5532,"line":8435},[5530,18350,18351],{},"    + total : float \u003C\u003Cproperty, override>>\n",[5530,18353,18354],{"class":5532,"line":8453},[5530,18355,5767],{},[5530,18357,18358],{"class":5532,"line":8459},[5530,18359,5565],{"emptyLinePlaceholder":5564},[5530,18361,18362],{"class":5532,"line":10597},[5530,18363,18364],{},"class Receipt {\n",[5530,18366,18367],{"class":5532,"line":10622},[5530,18368,18369],{},"    + items : list\n",[5530,18371,18372],{"class":5532,"line":10633},[5530,18373,18374],{},"    + subtotal : float\n",[5530,18376,18377],{"class":5532,"line":10647},[5530,18378,18379],{},"    + tax : float\n",[5530,18381,18382],{"class":5532,"line":10655},[5530,18383,18384],{},"    + discount : float\n",[5530,18386,18387],{"class":5532,"line":10660},[5530,18388,18389],{},"    + total : float\n",[5530,18391,18392],{"class":5532,"line":10665},[5530,18393,18394],{},"    + to_text() : str\n",[5530,18396,18397],{"class":5532,"line":10676},[5530,18398,5767],{},[5530,18400,18401],{"class":5532,"line":10687},[5530,18402,5565],{"emptyLinePlaceholder":5564},[5530,18404,18405],{"class":5532,"line":10696},[5530,18406,18407],{},"Product \"1\" --o \"0..*\" Cart : contains\n",[5530,18409,18410],{"class":5532,"line":10706},[5530,18411,18412],{},"Cart \u003C|-- PremiumCart\n",[5530,18414,18415],{"class":5532,"line":10711},[5530,18416,18417],{},"Cart --> Receipt : creates\n",[5530,18419,18420],{"class":5532,"line":10718},[5530,18421,18422],{},"PositiveFloat ..> Product : validates price\n",[5530,18424,18425],{"class":5532,"line":10726},[5530,18426,18427],{},"NonNegativeInt ..> Product : validates stock\n",[5530,18429,18430],{"class":5532,"line":10737},[5530,18431,5801],{},[5673,18433,18435],{"id":18434},"реалізація","Реалізація",[13982,18437,18438,19014,19681,22077],{},[5521,18439,18442],{"className":5523,"code":18440,"filename":18441,"language":5525,"meta":5526,"style":5526},"# Перевикористовувані дескриптори для числової валідації\n\nclass PositiveFloat:\n    \"\"\"Дескриптор: додатне дійсне число (> 0).\"\"\"\n\n    def __set_name__(self, owner: type, name: str) -> None:\n        self.public_name  = name\n        self.private_name = f\"_{name}\"\n\n    def __get__(self, instance, owner):\n        if instance is None:\n            return self\n        return getattr(instance, self.private_name)\n\n    def __set__(self, instance, value) -> None:\n        if not isinstance(value, (int, float)):\n            raise TypeError(\n                f\"'{self.public_name}' має бути числом, \"\n                f\"отримано {type(value).__name__!r}\"\n            )\n        if value \u003C= 0:\n            raise ValueError(\n                f\"'{self.public_name}' має бути > 0, отримано {value}\"\n            )\n        setattr(instance, self.private_name, float(value))\n\n\nclass NonNegativeInt:\n    \"\"\"Дескриптор: ціле невід'ємне число (>= 0).\"\"\"\n\n    def __set_name__(self, owner: type, name: str) -> None:\n        self.public_name  = name\n        self.private_name = f\"_{name}\"\n\n    def __get__(self, instance, owner):\n        if instance is None:\n            return self\n        return getattr(instance, self.private_name, 0)\n\n    def __set__(self, instance, value) -> None:\n        if not isinstance(value, int):\n            raise TypeError(\n                f\"'{self.public_name}' має бути int, \"\n                f\"отримано {type(value).__name__!r}\"\n            )\n        if value \u003C 0:\n            raise ValueError(\n                f\"'{self.public_name}' має бути >= 0, отримано {value}\"\n            )\n        setattr(instance, self.private_name, value)\n","descriptors.py",[5512,18443,18444,18449,18453,18462,18467,18471,18503,18509,18527,18531,18551,18563,18569,18582,18586,18610,18628,18636,18651,18669,18673,18683,18691,18714,18718,18733,18737,18741,18750,18755,18759,18791,18797,18815,18819,18839,18851,18857,18873,18877,18901,18915,18923,18937,18955,18959,18969,18977,19000,19004],{"__ignoreMap":5526},[5530,18445,18446],{"class":5532,"line":5533},[5530,18447,18448],{"class":5536},"# Перевикористовувані дескриптори для числової валідації\n",[5530,18450,18451],{"class":5532,"line":5540},[5530,18452,5565],{"emptyLinePlaceholder":5564},[5530,18454,18455,18457,18460],{"class":5532,"line":5561},[5530,18456,5832],{"class":5831},[5530,18458,18459],{"class":5835}," PositiveFloat",[5530,18461,5839],{"class":5543},[5530,18463,18464],{"class":5532,"line":5568},[5530,18465,18466],{"class":5547},"    \"\"\"Дескриптор: додатне дійсне число (> 0).\"\"\"\n",[5530,18468,18469],{"class":5532,"line":5574},[5530,18470,5565],{"emptyLinePlaceholder":5564},[5530,18472,18473,18475,18477,18479,18481,18483,18485,18487,18489,18491,18493,18495,18497,18499,18501],{"class":5532,"line":5586},[5530,18474,5844],{"class":5831},[5530,18476,11522],{"class":5847},[5530,18478,5851],{"class":5543},[5530,18480,5855],{"class":5854},[5530,18482,5551],{"class":5543},[5530,18484,5984],{"class":5854},[5530,18486,5863],{"class":5543},[5530,18488,8169],{"class":5835},[5530,18490,5551],{"class":5543},[5530,18492,11535],{"class":5854},[5530,18494,5863],{"class":5543},[5530,18496,5989],{"class":5835},[5530,18498,6063],{"class":5543},[5530,18500,6066],{"class":5831},[5530,18502,5839],{"class":5543},[5530,18504,18505,18507],{"class":5532,"line":5598},[5530,18506,5882],{"class":5831},[5530,18508,11790],{"class":5543},[5530,18510,18511,18513,18515,18517,18519,18521,18523,18525],{"class":5532,"line":5603},[5530,18512,5882],{"class":5831},[5530,18514,11564],{"class":5543},[5530,18516,6114],{"class":5831},[5530,18518,11569],{"class":5547},[5530,18520,6120],{"class":5831},[5530,18522,11535],{"class":5543},[5530,18524,6125],{"class":5831},[5530,18526,11809],{"class":5547},[5530,18528,18529],{"class":5532,"line":5609},[5530,18530,5565],{"emptyLinePlaceholder":5564},[5530,18532,18533,18535,18537,18539,18541,18543,18545,18547,18549],{"class":5532,"line":5758},[5530,18534,5844],{"class":5831},[5530,18536,10199],{"class":5847},[5530,18538,5851],{"class":5543},[5530,18540,5855],{"class":5854},[5530,18542,5551],{"class":5543},[5530,18544,9554],{"class":5854},[5530,18546,5551],{"class":5543},[5530,18548,5984],{"class":5854},[5530,18550,5877],{"class":5543},[5530,18552,18553,18555,18557,18559,18561],{"class":5532,"line":5764},[5530,18554,6074],{"class":6073},[5530,18556,10225],{"class":5543},[5530,18558,10228],{"class":5831},[5530,18560,10186],{"class":5831},[5530,18562,5839],{"class":5543},[5530,18564,18565,18567],{"class":5532,"line":5770},[5530,18566,10237],{"class":6073},[5530,18568,10240],{"class":5831},[5530,18570,18571,18573,18575,18577,18579],{"class":5532,"line":5775},[5530,18572,6243],{"class":6073},[5530,18574,11865],{"class":5847},[5530,18576,11868],{"class":5543},[5530,18578,5855],{"class":5831},[5530,18580,18581],{"class":5543},".private_name)\n",[5530,18583,18584],{"class":5532,"line":5781},[5530,18585,5565],{"emptyLinePlaceholder":5564},[5530,18587,18588,18590,18592,18594,18596,18598,18600,18602,18604,18606,18608],{"class":5532,"line":5786},[5530,18589,5844],{"class":5831},[5530,18591,10288],{"class":5847},[5530,18593,5851],{"class":5543},[5530,18595,5855],{"class":5854},[5530,18597,5551],{"class":5543},[5530,18599,9554],{"class":5854},[5530,18601,5551],{"class":5543},[5530,18603,7313],{"class":5854},[5530,18605,6063],{"class":5543},[5530,18607,6066],{"class":5831},[5530,18609,5839],{"class":5543},[5530,18611,18612,18614,18616,18618,18620,18622,18624,18626],{"class":5532,"line":5792},[5530,18613,6074],{"class":6073},[5530,18615,8134],{"class":5831},[5530,18617,8137],{"class":5847},[5530,18619,8140],{"class":5543},[5530,18621,8143],{"class":5835},[5530,18623,5551],{"class":5543},[5530,18625,5649],{"class":5835},[5530,18627,8150],{"class":5543},[5530,18629,18630,18632,18634],{"class":5532,"line":5798},[5530,18631,6087],{"class":6073},[5530,18633,8157],{"class":5835},[5530,18635,11938],{"class":5543},[5530,18637,18638,18640,18642,18644,18646,18648],{"class":5532,"line":6187},[5530,18639,11943],{"class":5831},[5530,18641,11946],{"class":5547},[5530,18643,6857],{"class":5831},[5530,18645,11951],{"class":5543},[5530,18647,6125],{"class":5831},[5530,18649,18650],{"class":5547},"' має бути числом, \"\n",[5530,18652,18653,18655,18657,18659,18661,18663,18665,18667],{"class":5532,"line":6195},[5530,18654,11943],{"class":5831},[5530,18656,11963],{"class":5547},[5530,18658,6120],{"class":5831},[5530,18660,8169],{"class":5835},[5530,18662,8172],{"class":5543},[5530,18664,8175],{"class":5854},[5530,18666,11974],{"class":5831},[5530,18668,11809],{"class":5547},[5530,18670,18671],{"class":5532,"line":6217},[5530,18672,11981],{"class":5543},[5530,18674,18675,18677,18679,18681],{"class":5532,"line":6222},[5530,18676,6074],{"class":6073},[5530,18678,13217],{"class":5543},[5530,18680,6080],{"class":5554},[5530,18682,5839],{"class":5543},[5530,18684,18685,18687,18689],{"class":5532,"line":6240},[5530,18686,6087],{"class":6073},[5530,18688,6090],{"class":5835},[5530,18690,11938],{"class":5543},[5530,18692,18693,18695,18697,18699,18701,18703,18706,18708,18710,18712],{"class":5532,"line":6635},[5530,18694,11943],{"class":5831},[5530,18696,11946],{"class":5547},[5530,18698,6857],{"class":5831},[5530,18700,11951],{"class":5543},[5530,18702,6125],{"class":5831},[5530,18704,18705],{"class":5547},"' має бути > 0, отримано ",[5530,18707,6120],{"class":5831},[5530,18709,7313],{"class":5543},[5530,18711,6125],{"class":5831},[5530,18713,11809],{"class":5547},[5530,18715,18716],{"class":5532,"line":6640},[5530,18717,11981],{"class":5543},[5530,18719,18720,18722,18724,18726,18728,18730],{"class":5532,"line":6646},[5530,18721,12074],{"class":5847},[5530,18723,11868],{"class":5543},[5530,18725,5855],{"class":5831},[5530,18727,11873],{"class":5543},[5530,18729,5649],{"class":5835},[5530,18731,18732],{"class":5543},"(value))\n",[5530,18734,18735],{"class":5532,"line":6659},[5530,18736,5565],{"emptyLinePlaceholder":5564},[5530,18738,18739],{"class":5532,"line":6664},[5530,18740,5565],{"emptyLinePlaceholder":5564},[5530,18742,18743,18745,18748],{"class":5532,"line":6670},[5530,18744,5832],{"class":5831},[5530,18746,18747],{"class":5835}," NonNegativeInt",[5530,18749,5839],{"class":5543},[5530,18751,18752],{"class":5532,"line":6678},[5530,18753,18754],{"class":5547},"    \"\"\"Дескриптор: ціле невід'ємне число (>= 0).\"\"\"\n",[5530,18756,18757],{"class":5532,"line":6687},[5530,18758,5565],{"emptyLinePlaceholder":5564},[5530,18760,18761,18763,18765,18767,18769,18771,18773,18775,18777,18779,18781,18783,18785,18787,18789],{"class":5532,"line":7770},[5530,18762,5844],{"class":5831},[5530,18764,11522],{"class":5847},[5530,18766,5851],{"class":5543},[5530,18768,5855],{"class":5854},[5530,18770,5551],{"class":5543},[5530,18772,5984],{"class":5854},[5530,18774,5863],{"class":5543},[5530,18776,8169],{"class":5835},[5530,18778,5551],{"class":5543},[5530,18780,11535],{"class":5854},[5530,18782,5863],{"class":5543},[5530,18784,5989],{"class":5835},[5530,18786,6063],{"class":5543},[5530,18788,6066],{"class":5831},[5530,18790,5839],{"class":5543},[5530,18792,18793,18795],{"class":5532,"line":7793},[5530,18794,5882],{"class":5831},[5530,18796,11790],{"class":5543},[5530,18798,18799,18801,18803,18805,18807,18809,18811,18813],{"class":5532,"line":7798},[5530,18800,5882],{"class":5831},[5530,18802,11564],{"class":5543},[5530,18804,6114],{"class":5831},[5530,18806,11569],{"class":5547},[5530,18808,6120],{"class":5831},[5530,18810,11535],{"class":5543},[5530,18812,6125],{"class":5831},[5530,18814,11809],{"class":5547},[5530,18816,18817],{"class":5532,"line":7804},[5530,18818,5565],{"emptyLinePlaceholder":5564},[5530,18820,18821,18823,18825,18827,18829,18831,18833,18835,18837],{"class":5532,"line":7813},[5530,18822,5844],{"class":5831},[5530,18824,10199],{"class":5847},[5530,18826,5851],{"class":5543},[5530,18828,5855],{"class":5854},[5530,18830,5551],{"class":5543},[5530,18832,9554],{"class":5854},[5530,18834,5551],{"class":5543},[5530,18836,5984],{"class":5854},[5530,18838,5877],{"class":5543},[5530,18840,18841,18843,18845,18847,18849],{"class":5532,"line":7835},[5530,18842,6074],{"class":6073},[5530,18844,10225],{"class":5543},[5530,18846,10228],{"class":5831},[5530,18848,10186],{"class":5831},[5530,18850,5839],{"class":5543},[5530,18852,18853,18855],{"class":5532,"line":7840},[5530,18854,10237],{"class":6073},[5530,18856,10240],{"class":5831},[5530,18858,18859,18861,18863,18865,18867,18869,18871],{"class":5532,"line":7846},[5530,18860,6243],{"class":6073},[5530,18862,11865],{"class":5847},[5530,18864,11868],{"class":5543},[5530,18866,5855],{"class":5831},[5530,18868,11873],{"class":5543},[5530,18870,6080],{"class":5554},[5530,18872,5558],{"class":5543},[5530,18874,18875],{"class":5532,"line":7853},[5530,18876,5565],{"emptyLinePlaceholder":5564},[5530,18878,18879,18881,18883,18885,18887,18889,18891,18893,18895,18897,18899],{"class":5532,"line":7862},[5530,18880,5844],{"class":5831},[5530,18882,10288],{"class":5847},[5530,18884,5851],{"class":5543},[5530,18886,5855],{"class":5854},[5530,18888,5551],{"class":5543},[5530,18890,9554],{"class":5854},[5530,18892,5551],{"class":5543},[5530,18894,7313],{"class":5854},[5530,18896,6063],{"class":5543},[5530,18898,6066],{"class":5831},[5530,18900,5839],{"class":5543},[5530,18902,18903,18905,18907,18909,18911,18913],{"class":5532,"line":7873},[5530,18904,6074],{"class":6073},[5530,18906,8134],{"class":5831},[5530,18908,8137],{"class":5847},[5530,18910,11925],{"class":5543},[5530,18912,8143],{"class":5835},[5530,18914,5877],{"class":5543},[5530,18916,18917,18919,18921],{"class":5532,"line":8384},[5530,18918,6087],{"class":6073},[5530,18920,8157],{"class":5835},[5530,18922,11938],{"class":5543},[5530,18924,18925,18927,18929,18931,18933,18935],{"class":5532,"line":8390},[5530,18926,11943],{"class":5831},[5530,18928,11946],{"class":5547},[5530,18930,6857],{"class":5831},[5530,18932,11951],{"class":5543},[5530,18934,6125],{"class":5831},[5530,18936,11956],{"class":5547},[5530,18938,18939,18941,18943,18945,18947,18949,18951,18953],{"class":5532,"line":8402},[5530,18940,11943],{"class":5831},[5530,18942,11963],{"class":5547},[5530,18944,6120],{"class":5831},[5530,18946,8169],{"class":5835},[5530,18948,8172],{"class":5543},[5530,18950,8175],{"class":5854},[5530,18952,11974],{"class":5831},[5530,18954,11809],{"class":5547},[5530,18956,18957],{"class":5532,"line":8412},[5530,18958,11981],{"class":5543},[5530,18960,18961,18963,18965,18967],{"class":5532,"line":8417},[5530,18962,6074],{"class":6073},[5530,18964,7329],{"class":5543},[5530,18966,6080],{"class":5554},[5530,18968,5839],{"class":5543},[5530,18970,18971,18973,18975],{"class":5532,"line":8423},[5530,18972,6087],{"class":6073},[5530,18974,6090],{"class":5835},[5530,18976,11938],{"class":5543},[5530,18978,18979,18981,18983,18985,18987,18989,18992,18994,18996,18998],{"class":5532,"line":8428},[5530,18980,11943],{"class":5831},[5530,18982,11946],{"class":5547},[5530,18984,6857],{"class":5831},[5530,18986,11951],{"class":5543},[5530,18988,6125],{"class":5831},[5530,18990,18991],{"class":5547},"' має бути >= 0, отримано ",[5530,18993,6120],{"class":5831},[5530,18995,7313],{"class":5543},[5530,18997,6125],{"class":5831},[5530,18999,11809],{"class":5547},[5530,19001,19002],{"class":5532,"line":8435},[5530,19003,11981],{"class":5543},[5530,19005,19006,19008,19010,19012],{"class":5532,"line":8453},[5530,19007,12074],{"class":5847},[5530,19009,11868],{"class":5543},[5530,19011,5855],{"class":5831},[5530,19013,12081],{"class":5543},[5521,19015,19018],{"className":5523,"code":19016,"filename":19017,"language":5525,"meta":5526,"style":5526},"from descriptors import PositiveFloat, NonNegativeInt\n\nclass Product:\n    \"\"\"\n    Товар інтернет-магазину.\n\n    Публічний інтерфейс:\n        name, price, stock — доступ через дескриптори\u002Fproperty\n        is_available        — обчислювана read-only властивість\n        reserve(qty)        — резервує stock\n        release(qty)        — повертає stock\n\n    Деталі реалізації (захищені):\n        _category           — категорія (рядок), може змінитися\n    \"\"\"\n\n    # Дескриптори — валідація при кожному присвоєнні\n    price = PositiveFloat()\n    stock = NonNegativeInt()\n\n    def __init__(\n        self,\n        name:     str,\n        price:    float,\n        stock:    int,\n        category: str = \"Загальне\",\n    ):\n        if not name.strip():\n            raise ValueError(\"Назва продукту не може бути порожньою\")\n        self.name      = name.strip()\n        self.price     = price    # → PositiveFloat.__set__ (валідація)\n        self.stock     = stock    # → NonNegativeInt.__set__ (валідація)\n        self._category = category # захищений: деталь реалізації\n\n    # ── Обчислювальні властивості (read-only) ─────────────────────────────────\n\n    @property\n    def is_available(self) -> bool:\n        \"\"\"True, якщо товар є у наявності.\"\"\"\n        return self.stock > 0\n\n    @property\n    def category(self) -> str:\n        \"\"\"Категорія товару (лише читання ззовні).\"\"\"\n        return self._category\n\n    # ── Методи бізнес-логіки ──────────────────────────────────────────────────\n\n    def reserve(self, qty: int) -> None:\n        \"\"\"Резервує qty одиниць товару (зменшує stock).\"\"\"\n        if not isinstance(qty, int) or qty \u003C= 0:\n            raise ValueError(f\"qty має бути додатним int, отримано {qty!r}\")\n        if qty > self.stock:\n            raise ValueError(\n                f\"Недостатньо '{self.name}': потрібно {qty}, \"\n                f\"доступно {self.stock}\"\n            )\n        self.stock -= qty\n\n    def release(self, qty: int) -> None:\n        \"\"\"Повертає qty одиниць товару (збільшує stock).\"\"\"\n        if not isinstance(qty, int) or qty \u003C= 0:\n            raise ValueError(f\"qty має бути додатним int\")\n        self.stock += qty\n\n    def __repr__(self) -> str:\n        status = \"✅\" if self.is_available else \"❌\"\n        return (\n            f\"Product({self.name!r}, price={self.price:.2f} грн, \"\n            f\"stock={self.stock} {status})\"\n        )\n","product.py",[5512,19019,19020,19032,19036,19044,19048,19053,19057,19062,19067,19072,19077,19082,19086,19091,19096,19100,19104,19109,19114,19119,19123,19131,19137,19149,19160,19171,19187,19191,19200,19213,19220,19230,19240,19250,19254,19259,19263,19269,19286,19291,19303,19307,19313,19330,19335,19344,19348,19353,19357,19383,19388,19412,19435,19447,19455,19479,19495,19499,19506,19510,19535,19540,19562,19577,19584,19588,19604,19624,19630,19654,19677],{"__ignoreMap":5526},[5530,19021,19022,19024,19027,19029],{"class":5532,"line":5533},[5530,19023,15072],{"class":6073},[5530,19025,19026],{"class":5543}," descriptors ",[5530,19028,7488],{"class":6073},[5530,19030,19031],{"class":5543}," PositiveFloat, NonNegativeInt\n",[5530,19033,19034],{"class":5532,"line":5540},[5530,19035,5565],{"emptyLinePlaceholder":5564},[5530,19037,19038,19040,19042],{"class":5532,"line":5561},[5530,19039,5832],{"class":5831},[5530,19041,17245],{"class":5835},[5530,19043,5839],{"class":5543},[5530,19045,19046],{"class":5532,"line":5568},[5530,19047,7990],{"class":5547},[5530,19049,19050],{"class":5532,"line":5574},[5530,19051,19052],{"class":5547},"    Товар інтернет-магазину.\n",[5530,19054,19055],{"class":5532,"line":5586},[5530,19056,5565],{"emptyLinePlaceholder":5564},[5530,19058,19059],{"class":5532,"line":5598},[5530,19060,19061],{"class":5547},"    Публічний інтерфейс:\n",[5530,19063,19064],{"class":5532,"line":5603},[5530,19065,19066],{"class":5547},"        name, price, stock — доступ через дескриптори\u002Fproperty\n",[5530,19068,19069],{"class":5532,"line":5609},[5530,19070,19071],{"class":5547},"        is_available        — обчислювана read-only властивість\n",[5530,19073,19074],{"class":5532,"line":5758},[5530,19075,19076],{"class":5547},"        reserve(qty)        — резервує stock\n",[5530,19078,19079],{"class":5532,"line":5764},[5530,19080,19081],{"class":5547},"        release(qty)        — повертає stock\n",[5530,19083,19084],{"class":5532,"line":5770},[5530,19085,5565],{"emptyLinePlaceholder":5564},[5530,19087,19088],{"class":5532,"line":5775},[5530,19089,19090],{"class":5547},"    Деталі реалізації (захищені):\n",[5530,19092,19093],{"class":5532,"line":5781},[5530,19094,19095],{"class":5547},"        _category           — категорія (рядок), може змінитися\n",[5530,19097,19098],{"class":5532,"line":5786},[5530,19099,7990],{"class":5547},[5530,19101,19102],{"class":5532,"line":5792},[5530,19103,5565],{"emptyLinePlaceholder":5564},[5530,19105,19106],{"class":5532,"line":5798},[5530,19107,19108],{"class":5536},"    # Дескриптори — валідація при кожному присвоєнні\n",[5530,19110,19111],{"class":5532,"line":6187},[5530,19112,19113],{"class":5543},"    price = PositiveFloat()\n",[5530,19115,19116],{"class":5532,"line":6195},[5530,19117,19118],{"class":5543},"    stock = NonNegativeInt()\n",[5530,19120,19121],{"class":5532,"line":6217},[5530,19122,5565],{"emptyLinePlaceholder":5564},[5530,19124,19125,19127,19129],{"class":5532,"line":6222},[5530,19126,5844],{"class":5831},[5530,19128,5848],{"class":5847},[5530,19130,11938],{"class":5543},[5530,19132,19133,19135],{"class":5532,"line":6240},[5530,19134,5882],{"class":5854},[5530,19136,15167],{"class":5543},[5530,19138,19139,19142,19145,19147],{"class":5532,"line":6635},[5530,19140,19141],{"class":5854},"        name",[5530,19143,19144],{"class":5543},":     ",[5530,19146,5989],{"class":5835},[5530,19148,15167],{"class":5543},[5530,19150,19151,19154,19156,19158],{"class":5532,"line":6640},[5530,19152,19153],{"class":5854},"        price",[5530,19155,15240],{"class":5543},[5530,19157,5649],{"class":5835},[5530,19159,15167],{"class":5543},[5530,19161,19162,19165,19167,19169],{"class":5532,"line":6646},[5530,19163,19164],{"class":5854},"        stock",[5530,19166,15240],{"class":5543},[5530,19168,8143],{"class":5835},[5530,19170,15167],{"class":5543},[5530,19172,19173,19176,19178,19180,19182,19185],{"class":5532,"line":6659},[5530,19174,19175],{"class":5854},"        category",[5530,19177,5863],{"class":5543},[5530,19179,5989],{"class":5835},[5530,19181,12293],{"class":5543},[5530,19183,19184],{"class":5547},"\"Загальне\"",[5530,19186,15167],{"class":5543},[5530,19188,19189],{"class":5532,"line":6664},[5530,19190,15253],{"class":5543},[5530,19192,19193,19195,19197],{"class":5532,"line":6670},[5530,19194,6074],{"class":6073},[5530,19196,8134],{"class":5831},[5530,19198,19199],{"class":5543}," name.strip():\n",[5530,19201,19202,19204,19206,19208,19211],{"class":5532,"line":6678},[5530,19203,6087],{"class":6073},[5530,19205,6090],{"class":5835},[5530,19207,5851],{"class":5543},[5530,19209,19210],{"class":5547},"\"Назва продукту не може бути порожньою\"",[5530,19212,5558],{"class":5543},[5530,19214,19215,19217],{"class":5532,"line":6687},[5530,19216,5882],{"class":5831},[5530,19218,19219],{"class":5543},".name      = name.strip()\n",[5530,19221,19222,19224,19227],{"class":5532,"line":7770},[5530,19223,5882],{"class":5831},[5530,19225,19226],{"class":5543},".price     = price    ",[5530,19228,19229],{"class":5536},"# → PositiveFloat.__set__ (валідація)\n",[5530,19231,19232,19234,19237],{"class":5532,"line":7793},[5530,19233,5882],{"class":5831},[5530,19235,19236],{"class":5543},".stock     = stock    ",[5530,19238,19239],{"class":5536},"# → NonNegativeInt.__set__ (валідація)\n",[5530,19241,19242,19244,19247],{"class":5532,"line":7798},[5530,19243,5882],{"class":5831},[5530,19245,19246],{"class":5543},"._category = category ",[5530,19248,19249],{"class":5536},"# захищений: деталь реалізації\n",[5530,19251,19252],{"class":5532,"line":7804},[5530,19253,5565],{"emptyLinePlaceholder":5564},[5530,19255,19256],{"class":5532,"line":7813},[5530,19257,19258],{"class":5536},"    # ── Обчислювальні властивості (read-only) ─────────────────────────────────\n",[5530,19260,19261],{"class":5532,"line":7835},[5530,19262,5565],{"emptyLinePlaceholder":5564},[5530,19264,19265,19267],{"class":5532,"line":7840},[5530,19266,7565],{"class":5847},[5530,19268,7568],{"class":5835},[5530,19270,19271,19273,19276,19278,19280,19282,19284],{"class":5532,"line":7846},[5530,19272,5844],{"class":5831},[5530,19274,19275],{"class":5847}," is_available",[5530,19277,5851],{"class":5543},[5530,19279,5855],{"class":5854},[5530,19281,6063],{"class":5543},[5530,19283,13534],{"class":5835},[5530,19285,5839],{"class":5543},[5530,19287,19288],{"class":5532,"line":7853},[5530,19289,19290],{"class":5547},"        \"\"\"True, якщо товар є у наявності.\"\"\"\n",[5530,19292,19293,19295,19297,19300],{"class":5532,"line":7862},[5530,19294,6243],{"class":6073},[5530,19296,6246],{"class":5831},[5530,19298,19299],{"class":5543},".stock > ",[5530,19301,19302],{"class":5554},"0\n",[5530,19304,19305],{"class":5532,"line":7873},[5530,19306,5565],{"emptyLinePlaceholder":5564},[5530,19308,19309,19311],{"class":5532,"line":8384},[5530,19310,7565],{"class":5847},[5530,19312,7568],{"class":5835},[5530,19314,19315,19317,19320,19322,19324,19326,19328],{"class":5532,"line":8390},[5530,19316,5844],{"class":5831},[5530,19318,19319],{"class":5847}," category",[5530,19321,5851],{"class":5543},[5530,19323,5855],{"class":5854},[5530,19325,6063],{"class":5543},[5530,19327,5989],{"class":5835},[5530,19329,5839],{"class":5543},[5530,19331,19332],{"class":5532,"line":8402},[5530,19333,19334],{"class":5547},"        \"\"\"Категорія товару (лише читання ззовні).\"\"\"\n",[5530,19336,19337,19339,19341],{"class":5532,"line":8412},[5530,19338,6243],{"class":6073},[5530,19340,6246],{"class":5831},[5530,19342,19343],{"class":5543},"._category\n",[5530,19345,19346],{"class":5532,"line":8417},[5530,19347,5565],{"emptyLinePlaceholder":5564},[5530,19349,19350],{"class":5532,"line":8423},[5530,19351,19352],{"class":5536},"    # ── Методи бізнес-логіки ──────────────────────────────────────────────────\n",[5530,19354,19355],{"class":5532,"line":8428},[5530,19356,5565],{"emptyLinePlaceholder":5564},[5530,19358,19359,19361,19364,19366,19368,19370,19373,19375,19377,19379,19381],{"class":5532,"line":8435},[5530,19360,5844],{"class":5831},[5530,19362,19363],{"class":5847}," reserve",[5530,19365,5851],{"class":5543},[5530,19367,5855],{"class":5854},[5530,19369,5551],{"class":5543},[5530,19371,19372],{"class":5854},"qty",[5530,19374,5863],{"class":5543},[5530,19376,8143],{"class":5835},[5530,19378,6063],{"class":5543},[5530,19380,6066],{"class":5831},[5530,19382,5839],{"class":5543},[5530,19384,19385],{"class":5532,"line":8453},[5530,19386,19387],{"class":5547},"        \"\"\"Резервує qty одиниць товару (зменшує stock).\"\"\"\n",[5530,19389,19390,19392,19394,19396,19399,19401,19403,19405,19408,19410],{"class":5532,"line":8459},[5530,19391,6074],{"class":6073},[5530,19393,8134],{"class":5831},[5530,19395,8137],{"class":5847},[5530,19397,19398],{"class":5543},"(qty, ",[5530,19400,8143],{"class":5835},[5530,19402,12809],{"class":5543},[5530,19404,10169],{"class":5831},[5530,19406,19407],{"class":5543}," qty \u003C= ",[5530,19409,6080],{"class":5554},[5530,19411,5839],{"class":5543},[5530,19413,19414,19416,19418,19420,19422,19425,19427,19429,19431,19433],{"class":5532,"line":10597},[5530,19415,6087],{"class":6073},[5530,19417,6090],{"class":5835},[5530,19419,5851],{"class":5543},[5530,19421,6114],{"class":5831},[5530,19423,19424],{"class":5547},"\"qty має бути додатним int, отримано ",[5530,19426,6120],{"class":5831},[5530,19428,19372],{"class":5543},[5530,19430,11974],{"class":5831},[5530,19432,6128],{"class":5547},[5530,19434,5558],{"class":5543},[5530,19436,19437,19439,19442,19444],{"class":5532,"line":10622},[5530,19438,6074],{"class":6073},[5530,19440,19441],{"class":5543}," qty > ",[5530,19443,5855],{"class":5831},[5530,19445,19446],{"class":5543},".stock:\n",[5530,19448,19449,19451,19453],{"class":5532,"line":10633},[5530,19450,6087],{"class":6073},[5530,19452,6090],{"class":5835},[5530,19454,11938],{"class":5543},[5530,19456,19457,19459,19462,19464,19466,19468,19471,19473,19475,19477],{"class":5532,"line":10647},[5530,19458,11943],{"class":5831},[5530,19460,19461],{"class":5547},"\"Недостатньо '",[5530,19463,6857],{"class":5831},[5530,19465,12373],{"class":5543},[5530,19467,6125],{"class":5831},[5530,19469,19470],{"class":5547},"': потрібно ",[5530,19472,6120],{"class":5831},[5530,19474,19372],{"class":5543},[5530,19476,6125],{"class":5831},[5530,19478,12388],{"class":5547},[5530,19480,19481,19483,19486,19488,19491,19493],{"class":5532,"line":10655},[5530,19482,11943],{"class":5831},[5530,19484,19485],{"class":5547},"\"доступно ",[5530,19487,6857],{"class":5831},[5530,19489,19490],{"class":5543},".stock",[5530,19492,6125],{"class":5831},[5530,19494,11809],{"class":5547},[5530,19496,19497],{"class":5532,"line":10660},[5530,19498,11981],{"class":5543},[5530,19500,19501,19503],{"class":5532,"line":10665},[5530,19502,5882],{"class":5831},[5530,19504,19505],{"class":5543},".stock -= qty\n",[5530,19507,19508],{"class":5532,"line":10676},[5530,19509,5565],{"emptyLinePlaceholder":5564},[5530,19511,19512,19514,19517,19519,19521,19523,19525,19527,19529,19531,19533],{"class":5532,"line":10687},[5530,19513,5844],{"class":5831},[5530,19515,19516],{"class":5847}," release",[5530,19518,5851],{"class":5543},[5530,19520,5855],{"class":5854},[5530,19522,5551],{"class":5543},[5530,19524,19372],{"class":5854},[5530,19526,5863],{"class":5543},[5530,19528,8143],{"class":5835},[5530,19530,6063],{"class":5543},[5530,19532,6066],{"class":5831},[5530,19534,5839],{"class":5543},[5530,19536,19537],{"class":5532,"line":10696},[5530,19538,19539],{"class":5547},"        \"\"\"Повертає qty одиниць товару (збільшує stock).\"\"\"\n",[5530,19541,19542,19544,19546,19548,19550,19552,19554,19556,19558,19560],{"class":5532,"line":10706},[5530,19543,6074],{"class":6073},[5530,19545,8134],{"class":5831},[5530,19547,8137],{"class":5847},[5530,19549,19398],{"class":5543},[5530,19551,8143],{"class":5835},[5530,19553,12809],{"class":5543},[5530,19555,10169],{"class":5831},[5530,19557,19407],{"class":5543},[5530,19559,6080],{"class":5554},[5530,19561,5839],{"class":5543},[5530,19563,19564,19566,19568,19570,19572,19575],{"class":5532,"line":10711},[5530,19565,6087],{"class":6073},[5530,19567,6090],{"class":5835},[5530,19569,5851],{"class":5543},[5530,19571,6114],{"class":5831},[5530,19573,19574],{"class":5547},"\"qty має бути додатним int\"",[5530,19576,5558],{"class":5543},[5530,19578,19579,19581],{"class":5532,"line":10718},[5530,19580,5882],{"class":5831},[5530,19582,19583],{"class":5543},".stock += qty\n",[5530,19585,19586],{"class":5532,"line":10726},[5530,19587,5565],{"emptyLinePlaceholder":5564},[5530,19589,19590,19592,19594,19596,19598,19600,19602],{"class":5532,"line":10737},[5530,19591,5844],{"class":5831},[5530,19593,12092],{"class":5847},[5530,19595,5851],{"class":5543},[5530,19597,5855],{"class":5854},[5530,19599,6063],{"class":5543},[5530,19601,5989],{"class":5835},[5530,19603,5839],{"class":5543},[5530,19605,19606,19609,19612,19614,19616,19619,19621],{"class":5532,"line":12391},[5530,19607,19608],{"class":5543},"        status = ",[5530,19610,19611],{"class":5547},"\"✅\"",[5530,19613,10177],{"class":6073},[5530,19615,6246],{"class":5831},[5530,19617,19618],{"class":5543},".is_available ",[5530,19620,10183],{"class":6073},[5530,19622,19623],{"class":5547}," \"❌\"\n",[5530,19625,19626,19628],{"class":5532,"line":12429},[5530,19627,6243],{"class":6073},[5530,19629,12109],{"class":5543},[5530,19631,19632,19634,19636,19638,19640,19642,19644,19646,19648,19651],{"class":5532,"line":12434},[5530,19633,12114],{"class":5831},[5530,19635,17531],{"class":5547},[5530,19637,6857],{"class":5831},[5530,19639,12373],{"class":5543},[5530,19641,11974],{"class":5831},[5530,19643,17540],{"class":5547},[5530,19645,6857],{"class":5831},[5530,19647,17545],{"class":5543},[5530,19649,19650],{"class":5831},":.2f}",[5530,19652,19653],{"class":5547}," грн, \"\n",[5530,19655,19656,19658,19661,19663,19665,19667,19670,19673,19675],{"class":5532,"line":12439},[5530,19657,12114],{"class":5831},[5530,19659,19660],{"class":5547},"\"stock=",[5530,19662,6857],{"class":5831},[5530,19664,19490],{"class":5543},[5530,19666,6125],{"class":5831},[5530,19668,19669],{"class":5831}," {",[5530,19671,19672],{"class":5543},"status",[5530,19674,6125],{"class":5831},[5530,19676,12426],{"class":5547},[5530,19678,19679],{"class":5532,"line":12444},[5530,19680,12155],{"class":5543},[5521,19682,19685],{"className":5523,"code":19683,"filename":19684,"language":5525,"meta":5526,"style":5526},"from __future__ import annotations\nfrom dataclasses import dataclass, field\nfrom product import Product\n\nTAX_RATE = 0.20  # ПДВ 20%\n\n# Словник активних купонів {код: відсоток_знижки}\nVALID_COUPONS: dict[str, float] = {\n    \"SALE10\": 10.0,\n    \"VIP20\":  20.0,\n    \"WELCOME5\": 5.0,\n}\n\n\n@dataclass\nclass Receipt:\n    \"\"\"Чек замовлення — незмінний запис після checkout.\"\"\"\n    items:        list[tuple[str, int, float]]  # (назва, qty, ціна)\n    subtotal:     float\n    tax:          float\n    discount:     float\n    total:        float\n    coupon_code:  str | None = None\n\n    def to_text(self) -> str:\n        lines = [\"=\" * 42, \"        ЧАРТЕР ЗАМОВЛЕННЯ\", \"=\" * 42]\n        for name, qty, price in self.items:\n            lines.append(f\"  {name:\u003C20} {qty} × {price:>7.2f} грн\")\n        lines += [\n            \"-\" * 42,\n            f\"  Сума без ПДВ:    {self.subtotal - self.tax:>10.2f} грн\",\n            f\"  ПДВ (20%):       {self.tax:>10.2f} грн\",\n            f\"  Знижка{(' (' + self.coupon_code + ')') if self.coupon_code else '':>9}: {self.discount:>10.2f} грн\",\n            \"=\" * 42,\n            f\"  РАЗОМ:           {self.total:>10.2f} грн\",\n            \"=\" * 42,\n        ]\n        return \"\\n\".join(lines)\n\n\nclass Cart:\n    \"\"\"\n    Кошик покупця.\n\n    Публічний інтерфейс:\n        add(product, qty)    — додає товар\n        remove(product_name) — видаляє рядок\n        coupon               — геттер\u002Fсеттер\u002Fделітер купона\n        subtotal, tax, discount_amount, final_price — обчислювальні\n        checkout()           — оформляє замовлення, повертає Receipt\n\n    Захищені деталі:\n        _items               — внутрішній словник рядків кошика\n\n    Приватні (Name Mangling):\n        __discount_code      → _Cart__discount_code\n        __discount_percent   → _Cart__discount_percent\n        Захищені від перезапису підкласами!\n    \"\"\"\n\n    def __init__(self, owner_name: str):\n        self.owner_name        = owner_name\n        self._items: dict[str, dict] = {}     # {product.name: {product, qty}}\n        self.__discount_code:    str | None = None  # → _Cart__discount_code\n        self.__discount_percent: float      = 0.0   # → _Cart__discount_percent\n\n    # ── Купон — геттер + сеттер + делітер ────────────────────────────────────\n\n    @property\n    def coupon(self) -> str | None:\n        \"\"\"Поточний активний купон (або None).\"\"\"\n        return self.__discount_code\n\n    @coupon.setter\n    def coupon(self, code: str) -> None:\n        \"\"\"Активує купон після перевірки його валідності.\"\"\"\n        if not isinstance(code, str):\n            raise TypeError(\"Код купона має бути рядком\")\n        code = code.strip().upper()\n        if code not in VALID_COUPONS:\n            raise ValueError(\n                f\"Купон {code!r} не знайдено або вже не діє. \"\n                f\"Доступні: {list(VALID_COUPONS.keys())}\"\n            )\n        self.__discount_code    = code\n        self.__discount_percent = VALID_COUPONS[code]\n        print(f\"✅ Купон {code!r} активовано: знижка {self.__discount_percent:.0f}%\")\n\n    @coupon.deleter\n    def coupon(self) -> None:\n        \"\"\"Скасовує активний купон.\"\"\"\n        if self.__discount_code is None:\n            print(\"ℹ️  Активний купон відсутній\")\n            return\n        removed = self.__discount_code\n        self.__discount_code    = None\n        self.__discount_percent = 0.0\n        print(f\"🗑️  Купон {removed!r} скасовано\")\n\n    # ── Обчислювальні властивості (read-only) ─────────────────────────────────\n\n    @property\n    def subtotal(self) -> float:\n        \"\"\"Сума всіх товарів з ПДВ (до знижки).\"\"\"\n        return sum(\n            row[\"product\"].price * row[\"qty\"]\n            for row in self._items.values()\n        )\n\n    @property\n    def tax(self) -> float:\n        \"\"\"Сума ПДВ (20% від subtotal).\"\"\"\n        return round(self.subtotal * TAX_RATE \u002F (1 + TAX_RATE), 2)\n\n    @property\n    def discount_amount(self) -> float:\n        \"\"\"Сума знижки в гривнях.\"\"\"\n        return round(self.subtotal * self.__discount_percent \u002F 100, 2)\n\n    @property\n    def final_price(self) -> float:\n        \"\"\"Підсумкова сума до оплати.\"\"\"\n        return round(self.subtotal - self.discount_amount, 2)\n\n    @property\n    def item_count(self) -> int:\n        \"\"\"Загальна кількість одиниць товарів.\"\"\"\n        return sum(row[\"qty\"] for row in self._items.values())\n\n    # ── Методи бізнес-логіки ──────────────────────────────────────────────────\n\n    def add(self, product: Product, qty: int = 1) -> None:\n        \"\"\"Додає qty одиниць product у кошик і резервує stock.\"\"\"\n        if not isinstance(qty, int) or qty \u003C= 0:\n            raise ValueError(f\"qty має бути додатним int\")\n        if not product.is_available:\n            raise ValueError(f\"Товар '{product.name}' недоступний\")\n\n        product.reserve(qty)   # зменшує stock та валідує наявність\n\n        if product.name in self._items:\n            self._items[product.name][\"qty\"] += qty\n        else:\n            self._items[product.name] = {\"product\": product, \"qty\": qty}\n\n        print(f\"  + {product.name} × {qty}  ({product.price:.2f} грн\u002Fшт)\")\n\n    def remove(self, product_name: str) -> None:\n        \"\"\"Видаляє товар з кошика та повертає stock.\"\"\"\n        if product_name not in self._items:\n            raise KeyError(f\"'{product_name}' немає у кошику\")\n        row = self._items.pop(product_name)\n        row[\"product\"].release(row[\"qty\"])\n        print(f\"  - {product_name} видалено з кошика\")\n\n    def checkout(self) -> Receipt:\n        \"\"\"Оформлює замовлення: повертає Receipt та очищає кошик.\"\"\"\n        if not self._items:\n            raise ValueError(\"Кошик порожній — нічого оформляти\")\n\n        receipt = Receipt(\n            items=[\n                (row[\"product\"].name, row[\"qty\"], row[\"product\"].price)\n                for row in self._items.values()\n            ],\n            subtotal=self.subtotal,\n            tax=self.tax,\n            discount=self.discount_amount,\n            total=self.final_price,\n            coupon_code=self.__discount_code,\n        )\n        self._items.clear()\n        del self.coupon   # скидаємо купон після checkout\n        return receipt\n\n    def __repr__(self) -> str:\n        return (\n            f\"Cart({self.owner_name!r}, \"\n            f\"items={self.item_count}, \"\n            f\"total={self.final_price:.2f} грн)\"\n        )\n\n\nclass PremiumCart(Cart):\n    \"\"\"\n    Кошик преміум-клієнта: додаткова знижка за лояльністю.\n\n    Демонстрація Name Mangling:\n        self.__discount_code → _PremiumCart__discount_code (РІЗНЕ поле!)\n        super().__discount_code залишається _Cart__discount_code (НЕ перезаписано)\n    \"\"\"\n\n    LOYALTY_DISCOUNT = 5.0  # 5% додатково для VIP-клієнтів\n\n    def __init__(self, owner_name: str, loyalty_years: int = 1):\n        super().__init__(owner_name)\n        self.__discount_code = \"LOYALTY\"  # → _PremiumCart__discount_code\n        self._loyalty_years  = loyalty_years\n\n    @property\n    def loyalty_discount(self) -> float:\n        \"\"\"Знижка за лояльністю: 5% × кількість років.\"\"\"\n        return min(self.LOYALTY_DISCOUNT * self._loyalty_years, 25.0)\n\n    @property\n    def final_price(self) -> float:\n        \"\"\"\n        Перевизначена властивість: знижка купона + знижка за лояльністю.\n        super().final_price використовує _Cart__discount_code (купон),\n        а self.loyalty_discount — з _PremiumCart__discount_code.\n        \"\"\"\n        base = super().final_price\n        loyalty_saving = round(base * self.loyalty_discount \u002F 100, 2)\n        return round(base - loyalty_saving, 2)\n\n    def __repr__(self) -> str:\n        return (\n            f\"PremiumCart({self.owner_name!r}, \"\n            f\"loyalty={self.loyalty_discount:.0f}%, \"\n            f\"total={self.final_price:.2f} грн)\"\n        )\n","cart.py",[5512,19686,19687,19700,19712,19724,19728,19739,19743,19748,19762,19773,19784,19795,19799,19803,19807,19812,19821,19826,19847,19855,19862,19869,19876,19891,19895,19912,19941,19955,19993,19998,20009,20033,20050,20103,20114,20132,20142,20147,20161,20165,20169,20178,20182,20187,20191,20195,20200,20205,20210,20215,20220,20224,20229,20234,20238,20243,20248,20253,20258,20262,20266,20287,20294,20314,20334,20351,20355,20360,20364,20370,20391,20396,20405,20409,20414,20438,20443,20458,20471,20476,20491,20499,20515,20533,20537,20544,20551,20584,20588,20593,20609,20614,20629,20641,20645,20654,20663,20673,20696,20700,20704,20708,20714,20731,20736,20745,20761,20776,20780,20784,20790,20807,20812,20836,20840,20846,20863,20868,20894,20898,20904,20921,20926,20947,20951,20957,20974,20979,21003,21007,21011,21015,21050,21055,21077,21091,21101,21127,21132,21141,21146,21161,21174,21182,21200,21205,21246,21251,21278,21284,21300,21325,21336,21352,21375,21380,21395,21401,21412,21426,21431,21437,21446,21467,21481,21487,21500,21513,21526,21539,21552,21557,21565,21578,21586,21591,21608,21615,21632,21649,21667,21672,21677,21682,21697,21702,21708,21713,21719,21725,21731,21736,21741,21752,21757,21791,21803,21817,21825,21830,21837,21855,21861,21885,21890,21897,21914,21920,21926,21932,21938,21943,21955,21980,21994,21999,22016,22023,22039,22057,22072],{"__ignoreMap":5526},[5530,19688,19689,19691,19694,19697],{"class":5532,"line":5533},[5530,19690,15072],{"class":6073},[5530,19692,19693],{"class":5854}," __future__",[5530,19695,19696],{"class":6073}," import",[5530,19698,19699],{"class":5543}," annotations\n",[5530,19701,19702,19704,19707,19709],{"class":5532,"line":5540},[5530,19703,15072],{"class":6073},[5530,19705,19706],{"class":5543}," dataclasses ",[5530,19708,7488],{"class":6073},[5530,19710,19711],{"class":5543}," dataclass, field\n",[5530,19713,19714,19716,19719,19721],{"class":5532,"line":5561},[5530,19715,15072],{"class":6073},[5530,19717,19718],{"class":5543}," product ",[5530,19720,7488],{"class":6073},[5530,19722,19723],{"class":5543}," Product\n",[5530,19725,19726],{"class":5532,"line":5568},[5530,19727,5565],{"emptyLinePlaceholder":5564},[5530,19729,19730,19733,19736],{"class":5532,"line":5574},[5530,19731,19732],{"class":5543},"TAX_RATE = ",[5530,19734,19735],{"class":5554},"0.20",[5530,19737,19738],{"class":5536},"  # ПДВ 20%\n",[5530,19740,19741],{"class":5532,"line":5586},[5530,19742,5565],{"emptyLinePlaceholder":5564},[5530,19744,19745],{"class":5532,"line":5598},[5530,19746,19747],{"class":5536},"# Словник активних купонів {код: відсоток_знижки}\n",[5530,19749,19750,19753,19755,19757,19759],{"class":5532,"line":5603},[5530,19751,19752],{"class":5543},"VALID_COUPONS: dict[",[5530,19754,5989],{"class":5835},[5530,19756,5551],{"class":5543},[5530,19758,5649],{"class":5835},[5530,19760,19761],{"class":5543},"] = {\n",[5530,19763,19764,19767,19769,19771],{"class":5532,"line":5609},[5530,19765,19766],{"class":5547},"    \"SALE10\"",[5530,19768,5863],{"class":5543},[5530,19770,5925],{"class":5554},[5530,19772,15167],{"class":5543},[5530,19774,19775,19778,19780,19782],{"class":5532,"line":5758},[5530,19776,19777],{"class":5547},"    \"VIP20\"",[5530,19779,15197],{"class":5543},[5530,19781,13912],{"class":5554},[5530,19783,15167],{"class":5543},[5530,19785,19786,19789,19791,19793],{"class":5532,"line":5764},[5530,19787,19788],{"class":5547},"    \"WELCOME5\"",[5530,19790,5863],{"class":5543},[5530,19792,7711],{"class":5554},[5530,19794,15167],{"class":5543},[5530,19796,19797],{"class":5532,"line":5770},[5530,19798,5767],{"class":5543},[5530,19800,19801],{"class":5532,"line":5775},[5530,19802,5565],{"emptyLinePlaceholder":5564},[5530,19804,19805],{"class":5532,"line":5781},[5530,19806,5565],{"emptyLinePlaceholder":5564},[5530,19808,19809],{"class":5532,"line":5786},[5530,19810,19811],{"class":5847},"@dataclass\n",[5530,19813,19814,19816,19819],{"class":5532,"line":5792},[5530,19815,5832],{"class":5831},[5530,19817,19818],{"class":5835}," Receipt",[5530,19820,5839],{"class":5543},[5530,19822,19823],{"class":5532,"line":5798},[5530,19824,19825],{"class":5547},"    \"\"\"Чек замовлення — незмінний запис після checkout.\"\"\"\n",[5530,19827,19828,19831,19833,19835,19837,19839,19841,19844],{"class":5532,"line":6187},[5530,19829,19830],{"class":5543},"    items:        list[tuple[",[5530,19832,5989],{"class":5835},[5530,19834,5551],{"class":5543},[5530,19836,8143],{"class":5835},[5530,19838,5551],{"class":5543},[5530,19840,5649],{"class":5835},[5530,19842,19843],{"class":5543},"]]  ",[5530,19845,19846],{"class":5536},"# (назва, qty, ціна)\n",[5530,19848,19849,19852],{"class":5532,"line":6195},[5530,19850,19851],{"class":5543},"    subtotal:     ",[5530,19853,19854],{"class":5835},"float\n",[5530,19856,19857,19860],{"class":5532,"line":6217},[5530,19858,19859],{"class":5543},"    tax:          ",[5530,19861,19854],{"class":5835},[5530,19863,19864,19867],{"class":5532,"line":6222},[5530,19865,19866],{"class":5543},"    discount:     ",[5530,19868,19854],{"class":5835},[5530,19870,19871,19874],{"class":5532,"line":6240},[5530,19872,19873],{"class":5543},"    total:        ",[5530,19875,19854],{"class":5835},[5530,19877,19878,19881,19883,19885,19887,19889],{"class":5532,"line":6635},[5530,19879,19880],{"class":5543},"    coupon_code:  ",[5530,19882,5989],{"class":5835},[5530,19884,14819],{"class":5543},[5530,19886,6066],{"class":5831},[5530,19888,12293],{"class":5543},[5530,19890,11734],{"class":5831},[5530,19892,19893],{"class":5532,"line":6640},[5530,19894,5565],{"emptyLinePlaceholder":5564},[5530,19896,19897,19899,19902,19904,19906,19908,19910],{"class":5532,"line":6646},[5530,19898,5844],{"class":5831},[5530,19900,19901],{"class":5847}," to_text",[5530,19903,5851],{"class":5543},[5530,19905,5855],{"class":5854},[5530,19907,6063],{"class":5543},[5530,19909,5989],{"class":5835},[5530,19911,5839],{"class":5543},[5530,19913,19914,19917,19920,19923,19926,19928,19931,19933,19935,19937,19939],{"class":5532,"line":6659},[5530,19915,19916],{"class":5543},"        lines = [",[5530,19918,19919],{"class":5547},"\"=\"",[5530,19921,19922],{"class":5543}," * ",[5530,19924,19925],{"class":5554},"42",[5530,19927,5551],{"class":5543},[5530,19929,19930],{"class":5547},"\"        ЧАРТЕР ЗАМОВЛЕННЯ\"",[5530,19932,5551],{"class":5543},[5530,19934,19919],{"class":5547},[5530,19936,19922],{"class":5543},[5530,19938,19925],{"class":5554},[5530,19940,12758],{"class":5543},[5530,19942,19943,19945,19948,19950,19952],{"class":5532,"line":6664},[5530,19944,17031],{"class":6073},[5530,19946,19947],{"class":5543}," name, qty, price ",[5530,19949,12556],{"class":6073},[5530,19951,6246],{"class":5831},[5530,19953,19954],{"class":5543},".items:\n",[5530,19956,19957,19960,19962,19965,19967,19969,19972,19974,19976,19978,19981,19983,19985,19988,19991],{"class":5532,"line":6670},[5530,19958,19959],{"class":5543},"            lines.append(",[5530,19961,6114],{"class":5831},[5530,19963,19964],{"class":5547},"\"  ",[5530,19966,6120],{"class":5831},[5530,19968,11535],{"class":5543},[5530,19970,19971],{"class":5831},":\u003C20}",[5530,19973,19669],{"class":5831},[5530,19975,19372],{"class":5543},[5530,19977,6125],{"class":5831},[5530,19979,19980],{"class":5547}," × ",[5530,19982,6120],{"class":5831},[5530,19984,17439],{"class":5543},[5530,19986,19987],{"class":5831},":>7.2f}",[5530,19989,19990],{"class":5547}," грн\"",[5530,19992,5558],{"class":5543},[5530,19994,19995],{"class":5532,"line":6678},[5530,19996,19997],{"class":5543},"        lines += [\n",[5530,19999,20000,20003,20005,20007],{"class":5532,"line":6687},[5530,20001,20002],{"class":5547},"            \"-\"",[5530,20004,19922],{"class":5543},[5530,20006,19925],{"class":5554},[5530,20008,15167],{"class":5543},[5530,20010,20011,20013,20016,20018,20021,20023,20026,20029,20031],{"class":5532,"line":7770},[5530,20012,12114],{"class":5831},[5530,20014,20015],{"class":5547},"\"  Сума без ПДВ:    ",[5530,20017,6857],{"class":5831},[5530,20019,20020],{"class":5543},".subtotal - ",[5530,20022,5855],{"class":5831},[5530,20024,20025],{"class":5543},".tax",[5530,20027,20028],{"class":5831},":>10.2f}",[5530,20030,19990],{"class":5547},[5530,20032,15167],{"class":5543},[5530,20034,20035,20037,20040,20042,20044,20046,20048],{"class":5532,"line":7793},[5530,20036,12114],{"class":5831},[5530,20038,20039],{"class":5547},"\"  ПДВ (20%):       ",[5530,20041,6857],{"class":5831},[5530,20043,20025],{"class":5543},[5530,20045,20028],{"class":5831},[5530,20047,19990],{"class":5547},[5530,20049,15167],{"class":5543},[5530,20051,20052,20054,20057,20059,20061,20064,20066,20068,20071,20074,20076,20078,20080,20083,20085,20087,20090,20092,20094,20097,20099,20101],{"class":5532,"line":7798},[5530,20053,12114],{"class":5831},[5530,20055,20056],{"class":5547},"\"  Знижка",[5530,20058,6120],{"class":5831},[5530,20060,5851],{"class":5543},[5530,20062,20063],{"class":5547},"' ('",[5530,20065,17101],{"class":5543},[5530,20067,5855],{"class":5831},[5530,20069,20070],{"class":5543},".coupon_code + ",[5530,20072,20073],{"class":5547},"')'",[5530,20075,12809],{"class":5543},[5530,20077,17196],{"class":6073},[5530,20079,6246],{"class":5831},[5530,20081,20082],{"class":5543},".coupon_code ",[5530,20084,10183],{"class":6073},[5530,20086,17213],{"class":5547},[5530,20088,20089],{"class":5831},":>9}",[5530,20091,5863],{"class":5547},[5530,20093,6857],{"class":5831},[5530,20095,20096],{"class":5543},".discount",[5530,20098,20028],{"class":5831},[5530,20100,19990],{"class":5547},[5530,20102,15167],{"class":5543},[5530,20104,20105,20108,20110,20112],{"class":5532,"line":7804},[5530,20106,20107],{"class":5547},"            \"=\"",[5530,20109,19922],{"class":5543},[5530,20111,19925],{"class":5554},[5530,20113,15167],{"class":5543},[5530,20115,20116,20118,20121,20123,20126,20128,20130],{"class":5532,"line":7813},[5530,20117,12114],{"class":5831},[5530,20119,20120],{"class":5547},"\"  РАЗОМ:           ",[5530,20122,6857],{"class":5831},[5530,20124,20125],{"class":5543},".total",[5530,20127,20028],{"class":5831},[5530,20129,19990],{"class":5547},[5530,20131,15167],{"class":5543},[5530,20133,20134,20136,20138,20140],{"class":5532,"line":7835},[5530,20135,20107],{"class":5547},[5530,20137,19922],{"class":5543},[5530,20139,19925],{"class":5554},[5530,20141,15167],{"class":5543},[5530,20143,20144],{"class":5532,"line":7840},[5530,20145,20146],{"class":5543},"        ]\n",[5530,20148,20149,20151,20154,20156,20158],{"class":5532,"line":7846},[5530,20150,6243],{"class":6073},[5530,20152,20153],{"class":5547}," \"",[5530,20155,8589],{"class":8588},[5530,20157,6128],{"class":5547},[5530,20159,20160],{"class":5543},".join(lines)\n",[5530,20162,20163],{"class":5532,"line":7853},[5530,20164,5565],{"emptyLinePlaceholder":5564},[5530,20166,20167],{"class":5532,"line":7862},[5530,20168,5565],{"emptyLinePlaceholder":5564},[5530,20170,20171,20173,20176],{"class":5532,"line":7873},[5530,20172,5832],{"class":5831},[5530,20174,20175],{"class":5835}," Cart",[5530,20177,5839],{"class":5543},[5530,20179,20180],{"class":5532,"line":8384},[5530,20181,7990],{"class":5547},[5530,20183,20184],{"class":5532,"line":8390},[5530,20185,20186],{"class":5547},"    Кошик покупця.\n",[5530,20188,20189],{"class":5532,"line":8402},[5530,20190,5565],{"emptyLinePlaceholder":5564},[5530,20192,20193],{"class":5532,"line":8412},[5530,20194,19061],{"class":5547},[5530,20196,20197],{"class":5532,"line":8417},[5530,20198,20199],{"class":5547},"        add(product, qty)    — додає товар\n",[5530,20201,20202],{"class":5532,"line":8423},[5530,20203,20204],{"class":5547},"        remove(product_name) — видаляє рядок\n",[5530,20206,20207],{"class":5532,"line":8428},[5530,20208,20209],{"class":5547},"        coupon               — геттер\u002Fсеттер\u002Fделітер купона\n",[5530,20211,20212],{"class":5532,"line":8435},[5530,20213,20214],{"class":5547},"        subtotal, tax, discount_amount, final_price — обчислювальні\n",[5530,20216,20217],{"class":5532,"line":8453},[5530,20218,20219],{"class":5547},"        checkout()           — оформляє замовлення, повертає Receipt\n",[5530,20221,20222],{"class":5532,"line":8459},[5530,20223,5565],{"emptyLinePlaceholder":5564},[5530,20225,20226],{"class":5532,"line":10597},[5530,20227,20228],{"class":5547},"    Захищені деталі:\n",[5530,20230,20231],{"class":5532,"line":10622},[5530,20232,20233],{"class":5547},"        _items               — внутрішній словник рядків кошика\n",[5530,20235,20236],{"class":5532,"line":10633},[5530,20237,5565],{"emptyLinePlaceholder":5564},[5530,20239,20240],{"class":5532,"line":10647},[5530,20241,20242],{"class":5547},"    Приватні (Name Mangling):\n",[5530,20244,20245],{"class":5532,"line":10655},[5530,20246,20247],{"class":5547},"        __discount_code      → _Cart__discount_code\n",[5530,20249,20250],{"class":5532,"line":10660},[5530,20251,20252],{"class":5547},"        __discount_percent   → _Cart__discount_percent\n",[5530,20254,20255],{"class":5532,"line":10665},[5530,20256,20257],{"class":5547},"        Захищені від перезапису підкласами!\n",[5530,20259,20260],{"class":5532,"line":10676},[5530,20261,7990],{"class":5547},[5530,20263,20264],{"class":5532,"line":10687},[5530,20265,5565],{"emptyLinePlaceholder":5564},[5530,20267,20268,20270,20272,20274,20276,20278,20281,20283,20285],{"class":5532,"line":10696},[5530,20269,5844],{"class":5831},[5530,20271,5848],{"class":5847},[5530,20273,5851],{"class":5543},[5530,20275,5855],{"class":5854},[5530,20277,5551],{"class":5543},[5530,20279,20280],{"class":5854},"owner_name",[5530,20282,5863],{"class":5543},[5530,20284,5989],{"class":5835},[5530,20286,5877],{"class":5543},[5530,20288,20289,20291],{"class":5532,"line":10706},[5530,20290,5882],{"class":5831},[5530,20292,20293],{"class":5543},".owner_name        = owner_name\n",[5530,20295,20296,20298,20301,20303,20305,20308,20311],{"class":5532,"line":10711},[5530,20297,5882],{"class":5831},[5530,20299,20300],{"class":5543},"._items: dict[",[5530,20302,5989],{"class":5835},[5530,20304,5551],{"class":5543},[5530,20306,20307],{"class":5835},"dict",[5530,20309,20310],{"class":5543},"] = {}     ",[5530,20312,20313],{"class":5536},"# {product.name: {product, qty}}\n",[5530,20315,20316,20318,20321,20323,20325,20327,20329,20331],{"class":5532,"line":10718},[5530,20317,5882],{"class":5831},[5530,20319,20320],{"class":5543},".__discount_code:    ",[5530,20322,5989],{"class":5835},[5530,20324,14819],{"class":5543},[5530,20326,6066],{"class":5831},[5530,20328,12293],{"class":5543},[5530,20330,6066],{"class":5831},[5530,20332,20333],{"class":5536},"  # → _Cart__discount_code\n",[5530,20335,20336,20338,20341,20343,20346,20348],{"class":5532,"line":10726},[5530,20337,5882],{"class":5831},[5530,20339,20340],{"class":5543},".__discount_percent: ",[5530,20342,5649],{"class":5835},[5530,20344,20345],{"class":5543},"      = ",[5530,20347,8840],{"class":5554},[5530,20349,20350],{"class":5536},"   # → _Cart__discount_percent\n",[5530,20352,20353],{"class":5532,"line":10737},[5530,20354,5565],{"emptyLinePlaceholder":5564},[5530,20356,20357],{"class":5532,"line":12391},[5530,20358,20359],{"class":5536},"    # ── Купон — геттер + сеттер + делітер ────────────────────────────────────\n",[5530,20361,20362],{"class":5532,"line":12429},[5530,20363,5565],{"emptyLinePlaceholder":5564},[5530,20365,20366,20368],{"class":5532,"line":12434},[5530,20367,7565],{"class":5847},[5530,20369,7568],{"class":5835},[5530,20371,20372,20374,20377,20379,20381,20383,20385,20387,20389],{"class":5532,"line":12439},[5530,20373,5844],{"class":5831},[5530,20375,20376],{"class":5847}," coupon",[5530,20378,5851],{"class":5543},[5530,20380,5855],{"class":5854},[5530,20382,6063],{"class":5543},[5530,20384,5989],{"class":5835},[5530,20386,14819],{"class":5543},[5530,20388,6066],{"class":5831},[5530,20390,5839],{"class":5543},[5530,20392,20393],{"class":5532,"line":12444},[5530,20394,20395],{"class":5547},"        \"\"\"Поточний активний купон (або None).\"\"\"\n",[5530,20397,20398,20400,20402],{"class":5532,"line":12450},[5530,20399,6243],{"class":6073},[5530,20401,6246],{"class":5831},[5530,20403,20404],{"class":5543},".__discount_code\n",[5530,20406,20407],{"class":5532,"line":12473},[5530,20408,5565],{"emptyLinePlaceholder":5564},[5530,20410,20411],{"class":5532,"line":12481},[5530,20412,20413],{"class":5847},"    @coupon.setter\n",[5530,20415,20416,20418,20420,20422,20424,20426,20428,20430,20432,20434,20436],{"class":5532,"line":12486},[5530,20417,5844],{"class":5831},[5530,20419,20376],{"class":5847},[5530,20421,5851],{"class":5543},[5530,20423,5855],{"class":5854},[5530,20425,5551],{"class":5543},[5530,20427,5512],{"class":5854},[5530,20429,5863],{"class":5543},[5530,20431,5989],{"class":5835},[5530,20433,6063],{"class":5543},[5530,20435,6066],{"class":5831},[5530,20437,5839],{"class":5543},[5530,20439,20440],{"class":5532,"line":12495},[5530,20441,20442],{"class":5547},"        \"\"\"Активує купон після перевірки його валідності.\"\"\"\n",[5530,20444,20445,20447,20449,20451,20454,20456],{"class":5532,"line":12518},[5530,20446,6074],{"class":6073},[5530,20448,8134],{"class":5831},[5530,20450,8137],{"class":5847},[5530,20452,20453],{"class":5543},"(code, ",[5530,20455,5989],{"class":5835},[5530,20457,5877],{"class":5543},[5530,20459,20460,20462,20464,20466,20469],{"class":5532,"line":12523},[5530,20461,6087],{"class":6073},[5530,20463,8157],{"class":5835},[5530,20465,5851],{"class":5543},[5530,20467,20468],{"class":5547},"\"Код купона має бути рядком\"",[5530,20470,5558],{"class":5543},[5530,20472,20473],{"class":5532,"line":12529},[5530,20474,20475],{"class":5543},"        code = code.strip().upper()\n",[5530,20477,20478,20480,20483,20486,20488],{"class":5532,"line":12583},[5530,20479,6074],{"class":6073},[5530,20481,20482],{"class":5543}," code ",[5530,20484,20485],{"class":5831},"not",[5530,20487,14581],{"class":5831},[5530,20489,20490],{"class":5543}," VALID_COUPONS:\n",[5530,20492,20493,20495,20497],{"class":5532,"line":12608},[5530,20494,6087],{"class":6073},[5530,20496,6090],{"class":5835},[5530,20498,11938],{"class":5543},[5530,20500,20501,20503,20506,20508,20510,20512],{"class":5532,"line":12613},[5530,20502,11943],{"class":5831},[5530,20504,20505],{"class":5547},"\"Купон ",[5530,20507,6120],{"class":5831},[5530,20509,5512],{"class":5543},[5530,20511,11974],{"class":5831},[5530,20513,20514],{"class":5547}," не знайдено або вже не діє. \"\n",[5530,20516,20517,20519,20522,20524,20526,20529,20531],{"class":5532,"line":12619},[5530,20518,11943],{"class":5831},[5530,20520,20521],{"class":5547},"\"Доступні: ",[5530,20523,6120],{"class":5831},[5530,20525,6030],{"class":5835},[5530,20527,20528],{"class":5543},"(VALID_COUPONS.keys())",[5530,20530,6125],{"class":5831},[5530,20532,11809],{"class":5547},[5530,20534,20535],{"class":5532,"line":12646},[5530,20536,11981],{"class":5543},[5530,20538,20539,20541],{"class":5532,"line":12651},[5530,20540,5882],{"class":5831},[5530,20542,20543],{"class":5543},".__discount_code    = code\n",[5530,20545,20546,20548],{"class":5532,"line":12657},[5530,20547,5882],{"class":5831},[5530,20549,20550],{"class":5543},".__discount_percent = VALID_COUPONS[code]\n",[5530,20552,20553,20555,20557,20559,20562,20564,20566,20568,20571,20573,20576,20579,20582],{"class":5532,"line":12663},[5530,20554,6847],{"class":5847},[5530,20556,5851],{"class":5543},[5530,20558,6114],{"class":5831},[5530,20560,20561],{"class":5547},"\"✅ Купон ",[5530,20563,6120],{"class":5831},[5530,20565,5512],{"class":5543},[5530,20567,11974],{"class":5831},[5530,20569,20570],{"class":5547}," активовано: знижка ",[5530,20572,6857],{"class":5831},[5530,20574,20575],{"class":5543},".__discount_percent",[5530,20577,20578],{"class":5831},":.0f}",[5530,20580,20581],{"class":5547},"%\"",[5530,20583,5558],{"class":5543},[5530,20585,20586],{"class":5532,"line":12697},[5530,20587,5565],{"emptyLinePlaceholder":5564},[5530,20589,20590],{"class":5532,"line":12726},[5530,20591,20592],{"class":5847},"    @coupon.deleter\n",[5530,20594,20595,20597,20599,20601,20603,20605,20607],{"class":5532,"line":12755},[5530,20596,5844],{"class":5831},[5530,20598,20376],{"class":5847},[5530,20600,5851],{"class":5543},[5530,20602,5855],{"class":5854},[5530,20604,6063],{"class":5543},[5530,20606,6066],{"class":5831},[5530,20608,5839],{"class":5543},[5530,20610,20611],{"class":5532,"line":12761},[5530,20612,20613],{"class":5547},"        \"\"\"Скасовує активний купон.\"\"\"\n",[5530,20615,20616,20618,20620,20623,20625,20627],{"class":5532,"line":12766},[5530,20617,6074],{"class":6073},[5530,20619,6246],{"class":5831},[5530,20621,20622],{"class":5543},".__discount_code ",[5530,20624,10228],{"class":5831},[5530,20626,10186],{"class":5831},[5530,20628,5839],{"class":5543},[5530,20630,20631,20634,20636,20639],{"class":5532,"line":12779},[5530,20632,20633],{"class":5847},"            print",[5530,20635,5851],{"class":5543},[5530,20637,20638],{"class":5547},"\"ℹ️  Активний купон відсутній\"",[5530,20640,5558],{"class":5543},[5530,20642,20643],{"class":5532,"line":12787},[5530,20644,14860],{"class":6073},[5530,20646,20647,20650,20652],{"class":5532,"line":12793},[5530,20648,20649],{"class":5543},"        removed = ",[5530,20651,5855],{"class":5831},[5530,20653,20404],{"class":5543},[5530,20655,20656,20658,20661],{"class":5532,"line":12817},[5530,20657,5882],{"class":5831},[5530,20659,20660],{"class":5543},".__discount_code    = ",[5530,20662,11734],{"class":5831},[5530,20664,20665,20667,20670],{"class":5532,"line":17315},[5530,20666,5882],{"class":5831},[5530,20668,20669],{"class":5543},".__discount_percent = ",[5530,20671,20672],{"class":5554},"0.0\n",[5530,20674,20675,20677,20679,20681,20684,20686,20689,20691,20694],{"class":5532,"line":17321},[5530,20676,6847],{"class":5847},[5530,20678,5851],{"class":5543},[5530,20680,6114],{"class":5831},[5530,20682,20683],{"class":5547},"\"🗑️  Купон ",[5530,20685,6120],{"class":5831},[5530,20687,20688],{"class":5543},"removed",[5530,20690,11974],{"class":5831},[5530,20692,20693],{"class":5547}," скасовано\"",[5530,20695,5558],{"class":5543},[5530,20697,20698],{"class":5532,"line":17330},[5530,20699,5565],{"emptyLinePlaceholder":5564},[5530,20701,20702],{"class":5532,"line":17367},[5530,20703,19258],{"class":5536},[5530,20705,20706],{"class":5532,"line":17372},[5530,20707,5565],{"emptyLinePlaceholder":5564},[5530,20709,20710,20712],{"class":5532,"line":17378},[5530,20711,7565],{"class":5847},[5530,20713,7568],{"class":5835},[5530,20715,20716,20718,20721,20723,20725,20727,20729],{"class":5532,"line":17387},[5530,20717,5844],{"class":5831},[5530,20719,20720],{"class":5847}," subtotal",[5530,20722,5851],{"class":5543},[5530,20724,5855],{"class":5854},[5530,20726,6063],{"class":5543},[5530,20728,5649],{"class":5835},[5530,20730,5839],{"class":5543},[5530,20732,20733],{"class":5532,"line":17396},[5530,20734,20735],{"class":5547},"        \"\"\"Сума всіх товарів з ПДВ (до знижки).\"\"\"\n",[5530,20737,20738,20740,20743],{"class":5532,"line":17408},[5530,20739,6243],{"class":6073},[5530,20741,20742],{"class":5847}," sum",[5530,20744,11938],{"class":5543},[5530,20746,20747,20750,20753,20756,20759],{"class":5532,"line":17413},[5530,20748,20749],{"class":5543},"            row[",[5530,20751,20752],{"class":5547},"\"product\"",[5530,20754,20755],{"class":5543},"].price * row[",[5530,20757,20758],{"class":5547},"\"qty\"",[5530,20760,12758],{"class":5543},[5530,20762,20763,20766,20769,20771,20773],{"class":5532,"line":17418},[5530,20764,20765],{"class":6073},"            for",[5530,20767,20768],{"class":5543}," row ",[5530,20770,12556],{"class":6073},[5530,20772,6246],{"class":5831},[5530,20774,20775],{"class":5543},"._items.values()\n",[5530,20777,20778],{"class":5532,"line":17470},[5530,20779,12155],{"class":5543},[5530,20781,20782],{"class":5532,"line":17478},[5530,20783,5565],{"emptyLinePlaceholder":5564},[5530,20785,20786,20788],{"class":5532,"line":17486},[5530,20787,7565],{"class":5847},[5530,20789,7568],{"class":5835},[5530,20791,20792,20794,20797,20799,20801,20803,20805],{"class":5532,"line":17494},[5530,20793,5844],{"class":5831},[5530,20795,20796],{"class":5847}," tax",[5530,20798,5851],{"class":5543},[5530,20800,5855],{"class":5854},[5530,20802,6063],{"class":5543},[5530,20804,5649],{"class":5835},[5530,20806,5839],{"class":5543},[5530,20808,20809],{"class":5532,"line":17502},[5530,20810,20811],{"class":5547},"        \"\"\"Сума ПДВ (20% від subtotal).\"\"\"\n",[5530,20813,20814,20816,20819,20821,20823,20826,20828,20831,20834],{"class":5532,"line":17507},[5530,20815,6243],{"class":6073},[5530,20817,20818],{"class":5847}," round",[5530,20820,5851],{"class":5543},[5530,20822,5855],{"class":5831},[5530,20824,20825],{"class":5543},".subtotal * TAX_RATE \u002F (",[5530,20827,12212],{"class":5554},[5530,20829,20830],{"class":5543}," + TAX_RATE), ",[5530,20832,20833],{"class":5554},"2",[5530,20835,5558],{"class":5543},[5530,20837,20838],{"class":5532,"line":17524},[5530,20839,5565],{"emptyLinePlaceholder":5564},[5530,20841,20842,20844],{"class":5532,"line":17562},[5530,20843,7565],{"class":5847},[5530,20845,7568],{"class":5835},[5530,20847,20848,20850,20853,20855,20857,20859,20861],{"class":5532,"line":17567},[5530,20849,5844],{"class":5831},[5530,20851,20852],{"class":5847}," discount_amount",[5530,20854,5851],{"class":5543},[5530,20856,5855],{"class":5854},[5530,20858,6063],{"class":5543},[5530,20860,5649],{"class":5835},[5530,20862,5839],{"class":5543},[5530,20864,20865],{"class":5532,"line":17572},[5530,20866,20867],{"class":5547},"        \"\"\"Сума знижки в гривнях.\"\"\"\n",[5530,20869,20870,20872,20874,20876,20878,20881,20883,20886,20888,20890,20892],{"class":5532,"line":17577},[5530,20871,6243],{"class":6073},[5530,20873,20818],{"class":5847},[5530,20875,5851],{"class":5543},[5530,20877,5855],{"class":5831},[5530,20879,20880],{"class":5543},".subtotal * ",[5530,20882,5855],{"class":5831},[5530,20884,20885],{"class":5543},".__discount_percent \u002F ",[5530,20887,11154],{"class":5554},[5530,20889,5551],{"class":5543},[5530,20891,20833],{"class":5554},[5530,20893,5558],{"class":5543},[5530,20895,20896],{"class":5532,"line":17589},[5530,20897,5565],{"emptyLinePlaceholder":5564},[5530,20899,20900,20902],{"class":5532,"line":17618},[5530,20901,7565],{"class":5847},[5530,20903,7568],{"class":5835},[5530,20905,20906,20908,20911,20913,20915,20917,20919],{"class":5532,"line":17626},[5530,20907,5844],{"class":5831},[5530,20909,20910],{"class":5847}," final_price",[5530,20912,5851],{"class":5543},[5530,20914,5855],{"class":5854},[5530,20916,6063],{"class":5543},[5530,20918,5649],{"class":5835},[5530,20920,5839],{"class":5543},[5530,20922,20923],{"class":5532,"line":17649},[5530,20924,20925],{"class":5547},"        \"\"\"Підсумкова сума до оплати.\"\"\"\n",[5530,20927,20928,20930,20932,20934,20936,20938,20940,20943,20945],{"class":5532,"line":17654},[5530,20929,6243],{"class":6073},[5530,20931,20818],{"class":5847},[5530,20933,5851],{"class":5543},[5530,20935,5855],{"class":5831},[5530,20937,20020],{"class":5543},[5530,20939,5855],{"class":5831},[5530,20941,20942],{"class":5543},".discount_amount, ",[5530,20944,20833],{"class":5554},[5530,20946,5558],{"class":5543},[5530,20948,20949],{"class":5532,"line":17670},[5530,20950,5565],{"emptyLinePlaceholder":5564},[5530,20952,20953,20955],{"class":5532,"line":17676},[5530,20954,7565],{"class":5847},[5530,20956,7568],{"class":5835},[5530,20958,20959,20961,20964,20966,20968,20970,20972],{"class":5532,"line":17704},[5530,20960,5844],{"class":5831},[5530,20962,20963],{"class":5847}," item_count",[5530,20965,5851],{"class":5543},[5530,20967,5855],{"class":5854},[5530,20969,6063],{"class":5543},[5530,20971,8143],{"class":5835},[5530,20973,5839],{"class":5543},[5530,20975,20976],{"class":5532,"line":17731},[5530,20977,20978],{"class":5547},"        \"\"\"Загальна кількість одиниць товарів.\"\"\"\n",[5530,20980,20981,20983,20985,20988,20990,20992,20994,20996,20998,21000],{"class":5532,"line":17759},[5530,20982,6243],{"class":6073},[5530,20984,20742],{"class":5847},[5530,20986,20987],{"class":5543},"(row[",[5530,20989,20758],{"class":5547},[5530,20991,12836],{"class":5543},[5530,20993,12550],{"class":6073},[5530,20995,20768],{"class":5543},[5530,20997,12556],{"class":6073},[5530,20999,6246],{"class":5831},[5530,21001,21002],{"class":5543},"._items.values())\n",[5530,21004,21005],{"class":5532,"line":17786},[5530,21006,5565],{"emptyLinePlaceholder":5564},[5530,21008,21009],{"class":5532,"line":17814},[5530,21010,19352],{"class":5536},[5530,21012,21013],{"class":5532,"line":17819},[5530,21014,5565],{"emptyLinePlaceholder":5564},[5530,21016,21017,21019,21022,21024,21026,21028,21031,21034,21036,21038,21040,21042,21044,21046,21048],{"class":5532,"line":17831},[5530,21018,5844],{"class":5831},[5530,21020,21021],{"class":5847}," add",[5530,21023,5851],{"class":5543},[5530,21025,5855],{"class":5854},[5530,21027,5551],{"class":5543},[5530,21029,21030],{"class":5854},"product",[5530,21032,21033],{"class":5543},": Product, ",[5530,21035,19372],{"class":5854},[5530,21037,5863],{"class":5543},[5530,21039,8143],{"class":5835},[5530,21041,12293],{"class":5543},[5530,21043,12212],{"class":5554},[5530,21045,6063],{"class":5543},[5530,21047,6066],{"class":5831},[5530,21049,5839],{"class":5543},[5530,21051,21052],{"class":5532,"line":17838},[5530,21053,21054],{"class":5547},"        \"\"\"Додає qty одиниць product у кошик і резервує stock.\"\"\"\n",[5530,21056,21057,21059,21061,21063,21065,21067,21069,21071,21073,21075],{"class":5532,"line":17843},[5530,21058,6074],{"class":6073},[5530,21060,8134],{"class":5831},[5530,21062,8137],{"class":5847},[5530,21064,19398],{"class":5543},[5530,21066,8143],{"class":5835},[5530,21068,12809],{"class":5543},[5530,21070,10169],{"class":5831},[5530,21072,19407],{"class":5543},[5530,21074,6080],{"class":5554},[5530,21076,5839],{"class":5543},[5530,21078,21079,21081,21083,21085,21087,21089],{"class":5532,"line":17854},[5530,21080,6087],{"class":6073},[5530,21082,6090],{"class":5835},[5530,21084,5851],{"class":5543},[5530,21086,6114],{"class":5831},[5530,21088,19574],{"class":5547},[5530,21090,5558],{"class":5543},[5530,21092,21094,21096,21098],{"class":5532,"line":21093},136,[5530,21095,6074],{"class":6073},[5530,21097,8134],{"class":5831},[5530,21099,21100],{"class":5543}," product.is_available:\n",[5530,21102,21104,21106,21108,21110,21112,21115,21117,21120,21122,21125],{"class":5532,"line":21103},137,[5530,21105,6087],{"class":6073},[5530,21107,6090],{"class":5835},[5530,21109,5851],{"class":5543},[5530,21111,6114],{"class":5831},[5530,21113,21114],{"class":5547},"\"Товар '",[5530,21116,6120],{"class":5831},[5530,21118,21119],{"class":5543},"product.name",[5530,21121,6125],{"class":5831},[5530,21123,21124],{"class":5547},"' недоступний\"",[5530,21126,5558],{"class":5543},[5530,21128,21130],{"class":5532,"line":21129},138,[5530,21131,5565],{"emptyLinePlaceholder":5564},[5530,21133,21135,21138],{"class":5532,"line":21134},139,[5530,21136,21137],{"class":5543},"        product.reserve(qty)   ",[5530,21139,21140],{"class":5536},"# зменшує stock та валідує наявність\n",[5530,21142,21144],{"class":5532,"line":21143},140,[5530,21145,5565],{"emptyLinePlaceholder":5564},[5530,21147,21149,21151,21154,21156,21158],{"class":5532,"line":21148},141,[5530,21150,6074],{"class":6073},[5530,21152,21153],{"class":5543}," product.name ",[5530,21155,12556],{"class":5831},[5530,21157,6246],{"class":5831},[5530,21159,21160],{"class":5543},"._items:\n",[5530,21162,21164,21166,21169,21171],{"class":5532,"line":21163},142,[5530,21165,6516],{"class":5831},[5530,21167,21168],{"class":5543},"._items[product.name][",[5530,21170,20758],{"class":5547},[5530,21172,21173],{"class":5543},"] += qty\n",[5530,21175,21177,21180],{"class":5532,"line":21176},143,[5530,21178,21179],{"class":6073},"        else",[5530,21181,5839],{"class":5543},[5530,21183,21185,21187,21190,21192,21195,21197],{"class":5532,"line":21184},144,[5530,21186,6516],{"class":5831},[5530,21188,21189],{"class":5543},"._items[product.name] = {",[5530,21191,20752],{"class":5547},[5530,21193,21194],{"class":5543},": product, ",[5530,21196,20758],{"class":5547},[5530,21198,21199],{"class":5543},": qty}\n",[5530,21201,21203],{"class":5532,"line":21202},145,[5530,21204,5565],{"emptyLinePlaceholder":5564},[5530,21206,21208,21210,21212,21214,21217,21219,21221,21223,21225,21227,21229,21231,21234,21236,21239,21241,21244],{"class":5532,"line":21207},146,[5530,21209,6847],{"class":5847},[5530,21211,5851],{"class":5543},[5530,21213,6114],{"class":5831},[5530,21215,21216],{"class":5547},"\"  + ",[5530,21218,6120],{"class":5831},[5530,21220,21119],{"class":5543},[5530,21222,6125],{"class":5831},[5530,21224,19980],{"class":5547},[5530,21226,6120],{"class":5831},[5530,21228,19372],{"class":5543},[5530,21230,6125],{"class":5831},[5530,21232,21233],{"class":5547},"  (",[5530,21235,6120],{"class":5831},[5530,21237,21238],{"class":5543},"product.price",[5530,21240,19650],{"class":5831},[5530,21242,21243],{"class":5547}," грн\u002Fшт)\"",[5530,21245,5558],{"class":5543},[5530,21247,21249],{"class":5532,"line":21248},147,[5530,21250,5565],{"emptyLinePlaceholder":5564},[5530,21252,21254,21256,21259,21261,21263,21265,21268,21270,21272,21274,21276],{"class":5532,"line":21253},148,[5530,21255,5844],{"class":5831},[5530,21257,21258],{"class":5847}," remove",[5530,21260,5851],{"class":5543},[5530,21262,5855],{"class":5854},[5530,21264,5551],{"class":5543},[5530,21266,21267],{"class":5854},"product_name",[5530,21269,5863],{"class":5543},[5530,21271,5989],{"class":5835},[5530,21273,6063],{"class":5543},[5530,21275,6066],{"class":5831},[5530,21277,5839],{"class":5543},[5530,21279,21281],{"class":5532,"line":21280},149,[5530,21282,21283],{"class":5547},"        \"\"\"Видаляє товар з кошика та повертає stock.\"\"\"\n",[5530,21285,21287,21289,21292,21294,21296,21298],{"class":5532,"line":21286},150,[5530,21288,6074],{"class":6073},[5530,21290,21291],{"class":5543}," product_name ",[5530,21293,20485],{"class":5831},[5530,21295,14581],{"class":5831},[5530,21297,6246],{"class":5831},[5530,21299,21160],{"class":5543},[5530,21301,21303,21305,21308,21310,21312,21314,21316,21318,21320,21323],{"class":5532,"line":21302},151,[5530,21304,6087],{"class":6073},[5530,21306,21307],{"class":5835}," KeyError",[5530,21309,5851],{"class":5543},[5530,21311,6114],{"class":5831},[5530,21313,11946],{"class":5547},[5530,21315,6120],{"class":5831},[5530,21317,21267],{"class":5543},[5530,21319,6125],{"class":5831},[5530,21321,21322],{"class":5547},"' немає у кошику\"",[5530,21324,5558],{"class":5543},[5530,21326,21328,21331,21333],{"class":5532,"line":21327},152,[5530,21329,21330],{"class":5543},"        row = ",[5530,21332,5855],{"class":5831},[5530,21334,21335],{"class":5543},"._items.pop(product_name)\n",[5530,21337,21339,21342,21344,21347,21349],{"class":5532,"line":21338},153,[5530,21340,21341],{"class":5543},"        row[",[5530,21343,20752],{"class":5547},[5530,21345,21346],{"class":5543},"].release(row[",[5530,21348,20758],{"class":5547},[5530,21350,21351],{"class":5543},"])\n",[5530,21353,21355,21357,21359,21361,21364,21366,21368,21370,21373],{"class":5532,"line":21354},154,[5530,21356,6847],{"class":5847},[5530,21358,5851],{"class":5543},[5530,21360,6114],{"class":5831},[5530,21362,21363],{"class":5547},"\"  - ",[5530,21365,6120],{"class":5831},[5530,21367,21267],{"class":5543},[5530,21369,6125],{"class":5831},[5530,21371,21372],{"class":5547}," видалено з кошика\"",[5530,21374,5558],{"class":5543},[5530,21376,21378],{"class":5532,"line":21377},155,[5530,21379,5565],{"emptyLinePlaceholder":5564},[5530,21381,21383,21385,21388,21390,21392],{"class":5532,"line":21382},156,[5530,21384,5844],{"class":5831},[5530,21386,21387],{"class":5847}," checkout",[5530,21389,5851],{"class":5543},[5530,21391,5855],{"class":5854},[5530,21393,21394],{"class":5543},") -> Receipt:\n",[5530,21396,21398],{"class":5532,"line":21397},157,[5530,21399,21400],{"class":5547},"        \"\"\"Оформлює замовлення: повертає Receipt та очищає кошик.\"\"\"\n",[5530,21402,21404,21406,21408,21410],{"class":5532,"line":21403},158,[5530,21405,6074],{"class":6073},[5530,21407,8134],{"class":5831},[5530,21409,6246],{"class":5831},[5530,21411,21160],{"class":5543},[5530,21413,21415,21417,21419,21421,21424],{"class":5532,"line":21414},159,[5530,21416,6087],{"class":6073},[5530,21418,6090],{"class":5835},[5530,21420,5851],{"class":5543},[5530,21422,21423],{"class":5547},"\"Кошик порожній — нічого оформляти\"",[5530,21425,5558],{"class":5543},[5530,21427,21429],{"class":5532,"line":21428},160,[5530,21430,5565],{"emptyLinePlaceholder":5564},[5530,21432,21434],{"class":5532,"line":21433},161,[5530,21435,21436],{"class":5543},"        receipt = Receipt(\n",[5530,21438,21440,21443],{"class":5532,"line":21439},162,[5530,21441,21442],{"class":5854},"            items",[5530,21444,21445],{"class":5543},"=[\n",[5530,21447,21449,21452,21454,21457,21459,21462,21464],{"class":5532,"line":21448},163,[5530,21450,21451],{"class":5543},"                (row[",[5530,21453,20752],{"class":5547},[5530,21455,21456],{"class":5543},"].name, row[",[5530,21458,20758],{"class":5547},[5530,21460,21461],{"class":5543},"], row[",[5530,21463,20752],{"class":5547},[5530,21465,21466],{"class":5543},"].price)\n",[5530,21468,21470,21473,21475,21477,21479],{"class":5532,"line":21469},164,[5530,21471,21472],{"class":6073},"                for",[5530,21474,20768],{"class":5543},[5530,21476,12556],{"class":6073},[5530,21478,6246],{"class":5831},[5530,21480,20775],{"class":5543},[5530,21482,21484],{"class":5532,"line":21483},165,[5530,21485,21486],{"class":5543},"            ],\n",[5530,21488,21490,21493,21495,21497],{"class":5532,"line":21489},166,[5530,21491,21492],{"class":5854},"            subtotal",[5530,21494,9447],{"class":5543},[5530,21496,5855],{"class":5831},[5530,21498,21499],{"class":5543},".subtotal,\n",[5530,21501,21503,21506,21508,21510],{"class":5532,"line":21502},167,[5530,21504,21505],{"class":5854},"            tax",[5530,21507,9447],{"class":5543},[5530,21509,5855],{"class":5831},[5530,21511,21512],{"class":5543},".tax,\n",[5530,21514,21516,21519,21521,21523],{"class":5532,"line":21515},168,[5530,21517,21518],{"class":5854},"            discount",[5530,21520,9447],{"class":5543},[5530,21522,5855],{"class":5831},[5530,21524,21525],{"class":5543},".discount_amount,\n",[5530,21527,21529,21532,21534,21536],{"class":5532,"line":21528},169,[5530,21530,21531],{"class":5854},"            total",[5530,21533,9447],{"class":5543},[5530,21535,5855],{"class":5831},[5530,21537,21538],{"class":5543},".final_price,\n",[5530,21540,21542,21545,21547,21549],{"class":5532,"line":21541},170,[5530,21543,21544],{"class":5854},"            coupon_code",[5530,21546,9447],{"class":5543},[5530,21548,5855],{"class":5831},[5530,21550,21551],{"class":5543},".__discount_code,\n",[5530,21553,21555],{"class":5532,"line":21554},171,[5530,21556,12155],{"class":5543},[5530,21558,21560,21562],{"class":5532,"line":21559},172,[5530,21561,5882],{"class":5831},[5530,21563,21564],{"class":5543},"._items.clear()\n",[5530,21566,21568,21570,21572,21575],{"class":5532,"line":21567},173,[5530,21569,8405],{"class":6073},[5530,21571,6246],{"class":5831},[5530,21573,21574],{"class":5543},".coupon   ",[5530,21576,21577],{"class":5536},"# скидаємо купон після checkout\n",[5530,21579,21581,21583],{"class":5532,"line":21580},174,[5530,21582,6243],{"class":6073},[5530,21584,21585],{"class":5543}," receipt\n",[5530,21587,21589],{"class":5532,"line":21588},175,[5530,21590,5565],{"emptyLinePlaceholder":5564},[5530,21592,21594,21596,21598,21600,21602,21604,21606],{"class":5532,"line":21593},176,[5530,21595,5844],{"class":5831},[5530,21597,12092],{"class":5847},[5530,21599,5851],{"class":5543},[5530,21601,5855],{"class":5854},[5530,21603,6063],{"class":5543},[5530,21605,5989],{"class":5835},[5530,21607,5839],{"class":5543},[5530,21609,21611,21613],{"class":5532,"line":21610},177,[5530,21612,6243],{"class":6073},[5530,21614,12109],{"class":5543},[5530,21616,21618,21620,21623,21625,21628,21630],{"class":5532,"line":21617},178,[5530,21619,12114],{"class":5831},[5530,21621,21622],{"class":5547},"\"Cart(",[5530,21624,6857],{"class":5831},[5530,21626,21627],{"class":5543},".owner_name",[5530,21629,11974],{"class":5831},[5530,21631,12388],{"class":5547},[5530,21633,21635,21637,21640,21642,21645,21647],{"class":5532,"line":21634},179,[5530,21636,12114],{"class":5831},[5530,21638,21639],{"class":5547},"\"items=",[5530,21641,6857],{"class":5831},[5530,21643,21644],{"class":5543},".item_count",[5530,21646,6125],{"class":5831},[5530,21648,12388],{"class":5547},[5530,21650,21652,21654,21657,21659,21662,21664],{"class":5532,"line":21651},180,[5530,21653,12114],{"class":5831},[5530,21655,21656],{"class":5547},"\"total=",[5530,21658,6857],{"class":5831},[5530,21660,21661],{"class":5543},".final_price",[5530,21663,19650],{"class":5831},[5530,21665,21666],{"class":5547}," грн)\"\n",[5530,21668,21670],{"class":5532,"line":21669},181,[5530,21671,12155],{"class":5543},[5530,21673,21675],{"class":5532,"line":21674},182,[5530,21676,5565],{"emptyLinePlaceholder":5564},[5530,21678,21680],{"class":5532,"line":21679},183,[5530,21681,5565],{"emptyLinePlaceholder":5564},[5530,21683,21685,21687,21690,21692,21695],{"class":5532,"line":21684},184,[5530,21686,5832],{"class":5831},[5530,21688,21689],{"class":5835}," PremiumCart",[5530,21691,5851],{"class":5543},[5530,21693,21694],{"class":5835},"Cart",[5530,21696,5877],{"class":5543},[5530,21698,21700],{"class":5532,"line":21699},185,[5530,21701,7990],{"class":5547},[5530,21703,21705],{"class":5532,"line":21704},186,[5530,21706,21707],{"class":5547},"    Кошик преміум-клієнта: додаткова знижка за лояльністю.\n",[5530,21709,21711],{"class":5532,"line":21710},187,[5530,21712,5565],{"emptyLinePlaceholder":5564},[5530,21714,21716],{"class":5532,"line":21715},188,[5530,21717,21718],{"class":5547},"    Демонстрація Name Mangling:\n",[5530,21720,21722],{"class":5532,"line":21721},189,[5530,21723,21724],{"class":5547},"        self.__discount_code → _PremiumCart__discount_code (РІЗНЕ поле!)\n",[5530,21726,21728],{"class":5532,"line":21727},190,[5530,21729,21730],{"class":5547},"        super().__discount_code залишається _Cart__discount_code (НЕ перезаписано)\n",[5530,21732,21734],{"class":5532,"line":21733},191,[5530,21735,7990],{"class":5547},[5530,21737,21739],{"class":5532,"line":21738},192,[5530,21740,5565],{"emptyLinePlaceholder":5564},[5530,21742,21744,21747,21749],{"class":5532,"line":21743},193,[5530,21745,21746],{"class":5543},"    LOYALTY_DISCOUNT = ",[5530,21748,7711],{"class":5554},[5530,21750,21751],{"class":5536},"  # 5% додатково для VIP-клієнтів\n",[5530,21753,21755],{"class":5532,"line":21754},194,[5530,21756,5565],{"emptyLinePlaceholder":5564},[5530,21758,21760,21762,21764,21766,21768,21770,21772,21774,21776,21778,21781,21783,21785,21787,21789],{"class":5532,"line":21759},195,[5530,21761,5844],{"class":5831},[5530,21763,5848],{"class":5847},[5530,21765,5851],{"class":5543},[5530,21767,5855],{"class":5854},[5530,21769,5551],{"class":5543},[5530,21771,20280],{"class":5854},[5530,21773,5863],{"class":5543},[5530,21775,5989],{"class":5835},[5530,21777,5551],{"class":5543},[5530,21779,21780],{"class":5854},"loyalty_years",[5530,21782,5863],{"class":5543},[5530,21784,8143],{"class":5835},[5530,21786,12293],{"class":5543},[5530,21788,12212],{"class":5554},[5530,21790,5877],{"class":5543},[5530,21792,21794,21796,21798,21800],{"class":5532,"line":21793},196,[5530,21795,6906],{"class":5835},[5530,21797,6909],{"class":5543},[5530,21799,6912],{"class":5847},[5530,21801,21802],{"class":5543},"(owner_name)\n",[5530,21804,21806,21808,21811,21814],{"class":5532,"line":21805},197,[5530,21807,5882],{"class":5831},[5530,21809,21810],{"class":5543},".__discount_code = ",[5530,21812,21813],{"class":5547},"\"LOYALTY\"",[5530,21815,21816],{"class":5536},"  # → _PremiumCart__discount_code\n",[5530,21818,21820,21822],{"class":5532,"line":21819},198,[5530,21821,5882],{"class":5831},[5530,21823,21824],{"class":5543},"._loyalty_years  = loyalty_years\n",[5530,21826,21828],{"class":5532,"line":21827},199,[5530,21829,5565],{"emptyLinePlaceholder":5564},[5530,21831,21833,21835],{"class":5532,"line":21832},200,[5530,21834,7565],{"class":5847},[5530,21836,7568],{"class":5835},[5530,21838,21840,21842,21845,21847,21849,21851,21853],{"class":5532,"line":21839},201,[5530,21841,5844],{"class":5831},[5530,21843,21844],{"class":5847}," loyalty_discount",[5530,21846,5851],{"class":5543},[5530,21848,5855],{"class":5854},[5530,21850,6063],{"class":5543},[5530,21852,5649],{"class":5835},[5530,21854,5839],{"class":5543},[5530,21856,21858],{"class":5532,"line":21857},202,[5530,21859,21860],{"class":5547},"        \"\"\"Знижка за лояльністю: 5% × кількість років.\"\"\"\n",[5530,21862,21864,21866,21869,21871,21873,21876,21878,21881,21883],{"class":5532,"line":21863},203,[5530,21865,6243],{"class":6073},[5530,21867,21868],{"class":5847}," min",[5530,21870,5851],{"class":5543},[5530,21872,5855],{"class":5831},[5530,21874,21875],{"class":5543},".LOYALTY_DISCOUNT * ",[5530,21877,5855],{"class":5831},[5530,21879,21880],{"class":5543},"._loyalty_years, ",[5530,21882,8487],{"class":5554},[5530,21884,5558],{"class":5543},[5530,21886,21888],{"class":5532,"line":21887},204,[5530,21889,5565],{"emptyLinePlaceholder":5564},[5530,21891,21893,21895],{"class":5532,"line":21892},205,[5530,21894,7565],{"class":5847},[5530,21896,7568],{"class":5835},[5530,21898,21900,21902,21904,21906,21908,21910,21912],{"class":5532,"line":21899},206,[5530,21901,5844],{"class":5831},[5530,21903,20910],{"class":5847},[5530,21905,5851],{"class":5543},[5530,21907,5855],{"class":5854},[5530,21909,6063],{"class":5543},[5530,21911,5649],{"class":5835},[5530,21913,5839],{"class":5543},[5530,21915,21917],{"class":5532,"line":21916},207,[5530,21918,21919],{"class":5547},"        \"\"\"\n",[5530,21921,21923],{"class":5532,"line":21922},208,[5530,21924,21925],{"class":5547},"        Перевизначена властивість: знижка купона + знижка за лояльністю.\n",[5530,21927,21929],{"class":5532,"line":21928},209,[5530,21930,21931],{"class":5547},"        super().final_price використовує _Cart__discount_code (купон),\n",[5530,21933,21935],{"class":5532,"line":21934},210,[5530,21936,21937],{"class":5547},"        а self.loyalty_discount — з _PremiumCart__discount_code.\n",[5530,21939,21941],{"class":5532,"line":21940},211,[5530,21942,21919],{"class":5547},[5530,21944,21946,21949,21952],{"class":5532,"line":21945},212,[5530,21947,21948],{"class":5543},"        base = ",[5530,21950,21951],{"class":5835},"super",[5530,21953,21954],{"class":5543},"().final_price\n",[5530,21956,21958,21961,21964,21967,21969,21972,21974,21976,21978],{"class":5532,"line":21957},213,[5530,21959,21960],{"class":5543},"        loyalty_saving = ",[5530,21962,21963],{"class":5847},"round",[5530,21965,21966],{"class":5543},"(base * ",[5530,21968,5855],{"class":5831},[5530,21970,21971],{"class":5543},".loyalty_discount \u002F ",[5530,21973,11154],{"class":5554},[5530,21975,5551],{"class":5543},[5530,21977,20833],{"class":5554},[5530,21979,5558],{"class":5543},[5530,21981,21983,21985,21987,21990,21992],{"class":5532,"line":21982},214,[5530,21984,6243],{"class":6073},[5530,21986,20818],{"class":5847},[5530,21988,21989],{"class":5543},"(base - loyalty_saving, ",[5530,21991,20833],{"class":5554},[5530,21993,5558],{"class":5543},[5530,21995,21997],{"class":5532,"line":21996},215,[5530,21998,5565],{"emptyLinePlaceholder":5564},[5530,22000,22002,22004,22006,22008,22010,22012,22014],{"class":5532,"line":22001},216,[5530,22003,5844],{"class":5831},[5530,22005,12092],{"class":5847},[5530,22007,5851],{"class":5543},[5530,22009,5855],{"class":5854},[5530,22011,6063],{"class":5543},[5530,22013,5989],{"class":5835},[5530,22015,5839],{"class":5543},[5530,22017,22019,22021],{"class":5532,"line":22018},217,[5530,22020,6243],{"class":6073},[5530,22022,12109],{"class":5543},[5530,22024,22026,22028,22031,22033,22035,22037],{"class":5532,"line":22025},218,[5530,22027,12114],{"class":5831},[5530,22029,22030],{"class":5547},"\"PremiumCart(",[5530,22032,6857],{"class":5831},[5530,22034,21627],{"class":5543},[5530,22036,11974],{"class":5831},[5530,22038,12388],{"class":5547},[5530,22040,22042,22044,22047,22049,22052,22054],{"class":5532,"line":22041},219,[5530,22043,12114],{"class":5831},[5530,22045,22046],{"class":5547},"\"loyalty=",[5530,22048,6857],{"class":5831},[5530,22050,22051],{"class":5543},".loyalty_discount",[5530,22053,20578],{"class":5831},[5530,22055,22056],{"class":5547},"%, \"\n",[5530,22058,22060,22062,22064,22066,22068,22070],{"class":5532,"line":22059},220,[5530,22061,12114],{"class":5831},[5530,22063,21656],{"class":5547},[5530,22065,6857],{"class":5831},[5530,22067,21661],{"class":5543},[5530,22069,19650],{"class":5831},[5530,22071,21666],{"class":5547},[5530,22073,22075],{"class":5532,"line":22074},221,[5530,22076,12155],{"class":5543},[5521,22078,22080],{"className":5523,"code":22079,"filename":15702,"language":5525,"meta":5526,"style":5526},"from product import Product\nfrom cart import Cart, PremiumCart\n\nprint(\"=\" * 50)\nprint(\"  E-COMMERCE СИСТЕМА: ПОВНА ДЕМОНСТРАЦІЯ\")\nprint(\"=\" * 50)\n\n# ── 1. Каталог товарів ────────────────────────────────────────────────────────\nprint(\"\\n📦 Каталог товарів:\")\nlaptop  = Product(\"MacBook Pro 14\", price=89_999.0, stock=3, category=\"Ноутбуки\")\nphone   = Product(\"iPhone 15 Pro\",  price=44_999.0, stock=10, category=\"Смартфони\")\nearbuds = Product(\"AirPods Pro\",    price=9_999.0,  stock=25, category=\"Аксесуари\")\ncable   = Product(\"USB-C кабель\",   price=499.0,   stock=0,  category=\"Аксесуари\")\n\nfor p in [laptop, phone, earbuds, cable]:\n    print(f\"  {p}\")\n\n# ── 2. Валідація Product ──────────────────────────────────────────────────────\nprint(\"\\n🔒 Валідація Product:\")\nfor bad, label in [\n    (lambda: setattr(laptop, 'price', -1),    \"price=-1\"),\n    (lambda: setattr(laptop, 'stock', -5),    \"stock=-5 (int)\"),\n    (lambda: setattr(laptop, 'stock', 1.5),   \"stock=1.5 (float)\"),\n]:\n    try:\n        bad()\n    except (ValueError, TypeError) as e:\n        print(f\"  [{label}] {type(e).__name__}: {e}\")\n\n# ── 3. Звичайний Cart ─────────────────────────────────────────────────────────\nprint(\"\\n🛒 Звичайний кошик:\")\ncart = Cart(\"Іван Петренко\")\ncart.add(laptop, qty=1)\ncart.add(phone,  qty=2)\ncart.add(earbuds, qty=3)\n\nprint(f\"\\n  {cart}\")\nprint(f\"  subtotal:  {cart.subtotal:>10.2f} грн\")\nprint(f\"  ПДВ:       {cart.tax:>10.2f} грн\")\n\n# Купон\nprint(\"\\n🎟️  Купони:\")\ntry:\n    cart.coupon = \"FAKE99\"     # невалідний\nexcept ValueError as e:\n    print(f\"  ❌ {e}\")\n\ncart.coupon = \"SALE10\"        # валідний — 10%\nprint(f\"  Знижка: {cart.discount_amount:.2f} грн\")\nprint(f\"  До оплати: {cart.final_price:.2f} грн\")\n\ndel cart.coupon                # скасувати купон\nprint(f\"  Після скасування: {cart.final_price:.2f} грн\")\n\n# Checkout\ncart.coupon = \"VIP20\"\nprint(f\"\\n💳 Checkout (VIP20 — 20%):\")\nreceipt = cart.checkout()\nprint(receipt.to_text())\n\n# ── 4. Name Mangling: PremiumCart vs Cart ────────────────────────────────────\nprint(\"\\n👑 PremiumCart (Name Mangling демонстрація):\")\npremium = PremiumCart(\"Олена VIP\", loyalty_years=3)\npremium.add(laptop, qty=1)\npremium.add(earbuds, qty=2)\npremium.coupon = \"WELCOME5\"   # 5% купон (в _Cart__discount_code)\n\nprint(f\"\\n  {premium}\")\nprint(f\"  subtotal:           {premium.subtotal:.2f} грн\")\nprint(f\"  Купон (5%):        -{premium.discount_amount:.2f} грн\")\nprint(f\"  Лояльність (15%): після купона\")\nprint(f\"  final_price:        {premium.final_price:.2f} грн\")\n\n# Доводимо, що __discount_code різний у Cart та PremiumCart\nprint(f\"\\n  _Cart__discount_code:        \"\n      f\"{premium.__dict__.get('_Cart__discount_code')!r}\")\nprint(f\"  _PremiumCart__discount_code: \"\n      f\"{premium.__dict__.get('_PremiumCart__discount_code')!r}\")\nprint(f\"  (два різних поля — Name Mangling захищає від колізій!)\")\n\n# ── 5. Спроба замовити недоступний товар ────────────────────────────────────\nprint(\"\\n❌ Недоступний товар:\")\ntry:\n    Cart(\"Тест\").add(cable)\nexcept ValueError as e:\n    print(f\"  ValueError: {e}\")\n",[5512,22081,22082,22092,22104,22108,22122,22133,22147,22151,22156,22171,22209,22246,22284,22319,22323,22335,22355,22359,22364,22379,22391,22417,22442,22469,22474,22480,22485,22503,22544,22548,22553,22568,22578,22591,22604,22617,22621,22644,22666,22688,22692,22697,22712,22718,22729,22739,22760,22764,22775,22797,22819,22823,22833,22854,22858,22863,22870,22887,22892,22899,22903,22908,22923,22941,22954,22967,22978,22982,23005,23027,23049,23062,23084,23088,23093,23108,23136,23147,23172,23185,23189,23194,23209,23215,23226,23236],{"__ignoreMap":5526},[5530,22083,22084,22086,22088,22090],{"class":5532,"line":5533},[5530,22085,15072],{"class":6073},[5530,22087,19718],{"class":5543},[5530,22089,7488],{"class":6073},[5530,22091,19723],{"class":5543},[5530,22093,22094,22096,22099,22101],{"class":5532,"line":5540},[5530,22095,15072],{"class":6073},[5530,22097,22098],{"class":5543}," cart ",[5530,22100,7488],{"class":6073},[5530,22102,22103],{"class":5543}," Cart, PremiumCart\n",[5530,22105,22106],{"class":5532,"line":5561},[5530,22107,5565],{"emptyLinePlaceholder":5564},[5530,22109,22110,22112,22114,22116,22118,22120],{"class":5532,"line":5568},[5530,22111,6283],{"class":5847},[5530,22113,5851],{"class":5543},[5530,22115,19919],{"class":5547},[5530,22117,19922],{"class":5543},[5530,22119,11277],{"class":5554},[5530,22121,5558],{"class":5543},[5530,22123,22124,22126,22128,22131],{"class":5532,"line":5574},[5530,22125,6283],{"class":5847},[5530,22127,5851],{"class":5543},[5530,22129,22130],{"class":5547},"\"  E-COMMERCE СИСТЕМА: ПОВНА ДЕМОНСТРАЦІЯ\"",[5530,22132,5558],{"class":5543},[5530,22134,22135,22137,22139,22141,22143,22145],{"class":5532,"line":5586},[5530,22136,6283],{"class":5847},[5530,22138,5851],{"class":5543},[5530,22140,19919],{"class":5547},[5530,22142,19922],{"class":5543},[5530,22144,11277],{"class":5554},[5530,22146,5558],{"class":5543},[5530,22148,22149],{"class":5532,"line":5598},[5530,22150,5565],{"emptyLinePlaceholder":5564},[5530,22152,22153],{"class":5532,"line":5603},[5530,22154,22155],{"class":5536},"# ── 1. Каталог товарів ────────────────────────────────────────────────────────\n",[5530,22157,22158,22160,22162,22164,22166,22169],{"class":5532,"line":5609},[5530,22159,6283],{"class":5847},[5530,22161,5851],{"class":5543},[5530,22163,6128],{"class":5547},[5530,22165,8589],{"class":8588},[5530,22167,22168],{"class":5547},"📦 Каталог товарів:\"",[5530,22170,5558],{"class":5543},[5530,22172,22173,22176,22179,22181,22183,22185,22188,22190,22192,22194,22197,22199,22202,22204,22207],{"class":5532,"line":5758},[5530,22174,22175],{"class":5543},"laptop  = Product(",[5530,22177,22178],{"class":5547},"\"MacBook Pro 14\"",[5530,22180,5551],{"class":5543},[5530,22182,17439],{"class":5854},[5530,22184,9447],{"class":5543},[5530,22186,22187],{"class":5554},"89_999.0",[5530,22189,5551],{"class":5543},[5530,22191,17457],{"class":5854},[5530,22193,9447],{"class":5543},[5530,22195,22196],{"class":5554},"3",[5530,22198,5551],{"class":5543},[5530,22200,22201],{"class":5854},"category",[5530,22203,9447],{"class":5543},[5530,22205,22206],{"class":5547},"\"Ноутбуки\"",[5530,22208,5558],{"class":5543},[5530,22210,22211,22214,22217,22220,22222,22224,22227,22229,22231,22233,22235,22237,22239,22241,22244],{"class":5532,"line":5764},[5530,22212,22213],{"class":5543},"phone   = Product(",[5530,22215,22216],{"class":5547},"\"iPhone 15 Pro\"",[5530,22218,22219],{"class":5543},",  ",[5530,22221,17439],{"class":5854},[5530,22223,9447],{"class":5543},[5530,22225,22226],{"class":5554},"44_999.0",[5530,22228,5551],{"class":5543},[5530,22230,17457],{"class":5854},[5530,22232,9447],{"class":5543},[5530,22234,14992],{"class":5554},[5530,22236,5551],{"class":5543},[5530,22238,22201],{"class":5854},[5530,22240,9447],{"class":5543},[5530,22242,22243],{"class":5547},"\"Смартфони\"",[5530,22245,5558],{"class":5543},[5530,22247,22248,22251,22254,22257,22259,22261,22264,22266,22268,22270,22273,22275,22277,22279,22282],{"class":5532,"line":5770},[5530,22249,22250],{"class":5543},"earbuds = Product(",[5530,22252,22253],{"class":5547},"\"AirPods Pro\"",[5530,22255,22256],{"class":5543},",    ",[5530,22258,17439],{"class":5854},[5530,22260,9447],{"class":5543},[5530,22262,22263],{"class":5554},"9_999.0",[5530,22265,22219],{"class":5543},[5530,22267,17457],{"class":5854},[5530,22269,9447],{"class":5543},[5530,22271,22272],{"class":5554},"25",[5530,22274,5551],{"class":5543},[5530,22276,22201],{"class":5854},[5530,22278,9447],{"class":5543},[5530,22280,22281],{"class":5547},"\"Аксесуари\"",[5530,22283,5558],{"class":5543},[5530,22285,22286,22289,22292,22294,22296,22298,22301,22303,22305,22307,22309,22311,22313,22315,22317],{"class":5532,"line":5775},[5530,22287,22288],{"class":5543},"cable   = Product(",[5530,22290,22291],{"class":5547},"\"USB-C кабель\"",[5530,22293,11446],{"class":5543},[5530,22295,17439],{"class":5854},[5530,22297,9447],{"class":5543},[5530,22299,22300],{"class":5554},"499.0",[5530,22302,11446],{"class":5543},[5530,22304,17457],{"class":5854},[5530,22306,9447],{"class":5543},[5530,22308,6080],{"class":5554},[5530,22310,22219],{"class":5543},[5530,22312,22201],{"class":5854},[5530,22314,9447],{"class":5543},[5530,22316,22281],{"class":5547},[5530,22318,5558],{"class":5543},[5530,22320,22321],{"class":5532,"line":5781},[5530,22322,5565],{"emptyLinePlaceholder":5564},[5530,22324,22325,22327,22330,22332],{"class":5532,"line":5786},[5530,22326,12550],{"class":6073},[5530,22328,22329],{"class":5543}," p ",[5530,22331,12556],{"class":6073},[5530,22333,22334],{"class":5543}," [laptop, phone, earbuds, cable]:\n",[5530,22336,22337,22339,22341,22343,22345,22347,22349,22351,22353],{"class":5532,"line":5792},[5530,22338,6593],{"class":5847},[5530,22340,5851],{"class":5543},[5530,22342,6114],{"class":5831},[5530,22344,19964],{"class":5547},[5530,22346,6120],{"class":5831},[5530,22348,5508],{"class":5543},[5530,22350,6125],{"class":5831},[5530,22352,6128],{"class":5547},[5530,22354,5558],{"class":5543},[5530,22356,22357],{"class":5532,"line":5798},[5530,22358,5565],{"emptyLinePlaceholder":5564},[5530,22360,22361],{"class":5532,"line":6187},[5530,22362,22363],{"class":5536},"# ── 2. Валідація Product ──────────────────────────────────────────────────────\n",[5530,22365,22366,22368,22370,22372,22374,22377],{"class":5532,"line":6195},[5530,22367,6283],{"class":5847},[5530,22369,5851],{"class":5543},[5530,22371,6128],{"class":5547},[5530,22373,8589],{"class":8588},[5530,22375,22376],{"class":5547},"🔒 Валідація Product:\"",[5530,22378,5558],{"class":5543},[5530,22380,22381,22383,22386,22388],{"class":5532,"line":6217},[5530,22382,12550],{"class":6073},[5530,22384,22385],{"class":5543}," bad, label ",[5530,22387,12556],{"class":6073},[5530,22389,22390],{"class":5543}," [\n",[5530,22392,22393,22395,22397,22399,22401,22404,22406,22408,22410,22413,22415],{"class":5532,"line":6222},[5530,22394,12666],{"class":5543},[5530,22396,12669],{"class":5831},[5530,22398,5863],{"class":5543},[5530,22400,12674],{"class":5847},[5530,22402,22403],{"class":5543},"(laptop, ",[5530,22405,17690],{"class":5547},[5530,22407,12713],{"class":5543},[5530,22409,12212],{"class":5554},[5530,22411,22412],{"class":5543},"),    ",[5530,22414,17699],{"class":5547},[5530,22416,12694],{"class":5543},[5530,22418,22419,22421,22423,22425,22427,22429,22431,22433,22435,22437,22440],{"class":5532,"line":6240},[5530,22420,12666],{"class":5543},[5530,22422,12669],{"class":5831},[5530,22424,5863],{"class":5543},[5530,22426,12674],{"class":5847},[5530,22428,22403],{"class":5543},[5530,22430,17772],{"class":5547},[5530,22432,12713],{"class":5543},[5530,22434,8290],{"class":5554},[5530,22436,22412],{"class":5543},[5530,22438,22439],{"class":5547},"\"stock=-5 (int)\"",[5530,22441,12694],{"class":5543},[5530,22443,22444,22446,22448,22450,22452,22454,22456,22458,22461,22464,22467],{"class":5532,"line":6635},[5530,22445,12666],{"class":5543},[5530,22447,12669],{"class":5831},[5530,22449,5863],{"class":5543},[5530,22451,12674],{"class":5847},[5530,22453,22403],{"class":5543},[5530,22455,17772],{"class":5547},[5530,22457,5551],{"class":5543},[5530,22459,22460],{"class":5554},"1.5",[5530,22462,22463],{"class":5543},"),   ",[5530,22465,22466],{"class":5547},"\"stock=1.5 (float)\"",[5530,22468,12694],{"class":5543},[5530,22470,22471],{"class":5532,"line":6640},[5530,22472,22473],{"class":5543},"]:\n",[5530,22475,22476,22478],{"class":5532,"line":6646},[5530,22477,12782],{"class":6073},[5530,22479,5839],{"class":5543},[5530,22481,22482],{"class":5532,"line":6659},[5530,22483,22484],{"class":5543},"        bad()\n",[5530,22486,22487,22489,22491,22493,22495,22497,22499,22501],{"class":5532,"line":6664},[5530,22488,12796],{"class":6073},[5530,22490,8277],{"class":5543},[5530,22492,12801],{"class":5835},[5530,22494,5551],{"class":5543},[5530,22496,12806],{"class":5835},[5530,22498,12809],{"class":5543},[5530,22500,12812],{"class":6073},[5530,22502,6610],{"class":5543},[5530,22504,22505,22507,22509,22511,22514,22516,22518,22520,22522,22524,22526,22528,22530,22532,22534,22536,22538,22540,22542],{"class":5532,"line":6670},[5530,22506,6847],{"class":5847},[5530,22508,5851],{"class":5543},[5530,22510,6114],{"class":5831},[5530,22512,22513],{"class":5547},"\"  [",[5530,22515,6120],{"class":5831},[5530,22517,12831],{"class":5543},[5530,22519,6125],{"class":5831},[5530,22521,12836],{"class":5547},[5530,22523,6120],{"class":5831},[5530,22525,8169],{"class":5835},[5530,22527,12843],{"class":5543},[5530,22529,8175],{"class":5854},[5530,22531,6125],{"class":5831},[5530,22533,5863],{"class":5547},[5530,22535,6120],{"class":5831},[5530,22537,6626],{"class":5543},[5530,22539,6125],{"class":5831},[5530,22541,6128],{"class":5547},[5530,22543,5558],{"class":5543},[5530,22545,22546],{"class":5532,"line":6678},[5530,22547,5565],{"emptyLinePlaceholder":5564},[5530,22549,22550],{"class":5532,"line":6687},[5530,22551,22552],{"class":5536},"# ── 3. Звичайний Cart ─────────────────────────────────────────────────────────\n",[5530,22554,22555,22557,22559,22561,22563,22566],{"class":5532,"line":7770},[5530,22556,6283],{"class":5847},[5530,22558,5851],{"class":5543},[5530,22560,6128],{"class":5547},[5530,22562,8589],{"class":8588},[5530,22564,22565],{"class":5547},"🛒 Звичайний кошик:\"",[5530,22567,5558],{"class":5543},[5530,22569,22570,22573,22576],{"class":5532,"line":7793},[5530,22571,22572],{"class":5543},"cart = Cart(",[5530,22574,22575],{"class":5547},"\"Іван Петренко\"",[5530,22577,5558],{"class":5543},[5530,22579,22580,22583,22585,22587,22589],{"class":5532,"line":7798},[5530,22581,22582],{"class":5543},"cart.add(laptop, ",[5530,22584,19372],{"class":5854},[5530,22586,9447],{"class":5543},[5530,22588,12212],{"class":5554},[5530,22590,5558],{"class":5543},[5530,22592,22593,22596,22598,22600,22602],{"class":5532,"line":7804},[5530,22594,22595],{"class":5543},"cart.add(phone,  ",[5530,22597,19372],{"class":5854},[5530,22599,9447],{"class":5543},[5530,22601,20833],{"class":5554},[5530,22603,5558],{"class":5543},[5530,22605,22606,22609,22611,22613,22615],{"class":5532,"line":7813},[5530,22607,22608],{"class":5543},"cart.add(earbuds, ",[5530,22610,19372],{"class":5854},[5530,22612,9447],{"class":5543},[5530,22614,22196],{"class":5554},[5530,22616,5558],{"class":5543},[5530,22618,22619],{"class":5532,"line":7835},[5530,22620,5565],{"emptyLinePlaceholder":5564},[5530,22622,22623,22625,22627,22629,22631,22633,22635,22638,22640,22642],{"class":5532,"line":7840},[5530,22624,6283],{"class":5847},[5530,22626,5851],{"class":5543},[5530,22628,6114],{"class":5831},[5530,22630,6128],{"class":5547},[5530,22632,8589],{"class":8588},[5530,22634,17875],{"class":5831},[5530,22636,22637],{"class":5543},"cart",[5530,22639,6125],{"class":5831},[5530,22641,6128],{"class":5547},[5530,22643,5558],{"class":5543},[5530,22645,22646,22648,22650,22652,22655,22657,22660,22662,22664],{"class":5532,"line":7846},[5530,22647,6283],{"class":5847},[5530,22649,5851],{"class":5543},[5530,22651,6114],{"class":5831},[5530,22653,22654],{"class":5547},"\"  subtotal:  ",[5530,22656,6120],{"class":5831},[5530,22658,22659],{"class":5543},"cart.subtotal",[5530,22661,20028],{"class":5831},[5530,22663,19990],{"class":5547},[5530,22665,5558],{"class":5543},[5530,22667,22668,22670,22672,22674,22677,22679,22682,22684,22686],{"class":5532,"line":7853},[5530,22669,6283],{"class":5847},[5530,22671,5851],{"class":5543},[5530,22673,6114],{"class":5831},[5530,22675,22676],{"class":5547},"\"  ПДВ:       ",[5530,22678,6120],{"class":5831},[5530,22680,22681],{"class":5543},"cart.tax",[5530,22683,20028],{"class":5831},[5530,22685,19990],{"class":5547},[5530,22687,5558],{"class":5543},[5530,22689,22690],{"class":5532,"line":7862},[5530,22691,5565],{"emptyLinePlaceholder":5564},[5530,22693,22694],{"class":5532,"line":7873},[5530,22695,22696],{"class":5536},"# Купон\n",[5530,22698,22699,22701,22703,22705,22707,22710],{"class":5532,"line":8384},[5530,22700,6283],{"class":5847},[5530,22702,5851],{"class":5543},[5530,22704,6128],{"class":5547},[5530,22706,8589],{"class":8588},[5530,22708,22709],{"class":5547},"🎟️  Купони:\"",[5530,22711,5558],{"class":5543},[5530,22713,22714,22716],{"class":5532,"line":8390},[5530,22715,6586],{"class":6073},[5530,22717,5839],{"class":5543},[5530,22719,22720,22723,22726],{"class":5532,"line":8402},[5530,22721,22722],{"class":5543},"    cart.coupon = ",[5530,22724,22725],{"class":5547},"\"FAKE99\"",[5530,22727,22728],{"class":5536},"     # невалідний\n",[5530,22730,22731,22733,22735,22737],{"class":5532,"line":8412},[5530,22732,6601],{"class":6073},[5530,22734,6090],{"class":5835},[5530,22736,6607],{"class":6073},[5530,22738,6610],{"class":5543},[5530,22740,22741,22743,22745,22747,22750,22752,22754,22756,22758],{"class":5532,"line":8417},[5530,22742,6593],{"class":5847},[5530,22744,5851],{"class":5543},[5530,22746,6114],{"class":5831},[5530,22748,22749],{"class":5547},"\"  ❌ ",[5530,22751,6120],{"class":5831},[5530,22753,6626],{"class":5543},[5530,22755,6125],{"class":5831},[5530,22757,6128],{"class":5547},[5530,22759,5558],{"class":5543},[5530,22761,22762],{"class":5532,"line":8423},[5530,22763,5565],{"emptyLinePlaceholder":5564},[5530,22765,22766,22769,22772],{"class":5532,"line":8428},[5530,22767,22768],{"class":5543},"cart.coupon = ",[5530,22770,22771],{"class":5547},"\"SALE10\"",[5530,22773,22774],{"class":5536},"        # валідний — 10%\n",[5530,22776,22777,22779,22781,22783,22786,22788,22791,22793,22795],{"class":5532,"line":8435},[5530,22778,6283],{"class":5847},[5530,22780,5851],{"class":5543},[5530,22782,6114],{"class":5831},[5530,22784,22785],{"class":5547},"\"  Знижка: ",[5530,22787,6120],{"class":5831},[5530,22789,22790],{"class":5543},"cart.discount_amount",[5530,22792,19650],{"class":5831},[5530,22794,19990],{"class":5547},[5530,22796,5558],{"class":5543},[5530,22798,22799,22801,22803,22805,22808,22810,22813,22815,22817],{"class":5532,"line":8453},[5530,22800,6283],{"class":5847},[5530,22802,5851],{"class":5543},[5530,22804,6114],{"class":5831},[5530,22806,22807],{"class":5547},"\"  До оплати: ",[5530,22809,6120],{"class":5831},[5530,22811,22812],{"class":5543},"cart.final_price",[5530,22814,19650],{"class":5831},[5530,22816,19990],{"class":5547},[5530,22818,5558],{"class":5543},[5530,22820,22821],{"class":5532,"line":8459},[5530,22822,5565],{"emptyLinePlaceholder":5564},[5530,22824,22825,22827,22830],{"class":5532,"line":10597},[5530,22826,8740],{"class":6073},[5530,22828,22829],{"class":5543}," cart.coupon                ",[5530,22831,22832],{"class":5536},"# скасувати купон\n",[5530,22834,22835,22837,22839,22841,22844,22846,22848,22850,22852],{"class":5532,"line":10622},[5530,22836,6283],{"class":5847},[5530,22838,5851],{"class":5543},[5530,22840,6114],{"class":5831},[5530,22842,22843],{"class":5547},"\"  Після скасування: ",[5530,22845,6120],{"class":5831},[5530,22847,22812],{"class":5543},[5530,22849,19650],{"class":5831},[5530,22851,19990],{"class":5547},[5530,22853,5558],{"class":5543},[5530,22855,22856],{"class":5532,"line":10633},[5530,22857,5565],{"emptyLinePlaceholder":5564},[5530,22859,22860],{"class":5532,"line":10647},[5530,22861,22862],{"class":5536},"# Checkout\n",[5530,22864,22865,22867],{"class":5532,"line":10655},[5530,22866,22768],{"class":5543},[5530,22868,22869],{"class":5547},"\"VIP20\"\n",[5530,22871,22872,22874,22876,22878,22880,22882,22885],{"class":5532,"line":10660},[5530,22873,6283],{"class":5847},[5530,22875,5851],{"class":5543},[5530,22877,6114],{"class":5831},[5530,22879,6128],{"class":5547},[5530,22881,8589],{"class":8588},[5530,22883,22884],{"class":5547},"💳 Checkout (VIP20 — 20%):\"",[5530,22886,5558],{"class":5543},[5530,22888,22889],{"class":5532,"line":10665},[5530,22890,22891],{"class":5543},"receipt = cart.checkout()\n",[5530,22893,22894,22896],{"class":5532,"line":10676},[5530,22895,6283],{"class":5847},[5530,22897,22898],{"class":5543},"(receipt.to_text())\n",[5530,22900,22901],{"class":5532,"line":10687},[5530,22902,5565],{"emptyLinePlaceholder":5564},[5530,22904,22905],{"class":5532,"line":10696},[5530,22906,22907],{"class":5536},"# ── 4. Name Mangling: PremiumCart vs Cart ────────────────────────────────────\n",[5530,22909,22910,22912,22914,22916,22918,22921],{"class":5532,"line":10706},[5530,22911,6283],{"class":5847},[5530,22913,5851],{"class":5543},[5530,22915,6128],{"class":5547},[5530,22917,8589],{"class":8588},[5530,22919,22920],{"class":5547},"👑 PremiumCart (Name Mangling демонстрація):\"",[5530,22922,5558],{"class":5543},[5530,22924,22925,22928,22931,22933,22935,22937,22939],{"class":5532,"line":10711},[5530,22926,22927],{"class":5543},"premium = PremiumCart(",[5530,22929,22930],{"class":5547},"\"Олена VIP\"",[5530,22932,5551],{"class":5543},[5530,22934,21780],{"class":5854},[5530,22936,9447],{"class":5543},[5530,22938,22196],{"class":5554},[5530,22940,5558],{"class":5543},[5530,22942,22943,22946,22948,22950,22952],{"class":5532,"line":10718},[5530,22944,22945],{"class":5543},"premium.add(laptop, ",[5530,22947,19372],{"class":5854},[5530,22949,9447],{"class":5543},[5530,22951,12212],{"class":5554},[5530,22953,5558],{"class":5543},[5530,22955,22956,22959,22961,22963,22965],{"class":5532,"line":10726},[5530,22957,22958],{"class":5543},"premium.add(earbuds, ",[5530,22960,19372],{"class":5854},[5530,22962,9447],{"class":5543},[5530,22964,20833],{"class":5554},[5530,22966,5558],{"class":5543},[5530,22968,22969,22972,22975],{"class":5532,"line":10737},[5530,22970,22971],{"class":5543},"premium.coupon = ",[5530,22973,22974],{"class":5547},"\"WELCOME5\"",[5530,22976,22977],{"class":5536},"   # 5% купон (в _Cart__discount_code)\n",[5530,22979,22980],{"class":5532,"line":12391},[5530,22981,5565],{"emptyLinePlaceholder":5564},[5530,22983,22984,22986,22988,22990,22992,22994,22996,22999,23001,23003],{"class":5532,"line":12429},[5530,22985,6283],{"class":5847},[5530,22987,5851],{"class":5543},[5530,22989,6114],{"class":5831},[5530,22991,6128],{"class":5547},[5530,22993,8589],{"class":8588},[5530,22995,17875],{"class":5831},[5530,22997,22998],{"class":5543},"premium",[5530,23000,6125],{"class":5831},[5530,23002,6128],{"class":5547},[5530,23004,5558],{"class":5543},[5530,23006,23007,23009,23011,23013,23016,23018,23021,23023,23025],{"class":5532,"line":12434},[5530,23008,6283],{"class":5847},[5530,23010,5851],{"class":5543},[5530,23012,6114],{"class":5831},[5530,23014,23015],{"class":5547},"\"  subtotal:           ",[5530,23017,6120],{"class":5831},[5530,23019,23020],{"class":5543},"premium.subtotal",[5530,23022,19650],{"class":5831},[5530,23024,19990],{"class":5547},[5530,23026,5558],{"class":5543},[5530,23028,23029,23031,23033,23035,23038,23040,23043,23045,23047],{"class":5532,"line":12439},[5530,23030,6283],{"class":5847},[5530,23032,5851],{"class":5543},[5530,23034,6114],{"class":5831},[5530,23036,23037],{"class":5547},"\"  Купон (5%):        -",[5530,23039,6120],{"class":5831},[5530,23041,23042],{"class":5543},"premium.discount_amount",[5530,23044,19650],{"class":5831},[5530,23046,19990],{"class":5547},[5530,23048,5558],{"class":5543},[5530,23050,23051,23053,23055,23057,23060],{"class":5532,"line":12444},[5530,23052,6283],{"class":5847},[5530,23054,5851],{"class":5543},[5530,23056,6114],{"class":5831},[5530,23058,23059],{"class":5547},"\"  Лояльність (15%): після купона\"",[5530,23061,5558],{"class":5543},[5530,23063,23064,23066,23068,23070,23073,23075,23078,23080,23082],{"class":5532,"line":12450},[5530,23065,6283],{"class":5847},[5530,23067,5851],{"class":5543},[5530,23069,6114],{"class":5831},[5530,23071,23072],{"class":5547},"\"  final_price:        ",[5530,23074,6120],{"class":5831},[5530,23076,23077],{"class":5543},"premium.final_price",[5530,23079,19650],{"class":5831},[5530,23081,19990],{"class":5547},[5530,23083,5558],{"class":5543},[5530,23085,23086],{"class":5532,"line":12473},[5530,23087,5565],{"emptyLinePlaceholder":5564},[5530,23089,23090],{"class":5532,"line":12481},[5530,23091,23092],{"class":5536},"# Доводимо, що __discount_code різний у Cart та PremiumCart\n",[5530,23094,23095,23097,23099,23101,23103,23105],{"class":5532,"line":12486},[5530,23096,6283],{"class":5847},[5530,23098,5851],{"class":5543},[5530,23100,6114],{"class":5831},[5530,23102,6128],{"class":5547},[5530,23104,8589],{"class":8588},[5530,23106,23107],{"class":5547},"  _Cart__discount_code:        \"\n",[5530,23109,23110,23113,23115,23117,23120,23122,23125,23128,23130,23132,23134],{"class":5532,"line":12495},[5530,23111,23112],{"class":5831},"      f",[5530,23114,6128],{"class":5547},[5530,23116,6120],{"class":5831},[5530,23118,23119],{"class":5543},"premium.",[5530,23121,6654],{"class":5854},[5530,23123,23124],{"class":5543},".get(",[5530,23126,23127],{"class":5547},"'_Cart__discount_code'",[5530,23129,12888],{"class":5543},[5530,23131,11974],{"class":5831},[5530,23133,6128],{"class":5547},[5530,23135,5558],{"class":5543},[5530,23137,23138,23140,23142,23144],{"class":5532,"line":12518},[5530,23139,6283],{"class":5847},[5530,23141,5851],{"class":5543},[5530,23143,6114],{"class":5831},[5530,23145,23146],{"class":5547},"\"  _PremiumCart__discount_code: \"\n",[5530,23148,23149,23151,23153,23155,23157,23159,23161,23164,23166,23168,23170],{"class":5532,"line":12523},[5530,23150,23112],{"class":5831},[5530,23152,6128],{"class":5547},[5530,23154,6120],{"class":5831},[5530,23156,23119],{"class":5543},[5530,23158,6654],{"class":5854},[5530,23160,23124],{"class":5543},[5530,23162,23163],{"class":5547},"'_PremiumCart__discount_code'",[5530,23165,12888],{"class":5543},[5530,23167,11974],{"class":5831},[5530,23169,6128],{"class":5547},[5530,23171,5558],{"class":5543},[5530,23173,23174,23176,23178,23180,23183],{"class":5532,"line":12529},[5530,23175,6283],{"class":5847},[5530,23177,5851],{"class":5543},[5530,23179,6114],{"class":5831},[5530,23181,23182],{"class":5547},"\"  (два різних поля — Name Mangling захищає від колізій!)\"",[5530,23184,5558],{"class":5543},[5530,23186,23187],{"class":5532,"line":12583},[5530,23188,5565],{"emptyLinePlaceholder":5564},[5530,23190,23191],{"class":5532,"line":12608},[5530,23192,23193],{"class":5536},"# ── 5. Спроба замовити недоступний товар ────────────────────────────────────\n",[5530,23195,23196,23198,23200,23202,23204,23207],{"class":5532,"line":12613},[5530,23197,6283],{"class":5847},[5530,23199,5851],{"class":5543},[5530,23201,6128],{"class":5547},[5530,23203,8589],{"class":8588},[5530,23205,23206],{"class":5547},"❌ Недоступний товар:\"",[5530,23208,5558],{"class":5543},[5530,23210,23211,23213],{"class":5532,"line":12619},[5530,23212,6586],{"class":6073},[5530,23214,5839],{"class":5543},[5530,23216,23217,23220,23223],{"class":5532,"line":12646},[5530,23218,23219],{"class":5543},"    Cart(",[5530,23221,23222],{"class":5547},"\"Тест\"",[5530,23224,23225],{"class":5543},").add(cable)\n",[5530,23227,23228,23230,23232,23234],{"class":5532,"line":12651},[5530,23229,6601],{"class":6073},[5530,23231,6090],{"class":5835},[5530,23233,6607],{"class":6073},[5530,23235,6610],{"class":5543},[5530,23237,23238,23240,23242,23244,23247,23249,23251,23253,23255],{"class":5532,"line":12657},[5530,23239,6593],{"class":5847},[5530,23241,5851],{"class":5543},[5530,23243,6114],{"class":5831},[5530,23245,23246],{"class":5547},"\"  ValueError: ",[5530,23248,6120],{"class":5831},[5530,23250,6626],{"class":5543},[5530,23252,6125],{"class":5831},[5530,23254,6128],{"class":5547},[5530,23256,5558],{"class":5543},[6302,23258,23259,23267,23271,23275,23278,23281,23285,23302,23317,23333,23349,23352,23356,23364,23372,23380,23383,23387,23395,23402,23410,23419,23427,23435,23438,23442,23450,23462,23470,23478,23482,23485,23489,23493,23497,23500,23507,23514,23521,23525,23533,23540,23548,23551,23559,23562,23565,23569,23577,23589,23592,23603,23616,23623,23626,23630],{"title":16131},[6306,23260,23262,6314,23265],{"className":23261},[5532],[5530,23263,6313],{"className":23264},[6312],[5629,23266,16131],{},[6306,23268,23270],{"className":23269},[5532],"==================================================",[6306,23272,23274],{"className":23273},[5532],"  E-COMMERCE СИСТЕМА: ПОВНА ДЕМОНСТРАЦІЯ",[6306,23276,23270],{"className":23277},[5532],[6306,23279],{"className":23280},[5532],[6306,23282,23284],{"className":23283},[5532],"📦 Каталог товарів:",[6306,23286,23288,23289,17540,23293,23297,23298,23301],{"className":23287},[5532],"  Product(",[5530,23290,23292],{"className":23291},[6720],"'MacBook Pro 14'",[5530,23294,23296],{"className":23295},[6720],"89999.00"," грн, stock=",[5530,23299,22196],{"className":23300},[6720]," ✅)",[6306,23303,23288,23305,23309,23310,23297,23314,23301],{"className":23304},[5532],[5530,23306,23308],{"className":23307},[6720],"'iPhone 15 Pro'",",  price=",[5530,23311,23313],{"className":23312},[6720],"44999.00",[5530,23315,14992],{"className":23316},[6720],[6306,23318,23288,23320,23324,23325,23329,23330,23301],{"className":23319},[5532],[5530,23321,23323],{"className":23322},[6720],"'AirPods Pro'",",    price=",[5530,23326,23328],{"className":23327},[6720],"9999.00","  грн, stock=",[5530,23331,22272],{"className":23332},[6720],[6306,23334,23288,23336,23340,23341,23329,23345,23348],{"className":23335},[5532],[5530,23337,23339],{"className":23338},[6720],"'USB-C кабель'",",   price=",[5530,23342,23344],{"className":23343},[6720],"499.00",[5530,23346,6080],{"className":23347},[6711],"  ❌)",[6306,23350],{"className":23351},[5532],[6306,23353,23355],{"className":23354},[5532],"🔒 Валідація Product:",[6306,23357,23359,23360],{"className":23358},[5532],"  [price=-1]   ",[5530,23361,23363],{"className":23362},[6711],"ValueError: 'price' має бути > 0, отримано -1",[6306,23365,23367,23368],{"className":23366},[5532],"  [stock=-5]   ",[5530,23369,23371],{"className":23370},[6711],"ValueError: 'stock' має бути >= 0, отримано -5",[6306,23373,23375,23376],{"className":23374},[5532],"  [stock=1.5]  ",[5530,23377,23379],{"className":23378},[6711],"TypeError: 'stock' має бути int, отримано 'float'",[6306,23381],{"className":23382},[5532],[6306,23384,23386],{"className":23385},[5532],"🛒 Звичайний кошик:",[6306,23388,23390,23391,23394],{"className":23389},[5532],"  + MacBook Pro 14 × 1  (",[5530,23392,23296],{"className":23393},[6720]," грн\u002Fшт)",[6306,23396,23398,23399,23394],{"className":23397},[5532],"  + iPhone 15 Pro  × 2  (",[5530,23400,23313],{"className":23401},[6720],[6306,23403,23405,23406,23409],{"className":23404},[5532],"  + AirPods Pro    × 3  (",[5530,23407,23328],{"className":23408},[6720],"  грн\u002Fшт)",[6306,23411,23413,23414,23418],{"className":23412},[5532],"  Cart('Іван Петренко', items=6, total=",[5530,23415,23417],{"className":23416},[6737],"209993.00"," грн)",[6306,23420,23422,23423,23426],{"className":23421},[5532],"  subtotal:   ",[5530,23424,23417],{"className":23425},[6720]," грн",[6306,23428,23430,23431,23426],{"className":23429},[5532],"  ПДВ:         ",[5530,23432,23434],{"className":23433},[6325],"34998.83",[6306,23436],{"className":23437},[5532],[6306,23439,23441],{"className":23440},[5532],"🎟️  Купони:",[6306,23443,23445,23446],{"className":23444},[5532],"  ❌ ",[5530,23447,23449],{"className":23448},[6711],"Купон 'FAKE99' не знайдено або вже не діє.",[6306,23451,23453,23454,20570,23458,23461],{"className":23452},[5532],"  ✅ Купон ",[5530,23455,23457],{"className":23456},[6720],"'SALE10'",[5530,23459,14992],{"className":23460},[6720],"%",[6306,23463,23465,23466,23426],{"className":23464},[5532],"  Знижка:      ",[5530,23467,23469],{"className":23468},[6720],"20999.30",[6306,23471,23473,23474,23426],{"className":23472},[5532],"  До оплати:  ",[5530,23475,23477],{"className":23476},[6720],"188993.70",[6306,23479,23481],{"className":23480},[5532],"  🗑️  Купон 'SALE10' скасовано",[6306,23483],{"className":23484},[5532],[6306,23486,23488],{"className":23487},[5532],"💳 Checkout (VIP20 — 20%):",[6306,23490,23492],{"className":23491},[5532],"==========================================",[6306,23494,23496],{"className":23495},[5532],"        ЧАРТЕР ЗАМОВЛЕННЯ",[6306,23498,23492],{"className":23499},[5532],[6306,23501,23503,23504,23426],{"className":23502},[5532],"  MacBook Pro 14       1 ×  ",[5530,23505,23296],{"className":23506},[6720],[6306,23508,23510,23511,23426],{"className":23509},[5532],"  iPhone 15 Pro        2 ×  ",[5530,23512,23313],{"className":23513},[6720],[6306,23515,23517,23518,23426],{"className":23516},[5532],"  AirPods Pro          3 ×   ",[5530,23519,23328],{"className":23520},[6720],[6306,23522,23524],{"className":23523},[5532],"------------------------------------------",[6306,23526,23528,23529,23426],{"className":23527},[5532],"  Сума без ПДВ:      ",[5530,23530,23532],{"className":23531},[6737],"174994.17",[6306,23534,23536,23537,23426],{"className":23535},[5532],"  ПДВ (20%):          ",[5530,23538,23434],{"className":23539},[6325],[6306,23541,23543,23544,23426],{"className":23542},[5532],"  Знижка (VIP20):    ",[5530,23545,23547],{"className":23546},[6720],"-41998.60",[6306,23549,23492],{"className":23550},[5532],[6306,23552,23554,23555,23426],{"className":23553},[5532],"  РАЗОМ:             ",[5530,23556,23558],{"className":23557},[6720],"167994.40",[6306,23560,23492],{"className":23561},[5532],[6306,23563],{"className":23564},[5532],[6306,23566,23568],{"className":23567},[5532],"👑 PremiumCart (Name Mangling демонстрація):",[6306,23570,23453,23572,23576],{"className":23571},[5532],[5530,23573,23575],{"className":23574},[6720],"'WELCOME5'"," активовано: знижка 5%",[6306,23578,23580,23581,23584,23585,23418],{"className":23579},[5532],"  PremiumCart('Олена VIP', loyalty=",[5530,23582,15004],{"className":23583},[6737],"%, total=",[5530,23586,23588],{"className":23587},[6720],"93894.37",[6306,23590],{"className":23591},[5532],[6306,23593,23595,23596,6738,23599],{"className":23594},[5532],"  _Cart__discount_code:        ",[5530,23597,23575],{"className":23598},[6325],[5530,23600,23602],{"className":23601},[6331],"# купон (з Cart)",[6306,23604,23606,23607,23611,23612],{"className":23605},[5532],"  _PremiumCart__discount_code: ",[5530,23608,23610],{"className":23609},[6737],"'LOYALTY'","   ",[5530,23613,23615],{"className":23614},[6331],"# loyalty (з PremiumCart)",[6306,23617,6738,23619],{"className":23618},[5532],[5530,23620,23622],{"className":23621},[6720],"(два різних поля — Name Mangling захищає від колізій!)",[6306,23624],{"className":23625},[5532],[6306,23627,23629],{"className":23628},[5532],"❌ Недоступний товар:",[6306,23631,23633,23634],{"className":23632},[5532],"  ValueError: ",[5530,23635,23637],{"className":23636},[6711],"Товар 'USB-C кабель' недоступний",[5666,23639],{},[5503,23641,23643],{"id":23642},"підсумки-та-найкращі-практики","Підсумки та найкращі практики",[5634,23645,23646,23654,23666,23688,23700,23711],{},[5637,23647,23650,23651,23653],{"icon":23648,"title":23649},"i-heroicons-arrow-trending-up","Починайте просто","Починайте з публічних атрибутів. Переходьте до ",[5512,23652,7199],{}," лише коли з'являється реальна потреба в валідації або обчисленні. Рання оптимізація — корінь усього зла.",[5637,23655,23657,23658,23661,23662,23665],{"icon":5639,"title":23656},"Угода _protected","Для більшості випадків ",[5512,23659,23660],{},"_single_underscore"," є достатнім. ",[5512,23663,23664],{},"__double_underscore"," (Name Mangling) застосовуйте виключно у базових класах бібліотек для захисту від колізій у підкласах.",[5637,23667,23670,23671,7954,23674,23677,23678,23680,23681,23684,23685,5702],{"icon":23668,"title":23669},"i-heroicons-check-circle","Pythonic @property","Не пишіть ",[5512,23672,23673],{},"get_balance()",[5512,23675,23676],{},"set_balance()",". Використовуйте ",[5512,23679,7199],{}," — зовнішній код буде мати синтаксис ",[5512,23682,23683],{},"account.balance = 1000"," замість ",[5512,23686,23687],{},"account.set_balance(1000)",[5637,23689,23692,23693,23695,23696,23699],{"icon":23690,"title":23691},"i-heroicons-squares-2x2","DRY з дескрипторами","Якщо одна й та сама валідаційна логіка потрібна у 3+ атрибутах — виносьте у дескриптор. Один раз написати ",[5512,23694,11630],{}," або ",[5512,23697,23698],{},"NonEmptyString"," і використовувати декларативно.",[5637,23701,23704,23706,23707,23710],{"icon":23702,"title":23703},"i-heroicons-bolt","Продуктивність",[5512,23705,7199],{}," додає незначний overhead (~50–100 нс). Не варто оптимізувати передчасно. Але якщо властивість виконує важкий запит — оформіть її як метод ",[5512,23708,23709],{},"get_data()",", щоб виклик був явним.",[5637,23712,23715,23716,7954,23719,23722],{"icon":23713,"title":23714},"i-heroicons-user-group","Consenting Adults","Python не забороняє доступ до ",[5512,23717,23718],{},"_private",[5512,23720,23721],{},"__mangled",". Поважайте чужі угоди та не лізьте під капот сторонніх об'єктів без крайньої потреби. Кожне порушення — ваш технічний борг.",[23724,23725,23726],"style",{},"html pre.shiki code .spJ8K, html code.shiki .spJ8K{--shiki-light:#008000;--shiki-default:#6A9955;--shiki-dark:#6A9955}html pre.shiki code .sHH4Y, html code.shiki .sHH4Y{--shiki-light:#000000;--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .sbdoH, html code.shiki .sbdoH{--shiki-light:#A31515;--shiki-default:#CE9178;--shiki-dark:#CE9178}html pre.shiki code .sJj4R, html code.shiki .sJj4R{--shiki-light:#098658;--shiki-default:#B5CEA8;--shiki-dark:#B5CEA8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .su1O8, html code.shiki .su1O8{--shiki-light:#0000FF;--shiki-default:#569CD6;--shiki-dark:#569CD6}html pre.shiki code .sN1BT, html code.shiki .sN1BT{--shiki-light:#267F99;--shiki-default:#4EC9B0;--shiki-dark:#4EC9B0}html pre.shiki code .s8Opu, html code.shiki .s8Opu{--shiki-light:#795E26;--shiki-default:#DCDCAA;--shiki-dark:#DCDCAA}html pre.shiki code .siwwj, html code.shiki .siwwj{--shiki-light:#001080;--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}html pre.shiki code .s8xlr, html code.shiki .s8xlr{--shiki-light:#AF00DB;--shiki-default:#C586C0;--shiki-dark:#C586C0}html pre.shiki code .sjcCO, html code.shiki .sjcCO{--shiki-light:#EE0000;--shiki-default:#D7BA7D;--shiki-dark:#D7BA7D}html pre.shiki code .shsrj, html code.shiki .shsrj{--shiki-light:#811F3F;--shiki-default:#D16969;--shiki-dark:#D16969}html pre.shiki code .sAV2Q, html code.shiki .sAV2Q{--shiki-light:#D16969;--shiki-default:#CE9178;--shiki-dark:#CE9178}html pre.shiki code .sYsli, html code.shiki .sYsli{--shiki-light:#000000;--shiki-default:#D7BA7D;--shiki-dark:#D7BA7D}",{"title":5526,"searchDepth":5540,"depth":5540,"links":23728},[23729,23730,23733,23743,23753,23769,23777,23782,23786],{"id":5505,"depth":5540,"text":5506},{"id":5670,"depth":5540,"text":5671,"children":23731},[23732],{"id":5675,"depth":5561,"text":5676},{"id":5806,"depth":5540,"text":5807,"children":23734},[23735,23737,23739,23741,23742],{"id":5810,"depth":5561,"text":23736},"public — за замовчуванням",{"id":5931,"depth":5561,"text":23738},"_protected — угода про внутрішнє використання",{"id":6377,"depth":5561,"text":23740},"__private — Name Mangling",{"id":6773,"depth":5561,"text":6774},{"id":7082,"depth":5561,"text":7083},{"id":7195,"depth":5540,"text":23744,"children":23745},"Частина III: @property — Pythonic-шлях до валідації",[23746,23747,23749,23750,23751],{"id":7203,"depth":5561,"text":7204},{"id":7460,"depth":5561,"text":23748},"Декоратор @property: обчислювальні властивості (read-only)",{"id":7946,"depth":5561,"text":7947},{"id":8877,"depth":5561,"text":8878},{"id":9127,"depth":5561,"text":23752},"Декоратори vs функція property()",{"id":9519,"depth":5540,"text":9520,"children":23754},[23755,23756,23757,23758,23759,23761,23762,23764,23765,23767],{"id":9523,"depth":5561,"text":9524},{"id":9589,"depth":5561,"text":9590},{"id":9610,"depth":5561,"text":9611},{"id":9625,"depth":5561,"text":9626},{"id":9657,"depth":5561,"text":23760},"Крок 3: Пошук у obj.__dict__",{"id":9668,"depth":5561,"text":9669},{"id":9690,"depth":5561,"text":23763},"Крок 5: __getattr__",{"id":9896,"depth":5561,"text":9897},{"id":10043,"depth":5561,"text":23766},"Симуляція property на чистому Python",{"id":10792,"depth":5561,"text":23768},"Незмінність об'єктів property: чому .setter створює новий об'єкт",{"id":11021,"depth":5540,"text":11022,"children":23770},[23771,23773,23775],{"id":11025,"depth":5561,"text":23772},"Проблема: десятки однакових @property",{"id":11310,"depth":5561,"text":23774},"__set_name__: автоматичне отримання імені атрибута (Python 3.6+)",{"id":11626,"depth":5561,"text":23776},"Повна реалізація IntegerRange дескриптора",{"id":12993,"depth":5540,"text":12994,"children":23778},[23779,23780,23781],{"id":12997,"depth":5561,"text":12998},{"id":13973,"depth":5561,"text":13974},{"id":16242,"depth":5561,"text":16243},{"id":17987,"depth":5540,"text":17988,"children":23783},[23784,23785],{"id":18116,"depth":5561,"text":18117},{"id":18434,"depth":5561,"text":18435},{"id":23642,"depth":5540,"text":23643},"Глибоке дослідження інкапсуляції в Python — від філософії «дорослих людей» та угод про іменування до механізму Name Mangling, обчислювальних властивостей з @property, кастомних дескрипторів та валідації даних через геттери й сеттери.","md",null,{},{"title":2933,"description":23787},"MaK7_6HOjYOkIU44V_ckWOaoxYgjjyr-RmB6npYcOHA",[23794,23796],{"title":71,"path":2930,"stem":2931,"description":23795,"children":-1},"Глибоке дослідження механізму класів і об'єктів у Python — від фундаментальних принципів інстанціювання до CPython internals, різниці між __init__ та __new__, оптимізації пам'яті через __slots__ та природи self як неявного першого аргументу.",{"title":2937,"path":2938,"stem":2939,"description":23797,"children":-1},"Глибоке дослідження механізмів наслідування в Python — від одиночного наслідування та перевизначення методів до cooperative multiple inheritance, внутрішнього влаштування super() як проксі-об'єкта, детального математичного аналізу C3-лінеаризації, CPython Internals MRO та патерну Mixins.",1794581914558]