commit 5ece589fbe338cfe77b3d8ec98fc9a363d85955b Author: Chris Sanden Date: Sun May 31 14:05:22 2026 +0200 Final push before system formatting diff --git a/AdvOpsys/AdvOpsys.pdf b/AdvOpsys/AdvOpsys.pdf new file mode 100644 index 0000000..1a49346 Binary files /dev/null and b/AdvOpsys/AdvOpsys.pdf differ diff --git a/AdvOpsys/notes/report/1.tex b/AdvOpsys/notes/report/1.tex new file mode 100644 index 0000000..50f692a --- /dev/null +++ b/AdvOpsys/notes/report/1.tex @@ -0,0 +1,106 @@ +\section{Boot Process Background} + +This section gives background context for the boot process before the kernel-specific implementation described in the rest of the report. It covers the firmware stages, bootloader responsibilities, memory layout, and the effect of virtualization on booting. + + + +\subsection{Power-On Self-Test} +When a computer is powered on or reset, the processor begins execution from a firmware-defined reset vector. At this point, the operating system is not running yet. The first responsibility belongs to the system firmware, either Basic Input/Output system (BIOS) on older x86 systems or Unified Extensive Firmware Interface (UEFI) on newer systems \cite{littleosbook, wikipediaPOST}. + +One of the earliest firmware tasks is the Power-On Self-Test, usually shortened to POST. POST checks that the basic hardware needed to continue booting is present and responding \cite{manybutfinite}. + +POST might include testing and verifying some of these components: +\begin{itemize} + \item Processors + \item Storage + \item Memory + \item Keyboard (Keyboard not found. Press f1 to continue.) +\end{itemize} + +Note: The exact list depends on the system \cite{techtargetPOST}. + +POST is important because later boot stages assume that the basic machine state is usable. If a required device fails or memory cannot be initialized, the firmware may stop the boot process and report the failure through screen output, status LEDs, or beep codes \cite{techtargetPOST}. + +The interaction between POST and hardware is therefore direct and low-level. Firmware initializes chipset state, configures memory controllers, discovers attached devices, and prepares enough of the platform that a bootloader can be found and executed. This is different from normal operating-system hardware management, because POST happens before the OS has loaded drivers or enabled its own abstractions. + + + +\subsection{Boot Sequence After POST} +After a successful POST, the firmware chooses a boot device according to its configured boot order. On BIOS systems, this usually means reading the first sector of a bootable disk into memory and jumping to it. On UEFI systems, the firmware instead loads an EFI application from a filesystem on the EFI System Partition \cite{cyberraidenUEFIBoot, manybutfinite}. + +The high-level sequence after POST is: +\begin{enumerate} + \item firmware completes hardware initialization, + \item firmware selects a boot device, + \item the first bootloader stage or EFI boot application is loaded, + \item the bootloader prepares the environment expected by the kernel, + \item the kernel image is loaded into memory, + \item control is transferred to the kernel entry point. +\end{enumerate} + +In a BIOS boot flow, the first loaded code is small because the initial boot sector is limited to 512 bytes. This usually forces the bootloader to use multiple stages. The first stage is responsible for loading a larger second stage, and the second stage can then parse filesystems, load the kernel, and prepare boot information\cite{osdevBootSequence, manybutfinite}. + +In a UEFI boot flow, the firmware provides more services before the operating system starts. A UEFI bootloader can use firmware-provided filesystem and device services, and it is loaded as a normal executable rather than as raw code from a fixed disk sector. This makes UEFI bootloaders more flexible, but the kernel must still eventually take control and stop depending on firmware runtime assumptions \cite{cyberraidenUEFIBoot}. + +\subsection{Bootloaders} +A bootloader is the bridge between firmware and the operating-system kernel. Its purpose is not only to start the kernel, but also to place the machine into a state the kernel understands \cite{ionosBootloader, littleosbook}. + +Common bootloader responsibilities include: +\begin{itemize} + \item locating and loading the kernel image, + \item loading additional modules or initrd files, + \item obtaining a memory map from the firmware, + \item selecting or setting a graphics mode, + \item preparing boot information structures, + \item switching CPU mode when required, + \item transferring control to the kernel entry point. +\end{itemize} + +Different bootloaders provide different levels of support. GRUB is a general-purpose bootloader with filesystem support, configuration files, multiboot support, and broad hardware compatibility. Limine is a modern boot protocol and bootloader often used in hobby OS development because it provides a clear boot protocol and supports both BIOS and UEFI systems\cite{osdevBootSequence,limineProtocol, wikipediaLimine}. A manually implemented bootloader gives full control over the boot path, but requires more work and exposes the project to more early-stage hardware and filesystem details. + +The choice of bootloader depends on the goals of the operating-system project. For a kernel-focused project, using an existing bootloader is usually the most practical choice because it avoids spending most of the work on disk loading, filesystem parsing, firmware differences, and CPU mode transitions. For a project specifically about bootstrapping, implementing a bootloader manually can be useful because it exposes the details normally hidden by existing tools \cite{osdevBootSequence}. + +Manual bootloader implementation is challenging because the environment is very limited. In a BIOS first-stage bootloader, code size is constrained, there is no standard library, only a small amount of state is initialized, and disk access must use firmware interrupts or direct hardware access. The bootloader must also be careful about where it places itself, the kernel, stacks, tables, and temporary buffers in memory. + +\subsection{Memory Layout in the Boot Process} +In a traditional i386 BIOS boot process, early memory layout is constrained by legacy conventions. The first MiB of memory contains several important regions, including the interrupt vector table, BIOS data area, conventional memory, video memory, and firmware regions\cite{osdevMemoryMapX86}. + +The bootloader and kernel must avoid overwriting memory that is already used by firmware, hardware mappings, or the bootloader itself. In small BIOS examples, a common simple kernel load address is \texttt{0x10000}. This address is above the lowest BIOS data structures and gives the kernel more room than the original boot sector area, while still being within conventional memory that is easy to access in early boot stages. In this project, the linker script places the kernel at \texttt{1 MiB}, which is also a common protected-mode kernel load address and keeps the kernel away from the lowest legacy BIOS regions \cite{osdevMemoryMapX86}. + +Choosing a fixed early kernel load address has practical implications: +\begin{itemize} + \item the bootloader needs to copy or load the kernel to a known address, + \item the kernel linker script must match the address where the kernel expects to run, + \item early stacks and temporary buffers must be placed so they do not overlap the kernel, + \item later memory management must identify which regions are already occupied. +\end{itemize} + +Once the kernel has control, it can replace this simple early memory model with its own memory management. In this project, that later stage is represented by kernel heap initialization, page-aligned allocation, and paging setup. + +\subsection{Boot Process in Modern Operating Systems} +Modern operating systems use more complex boot processes than small teaching kernels, but the same basic idea remains: firmware initializes the platform, a bootloader or boot manager loads the kernel, and the kernel takes control of the machine. + +Linux systems commonly use firmware to start a bootloader such as GRUB or systemd-boot. The bootloader loads the kernel and an initramfs, passes a command line and boot information, and then transfers control to the Linux kernel. Windows systems use Windows Boot Manager, which loads the Windows OS loader before the kernel and core system components are started. macOS uses Apple's boot chain, which is tightly integrated with Apple hardware, APFS, Secure Boot policies, and system volume verification\cite{linuxX86BootProtocol,microsoftWindowsBootOptions,appleSiliconBootProcess,appleIntelBootProcess}. + +Modern boot processes have changed because hardware and security requirements have changed. UEFI replaced many BIOS conventions, disks moved from MBR partitioning toward GPT, and Secure Boot introduced signature verification into the boot chain. Storage devices are also more complex than older BIOS-era disks, and modern systems often need early support for NVMe, encryption, graphics initialization, and platform security features. + +The result is that modern booting is both more capable and more controlled. Firmware and bootloaders provide richer services, but the operating system must also participate in a stricter trust chain and handle more platform variation. + +\subsection{Virtual Machines and Booting} +Booting inside a virtual machine follows the same conceptual stages as booting on physical hardware, but the hardware being initialized is virtual. The guest operating system still sees firmware, CPU state, memory, storage devices, timers, and interrupt controllers. However, those devices are provided or emulated by the hypervisor\cite{qemuPcMachine}. + +The main difference is that a virtual machine does not start from real motherboard hardware. Instead, the hypervisor creates a virtual hardware environment and then starts the guest firmware inside it. The guest firmware performs a boot sequence that looks normal from inside the VM, but many device operations are handled by the hypervisor on the host \cite{hashnodeVMboot}. + +The hypervisor has several roles in this process: +\begin{itemize} + \item allocating guest memory, + \item exposing virtual CPUs, + \item providing virtual disks and network devices, + \item emulating or virtualizing interrupt controllers and timers, + \item presenting BIOS or UEFI firmware to the guest, + \item handling privileged operations that cannot run directly on the host CPU. +\end{itemize} + +Virtualized booting has advantages for operating-system development. It is faster to test than rebooting physical hardware, the virtual machine can be reset easily, debugging is easier with tools such as QEMU and GDB, and hardware behaviour is more reproducible. This is why the kernel in this project was tested through QEMU rather than directly on physical hardware. + +There are also limitations. Emulated hardware may not behave exactly like real hardware, and some devices are simplified compared to physical machines. For example, PC speaker output in QEMU can be limited, which affected the clarity of fast note changes in the music player. Even so, virtualization is highly useful for kernel development because it provides a controlled environment for testing boot, interrupts, memory management, and device interaction\cite{qemuPcMachine, hashnodeVMboot}. \ No newline at end of file diff --git a/AdvOpsys/notes/report/2.tex b/AdvOpsys/notes/report/2.tex new file mode 100644 index 0000000..55a4295 --- /dev/null +++ b/AdvOpsys/notes/report/2.tex @@ -0,0 +1,122 @@ +\section{Boot Process and Processor Setup} + +The first stage of the project established a more complete early boot path for the kernel. Before this work, the kernel entered C code, initialized the VGA terminal, printed \texttt{Hello, World!}, and then remained in an infinite halt loop. The terminal output in this stage used direct VGA text-mode writes rather than BIOS text services, which is the normal approach once the kernel is running in protected mode \cite{osdevPrintingToScreen}. The visible output remained the same after this stage, but the processor setup became more explicit and reliable. + +The main change was the addition of a minimal Global Descriptor Table for the i386 kernel. Even though the kernel uses a flat memory model, protected mode still requires valid segment descriptors. The GDT therefore gives the processor valid code and data segment definitions before the kernel continues into higher-level initialization\cite{osdevGdtTutorial}. + +\subsection{Kernel Entry Flow} +After the GDT work, the early kernel flow became: +\begin{enumerate} + \item the bootloader transfers control to the kernel entry point, + \item the kernel begins execution in C, + \item the GDT is initialized and loaded, + \item segment registers are reloaded, + \item the VGA terminal is initialized, + \item \texttt{Hello, World!} is written to the screen, + \item the kernel enters an infinite halt loop. +\end{enumerate} + +This keeps processor setup before terminal setup. Later stages build on this ordering by adding interrupts, memory management, timing, and applications after the low-level CPU state has been initialized. +\clearpage + +\subsection{GDT Layout} +The implemented GDT contains three descriptors: +\begin{itemize} + \item a null descriptor, + \item a kernel code segment descriptor, + \item a kernel data segment descriptor. +\end{itemize} + +The code and data segments both use base address \texttt{0x00000000}, a 4 GiB address span, 4 KiB granularity, and ring 0 privilege level. The code segment uses selector \texttt{0x08}, while the data segment uses selector \texttt{0x10}. This matches the flat protected-mode layout commonly used in small i386 kernels \cite{osdevGdtTutorial,intelSdm}. + +\begin{listing}[H] +\begin{minted}{c} +void GdtInitialize(void) { + gdtDescriptor.size = sizeof(gdtEntries) - 1; + gdtDescriptor.offset = (uint32_t)&gdtEntries; + + GdtSetEntry(0, 0, 0, 0, 0); + GdtSetEntry(1, 0, 0x000FFFFF, 0x9A, 0xCF); + GdtSetEntry(2, 0, 0x000FFFFF, 0x92, 0xCF); + + GdtFlush((uint32_t)&gdtDescriptor); +} +\end{minted} +\caption{Minimal GDT initialization with null, kernel code, and kernel data descriptors.} +\end{listing} + +\subsection{Descriptor Construction} +The GDT setup is split between C and assembly. The C code builds the descriptor table and prepares the GDT descriptor that contains the table size and address. The helper that creates each descriptor splits the base and limit into the fields expected by the processor \cite{osdevGdtTutorial,intelSdm}. + +\begin{listing}[H] +\begin{minted}{c} +static void GdtSetEntry( + uint32_t index, + uint32_t base, + uint32_t limit, + uint8_t access, + uint8_t granularity +) { + gdtEntries[index].base_low = (uint16_t)(base & 0xFFFF); + gdtEntries[index].base_middle = (uint8_t)((base >> 16) & 0xFF); + gdtEntries[index].base_high = (uint8_t)((base >> 24) & 0xFF); + + gdtEntries[index].limit_low = (uint16_t)(limit & 0xFFFF); + gdtEntries[index].granularity = (uint8_t)((limit >> 16) & 0x0F); + gdtEntries[index].granularity |= (uint8_t)(granularity & 0xF0); + gdtEntries[index].access = access; +} +\end{minted} +\caption{Building an x86 GDT descriptor from base, limit, access, and granularity fields.} +\end{listing} +\clearpage + +\subsection{Reloading Segment Registers} +Loading the GDT with \texttt{lgdt} is not enough by itself. The CPU caches segment descriptor information in the segment registers, so the kernel must reload those registers after installing the new table. The assembly routine performs the architecture-specific part: it loads the GDT, performs a far jump to reload \texttt{cs}, and then reloads the data segment registers\cite{osdevGdtTutorial}. + +\begin{listing}[H] +\begin{minted}{nasm} +GdtFlush: + mov eax, [esp + 4] + lgdt [eax] + + jmp GDT_CODE_SELECTOR:.reload_cs + +.reload_cs: + mov ax, GDT_DATA_SELECTOR + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + ret +\end{minted} +\caption{Loading the GDT and refreshing the cached code and data segment registers.} +\end{listing} + +\section{Build and Verification} + +The build configuration was updated so that both the C GDT implementation and the assembly reload routine are compiled and linked into the kernel binary. New build artifacts were generated, including an updated kernel binary and bootable ISO image. + +\subsection{Static Binary Inspection} +The generated kernel binary was inspected to confirm that the expected GDT setup sequence was present. The inspection showed a call to the GDT load routine, a far jump to selector \texttt{0x08}, and data segment reloads using selector \texttt{0x10}. + +\subsection{Runtime Debugging} +The GDT setup was also verified in QEMU using \texttt{gdb-multiarch}. Execution was stopped inside the GDT initialization and reload path. The GDT descriptor limit was \texttt{0x17}, which matches three 8-byte entries minus one. After the far jump, \texttt{cs} contained \texttt{0x08}; after the reload instructions, \texttt{ds}, \texttt{es}, \texttt{fs}, \texttt{gs}, and \texttt{ss} contained \texttt{0x10}. +\clearpage + +\section{State After Processor Setup} + +At the end of this stage, the kernel: +\begin{itemize} + \item builds inside the development container, + \item includes a minimal i386 GDT implementation, + \item loads the GDT during startup, + \item reloads the code and data segment registers correctly, + \item still initializes the VGA terminal, + \item still prints \texttt{Hello, World!} after boot. +\end{itemize} + +This stage did not add new user-facing behaviour. Its purpose was to make the early processor state explicit so later kernel subsystems could be added on top of a controlled protected-mode setup. + +Later stages changed the visible startup flow by initializing the terminal before later setup code prints diagnostics for interrupt, memory, and paging work. The important dependency from this stage remains that the GDT is loaded before the kernel relies on later interrupt and application behaviour. diff --git a/AdvOpsys/notes/report/3.tex b/AdvOpsys/notes/report/3.tex new file mode 100644 index 0000000..c770861 --- /dev/null +++ b/AdvOpsys/notes/report/3.tex @@ -0,0 +1,185 @@ +\newpage + +\section{Interrupt Handling} + +The next stage added interrupt support to the kernel. This required an Interrupt Descriptor Table so the processor has defined entry points for CPU exceptions and hardware interrupts. The implementation follows the same model used by the OSDev Wiki material, the \texttt{os-tutorial} project, and the lecturer-provided assignment files \cite{osdevInterruptsTutorial,fenollosaOsTutorial,assignmentFiles}. + +Interrupt support changed the kernel from a purely linear boot program into a system that can react to events while it is running. CPU exceptions are handled through ISR stubs, hardware interrupts are handled through IRQ stubs, and both paths eventually reach C handlers with a saved register state. + +\subsection{IDT Descriptor Setup} +Each IDT entry stores the handler address, the kernel code segment selector, and the descriptor attributes used by the processor. The handler address is split into low and high parts because this is the layout expected by the 32-bit x86 IDT format \cite{osdevInterruptsTutorial}. + +\begin{listing}[H] +\begin{minted}{c} +void IdtSetDescriptor(uint8_t vector, uint32_t interrupt, uint8_t flags) { + struct IdtEntry* descriptor = &idt[vector]; + + descriptor->interrupt_low = (uint32_t)interrupt & 0xFFFF; + descriptor->kernel_cs = GDT_CODE_SELECTOR; + descriptor->attributes = flags; + descriptor->interrupt_high = (uint32_t)interrupt >> 16; + descriptor->reserved = 0; +} +\end{minted} +\caption{Constructing an IDT gate for a specific interrupt vector.} +\end{listing} +\clearpage + +\subsection{IDT Initialization} +During initialization, the kernel fills vectors \texttt{0} through \texttt{31} with CPU exception stubs and vectors \texttt{32} through \texttt{47} with hardware IRQ stubs. This means the implementation provides ISR coverage for all 32 standard CPU exception vectors, which is more complete than only defining the minimum three handlers required for basic testing. The PIC is then remapped before the IDT is loaded with \texttt{lidt} and interrupts are enabled with \texttt{sti}. + +\begin{listing}[H] +\begin{minted}{c} +void IdtInitialize(void) { + idtr.base = (uint32_t)&idt[0]; + idtr.limit = (uint16_t)sizeof(struct IdtEntry) * IDT_ENTRIES - 1; + + for (uint8_t iNum = 0; iNum < 32; iNum++) { + IdtSetDescriptor(iNum, (uint32_t)isr_stub_table[iNum], 0x8E); + } + + for (uint8_t iNum = 32; iNum < 48; iNum++) { + IdtSetDescriptor(iNum, (uint32_t)irq_stub_table[iNum - 32], 0x8E); + } + + PicRemap(); + __asm__ volatile ("lidt %0" : : "m"(idtr)); + __asm__ volatile ("sti"); +} +\end{minted} +\caption{Initializing the IDT with CPU exception and hardware IRQ entries.} +\end{listing} +\clearpage + +\section{CPU Exceptions} + +Basic Interrupt Service Routines were implemented for CPU exceptions. The low-level stubs save the CPU state and pass a \texttt{Registers} structure into the shared C handler. This lets the kernel inspect which exception occurred and print useful debugging information to the terminal. Instead of each ISR containing its own separate print logic, the individual stubs share the same C handler, which prints the interrupt number and message for the triggered exception. + +\begin{listing}[H] +\begin{minted}{c} +void IsrHandler(struct Registers* registers) { + TerminalWriteString("\n=== INTERRUPT RECEIVED ===\n"); + + TerminalWriteString("Interrupt Number: "); + TerminalWriteUInt(registers->int_no); + TerminalWriteString("\n"); + + TerminalWriteString("Message: "); + if (registers->int_no < 32) { + TerminalWriteString(isrMessages[registers->int_no]); + } else { + TerminalWriteString("Unknown Interrupt"); + } + + for (;;) { + __asm__ volatile("cli; hlt"); + } +} +\end{minted} +\caption{Shared CPU exception handler using the saved interrupt number.} +\end{listing} + +The handler stops the kernel after reporting the exception. This is appropriate for the current stage because exception recovery has not yet been implemented, and halting prevents the kernel from continuing after an undefined or unsafe processor state. +\clearpage + +\section{Hardware Interrupts} + +Hardware interrupt support was added for IRQ0 through IRQ15. These interrupts come from devices through the Programmable Interrupt Controller. The PIC is remapped so that hardware IRQs begin at vector \texttt{32} instead of overlapping with the CPU exception vectors\cite{osdev8259Pic}. + +\begin{listing}[H] +\begin{minted}{c} +void PicRemap(void) { + OutPortByte(PIC1_COMMAND, 0x11); + OutPortByte(PIC2_COMMAND, 0x11); + + OutPortByte(PIC1_DATA, 0x20); + OutPortByte(PIC2_DATA, 0x28); + + OutPortByte(PIC1_DATA, 0x04); + OutPortByte(PIC2_DATA, 0x02); + + OutPortByte(PIC1_DATA, 0x01); + OutPortByte(PIC2_DATA, 0x01); + + OutPortByte(PIC1_DATA, 0x00); + OutPortByte(PIC2_DATA, 0x00); +} +\end{minted} +\caption{Remapping the PIC so IRQs use interrupt vectors \texttt{32} through \texttt{47}.} +\end{listing} + +The IRQ handler dispatches to a registered C handler when one exists. After the interrupt has been handled, the kernel sends an end-of-interrupt signal to the PIC. This tells the controller that the current interrupt has been processed and that new interrupts may be delivered. + +\begin{listing}[H] +\begin{minted}{c} +void IrqHandler(struct Registers* registers) { + uint8_t irqNum = (uint8_t)(registers->int_no - 32); + + if (interruptHandlers[registers->int_no] != 0) { + interruptHandlers[registers->int_no](registers); + } else if (irqNum != 0) { + TerminalWriteString("IRQ triggered: "); + TerminalWriteUInt(irqNum); + TerminalWriteString("\n"); + } + + PicSendEoi(irqNum); +} +\end{minted} +\caption{Dispatching hardware interrupts and acknowledging them with the PIC.} +\end{listing} +\clearpage + +\section{Keyboard Input} + +Keyboard support was implemented using IRQ1. The keyboard handler reads the scancode from port \texttt{0x60}, stores it in a small buffer, ignores key-release events, and translates key-press scancodes into ASCII through a lookup table\cite{osdevPs2Controller}. + +The assignment describes the keyboard task as printing translated ASCII characters to the screen. In this project, the keyboard logic was extended slightly beyond a direct logger: the handler stores the latest translated ASCII character, and higher-level terminal or application code consumes it. This allows the same keyboard path to support the application menu and Snake input instead of only echoing characters immediately from the interrupt handler. + +\begin{listing}[H] +\begin{minted}{c} +void KeyboardHandler(struct Registers* registers) { + (void) registers; + + uint8_t scancode = InPortByte(KEYBOARD_DATA_PORT); + + if (index < KEYBOARD_BUFFER_SIZE) { + keyboardBuffer[index] = scancode; + index++; + } + + if (scancode & 0x80) { + return; + } + + if (scancode < 128) { + char ascii = scancodeToAscii[scancode]; + if (ascii != 0) { + lastKeyPressed = ascii; + } + } +} +\end{minted} +\caption{Keyboard IRQ handler reading scancodes and storing the latest ASCII key.} +\end{listing} + +The most recent translated key can then be consumed by higher-level code through \texttt{GetLastKeyPressed()}. This becomes important in later stages where the application menu and Snake game need keyboard input without directly handling raw scancodes. +\clearpage + +\section{State After Interrupt Work} + +At the end of this stage, the kernel: +\begin{itemize} + \item initializes and loads an Interrupt Descriptor Table, + \item handles CPU exceptions through ISR support, + \item supports hardware IRQs from IRQ0 to IRQ15, + \item remaps the PIC so hardware interrupts do not overlap with CPU exceptions, + \item dispatches hardware interrupts to registered handlers, + \item sends end-of-interrupt signals after IRQ handling, + \item handles keyboard input through IRQ1, + \item reads keyboard scancodes from port \texttt{0x60}, + \item translates key presses into ASCII characters, + \item stores the latest key for later application-level input. +\end{itemize} + +This stage moved the kernel from static startup output to event-driven execution. The later PIT, music, menu, and Snake work all depend on this interrupt layer. diff --git a/AdvOpsys/notes/report/4-5.tex b/AdvOpsys/notes/report/4-5.tex new file mode 100644 index 0000000..892b79c --- /dev/null +++ b/AdvOpsys/notes/report/4-5.tex @@ -0,0 +1,164 @@ +\section{Memory Management} + +The next stage added basic memory management to the kernel. This work introduced kernel heap initialization, paging, dynamic allocation, page-aligned allocation, and memory debugging output. Together these changes allow later kernel components to request memory dynamically instead of relying only on static storage\cite{assignmentFiles,osdevMemoryAllocation}. + +\subsection{Kernel Heap Initialization} +The heap is initialized from the linker-provided end of the kernel image. The kernel stores this address in \texttt{last\_alloc}, then reserves a normal heap region below the page heap area. A separate page heap is placed below \texttt{0x400000}, with one descriptor byte per page-aligned allocation \cite{assignmentFiles}. + +\begin{listing}[H] +\begin{minted}{c} +void InitKernelMemory(uint32_t* kernel_end) { + uint32_t kernelEndAddr = (uint32_t)kernel_end; + + last_alloc = kernelEndAddr + 0x1000; + heap_begin = last_alloc; + pheap_end = 0x400000; + pheap_begin = pheap_end - (MAX_PAGE_ALIGNED_ALLOCS * 4096); + heap_end = pheap_begin; + memset((char*)heap_begin, 0, heap_end - heap_begin); + pheap_desc = (uint8_t *)malloc(MAX_PAGE_ALIGNED_ALLOCS); +} +\end{minted} +\caption{Kernel heap initialization using the linker-provided kernel end symbol.} +\end{listing} + +This creates two allocation areas: +\begin{itemize} + \item a byte-addressed heap for normal \texttt{malloc()} allocations, + \item a page heap for 4 KiB page-aligned allocations through \texttt{pmalloc()}. +\end{itemize} +\clearpage + +\subsection{Paging} +Paging was implemented using a page directory at \texttt{0x400000} and page tables starting at \texttt{0x404000}. The setup identity-maps the first 4 MiB of memory and the 4 MiB region beginning at \texttt{0x400000}. This keeps virtual addresses equal to physical addresses for the early kernel environment while still enabling the processor's paging mechanism\cite{assignmentFiles,osdevSettingUpPaging}. + +The paging setup writes the page directory address to \texttt{cr3} and sets the paging bit in \texttt{cr0}. After that point, memory references are translated through the page tables \cite{osdevSettingUpPaging,intelSdm}. + +\begin{listing}[H] +\begin{minted}{c} +void paging_enable() { + asm volatile("mov %%eax, %%cr3": :"a"(page_dir_loc)); + asm volatile("mov %cr0, %eax"); + asm volatile("orl $0x80000000, %eax"); + asm volatile("mov %eax, %cr0"); +} +\end{minted} +\caption{Enabling paging by loading \texttt{cr3} and setting the paging bit in \texttt{cr0}.} +\end{listing} + +\subsection{Dynamic Allocation} +A simple heap allocator was implemented for \texttt{malloc()} and \texttt{free()}. Each allocation is preceded by a small metadata header containing the allocation status and size. New allocations advance \texttt{last\_alloc}, while freed blocks are marked as unused and may be reused by later allocations \cite{osdevMemoryAllocation}. + +The allocator scans existing blocks before creating a new one. If it finds an unused block large enough for the request, that block is reactivated and returned. This was verified by freeing one allocation, requesting a smaller block, and observing that the allocator reused the same address. + +\begin{listing}[H] +\begin{minted}{c} +if(a->size >= size) { + a->status = 1; + memset(mem + sizeof(alloc_t), 0, size); + memory_used += a->size + sizeof(alloc_t) + 4; + return (char*)(mem + sizeof(alloc_t)); +} +\end{minted} +\caption{Reusing a freed heap block when it is large enough for a new allocation.} +\end{listing} + +\subsection{Memory Debugging} +The kernel also gained memory debugging output. \texttt{PrintMemoryLayout()} prints the amount of memory used, the amount free, the heap size, and the start and end addresses of both the normal heap and page heap. \texttt{TerminalWriteHex()} was added so addresses can be printed in hexadecimal instead of being confused with decimal values \cite{assignmentFiles}. +\clearpage + +\section{Programmable Interval Timer} + +The Programmable Interval Timer was then added so the kernel can measure time and schedule delays. The PIT is configured on channel 0 at \texttt{1000 Hz}, so one timer tick corresponds approximately to one millisecond \cite{osdevPit}. + +\subsection{PIT Initialization} +The PIT driver defines the command port, channel 0 port, base frequency, target frequency, divider, and tick conversion in \texttt{pit.h}. During initialization, the kernel registers an IRQ0 handler, programs the PIT command byte, and writes the divisor as low byte followed by high byte\cite{assignmentFiles,osdevPit}. + +\begin{listing}[H] +\begin{minted}{c} +void PitInitialize(void){ + uint16_t divisor = DIVIDER; + + RegisterInterruptHandler(IRQ0, PitIrqHandler); + + OutPortByte(PIT_CMD_PORT, 0x36); + OutPortByte(PIT_CHANNEL0_PORT, (uint8_t)(divisor & 0xFF)); + OutPortByte(PIT_CHANNEL0_PORT, (uint8_t)((divisor >> 8) & 0xFF)); +} +\end{minted} +\caption{PIT channel 0 initialization and IRQ0 handler registration.} +\end{listing} + +The IRQ0 handler increments a \texttt{volatile} tick counter. Keeping the counter inside \texttt{pit.c} reduces the chance of accidental writes from unrelated kernel code \cite{assignmentFiles,osdevPit}. + +\subsection{Sleep Functions} +Two sleep functions were implemented. \texttt{SleepBusy()} repeatedly checks the tick counter until enough time has passed. This is simple but consumes CPU time for the whole delay. + +\texttt{SleepInterrupt()} uses \texttt{sti; hlt} inside the loop. This enables interrupts and halts the CPU until the next interrupt occurs. The loop then rechecks the current tick and halts again if the requested delay has not elapsed \cite{assignmentFiles,intelSdm}. + +\begin{listing}[H] +\begin{minted}{c} +void SleepInterrupt(uint32_t ticks_to_wait){ + uint32_t start_tick = GetCurrentTick(); + uint32_t end_tick = start_tick + ticks_to_wait; + + while(GetCurrentTick() < end_tick){ + __asm__ volatile ("sti; hlt"); + } +} +\end{minted} +\caption{Interrupt-based sleeping using the PIT tick counter and \texttt{hlt}.} +\end{listing} + +\subsection{Verification} +Several integration issues were fixed during PIT work. Incorrect inline assembly syntax was corrected, terminal output functions replaced unsuitable \texttt{printf()} calls, and the missing \texttt{TerminalWriteHex()} declaration was added to \texttt{terminal.h}. + +The build process also showed that rebuilding only \texttt{uiaos-kernel} updates \texttt{kernel.bin}, but does not update the bootable ISO image. Rebuilding \texttt{uiaos-create-image} was necessary before QEMU booted the newest kernel. Runtime testing then showed paging output, heap output, allocation output, and repeated sleep-test messages for both busy-wait and interrupt-based sleeping. + +\section{PC Speaker Music Player} + +Assignment 5 used the PIT and PC speaker to implement a simple music player. The PC speaker is controlled through I/O port \texttt{0x61}, while PIT channel 2 generates the square wave used for audible notes\cite{osdevPcSpeaker}. + +\subsection{Sound Generation} +The speaker is enabled by setting bits 0 and 1 on port \texttt{0x61}. To play a note, the kernel calculates a divisor from the PIT base frequency and the requested note frequency, programs PIT channel 2, and then enables the speaker. + +\begin{listing}[H] +\begin{minted}{c} +void PlaySound(uint32_t frequency) { + if (!frequency) return; + + uint32_t divisor = PIT_BASE_FREQ / frequency; + + OutPortByte(PIT_CMD_PORT, 0xB6); + OutPortByte(PIT_CHANNEL2_PORT, divisor & 0xFF); + OutPortByte(PIT_CHANNEL2_PORT, (divisor >> 8) & 0xFF); + + EnableSpeaker(); +} +\end{minted} +\caption{Programming PIT channel 2 to generate a PC speaker tone.} +\end{listing} +\clearpage + +\subsection{Song Representation and Playback} +Songs are represented as arrays of notes. Each note stores a frequency and duration in milliseconds. A rest is represented by frequency \texttt{R}, which is defined as \texttt{0}. Playback therefore consists of selecting a frequency, sleeping for the note duration, and then stopping the speaker. + +The implementation uses \texttt{SleepInterrupt()} for note timing. This replaced busy-wait delays because the interrupt-based delay gave better timing and avoided wasting CPU cycles while each note was playing. + +QEMU's PC speaker support made fast note changes unclear. To make playback more distinguishable, durations were doubled during playback. + +\begin{listing}[H] +\begin{minted}{c} +if (currentNote.frequency == R) { + StopSound(); + SleepInterrupt(currentNote.duration * 2); +} else { + PlaySound(currentNote.frequency); + SleepInterrupt(currentNote.duration * 2); + StopSound(); +} +\end{minted} +\caption{Song playback using rests, PC speaker tones, and interrupt-based timing.} +\end{listing} +\clearpage + diff --git a/AdvOpsys/notes/report/6.tex b/AdvOpsys/notes/report/6.tex new file mode 100644 index 0000000..1414119 --- /dev/null +++ b/AdvOpsys/notes/report/6.tex @@ -0,0 +1,227 @@ +\section{Application Framework, Snake, and Piano} + +The final stage integrated the individual OS components into a simple application framework. Instead of booting into a single test routine, the kernel now presents a terminal menu where the user can choose between the music player, Snake, and a piano application. + +\subsection{Menu-Based Control Flow} +The kernel initialization path now sets up the terminal, GDT, IDT, PIT, keyboard interrupt handler, kernel memory, and paging. After that initialization, the kernel repeatedly asks for an application number and dispatches to one of the available programs. This ties the higher-level menu flow back to the keyboard, PIT, and memory-management infrastructure implemented earlier \cite{osdevPs2Controller,osdevPit,osdevMemoryAllocation}. + +\begin{listing}[H] +\begin{minted}{c} +while (1) { + TerminalWriteString("Enter application number:\n"); + TerminalWriteString("0. Play Music\n"); + TerminalWriteString("1. Play Snake\n"); + TerminalWriteString("2. Play Piano\n"); + char input = TerminalGetChar(); + + switch (input) { + case '0': + TerminalClear(); + PlayMusic(); + TerminalClear(); + break; + case '1': + TerminalClear(); + PlayGame(); + TerminalClear(); + break; + case '2': + TerminalClear(); + PlayPiano(); + TerminalClear(); + break; + default: + TerminalWriteString("\nInvalid application number.\n"); + SleepInterrupt(1000); + TerminalClear(); + break; + } +} +\end{minted} +\caption{Application menu dispatch in the kernel main loop.} +\end{listing} + +This demonstrates that the terminal, keyboard, interrupt, timer, memory, and application code can cooperate through a single kernel control flow. +\clearpage + +\subsection{Snake Game State} +Snake uses a dynamically allocated game state. The game state contains the board, snake, food, score, and pseudo-random state. Creating and destroying the game therefore exercises the kernel's \texttt{malloc()} and \texttt{free()} implementation in a more realistic setting than isolated allocation tests. + +\begin{listing}[H] +\begin{minted}{c} +struct GameState* CreateGame(void) { + struct GameState* game = (struct GameState*)malloc(sizeof(struct GameState)); + if (!game) return 0; + + game->snake = (struct Snake*)malloc(sizeof(struct Snake)); + if (!game->snake) { + free(game); + return 0; + } + + game->food = (struct Food*)malloc(sizeof(struct Food)); + if (!game->food) { + free(game->snake); + free(game); + return 0; + } + + game->score = 0; + game->rngState = GetCurrentTick(); + return game; +} +\end{minted} +\caption{Snake creates its game objects using the kernel heap allocator.} +\end{listing} +\clearpage + +\subsection{Input, Timing, and Feedback} +The Snake loop reads the last key pressed by the keyboard handler, updates the snake direction, moves the snake, checks collisions, redraws the board, and then sleeps using the PIT. The game uses \texttt{GAME\_SPEED\_MS} to control pacing. + +Sound is also integrated into the game. Eating food, dying, and winning each trigger short PC speaker effects. This connects the application layer back to the PIT and PC speaker support implemented earlier. + +\begin{listing}[H] +\begin{minted}{c} +input = GetLastKeyPressed(); +HandleInput(game, input); +tail = MoveSnake(game->snake); + +collisionType = CheckCollision(game->snake, game->food); +if (collisionType == FOOD) { + game->score++; + PlayFoodSound(); + AddSegment(game->snake, tail.x, tail.y); + SpawnFood(game); +} + +DrawBoard(game); +SleepInterrupt(GAME_SPEED_MS); +\end{minted} +\caption{Main Snake loop combining keyboard input, game state, sound, drawing, and PIT timing.} +\end{listing} +\clearpage + +\subsection{Piano Application State} +The piano application adds a second interactive program that uses the same core kernel services in a different way. Instead of a continuously advancing game loop, the piano keeps a dynamically allocated application state with recording flags, the current note, timing information, and a song library. This makes the application a direct integration point between the heap allocator, keyboard input, PIT timing, and PC speaker output. + +\begin{listing}[H] +\begin{minted}{c} +struct PianoAppState* CreatePiano(void) { + struct PianoAppState* piano = + (struct PianoAppState*)malloc(sizeof(struct PianoAppState)); + if (!piano) return 0; + + piano->songLibrary = + (struct SongLibrary*)malloc(sizeof(struct SongLibrary)); + if (!piano->songLibrary) { + free(piano); + return 0; + } + + piano->songLibrary->songs = + (struct Song*)malloc(sizeof(struct Song) * MAX_SONG_COUNT); + if (!piano->songLibrary->songs) { + free(piano->songLibrary); + free(piano); + return 0; + } +} +\end{minted} +\caption{The piano allocates persistent application state and storage for recorded songs.} +\end{listing} + +\subsection{Key Mapping and Sound Generation} +The piano maps keyboard characters to musical notes. White and black keys are laid out in the terminal UI, and pressing a mapped key programs PIT channel 2 with the matching frequency before enabling the PC speaker. This reuses the same low-level mechanism as the earlier music player, but now the sound generation is driven directly by live keyboard input rather than a predefined song array \cite{osdevPcSpeaker,osdevPit}. + +\begin{listing}[H] +\begin{minted}{c} +case 'z': + PianoPlaySound(C4); + piano->activeFrequency = C4; + break; + +case 's': + PianoPlaySound(Cs4); + piano->activeFrequency = Cs4; + break; + +case 'x': + PianoPlaySound(D4); + piano->activeFrequency = D4; + break; +\end{minted} +\caption{Keyboard input is translated into note frequencies for live piano playback.} +\end{listing} + +\subsection{Recording and Playback} +The piano also adds a simple song-recording feature. When recording is enabled, played notes are stored in a song buffer together with their durations. The code also tracks the PIT tick count between notes, so pauses longer than a small threshold are stored as rests. During playback, those notes and rests are replayed through the PC speaker using \texttt{SleepInterrupt()} for timing \cite{osdevPit,osdevPcSpeaker}. + +\begin{listing}[H] +\begin{minted}{c} +if (piano->recording && piano->lastNoteEndTick != 0) { + uint32_t now = GetCurrentTick(); + uint32_t restDuration = now - piano->lastNoteEndTick; + + if (restDuration > 20) { + RecordNote(piano, R, restDuration); + } +} + +PianoHandleInput(piano); + +if (piano->recording) { + RecordNote(piano, piano->activeFrequency, PIANO_NOTE_DURATION); +} +\end{minted} +\caption{The piano stores both played notes and longer gaps so recorded songs preserve rhythm.} +\end{listing} +\clearpage + +\subsection{Interactive Piano Loop} +The runtime structure of the piano differs from Snake. Snake updates on every timer-based iteration, while the piano mostly waits for keyboard input, reacts to note and control keys, redraws the terminal UI, and uses short PIT sleeps to avoid a tight polling loop when no key has been pressed. This makes the piano a useful example of an event-driven terminal application built from the same kernel mechanisms as the rest of the project \cite{osdevPs2Controller,osdevPit}. + +\begin{listing}[H] +\begin{minted}{c} +while (1) { + char input = GetLastKeyPressed(); + + if (!input) { + SleepInterrupt(1); + continue; + } + + if (input == 'q') { + PianoStopSound(); + break; + } + + if (input == 'r' || input == 'p') { + piano->lastInput = input; + PianoHandleInput(piano); + TerminalClear(); + DrawPianoUi(piano); + continue; + } +} +\end{minted} +\caption{The piano loop combines keyboard polling, terminal redraws, and PIT-backed waiting.} +\end{listing} +\clearpage + +\section{Final State of the Project} + +At the end of the documented work, the kernel contains: +\begin{itemize} + \item early GDT setup and segment register reloading, + \item IDT, ISR, IRQ, PIC, and keyboard interrupt support, + \item kernel heap initialization and simple dynamic allocation, + \item identity-mapped paging for the early kernel address space, + \item PIT-based timer ticks and sleep functions, + \item PC speaker sound generation through PIT channel 2, + \item a menu-driven application flow, + \item a music player application, + \item an interactive Snake game using memory allocation, keyboard input, timing, terminal drawing, and sound feedback, + \item an interactive piano application with live note input, song recording, and playback. +\end{itemize} + +The project therefore moved from a minimal booting kernel that printed static text into a small interactive operating-system environment with hardware interrupts, timing, memory management, terminal input, sound, and application-level control flow. The final piano addition is especially useful as an integration example because it combines dynamic allocation, live keyboard input, PIT-based timing, terminal rendering, and PC speaker output inside one self-contained application. diff --git a/AdvOpsys/notes/report/bib.tex b/AdvOpsys/notes/report/bib.tex new file mode 100644 index 0000000..b98bed2 --- /dev/null +++ b/AdvOpsys/notes/report/bib.tex @@ -0,0 +1,244 @@ +%Referansene listet her kan bli brukt med \cite{name} +%De dukker bare opp om de refereres til minst en gang. +%OBS! om man har mer enn 3 forfattere er det mulig referansen ikke vil fungere, skriv da heller de to første og så et. al. + +@misc{techtargetPOST, + author = {Robert Sheldon}, + title = {{POST (Power-On Self-Test)}}, + year = {2022}, + month = {august}, + day = {2}, + howpublished = {\url{https://www.techtarget.com/whatis/definition/POST-Power-On-Self-Test}}, + note = {Accessed: 2026-04-28} +} + +@misc{osdevBootloader, + author = {{OSDev Wiki}}, + title = {{Bootloader}}, + year = {2023}, + month = {july}, + day = {9}, + howpublished = {\url{https://wiki.osdev.org/Bootloader}}, + note = {Accessed: 2026-04-28} +} + +@misc{wikipediaLimine, + author = {{Wikipedia contributors}}, + title = {{Limine (bootloader)}}, + year = {2026}, + month = {april}, + day = {9}, + howpublished = {\url{https://en.wikipedia.org/wiki/Limine_(bootloader)}}, + note = {Accessed: 2026-04-28} +} +@misc{ionosBootloader, + author = {{IONOS}}, + title = {{What is a bootloader?}}, + year = {2022}, + month = {november}, + day = {5}, + howpublished = {\url{https://www.ionos.com/digitalguide/server/configuration/what-is-a-bootloader/}}, + note = {Accessed: 2026-04-28} +} + +@misc{cyberraidenUEFIBoot, + author = {{Raiden}}, + title = {{The Windows Operating System Boot Process in UEFI Mode}}, + year = {2025}, + month = {july}, + day = {24}, + howpublished = {\url{https://cyberraiden.wordpress.com/2025/07/24/the-windows-operating-system-boot-process-in-uefi-mode/}}, + note = {Accessed: 2026-04-28} +} + +@misc{wikipediaPOST, + author = {{Wikipedia}}, + title = {{Power-on self-test}}, + year = {2026}, + month = {april}, + day = {25}, + howpublished = {\url{https://en.wikipedia.org/wiki/Power-on_self-test}}, + note = {Accessed: 2026-04-28} +} + +@misc{littleosbook, + author = {Erik Helin and Adam Renberg}, + title = {The Little Book About OS Development}, + year = {2015}, + howpublished = {\url{https://littleosbook.github.io/}}, + note = {Accessed: 2026-04-28} +} + +@misc{manybutfinite, + author = {Gustavo Duarte}, + title = {How Computers Boot Up}, + year = {2011}, + howpublished = {\url{https://manybutfinite.com/post/how-computers-boot-up/}}, + note = {Accessed: 2026-04-28} +} + +@misc{osdevInterruptsTutorial, + author = {{OSDev Wiki}}, + title = {{Interrupts Tutorial}}, + howpublished = {\url{https://wiki.osdev.org/Interrupts_Tutorial}}, + note = {Accessed 2026-04-16} +} + +@misc{fenollosaOsTutorial, + author = {Carlos Fenollosa}, + title = {{os-tutorial}}, + howpublished = {\url{https://github.com/cfenollosa/os-tutorial/tree/master}}, + note = {Accessed 2026-04-16} +} + +@misc{assignmentFiles, + author = {{Turgay Celik}}, + title = {{assignment\_files.zip}}, + note = {Source code and assignment material provided by course lecturer} +} + +@misc{osdevBootSequence, + author = {{OSDev Wiki}}, + title = {{Boot Sequence}}, + howpublished = {\url{https://wiki.osdev.org/Boot_Sequence}}, + note = {Accessed 2026-04-20} +} + +@misc{osdevMemoryMapX86, + author = {{OSDev Wiki}}, + title = {{Memory Map (x86)}}, + howpublished = {\url{https://wiki.osdev.org/Memory_Map_(x86)}}, + note = {Accessed 2026-04-20} +} + +@misc{osdevGdtTutorial, + author = {{OSDev Wiki}}, + title = {{GDT Tutorial}}, + howpublished = {\url{https://wiki.osdev.org/GDT_Tutorial}}, + note = {Accessed 2026-04-20} +} + +@misc{osdev8259Pic, + author = {{OSDev Wiki}}, + title = {{8259 PIC}}, + howpublished = {\url{https://wiki.osdev.org/8259_PIC}}, + note = {Accessed 2026-04-20} +} + +@misc{osdevPs2Controller, + author = {{OSDev Wiki}}, + title = {{I8042 PS/2 Controller}}, + howpublished = {\url{https://wiki.osdev.org/I8042_PS/2_Controller}}, + note = {Accessed 2026-04-20} +} + +@misc{osdevMemoryAllocation, + author = {{OSDev Wiki}}, + title = {{Memory Allocation}}, + howpublished = {\url{https://wiki.osdev.org/Memory_Allocation}}, + note = {Accessed 2026-04-20} +} + +@misc{osdevSettingUpPaging, + author = {{OSDev Wiki}}, + title = {{Setting Up Paging}}, + howpublished = {\url{https://wiki.osdev.org/Setting_Up_Paging}}, + note = {Accessed 2026-04-20} +} + +@misc{osdevPit, + author = {{OSDev Wiki}}, + title = {{Programmable Interval Timer}}, + howpublished = {\url{https://wiki.osdev.org/Programmable_Interval_Timer}}, + note = {Accessed 2026-04-20} +} + +@misc{osdevPcSpeaker, + author = {{OSDev Wiki}}, + title = {{PC Speaker}}, + howpublished = {\url{https://wiki.osdev.org/PC_Speaker}}, + note = {Accessed 2026-04-20} +} + +@misc{osdevInterrupts, + author = {{OSDev Wiki}}, + title = {{Interrupts}}, + year = {2026}, + month = {march}, + day = {17}, + howpublished = {\url{https://wiki.osdev.org/Interrupts}}, + note = {Accessed: 2026-04-28} +} + +@misc{uefiSpecifications, + author = {{UEFI Forum}}, + title = {{UEFI Specifications}}, + howpublished = {\url{https://uefi.org/specifications}}, + note = {Accessed 2026-04-20} +} + +@misc{limineProtocol, + author = {{Limine Bootloader Project}}, + title = {{Limine Boot Protocol}}, + howpublished = {\url{https://github.com/limine-bootloader/limine-protocol}}, + note = {Accessed 2026-04-20} +} + +@misc{linuxX86BootProtocol, + author = {{Linux Kernel Documentation}}, + title = {{The Linux/x86 Boot Protocol}}, + howpublished = {\url{https://docs.kernel.org/arch/x86/boot.html}}, + note = {Accessed 2026-04-20} +} + +@misc{microsoftWindowsBootOptions, + author = {{Microsoft}}, + title = {{Configure and edit boot options in Windows for driver development}}, + howpublished = {\url{https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/boot-options-in-windows}}, + note = {Accessed 2026-04-20} +} + +@misc{appleSiliconBootProcess, + author = {{Apple}}, + title = {{Boot process for a Mac with Apple silicon}}, + howpublished = {\url{https://support.apple.com/guide/security/secac71d5623/web}}, + note = {Accessed 2026-04-20} +} + +@misc{appleIntelBootProcess, + author = {{Apple}}, + title = {{Boot process for an Intel-based Mac}}, + howpublished = {\url{https://support.apple.com/guide/security/sec5d0fab7c6/web}}, + note = {Accessed 2026-04-20} +} + +@misc{qemuPcMachine, + author = {{QEMU Project}}, + title = {{i440fx PC (pc-i440fx, pc)}}, + howpublished = {\url{https://qemu.readthedocs.io/en/v8.1.5/system/i386/pc.html}}, + note = {Accessed 2026-04-20} +} + +@misc{hashnodeVMboot, + author = {{Logeshwaran N}}, + title = {{Virtual Machine Boot Process Explained – Easy Guide}}, + year = {2024}, + month = {october}, + day = {12}, + howpublished = {\url{https://logeshwrites.hashnode.dev/virtual-machine-boot-process-explained-easy-guide}}, + note = {Accessed: 2026-04-28} +} + +@misc{intelSdm, + author = {{Intel}}, + title = {{Intel 64 and IA-32 Architectures Software Developer's Manual}}, + howpublished = {\url{https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html}}, + note = {Accessed 2026-04-28} +} + +@misc{osdevPrintingToScreen, + author = {{OSDev Wiki}}, + title = {{Printing To Screen}}, + howpublished = {\url{https://wiki.osdev.org/Printing_To_Screen}}, + note = {Accessed 2026-04-28} +} \ No newline at end of file diff --git a/AdvOpsys/notes/report/boot_topics.tex b/AdvOpsys/notes/report/boot_topics.tex new file mode 100644 index 0000000..0225d37 --- /dev/null +++ b/AdvOpsys/notes/report/boot_topics.tex @@ -0,0 +1,100 @@ +\section{Boot Process Background} + +This section gives background context for the boot process before the kernel-specific implementation described in the rest of the report. It covers the firmware stages, bootloader responsibilities, memory layout, and the effect of virtualization on booting. + +\subsection{Power-On Self-Test} +When a computer is powered on or reset, the processor begins execution from a firmware-defined reset vector. At this point, the operating system is not running yet. The first responsibility belongs to the system firmware, either BIOS on older x86 systems or UEFI on newer systems \cite{osdevBootSequence,uefiSpecifications}. + +One of the earliest firmware tasks is the Power-On Self-Test, usually shortened to POST. POST checks that the basic hardware needed to continue booting is present and responding. This includes components such as: +\begin{itemize} + \item the CPU, + \item system memory, + \item firmware storage, + \item video output, + \item keyboard or input controllers, + \item storage controllers and bootable devices. +\end{itemize} + +POST is important because later boot stages assume that the basic machine state is usable. If a required device fails or memory cannot be initialized, the firmware may stop the boot process and report the failure through screen output, status LEDs, or beep codes. + +The interaction between POST and hardware is therefore direct and low-level. Firmware initializes chipset state, configures memory controllers, discovers attached devices, and prepares enough of the platform that a bootloader can be found and executed. This is different from normal operating-system hardware management, because POST happens before the OS has loaded drivers or enabled its own abstractions. + +\subsection{Boot Sequence After POST} +After a successful POST, the firmware chooses a boot device according to its configured boot order. On BIOS systems, this usually means reading the first sector of a bootable disk into memory and jumping to it. On UEFI systems, the firmware instead loads an EFI application from a filesystem on the EFI System Partition \cite{osdevBootSequence,uefiSpecifications}. + +The high-level sequence after POST is: +\begin{enumerate} + \item firmware completes hardware initialization, + \item firmware selects a boot device, + \item the first bootloader stage or EFI boot application is loaded, + \item the bootloader prepares the environment expected by the kernel, + \item the kernel image is loaded into memory, + \item control is transferred to the kernel entry point. +\end{enumerate} + +In a BIOS boot flow, the first loaded code is small because the initial boot sector is limited to 512 bytes. This usually forces the bootloader to use multiple stages. The first stage is responsible for loading a larger second stage, and the second stage can then parse filesystems, load the kernel, and prepare boot information \cite{osdevBootSequence}. + +In a UEFI boot flow, the firmware provides more services before the operating system starts. A UEFI bootloader can use firmware-provided filesystem and device services, and it is loaded as a normal executable rather than as raw code from a fixed disk sector. This makes UEFI bootloaders more flexible, but the kernel must still eventually take control and stop depending on firmware runtime assumptions. + +\subsection{Bootloaders} +A bootloader is the bridge between firmware and the operating-system kernel. Its purpose is not only to start the kernel, but also to place the machine into a state the kernel understands. + +Common bootloader responsibilities include: +\begin{itemize} + \item locating and loading the kernel image, + \item loading additional modules or initrd files, + \item obtaining a memory map from the firmware, + \item selecting or setting a graphics mode, + \item preparing boot information structures, + \item switching CPU mode when required, + \item transferring control to the kernel entry point. +\end{itemize} + +Different bootloaders provide different levels of support. GRUB is a general-purpose bootloader with filesystem support, configuration files, multiboot support, and broad hardware compatibility. Limine is a modern boot protocol and bootloader often used in hobby OS development because it provides a clear boot protocol and supports both BIOS and UEFI systems \cite{osdevBootSequence,limineProtocol}. A manually implemented bootloader gives full control over the boot path, but requires more work and exposes the project to more early-stage hardware and filesystem details. + +The choice of bootloader depends on the goals of the operating-system project. For a kernel-focused project, using an existing bootloader is usually the most practical choice because it avoids spending most of the work on disk loading, filesystem parsing, firmware differences, and CPU mode transitions. For a project specifically about bootstrapping, implementing a bootloader manually can be useful because it exposes the details normally hidden by existing tools. + +Manual bootloader implementation is challenging because the environment is very limited. In a BIOS first-stage bootloader, code size is constrained, there is no standard library, only a small amount of state is initialized, and disk access must use firmware interrupts or direct hardware access. The bootloader must also be careful about where it places itself, the kernel, stacks, tables, and temporary buffers in memory. + +\subsection{Memory Layout in the Boot Process} +In a traditional i386 BIOS boot process, early memory layout is constrained by legacy conventions. The first MiB of memory contains several important regions, including the interrupt vector table, BIOS data area, conventional memory, video memory, and firmware regions \cite{osdevMemoryMapX86}. + +The bootloader and kernel must avoid overwriting memory that is already used by firmware, hardware mappings, or the bootloader itself. In small BIOS examples, a common simple kernel load address is \texttt{0x10000}. This address is above the lowest BIOS data structures and gives the kernel more room than the original boot sector area, while still being within conventional memory that is easy to access in early boot stages. In this project, the linker script places the kernel at \texttt{1 MiB}, which is also a common protected-mode kernel load address and keeps the kernel away from the lowest legacy BIOS regions. + +Choosing a fixed early kernel load address has practical implications: +\begin{itemize} + \item the bootloader needs to copy or load the kernel to a known address, + \item the kernel linker script must match the address where the kernel expects to run, + \item early stacks and temporary buffers must be placed so they do not overlap the kernel, + \item later memory management must identify which regions are already occupied. +\end{itemize} + +Once the kernel has control, it can replace this simple early memory model with its own memory management. In this project, that later stage is represented by kernel heap initialization, page-aligned allocation, and paging setup. + +\subsection{Boot Process in Modern Operating Systems} +Modern operating systems use more complex boot processes than small teaching kernels, but the same basic idea remains: firmware initializes the platform, a bootloader or boot manager loads the kernel, and the kernel takes control of the machine. + +Linux systems commonly use firmware to start a bootloader such as GRUB or systemd-boot. The bootloader loads the kernel and an initramfs, passes a command line and boot information, and then transfers control to the Linux kernel. Windows systems use Windows Boot Manager, which loads the Windows OS loader before the kernel and core system components are started. macOS uses Apple's boot chain, which is tightly integrated with Apple hardware, APFS, Secure Boot policies, and system volume verification \cite{linuxX86BootProtocol,microsoftWindowsBootOptions,appleSiliconBootProcess,appleIntelBootProcess}. + +Modern boot processes have changed because hardware and security requirements have changed. UEFI replaced many BIOS conventions, disks moved from MBR partitioning toward GPT, and Secure Boot introduced signature verification into the boot chain. Storage devices are also more complex than older BIOS-era disks, and modern systems often need early support for NVMe, encryption, graphics initialization, and platform security features. + +The result is that modern booting is both more capable and more controlled. Firmware and bootloaders provide richer services, but the operating system must also participate in a stricter trust chain and handle more platform variation. + +\subsection{Virtual Machines and Booting} +Booting inside a virtual machine follows the same conceptual stages as booting on physical hardware, but the hardware being initialized is virtual. The guest operating system still sees firmware, CPU state, memory, storage devices, timers, and interrupt controllers. However, those devices are provided or emulated by the hypervisor \cite{qemuPcMachine}. + +The main difference is that a virtual machine does not start from real motherboard hardware. Instead, the hypervisor creates a virtual hardware environment and then starts the guest firmware inside it. The guest firmware performs a boot sequence that looks normal from inside the VM, but many device operations are handled by the hypervisor on the host. + +The hypervisor has several roles in this process: +\begin{itemize} + \item allocating guest memory, + \item exposing virtual CPUs, + \item providing virtual disks and network devices, + \item emulating or virtualizing interrupt controllers and timers, + \item presenting BIOS or UEFI firmware to the guest, + \item handling privileged operations that cannot run directly on the host CPU. +\end{itemize} + +Virtualized booting has advantages for operating-system development. It is faster to test than rebooting physical hardware, the virtual machine can be reset easily, debugging is easier with tools such as QEMU and GDB, and hardware behaviour is more reproducible. This is why the kernel in this project was tested through QEMU rather than directly on physical hardware. + +There are also limitations. Emulated hardware may not behave exactly like real hardware, and some devices are simplified compared to physical machines. For example, PC speaker output in QEMU can be limited, which affected the clarity of fast note changes in the music player. Even so, virtualization is highly useful for kernel development because it provides a controlled environment for testing boot, interrupts, memory management, and device interaction \cite{qemuPcMachine}. diff --git a/AdvOpsys/notes/report/conclusion.tex b/AdvOpsys/notes/report/conclusion.tex new file mode 100644 index 0000000..fa644ca --- /dev/null +++ b/AdvOpsys/notes/report/conclusion.tex @@ -0,0 +1,14 @@ +\section{Conclusion} + +The project started with a minimal bootable kernel and developed it into a small interactive operating-system environment. The final kernel includes early processor setup, interrupt handling, memory management, PIT-based timing, PC speaker sound, keyboard input, terminal output, a menu system, a music player, and a Snake game. + +The first major step was to make the processor setup explicit by adding a minimal Global Descriptor Table and reloading the segment registers correctly. This provided a controlled protected-mode foundation for later work. Interrupt handling then extended the kernel from linear startup code into an event-driven system, with CPU exceptions, hardware IRQs, PIC remapping, and keyboard input. + +Memory management and paging added another important layer. The kernel gained heap initialization, dynamic allocation, page-aligned allocation, memory utility functions, and identity-mapped paging. These features made it possible for later code to allocate state dynamically rather than relying only on static data. + +The PIT then provided a timing source through IRQ0. This supported both busy-wait and interrupt-based sleeping, with the interrupt-based version becoming important for later features. The same timing infrastructure was reused by the music player and Snake game. The PC speaker work showed how PIT channel 2 could be used for sound generation, while also showing the practical limits of testing audio through QEMU. + +The final application framework tied the lower-level pieces together. The menu system used terminal output and keyboard input to choose between applications. The music player used PIT timing and PC speaker output. Snake combined memory allocation, keyboard input, PIT-based pacing, terminal drawing, and sound effects. This made the final application stage a practical test of whether the kernel subsystems could work together. + +Overall, the project demonstrates how small operating-system mechanisms build on each other. GDT setup makes the early CPU state reliable, interrupts make asynchronous hardware events usable, memory management allows dynamic state, timing enables delays and pacing, and device output makes applications interactive. The result is not a complete general-purpose operating system, but it is a working kernel environment that shows the relationship between low-level hardware control and higher-level program behaviour. + diff --git a/AdvOpsys/notes/report/intro.tex b/AdvOpsys/notes/report/intro.tex new file mode 100644 index 0000000..0e3ee2a --- /dev/null +++ b/AdvOpsys/notes/report/intro.tex @@ -0,0 +1,11 @@ +\section{Introduction} + +This report documents both the boot-process background behind operating-system startup and the development of a small 32-bit operating-system kernel for the \texttt{Advanced Operatingsystems} project. It starts by explaining the firmware and bootloader stages that happen before a kernel runs, then follows the project implementation from a minimal bootable kernel into a more interactive environment with processor setup, interrupts, memory management, timing, sound, keyboard input, and simple applications. + +The background section covers the general boot sequence: Power-On Self-Test, firmware handoff, BIOS and UEFI differences, bootloader responsibilities, early i386 memory layout, modern operating-system boot chains, and the role of virtualization. This gives context for why the project can rely on a bootloader, why the kernel starts from a constrained early machine state, and why QEMU is useful for testing this kind of low-level work. + +The implementation itself is intentionally low-level. Most of the kernel interacts directly with x86 processor structures and hardware interfaces, including the Global Descriptor Table, Interrupt Descriptor Table, Programmable Interrupt Controller, Programmable Interval Timer, VGA text output, keyboard controller, and PC speaker. Because the kernel runs in a freestanding environment, basic facilities that are normally provided by an operating system or standard library also had to be implemented inside the project. + +After the boot background, the report follows the same order as the implementation work. The first implementation part covers the early boot path and processor setup, with particular focus on the Global Descriptor Table and the need to reload segment registers after installing it. The second part describes interrupt handling, including CPU exceptions, hardware IRQs, PIC remapping, and keyboard input. The third part introduces memory management, paging, PIT-based timing, sleep functions, and PC speaker music playback. The final part shows how these individual subsystems were combined into a small menu-driven application environment with a music player, an interactive Snake game and a piano application. + +The overall goal was not to build a complete general-purpose operating system, but to demonstrate how core operating-system mechanisms fit together. Each stage adds a specific capability, and later stages reuse earlier ones: the PIT depends on interrupt handling, the music player depends on PIT timing and PC speaker output, Snake depends on memory allocation, keyboard input, terminal drawing, timing, and sound feedback, and Piano app depends on keyboard input, terminal drawing, PIT timing and memory allocation. By the end of the project, the kernel has moved from static startup output to an event-driven system that can run simple interactive applications. diff --git a/AdvOpsys/notes/report/problems.tex b/AdvOpsys/notes/report/problems.tex new file mode 100644 index 0000000..b9aad44 --- /dev/null +++ b/AdvOpsys/notes/report/problems.tex @@ -0,0 +1,41 @@ +\section{Problems and Challenges} + +Several issues appeared during the project because the kernel runs in a freestanding environment where there is little separation between build configuration, CPU state, hardware programming, and application behaviour. Most problems were not isolated to one source file; they came from interactions between the boot image, low-level initialization, interrupts, timing, and terminal output. + +\subsection{Processor State and Verification} +The GDT implementation required careful verification because a mistake in this stage can prevent the kernel from continuing at all. One important detail was that loading the GDT with \texttt{lgdt} does not automatically update the cached segment registers. The implementation therefore needed a far jump to reload \texttt{cs}, followed by explicit reloads of \texttt{ds}, \texttt{es}, \texttt{fs}, \texttt{gs}, and \texttt{ss}. + +This was verified both statically and at runtime. Static inspection confirmed that the kernel binary contained the expected GDT load sequence, far jump, and data segment reloads. Runtime debugging in QEMU with \texttt{gdb-multiarch} confirmed that \texttt{cs} became \texttt{0x08} and that the data segment registers became \texttt{0x10}. This was necessary because the code could compile correctly while still failing if the processor did not actually enter the expected segment state. + +\subsection{Build and Boot Image Mismatch} +A major integration problem appeared during the PIT work. Rebuilding only the kernel target updated \texttt{kernel.bin}, but did not update the bootable ISO image. As a result, QEMU could still boot an older image even after the source code and kernel binary had changed. + +This made the runtime output misleading. The newer \texttt{kernel.bin} contained PIT and memory-management strings, while the older \texttt{kernel.iso} still showed the earlier \texttt{Hello, World!} output. The issue was resolved by rebuilding the bootable image target so the ISO contained the updated kernel. + +This problem showed that kernel development requires verifying not only the source code, but also the exact artifact being booted. When the build system produces multiple outputs, it is possible to test the wrong one without noticing immediately. + +\subsection{Freestanding C and Header Consistency} +Because the kernel does not run with a normal hosted C environment, ordinary library assumptions do not always apply. During the PIT integration, \texttt{printf()} calls had to be removed from test code and replaced with the kernel's terminal output functions. The terminal interface also needed to expose \texttt{TerminalWriteHex()} through the header because the function was implemented in \texttt{terminal.c} but not declared for other modules. + +Inline assembly syntax also caused a build issue. An incorrect form of \texttt{\_\_asm\_\_volatile} had to be corrected to \texttt{\_\_asm\_\_ volatile}. This was a small syntax problem, but in low-level code it blocked the PIT sleep implementation because \texttt{sti; hlt} was part of the interrupt-based delay loop. + +\subsection{Interrupt Dependencies} +Several later features depended on interrupt handling being correct. The PIT relies on IRQ0, keyboard input relies on IRQ1, and both the music player and Snake depend on timer and keyboard behaviour. This meant that interrupt setup was not only an isolated assignment task; it became part of the foundation for the rest of the project. + +The PIC also had to be remapped so hardware IRQs did not overlap with CPU exception vectors. Without this separation, hardware events and processor exceptions would be harder to distinguish, and debugging later features would become much less reliable. + +\subsection{Terminal Output Limitations} +The terminal output implementation was sufficient for early debugging and application display, but repeated output exposed a limitation. During the PIT sleep test, once the VGA text buffer wrapped back to the top of the screen, new text overwrote old text directly. This made long-running debug output harder to read. + +The later application framework reduced this issue by clearing the terminal before drawing menus and game frames. However, the underlying limitation remains: the terminal would benefit from proper scrolling or a cleaner screen-management model for continuous logs. + +\subsection{PC Speaker and QEMU Limitations} +The music player used the PC speaker and PIT channel 2 to generate square wave tones. The implementation worked, but QEMU's PC speaker support limited the clarity of playback. Fast note changes could sound unclear, and songs degraded when played at the original speed. + +The practical adjustment was to double note durations during playback. This slowed down the music and made individual notes easier to distinguish. The limitation was therefore not mainly in the note representation or PIT timing logic, but in the quality and behaviour of the emulated sound output. + +\subsection{Subsystem Integration} +The final Snake application exposed the main integration challenge of the project. Snake uses dynamic memory allocation for game state, keyboard interrupts for input, PIT timing for movement speed, terminal output for drawing, and PC speaker output for feedback. A problem in any of these lower-level systems can appear as an application-level bug. + +This made the final stage useful as more than a demonstration. It acted as an integration test for the kernel. The menu and Snake game showed that the separate subsystems could cooperate through a single control flow, but they also made clear that kernel features must be built in a stable order: processor setup first, then interrupts, then memory and timing, then application behaviour. + diff --git a/AdvOpsys/notes/report/references.tex b/AdvOpsys/notes/report/references.tex new file mode 100644 index 0000000..ef5f74f --- /dev/null +++ b/AdvOpsys/notes/report/references.tex @@ -0,0 +1,220 @@ +%Referansene listet her kan bli brukt med \cite{name} +%De dukker bare opp om de refereres til minst en gang. +%OBS! om man har mer enn 3 forfattere er det mulig referansen ikke vil fungere, skriv da heller de to første og så et. al. + +@misc{techtargetPOST, + author = {Robert Sheldon}, + title = {{POST (Power-On Self-Test)}}, + year = {2022}, + month = {august}, + day = {2}, + howpublished = {\url{https://www.techtarget.com/whatis/definition/POST-Power-On-Self-Test}}, + note = {Accessed: 2026-04-28} +} + +@misc{osdevBootloader, + author = {{OSDev Wiki}}, + title = {{Bootloader}}, + year = {2023}, + month = {july}, + day = {9}, + howpublished = {\url{https://wiki.osdev.org/Bootloader}}, + note = {Accessed: 2026-04-28} +} + +@misc{wikipediaLimine, + author = {{Wikipedia contributors}}, + title = {{Limine (bootloader)}}, + year = {2026}, + month = {april}, + day = {9}, + howpublished = {\url{https://en.wikipedia.org/wiki/Limine_(bootloader)}}, + note = {Accessed: 2026-04-28} +} +@misc{ionosBootloader, + author = {{IONOS}}, + title = {{What is a bootloader?}}, + year = {2022}, + month = {november}, + day = {5}, + howpublished = {\url{https://www.ionos.com/digitalguide/server/configuration/what-is-a-bootloader/}}, + note = {Accessed: 2026-04-28} +} + +@misc{cyberraidenUEFIBoot, + author = {{Raiden}}, + title = {{The Windows Operating System Boot Process in UEFI Mode}}, + year = {2025}, + month = {july}, + day = {24}, + howpublished = {\url{https://cyberraiden.wordpress.com/2025/07/24/the-windows-operating-system-boot-process-in-uefi-mode/}}, + note = {Accessed: 2026-04-28} +} + +@misc{wikipediaPOST, + author = {{Wikipedia}}, + title = {{Power-on self-test}}, + year = {2026}, + month = {april}, + day = {25}, + howpublished = {\url{https://en.wikipedia.org/wiki/Power-on_self-test}}, + note = {Accessed: 2026-04-28} +} + +@misc{littleosbook, + author = {Erik Helin and Adam Renberg}, + title = {The Little Book About OS Development}, + year = {2015}, + howpublished = {\url{https://littleosbook.github.io/}}, + note = {Accessed: 2026-04-28} +} + +@misc{manybutfinite, + author = {Gustavo Duarte}, + title = {How Computers Boot Up}, + year = {2011}, + howpublished = {\url{https://manybutfinite.com/post/how-computers-boot-up/}}, + note = {Accessed: 2026-04-28} +} + +@misc{osdevInterruptsTutorial, + author = {{OSDev Wiki}}, + title = {{Interrupts Tutorial}}, + howpublished = {\url{https://wiki.osdev.org/Interrupts_Tutorial}}, + note = {Accessed 2026-04-16} +} + +@misc{fenollosaOsTutorial, + author = {Carlos Fenollosa}, + title = {{os-tutorial}}, + howpublished = {\url{https://github.com/cfenollosa/os-tutorial/tree/master}}, + note = {Accessed 2026-04-16} +} + +@misc{assignmentFiles, + author = {{Turgay Celik}}, + title = {{assignment\_files.zip}}, + note = {Source code and assignment material provided by course lecturer} +} + +@misc{osdevBootSequence, + author = {{OSDev Wiki}}, + title = {{Boot Sequence}}, + howpublished = {\url{https://wiki.osdev.org/Boot_Sequence}}, + note = {Accessed 2026-04-20} +} + +@misc{osdevMemoryMapX86, + author = {{OSDev Wiki}}, + title = {{Memory Map (x86)}}, + howpublished = {\url{https://wiki.osdev.org/Memory_Map_(x86)}}, + note = {Accessed 2026-04-20} +} + +@misc{osdevGdtTutorial, + author = {{OSDev Wiki}}, + title = {{GDT Tutorial}}, + howpublished = {\url{https://wiki.osdev.org/GDT_Tutorial}}, + note = {Accessed 2026-04-20} +} + +@misc{osdev8259Pic, + author = {{OSDev Wiki}}, + title = {{8259 PIC}}, + howpublished = {\url{https://wiki.osdev.org/8259_PIC}}, + note = {Accessed 2026-04-20} +} + +@misc{osdevPs2Controller, + author = {{OSDev Wiki}}, + title = {{I8042 PS/2 Controller}}, + howpublished = {\url{https://wiki.osdev.org/I8042_PS/2_Controller}}, + note = {Accessed 2026-04-20} +} + +@misc{osdevMemoryAllocation, + author = {{OSDev Wiki}}, + title = {{Memory Allocation}}, + howpublished = {\url{https://wiki.osdev.org/Memory_Allocation}}, + note = {Accessed 2026-04-20} +} + +@misc{osdevSettingUpPaging, + author = {{OSDev Wiki}}, + title = {{Setting Up Paging}}, + howpublished = {\url{https://wiki.osdev.org/Setting_Up_Paging}}, + note = {Accessed 2026-04-20} +} + +@misc{osdevPit, + author = {{OSDev Wiki}}, + title = {{Programmable Interval Timer}}, + howpublished = {\url{https://wiki.osdev.org/Programmable_Interval_Timer}}, + note = {Accessed 2026-04-20} +} + +@misc{osdevPcSpeaker, + author = {{OSDev Wiki}}, + title = {{PC Speaker}}, + howpublished = {\url{https://wiki.osdev.org/PC_Speaker}}, + note = {Accessed 2026-04-20} +} + +@misc{uefiSpecifications, + author = {{UEFI Forum}}, + title = {{UEFI Specifications}}, + howpublished = {\url{https://uefi.org/specifications}}, + note = {Accessed 2026-04-20} +} + +@misc{limineProtocol, + author = {{Limine Bootloader Project}}, + title = {{Limine Boot Protocol}}, + howpublished = {\url{https://github.com/limine-bootloader/limine-protocol}}, + note = {Accessed 2026-04-20} +} + +@misc{linuxX86BootProtocol, + author = {{Linux Kernel Documentation}}, + title = {{The Linux/x86 Boot Protocol}}, + howpublished = {\url{https://docs.kernel.org/arch/x86/boot.html}}, + note = {Accessed 2026-04-20} +} + +@misc{microsoftWindowsBootOptions, + author = {{Microsoft}}, + title = {{Configure and edit boot options in Windows for driver development}}, + howpublished = {\url{https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/boot-options-in-windows}}, + note = {Accessed 2026-04-20} +} + +@misc{appleSiliconBootProcess, + author = {{Apple}}, + title = {{Boot process for a Mac with Apple silicon}}, + howpublished = {\url{https://support.apple.com/guide/security/secac71d5623/web}}, + note = {Accessed 2026-04-20} +} + +@misc{appleIntelBootProcess, + author = {{Apple}}, + title = {{Boot process for an Intel-based Mac}}, + howpublished = {\url{https://support.apple.com/guide/security/sec5d0fab7c6/web}}, + note = {Accessed 2026-04-20} +} + +@misc{qemuPcMachine, + author = {{QEMU Project}}, + title = {{i440fx PC (pc-i440fx, pc)}}, + howpublished = {\url{https://qemu.readthedocs.io/en/v8.1.5/system/i386/pc.html}}, + note = {Accessed 2026-04-20} +} + +@misc{hashnodeVMboot, + author = {{Logeshwaran N}}, + title = {{Virtual Machine Boot Process Explained – Easy Guide}}, + year = {2024}, + month = {october}, + day = {12}, + howpublished = {\url{https://logeshwrites.hashnode.dev/virtual-machine-boot-process-explained-easy-guide}}, + note = {Accessed: 2026-04-28} +} \ No newline at end of file diff --git a/AdvOpsys/notes/report/work_distribution.tex b/AdvOpsys/notes/report/work_distribution.tex new file mode 100644 index 0000000..c0faa4b --- /dev/null +++ b/AdvOpsys/notes/report/work_distribution.tex @@ -0,0 +1,9 @@ +\section{Work Distribution} + +The project work was divided primarily by assignment stage. Teodor was mainly responsible for assignments 2, 4, and 5, and shared assignment 6. I was mainly responsible for assignments 1 and 3, and also shared assignment 6. If only the implementation assignments are considered, this gives an approximate 60/40 split in Teodor's favour. + +The report writing was distributed somewhat differently. I wrote approximately 60\% of the report text, which balanced much of the earlier implementation difference. Taken together, the implementation work and the report writing therefore gave a contribution split that was close to 50/50 overall, which we consider a reasonable balance for a group project of this type. + +We also worked deliberately to maximize learning from the parts of the project that each of us had not implemented directly. After each work session, we wrote short notes describing what had been done, what design choices had been made, and what problems had appeared. This made it possible for the other person to read the notes afterward and then write that part into the report with a clear understanding of both the implementation and the reasoning behind it. + +In practice, this meant that when Teodor implemented an assignment task, I would usually write the corresponding report section, and the same principle also applied in the opposite direction. This gave both of us a reason to study and explain the other person's work instead of only documenting our own. In that way, the report became part of the learning process rather than a duplicate writing pass over the same task. diff --git a/AdvOpsys/notes/work-summary-2026-04-10.md b/AdvOpsys/notes/work-summary-2026-04-10.md new file mode 100644 index 0000000..691f823 --- /dev/null +++ b/AdvOpsys/notes/work-summary-2026-04-10.md @@ -0,0 +1,101 @@ +# Summary of Work Done on April 10, 2026 + +## Overview + +Today, work was done on the `OSDev_18` project to improve the kernel startup sequence and to make sure the kernel still boots correctly and prints output to the screen. The main focus was to add a minimal Global Descriptor Table (GDT) setup for the i386 version of the kernel and verify that it works as expected. + +The project is set up to use a dev container, so the build and test steps were carried out in that environment. This was necessary because the container already includes the required cross-compilation and debugging tools. + +## GDT Implementation + +A minimal GDT was added for 32-bit protected mode. The implementation uses three entries: + +1. A null descriptor +2. A kernel code segment descriptor +3. A kernel data segment descriptor + +The code and data segments were configured with: + +- base address `0x00000000` +- effective 4 GiB address space +- 4 KiB granularity +- ring 0 privilege level + +The GDT setup code builds these descriptors in memory and prepares a GDT descriptor that can be loaded by the CPU. + +After that, an assembly routine loads the new GDT with `lgdt`, performs a far jump to reload the code segment register, and then reloads the remaining segment registers for data access. This step is important because loading the GDT alone does not automatically update the segment registers already cached by the processor. + +## Kernel Startup Changes + +The kernel startup code was updated so that the GDT is initialized before the terminal is set up. After the GDT setup is finished, the terminal initialization still runs and the kernel prints `Hello, World!` to the VGA text buffer. + +This means the boot flow now works roughly like this: + +1. The bootloader transfers control to the kernel entry point. +2. The kernel starts execution in C code. +3. The GDT is initialized and loaded. +4. Segment registers are reloaded. +5. The VGA terminal is initialized. +6. `Hello, World!` is printed. +7. The kernel enters an infinite halt loop. + +## Build System Changes + +The build configuration was updated so the kernel now includes both the new C source for the GDT logic and the new assembly source for the reload routine. This ensures that the GDT implementation is compiled and linked into the kernel binary together with the rest of the startup code. + +New build artifacts were generated today, including an updated kernel binary and bootable ISO image. + +## Documentation Work + +The project documentation was also improved today. Short explanations were added to describe: + +- the general kernel boot flow +- where the GDT setup happens +- why `lgdt` is not enough on its own +- why a far jump and segment-register reload are required after loading the GDT + +This was done to make the code easier to follow and to connect the implementation more clearly to the assignment requirements. + +## Verification and Testing + +The GDT implementation was tested in two ways. + +### 1. Static inspection of the kernel binary + +The built kernel binary was inspected to confirm that the expected GDT-related symbols were present and that the generated machine code actually contained: + +- a call to load the GDT +- a far jump to selector `0x08` +- reloads of the data segment registers using selector `0x10` + +This showed that the expected GDT setup sequence had been compiled into the kernel. + +### 2. Runtime debugging in QEMU with GDB + +The kernel was then started in QEMU and examined with `gdb-multiarch`. During this session, execution was stopped inside the GDT initialization code and inside the assembly reload routine. + +The following results were observed: + +- the GDT descriptor size was `0x17`, which matches three 8-byte entries minus 1 +- the code segment entry was populated with the expected values +- after the far jump, the `cs` register changed to `0x08` +- after stepping through the segment reload instructions, `ds`, `es`, `fs`, `gs`, and `ss` all became `0x10` + +These checks show that the processor did not just compile the code correctly, but also used the new GDT correctly at runtime. + +## Current State at the End of the Day + +At the end of today’s work, the `OSDev_18` kernel: + +- builds inside the dev container +- includes a minimal i386 GDT implementation +- loads the GDT during kernel startup +- reloads the code and data segment registers correctly +- still initializes the VGA terminal +- still prints `Hello, World!` after boot + +Based on the testing that was done today, the GDT implementation appears to be working correctly for this minimal protected-mode kernel setup. + +## Later Integration Note + +Later project stages changed the visible startup order so `TerminalInitialize()` runs before `GdtInitialize()` in the final `kernel.c`. This allows later initialization code to print diagnostics through the terminal. The GDT implementation itself remains part of the early startup path and is still initialized before the interrupt, memory, timing, and application layers are used. diff --git a/AdvOpsys/notes/work-summary-2026-04-11-to-14.md b/AdvOpsys/notes/work-summary-2026-04-11-to-14.md new file mode 100644 index 0000000..8304a0e --- /dev/null +++ b/AdvOpsys/notes/work-summary-2026-04-11-to-14.md @@ -0,0 +1,43 @@ +# Summary of Work Done on Interrupt System + +## Overview + +The last 4 days, work was done on implementing interrupt support for the OSDev_18 project. The goal was to allow the kernel to handle both CPU exceptions and hardware interrupts. + +This included setting up the Interrupt Descriptor Table (IDT), implementing basic Interrupt Service Routines (ISRs), adding support for hardware interrupts (IRQs), and handling keyboard input. After completing these steps, the system is now able to respond to interrupts and display output when they occur. + +## IDT Implementation + +The Interrupt Descriptor Table (IDT) was implemented to define how the CPU should respond to interrupts. + +A structure for IDT entries was created, storing the handler address, segment selector, and flags. An IDT pointer structure was also defined to hold the base and size of the table. + +The IDT is initialized in IdtInitialize() and loaded using the lidt instruction. A helper function is used to set up each descriptor. + +## ISR Implementation + +Interrupt Service Routines (ISRs) were implemented to handle CPU exceptions. + +A Registers structure was created to store the CPU state during an interrupt. The IsrHandler() function uses this information to determine which interrupt occurred and prints a message to the terminal. + +Interrupts can also be triggered manually for testing purposes. + +## IRQ Implementation + +Support for hardware interrupts (IRQs) was added for IRQ0 to IRQ15. + +The Programmable Interrupt Controller (PIC) was remapped so that IRQs do not overlap with CPU exceptions. An IrqHandler() function was implemented to handle incoming hardware interrupts and dispatch them to registered handlers. + +End-of-interrupt signals are sent to the PIC after handling each interrupt. + +## Keyboard Implementation + +Keyboard input was implemented using IRQ1. + +A keyboard handler reads scancodes from port 0x60 and translates key presses into ASCII characters using a lookup table. Raw scancodes are kept in a small buffer, while the latest translated character is stored for higher-level terminal and application code to consume. + +This allows the system to respond to user input from the keyboard. + +## Conclusion + +The system now supports basic interrupt handling, including CPU exceptions and hardware interrupts. This is an important step towards building a more advanced and interactive operating system. diff --git a/AdvOpsys/notes/work-summary-2026-04-14.md b/AdvOpsys/notes/work-summary-2026-04-14.md new file mode 100644 index 0000000..c15043e --- /dev/null +++ b/AdvOpsys/notes/work-summary-2026-04-14.md @@ -0,0 +1,164 @@ +# Assignment 4 – Part 1: Memory Management + +## Overview +In this part of the assignment, a basic memory management system was implemented for a simple OS kernel. The goal was to initialize kernel memory, enable paging, and implement dynamic memory allocation using `malloc()` and `free()`. + +--- + +## Implemented Features + +### Kernel Memory Initialization +- Used: + ```c + extern uint32_t end; + ``` + to get the end address of the kernel from the linker. +- Implemented: + ```c + InitKernelMemory(&end); + ``` +- Set up: + - `heap_begin` + - `heap_end` + - `pheap_begin` (page-aligned heap) + - `pheap_end` + +--- + +### Paging +- Implemented: + ```c + InitPaging(); + ``` +- Set up: + - Page directory at `0x400000` + - Page tables starting at `0x404000` +- Identity-mapped: + - `0x00000000 → 0x00000000` + - `0x400000 → 0x400000` +- Enabled paging by modifying `cr0` and `cr3`. + +--- + +### Dynamic Memory Allocation + +#### malloc() +- Implemented a simple heap allocator. +- Stores metadata using: + ```c + typedef struct { + uint8_t status; + uint32_t size; + } alloc_t; + ``` +- Supports: + - Sequential allocation + - Reuse of freed blocks +- Zeroes allocated memory using `memset`. + +--- + +#### free() +- Frees memory by marking the block as unused. +- Prevents errors by: + ```c + if (!mem) return; + ``` +- Correctly updates `memory_used`. + +--- + +#### Block Reuse +- When a block is freed, it can be reused by future `malloc()` calls. +- Verified by: + - Freeing a block + - Allocating a smaller block + - Observing same address reused + +--- + +### Page-Aligned Allocation (pmalloc) +- Implemented `pmalloc()` and `pfree()`: + - Allocates memory in 4KB pages + - Uses a descriptor array (`pheap_desc`) +- Located in upper memory region near `0x400000` + +--- + +### Memory Utility Functions +Implemented: +- `memcpy()` +- `memset()` +- `memset16()` + +These replace standard library functions in kernel space. + +--- + +### Debug Output + +#### Memory Layout +- Implemented: + ```c + PrintMemoryLayout(); + ``` +- Displays: + - Memory used + - Memory free + - Heap size + - Heap start/end + - Page heap start/end + +#### Allocation Logs +- Outputs allocation details: + ``` + Allocated X bytes from 0x... to 0x... + Re-allocated X bytes from 0x... to 0x... + ``` + +--- + +### Hex Output for Addresses +- Implemented: + ```c + TerminalWriteHex(uint32_t num); + ``` +- Ensures correct formatting of memory addresses (base 16) +- Avoids confusion from decimal output + +--- + +## Testing & Verification + +### Allocation Test +```c +void* memory1 = malloc(48261); +void* memory2 = malloc(27261); +void* memory3 = malloc(12617); +``` + +### Free and Reuse Test +```c +free(memory2); +void* memory4 = malloc(1000); +``` + +### Result +- `memory4` reused the same address as `memory2` +- Confirms: + - `free()` works + - allocator reuses memory correctly + +--- + +## Conclusion +- Successfully implemented a basic kernel memory manager +- Paging is enabled and functioning +- `malloc()` and `free()` work correctly +- Memory reuse is verified +- Debug output is clear and correctly formatted + +--- + +## Next Step +Proceed to **Part 2: PIT and Sleep Functions** diff --git a/AdvOpsys/notes/work-summary-2026-04-15-v2.md b/AdvOpsys/notes/work-summary-2026-04-15-v2.md new file mode 100644 index 0000000..8fdf483 --- /dev/null +++ b/AdvOpsys/notes/work-summary-2026-04-15-v2.md @@ -0,0 +1,81 @@ +# Assignment 5 + +## #Overview +This assignment implements a simple music player using the **PC speaker (PCSPK)** and the **Programmable Interval Timer (PIT)**. +Songs are played by generating frequencies and controlling timing between notes. + +--- + +## #HowItWorks + +### #PCSpeaker +The PC speaker is controlled through **port `0x61`**: +- Bits 0 and 1 enable/disable sound output + +--- + +### #PIT +The PIT is used for: + +#### #SoundGeneration +- Channel 2 generates square wave audio +- Frequency is set using: + +divisor = PIT_BASE_FREQ / frequency + + +#### #Timing +- Channel 0 runs at ~1000 Hz +- A tick counter is incremented via interrupts +- `SleepInterrupt()` is used for accurate note timing + +--- + +## #Implementation + +### #Playback +Each note contains: +- Frequency (Hz) +- Duration (ms) + +Playback works by: +1. Setting frequency with `PlaySound()` +2. Waiting using `SleepInterrupt()` +3. Stopping sound with `StopSound()` + +Rests are handled using `R = 0`. + +--- + +## #Challenges + +### #Timing +Busy-wait delays caused incorrect timing. +This was solved by using interrupt-based sleeping. + +### #QEMU +QEMU has limited PC speaker support: +- Fast note changes sound unclear +- Songs degrade at high speed + +--- + +## #Adjustments + +To improve playback clarity: + +duration = original_duration * 2 + + +This slows down the songs and makes notes more distinguishable. + +--- + +## #Conclusion + +The system successfully: +- Generates sound using the PC speaker +- Uses PIT for timing and frequency control +- Plays songs with multiple notes + +Limitations in QEMU affect sound quality, but the implementation itself works as intended. diff --git a/AdvOpsys/notes/work-summary-2026-04-15.md b/AdvOpsys/notes/work-summary-2026-04-15.md new file mode 100644 index 0000000..83749d8 --- /dev/null +++ b/AdvOpsys/notes/work-summary-2026-04-15.md @@ -0,0 +1,221 @@ +# Assignment 4 – Part 2: Programmable Interval Timer + +## Overview +In this part of the assignment, work was done on adding a basic driver for the Programmable Interval Timer (PIT) to the `OSDev_18` kernel. The goal was to initialize the PIT, count timer ticks using IRQ0, and use those ticks to support both busy-wait sleeping and interrupt-based sleeping. + +The PIT was configured to use channel 0 and generate regular timer interrupts at `1000 Hz`. This gives a simple timing model where one timer tick is approximately equal to one millisecond. + +--- + +## Implemented Features + +### PIT Header and Constants +- Added: + ```c + include/kernel/pit.h + ``` +- Defined constants for: + - PIT command port + - PIT channel 0 port + - PIT base frequency + - target frequency + - calculated divider + - ticks-per-millisecond conversion + +This provides a single place for PIT-related configuration and function declarations. + +--- + +### PIT Initialization +- Implemented: + ```c + void PitInitialize(void); + ``` +- Configures the PIT using: + ```c + OutPortByte(PIT_CMD_PORT, 0x36); + ``` +- Loads the PIT divisor into channel 0: + - low byte first + - high byte second +- Registers the PIT interrupt handler on: + ```c + IRQ0 + ``` + +This allows the kernel to start receiving regular timer interrupts from the PIT. + +--- + +### Tick Counter +- Added a global tick counter: + ```c + static volatile uint32_t pit_ticks = 0; + ``` +- Implemented a helper function: + ```c + uint32_t GetCurrentTick(void); + ``` + +The tick counter is incremented every time IRQ0 is triggered. Since the PIT is configured to `1000 Hz`, this gives a simple way to measure elapsed time in milliseconds. + +--- + +### PIT IRQ Handler +- Implemented: + ```c + static void PitIrqHandler(struct Registers* regs); + ``` +- The handler: + - ignores the register argument + - increments `pit_ticks` + +This keeps the timer interrupt path minimal and lets the rest of the kernel measure time by reading the current tick count. + +--- + +### Busy-Wait Sleep +- Implemented: + ```c + void SleepBusy(uint32_t milliseconds); + ``` +- Uses the current tick count to wait until enough time has passed +- Continuously checks the tick counter in a loop + +This version works by actively spinning on the CPU, so it is simple but inefficient. + +--- + +### Interrupt-Based Sleep +- Implemented: + ```c + void SleepInterrupt(uint32_t ticks); + ``` +- Uses: + ```c + __asm__ volatile ("sti; hlt"); + ``` + inside a loop +- Re-checks the current tick count after each wake-up + +This version is more efficient than busy waiting because the CPU is halted between interrupts instead of constantly polling in a tight loop. + +--- + +### Kernel Integration +- Added: + ```c + #include + ``` + to `kernel.c` +- Added: + ```c + PitInitialize(); + ``` + during kernel startup +- Added: + ```c + SleepTest(); + ``` + during the PIT verification stage. In the final application-oriented kernel flow, this standalone test loop is no longer called from `main()`. + +This connects the PIT driver to the boot flow so the timer logic is available after interrupt setup is complete. + +--- + +### Build System Update +- Added: + ```c + src/pit.c + ``` + to `CMakeLists.txt` + +This ensures the PIT implementation is compiled and linked into the kernel binary together with the rest of the source files. + +--- + +### Terminal Output Fix +- Added the missing declaration for: + ```c + void TerminalWriteHex(uint32_t num); + ``` + to `terminal.h` + +This was necessary because `TerminalWriteHex()` was already implemented in `terminal.c` and used in several source files, but it was not exposed through the header. + +--- + +## Testing & Verification + +### Build Issues Resolved +During integration, several issues were found and corrected: + +- incorrect inline assembly syntax: + ```c + __asm__volatile + ``` + was corrected to: + ```c + __asm__ volatile + ``` +- `printf()` calls were removed from PIT test code and replaced with terminal output functions +- the missing `TerminalWriteHex()` declaration in `terminal.h` was added + +These changes allowed the kernel to build again with the PIT source included. + +--- + +### Boot Image Verification +- Verified that rebuilding only: + ```c + uiaos-kernel + ``` + updates `kernel.bin`, but does not update the bootable ISO image +- Confirmed that: + - the new `kernel.bin` contained the new PIT- and memory-related strings + - the older `kernel.iso` still contained `Hello, World!` +- Rebuilt the image using: + ```c + uiaos-create-image + ``` + so QEMU would boot the updated kernel + +This explained why old output was still appearing even after the source code had changed. + +--- + +### Runtime Result +After rebuilding the bootable image, the kernel successfully booted into the updated code and displayed: +- paging setup output +- heap and allocation debug output +- the `memory1`, `memory2`, `memory3`, and `memory4` address prints + +This confirms that the updated kernel binary is now being booted correctly. + +The PIT sleep test loop was also verified at runtime. The kernel repeatedly prints the expected sleep messages for both: +- busy-wait sleeping +- interrupt-based sleeping + +This shows that the PIT tick counter is advancing and that both sleep functions return as expected during execution. + +During this test, one remaining issue was observed in the terminal output: once the VGA text buffer wraps back to the top of the screen, new text overwrites old text directly. The later menu and game flow reduces this by clearing the screen before redrawing, but the terminal still does not implement proper scrolling. + +--- + +## Conclusion +- Added a PIT driver skeleton to the kernel +- Configured PIT channel 0 for periodic timer interrupts +- Registered an IRQ0 handler and added a global tick counter +- Implemented both busy-wait and interrupt-based sleep functions +- Integrated PIT support into `kernel.c` +- Added `pit.c` to the build system +- Fixed the missing `TerminalWriteHex()` declaration +- Verified that the updated kernel is now booting from the rebuilt ISO image +- Verified that the PIT sleep test loop runs at runtime + +This means the code structure for Part 2 is present in the kernel and has been tested at runtime. The remaining terminal limitation is that continuous logs still wrap instead of scrolling. + +--- + +## Later Integration Note +The final application framework clears the screen before menu and game redraws, so the wraparound problem is less visible during normal use. Proper terminal scrolling would still be a useful future improvement for debug output. diff --git a/AdvOpsys/notes/work-summary-2026-04-16-to-18.md b/AdvOpsys/notes/work-summary-2026-04-16-to-18.md new file mode 100644 index 0000000..07d96ff --- /dev/null +++ b/AdvOpsys/notes/work-summary-2026-04-16-to-18.md @@ -0,0 +1,7 @@ +I developed a simple application framework inside my OS by creating a menu system that lets the user switch between applications, currently music and Snake. I implemented a basic terminal input method using keyboard interrupts so the user can select an application from the menu and return back to it after use. This demonstrates integration between screen output, keyboard handling, and overall OS control flow. + +For the Snake application, I designed a full game loop with its own game state, including the snake, food, score, and board representation. I used dynamic memory allocation to create and destroy the game state, which shows practical use of memory management in my OS. The game uses PIT/timing to control movement speed and game pacing, while keyboard input is used in real time to change direction, restart, or quit. + +I also integrated sound through the PC speaker to give feedback for events such as eating food, dying, and winning. Overall, this task shows integration of multiple OS components, real-time system programming, practical application of operating system concepts, and creative problem-solving through building an interactive menu-driven game environment. + +Finally everything is printed to the screen using existing TerminalWrite...(); infrastructure. \ No newline at end of file diff --git a/AdvOpsys/notes/work-summary-2026-04-27.md b/AdvOpsys/notes/work-summary-2026-04-27.md new file mode 100644 index 0000000..38dc8dc --- /dev/null +++ b/AdvOpsys/notes/work-summary-2026-04-27.md @@ -0,0 +1,210 @@ +# Summary of Work Done on April 27, 2026 + +## Overview + +Today, work was done on the `OSDev_18` project to add a new piano application to the kernel. The main change was the introduction of a small PC-speaker piano mode that lets the user play notes from the keyboard, record note sequences, and replay recorded songs. + +This work also required changes to the application menu in `kernel.c`, the build system, terminal input handling, and a few small adjustments to existing sound and game code so the new feature could fit into the current menu-driven OS flow. + +## Git Evidence + +The changes described in this note come from the newest local commit: + +```text +7686d3e added piano feature +``` + +This commit is local work that has not been pushed yet. + +## Piano Application + +The largest part of the work was the addition of a new piano application: + +- Added: + ```c + include/pianoApp/piano.h + include/pianoApp/frequencies.h + src/piano.c + ``` + +The new piano code introduces: + +- note frequency constants from `C4` up to `C5` +- a `Note` structure storing frequency and duration +- a `Song` structure storing a recorded note sequence +- a `SongLibrary` structure for keeping multiple saved songs +- a `PianoAppState` structure for tracking recording state, active note, and timing between notes + +This gives the kernel a dedicated application module instead of placing all piano logic directly inside `kernel.c`. + +## How the Piano Works + +The piano uses the existing PIT and PC-speaker infrastructure already present in the kernel: + +- `PianoPlaySound()` configures PIT channel 2 to generate the selected note frequency +- `PianoEnableSpeaker()` and `PianoDisableSpeaker()` control whether the sound is actually sent to the PC speaker +- `SleepInterrupt()` is used to control note timing + +The key layout maps keyboard keys such as `z`, `x`, `c`, `v`, `b`, `n`, `m`, and `,` to white keys, while keys such as `s`, `d`, `g`, `h`, and `j` act as black keys. + +The application also supports: + +- `r` to start and stop recording +- `p` to play back a stored song +- `q` to quit the piano application + +While recording, the code stores both notes and rests. Rests are detected by comparing the current PIT tick count with the time when the previous note ended. This means the playback system can preserve simple pauses between notes instead of only storing the frequencies themselves. + +## Kernel and Menu Integration + +The kernel menu in `src/kernel.c` was expanded so the user can launch the new application. + +The menu now shows: + +- `0. Play Music` +- `1. Play Snake` +- `2. Play Piano` + +The kernel now includes `piano.h` and calls `PlayPiano()` when the user selects option `2`. + +The menu flow was also cleaned up slightly: + +- the terminal is cleared before entering each application +- the terminal is cleared again after returning from an application +- invalid input now prints an error, waits briefly using `SleepInterrupt(1000)`, and then clears the screen + +This makes the menu loop more suitable for switching between multiple interactive kernel applications. + +## Terminal and Input Support + +To support the piano playback menu, terminal input handling was extended: + +- Added to `terminal.h`: + ```c + int TerminalGetUInt(uint32_t *number); + ``` + +- Implemented in `terminal.c`: + ```c + int TerminalGetUInt(uint32_t *number); + ``` + +This helper reads a numeric value from keyboard input and converts it into an unsigned integer while checking for invalid characters and overflow. + +It is used when the piano application asks which recorded song should be replayed. + +Another visible input-related change was made in `keyboard.c`: + +- `TerminalPutChar(ascii);` + +was added inside the keyboard handler so typed characters are echoed to the terminal when key presses are processed. + +## Related Adjustments to Existing Code + +Some smaller changes were also made outside the new piano module: + +- `src/songPlayer.c` no longer doubles note duration during playback, so it now uses the exact stored duration values +- `src/snake.c` now prints `Press q to exit` on the game screen +- `include/libc/limits.h` now defines `UINT32_MAX`, which is needed by `TerminalGetUInt()` + +These are small changes, but they support the new interaction model and make the applications more consistent. + +## Build System Update + +The build configuration was updated so the new piano source is compiled into the kernel: + +- Added to `CMakeLists.txt`: + ```c + src/piano.c + ``` + +Without this change, the new application code would exist in the source tree but would not be linked into the final kernel binary. + +## Current State + +At the end of this work, the source tree contains a third kernel application alongside the existing music player and Snake game. The new code introduces: + +- a keyboard-playable piano +- support for recording note sequences +- support for replaying saved songs +- a menu option for launching the piano from the main kernel loop + +This note reflects the code changes present in the newest local commit. It describes the implementation work, but it does not by itself prove runtime verification in QEMU during this session. + +## Later Debug and Audio Setup Work + +After the piano feature was added, more work was done on the development setup so the new PC-speaker functionality could be tested through the existing VS Code and devcontainer workflow. + +The first step was to compare a new QEMU command snippet against the current `AdvOpsys` setup. That check showed that the suggested command did not fit this machine and repository unchanged. + +This was treated as a local environment compatibility issue, not as a problem in the `OSDev_18` source tree itself. + +The main problems were: + +- the suggested PulseAudio path `/mnt/wslg/PulseServer` is for WSLg, while this machine uses a Linux host Pulse socket instead +- the suggested `-s` flag exposes GDB on the default port `1234`, but the repository debug setup already uses port `26000` +- the repository boot flow expects `kernel.iso` as the CD image and `disk.iso` as a separate drive, so using `-hda` for `kernel.iso` does not match the current image layout + +## VS Code Debug Script Changes + +The existing QEMU launcher in `.vscode/qemu-debug.sh` was updated so it can choose an audio backend more carefully. + +The script now: + +- prefers PulseAudio when a usable Pulse socket or `PULSE_SERVER` value is available +- falls back to SDL audio when PulseAudio is not available +- keeps the existing `127.0.0.1:26000` GDB server path used by the VS Code debugger + +This preserves the original debug flow while making the QEMU launch logic less tied to one audio backend. + +## Devcontainer Mount Attempt and Revert + +An attempt was also made to forward the Linux PulseAudio socket into the devcontainer through `.devcontainer/devcontainer.json`. + +That change did not work with the current Docker Desktop `desktop-linux` environment. Rebuilding the container failed because Docker could not bind-mount the expected Pulse runtime directory: + +```text +/run/user/1000/pulse +``` + +As a result, the PulseAudio mount and related container environment variable were removed again so the devcontainer could build and start normally. + +This failure was specific to the local container/runtime setup on this machine. It did not indicate that the kernel project, the piano code, or the normal image build process were broken. + +This means: + +- the devcontainer build and debug workflow works again +- audio support cannot be relied on from the container itself in the same way + +## Host-Side QEMU Workaround + +Because the devcontainer could build and debug the kernel but still had no sound, a separate host-side QEMU workflow was added. + +Two files were updated for this: + +- `.vscode/launch.json` +- `.vscode/qemu-debug-host.sh` + +The new host-side setup works by splitting the responsibilities: + +- the kernel is still built from the existing VS Code/devcontainer environment +- QEMU is launched on the host, where it can access the real PulseAudio socket +- the debugger inside VS Code attaches to that host-side QEMU instance on port `26000` + +This gives a more realistic path for testing PC-speaker audio on this machine, because the emulator process that generates sound now runs in the same environment as the actual audio server. + +In other words, the remaining sound problem was due to where QEMU was running relative to the local audio server, not due to a fault in the repository code. + +## Updated Current State + +At the end of the day, the work on April 27 consisted of both feature development and environment debugging: + +- a new piano application was added to the kernel +- the application menu and terminal input code were extended to support it +- the QEMU debug setup was reviewed against a new sound-enabled launch command +- the container-based PulseAudio mount attempt was tested and then rolled back because it broke devcontainer startup +- a host-side QEMU launch script and matching VS Code attach configuration were added as the current workaround for testing sound + +So the codebase now contains the piano implementation itself, and the surrounding debug setup has also been adjusted to better support testing that feature on this specific machine. + +The important distinction is that the main issue here was local system integration between Docker Desktop, the devcontainer, QEMU, and the host audio stack. It was not a core project issue in `AdvOpsys`. diff --git a/AppDev/deployment-section-note.md b/AppDev/deployment-section-note.md new file mode 100644 index 0000000..0e51a0c --- /dev/null +++ b/AppDev/deployment-section-note.md @@ -0,0 +1,38 @@ +# Deployment Section Note + +The process of uploading the Android app bundle to Google Play Console and setting up an internal test track should generally **not** be described in the `Solution` section. + +## Why it does not fit `Solution` + +The `Solution` section should primarily explain: + +- what the product is, +- which main components it consists of, +- how those components solve the user problem. + +Google Play Console setup, app-bundle upload, signing, and internal testing are not really part of the product solution itself. They are part of the **delivery and distribution process**. + +## Better placement + +This material fits better in one of these sections: + +- `Implementation` + - if the point is to describe the practical technical work required to prepare the app for Android delivery and real-device testing +- `Discussion` + - if the point is to reflect on deployment challenges, release-readiness, signing issues, package identity, or lessons learned +- `Appendix` + - if the point is simply to document that internal testing was configured and completed + +## Recommended approach + +If deployment readiness is important for the report, the cleanest solution is: + +- keep `Solution` focused on the app as a product, +- mention Android deployment and internal testing in `Implementation`, +- mention any notable release problems or limitations in `Discussion` if relevant. + +## Short report-friendly summary + +If needed, a short version could be phrased like this: + +> Preparation for Android deployment, including app-bundle generation and Google Play internal testing, was treated as part of the implementation and delivery process rather than as part of the product solution itself. diff --git a/AppDev/example-report-from-previous-year.pdf b/AppDev/example-report-from-previous-year.pdf new file mode 100644 index 0000000..a383a21 Binary files /dev/null and b/AppDev/example-report-from-previous-year.pdf differ diff --git a/AppDev/ikt205_2026_18_study_sprint.zip b/AppDev/ikt205_2026_18_study_sprint.zip new file mode 100644 index 0000000..69c4685 Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint.zip differ diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/examinerCredentials.pdf b/AppDev/ikt205_2026_18_study_sprint/Appendices/examinerCredentials.pdf new file mode 100644 index 0000000..694e311 Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/Appendices/examinerCredentials.pdf differ diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/gitLog.pdf b/AppDev/ikt205_2026_18_study_sprint/Appendices/gitLog.pdf new file mode 100644 index 0000000..921a9fc Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/Appendices/gitLog.pdf differ diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/architecture-note.md b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/architecture-note.md new file mode 100644 index 0000000..443c34c --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/architecture-note.md @@ -0,0 +1,564 @@ +# Study Sprint - Architecture Redesign Notes + +## Purpose of this note +This note documents the architectural and UI redesign work completed on the app documenting +- what changed +- why it changed +- how the strucutre improved +- which design decisions were intentional + +--- + +## Initial app state +The app originally had a flatter and more fragmented structure than the actual data model supported. + +The conceptual data hierarchy of the app is: + +**Subject -> Assignment -> Task** + +However, the earlier navigation and screen structure did not consistently reflect that hierarchy. In practice, this caused duplicated views, weak context, and screens that felt disconnected from their parent entities. + +Main problems in the earlier version: +- top-level tabs included separate screens for **Subjects**, **Assignments**, and **Tasks** +- tasks existed as their own top-level area even though they are children of assignments +- assignments also felt partially detached from subjects +- repeated CRUD patterns created too many screens and too much UI duplication +- many screens relied on older `defaultStyles` patterns rather than a clearer component/card-based structure +- raw timestamps and brrittle date inputs created poor usability +- create/edit flows were separated even when both used the same form structure + +--- + +## Core redesign goal +The redesign aimed to make the app follow its real conceptual model more closely + +**Dashboard -> overview** +**Subjects -> actual content hierarchy entry point** +**Timer -> separate utility tool** + +And inside the content structure: + +**Subject -> Assignment -> Task** + +The main design philosophy throughout the redesign was: + +- calm +- intuitive +- minimal +- low visual noise +- predictable interaction patterns +- stronger hierarchy +- less redundancy + +--- + +# 1. Navigation architecture redesign + +## Previous navigation problem +The earlier tab setup exposed too many top-level destinations: +- Dashboard/Home +- Subjects +- Assignments +- Tasks +- Timer + +THis was a problem because Tasks and Assignments were not truly top-level concepts in the product model. They belong to parent entities. + +This caused: +- duplicated list views +- extra screens with weaker contextual meaning +- cognitive overload +- a flatter app structure than intended + +## Navigation redesign decision +The top-level tabs were simplified to: + +- **Dashboard** +- **Subjects** +- **Timer** + +## Why this is better +This better matches the app structure: +- **Dashboard** = overview and corss-cutting information +- **Subjects** = main entry point into academic content +- **Timer** = standalone utility + +Assignments and tasks were removed from the top-level tab bar and are now only accessed through the hierarchy: +- subject details contains assignments +- assignment details contain tasks + +### Effect of this change +This reduced redundancy and made the app feel more coherent. It also aligned the user flow with the actual data relationships rather than exposing every model as its own first-class navigation area. + +--- + +# 2. Content hierarchy redesign + +## Original issue +Subjects, assignments, and tasks were partially treated like parallel entities rather than nested entities. + +This weakened context: +- a task could appear without clearly indicating its assignment or subject +- an assignment could feel detached from its subject +- the hierarchy existed in the database but was not always communicated in the UI + +## Redesign decision +The hierarchy was made explicit in the UI + +- subjects page shows only subject cards +- subject detail page becomes the main hub fro the selected subject +- assignment detail page becomes the main hub for the selected assignment +- task detail page becomes the main hub for the selected task + +### Result +The app now better communicates: +- where the user is +- what the current item belongs to +- how to move deeper into the structure + +--- + +# 3. Subject list redesign + +## Original issue +The subject list screen contained too much management UI directly in the list: +- edit buttons +- delete buttons +- progress bar +- cluttered card actions + +This made the subject list feel like a control panel rather than a clean browsing screen. + +## Redesign decision +The subject list was simplified into clean, tappable subject cards. + +Each subject card now focuses on: +- subject title +- optional description +- active/inactive pill +- subject-specific color identity +- full-card tap to open subject details + +### Removed from list cards +- inline edit button +- inline delete button +- progress bar +- management-heavy layout + +### Why +The list screen should be for browsing and selecting. Management actions belong inside the detail screen for that entitiy + +### Result +The subject list become calmer, easier to scan, and more aligned with the principle that cards should act as entry points rather than mini dashboards. + +--- + +# 4. Subject detail screen redesign + +## Original issue +The subject detail screenw as still using older styling patterns and did not fully behave as the subject "hub". + +## Redesign decision +The subject detail screen was redesigned as the main management hub for the specific subject. + +It now includes: +- a subject summary card +- subject status and metadata +- subject-specific color styling +- subject actions (edit/delete) +- create assignment action +- assignment sections below the subject summary + +### Why this matters +This screen now clearly answers: +- what this subject is +- how active/complete it is +- what assignments belong to it +- what actions can be taken at the subject level + +This better reflects the product structure. + +--- + +# 5. Assignment detail screen redesign + +### Original issue +Assignments were previously styled more generically and did not always preserve clear subject context. + +## Redesign decision +The assignment detail screen was redesigned to: +- function as the hub for one assignment +- show clear metadata +- show progress through child tasks +- expose only assignment-relevant actions +- preserve visual inheritance from the parent subject + +### New structure +The assignment detail screen now includes: +- assignment summary card +- subject context pill +- deadline metadata +- progress section showing task completion +- task list organized by completion state +- create task action + +### Why +Assignments are not independent from subjects. The redesign makes that relationship visible without making the screen visually noisy. + +--- + +# 6. Task detail screen redesign + +## Original issue +Tasks were at risk of losing hierarchical context because they are the deepest level in the model. + +## Redesign decision +The task detail screen was redesigned to preserve parent context explicitly. + +It now includes: +- task summary card +- subject context pill +- assignment context pill +- task state and metadata +- parent-aware styling + +### Why +Tasks are the easiest place for context loss. By surfacing both subject and assignment, the user always knows where the task belongs. + +--- + +# 7. Upsert-based form architecture + +## Original issue +The app originally used separate create and edit screens for the same entities, even when both screens used almost identical form fields and validation. + +This created: +- duplicated UI code +- repeated logic +- more route clutter +- higher maintenance cost + +## Redesign decision +Create/edit flows were consolidated into upsert-style screens where appropriate. + +### Implemented +- `upsertSubject` +- `upsertAssignment` +- `upsertTask` + +### Pattern used +The form checks whether an ID exists: +- if no ID exists -> create mode +- if an ID exists -> edit mode + +The same screen handles: +- initial default values +- loading existing data when editing +- submit behavior for insert vs update + +### Why this is better +This reduces duplication while keeping the form styling and validation consistent. + +### Tradeoff +This introduces a little more branching inside a single screen, but the tradeoff is worth it because create and edit flows are structurally very similar for these entities. + +--- + +# 8. Shared utility extraction + +## Original issue +Small but important logic was duplicated across screens. + +## Redesign decision +Shared helpers were moved into reusable modules. + +### Added shared utilities +- `lib/date.ts` +- `lib/subjectColors.ts` + +## Date formatting utility +A shared date formatting module was introduced to standardize: +- date-only display +- date-time display + +This replaced raw timestamp rendering such as ISO strings. + +### Why +Raw database timestamps were ugly and difficult to read. Formatting them centrally improves both UI quality and consistency. + +## Subject color utility +A shared subject color configuration was introduced to centralize: +- available subject colors +- subject color type +- mapping from logical color key to visual values +- helper function for retrieving the correct color set + +### Why +This prevents duplicated color logic and ensures consistent us of subject-specific accent colors across screens. + +--- + +# 9. Subject color system and inheritance + +## Original issue +The app initially relied mainly on global app accent colors, which made it harder to preserve identity across nested subject content. + +## Redesign decision +Subjects were given their own user-selectable accent color. + +### Color choice +The user chooses from a controlled palette instead of arbitrary colors. + +### Why a controlled palette +This preserves: +- aesthetic consistency +- readability +- predictable contrast +- low visual noise + +## How color is used +The subject color is used as a contextual accent, not a replacement for the whole theme. + +Used on: +- subject card border +- subject preview card +- subject pills +- inherited borders and indicators in assignment/task screens +- progress bars and completion indicators where appropriate + +## Important design rule +The subject color was not used for everything. + +Primary action buttons such as: +- create +- save +- login +remain on the **global app accent** + +### Why +This preserves a consistent interaction language: +- app accent = primary action +- subject color = content identity / context + +This separation was an intentional design decision. + +--- + +# 10. Card-based UI redesign + +## Original issue +Several screens still relied on older layout/styling conventions that felt less coherent and more cluttered. + +## Redesign decision +The redesign shifted toward a more consistent card-based interface using: +- bordered surface cards +- semantic Tailwind theme classes +- more restrained spacing +- contextual pills +- reduced action clutter + +### Card design goals +- easier scanning +- stronger visual hierarchy +- fewer floating controls +- more predictable composition + +### Result +The app feels more structured and less noisy. + +--- + +# 11. Metadata and pill system + +## Original issue +Status and metadata were previously shown in less consistent ways, including redundant indicators. + +## Redesign decision +Metadata display was standardized using pill elements for small contextual information. + +Examples include: +- subject name +- assignment parent +- deadline +- active/inactive state + +## Important cleanup decision +Some pills were removed when they became redundant. + +Example: +- completed/in-progress pill was removed in places where the same information was already communicated by a checkbox or progress structure + +### Why +This reduced duplication and visual clutter. + +--- + +# 12. Progress display redesign + +## Original issue +Progress indicators were previously placed too aggressively in list views where they created clutter. + +## Redesign decision +Progress bars were kept only where they make structural sense: +- subject detail +- assignment detail + +### Why +These are hub screens where progress is meaningful. + +Progress bars were intentionally removed from places like subject list cards where they overloaded a browsing view. + +### Additional improvement +Progress is now shown with both: +- a percentage bar +- an `x / y` completed count +- remaining item count text + +This makes progress more understandable than a bar alone. + +--- + +# 13. Authentication-related debugging insight +During development, a major debugging issue turned out not to be screen architecture at all, but session/auth failure. + +This surfaced as: +- fetch failures +- apparent data loading errors +- misleading “network request failed” behavior + +### Takeaway +Auth state and session expiry can easily masquerade as architecture or fetch bugs. + +This reinforced the importance of: +- clearer auth handling +- not assuming every fetch failure is a UI/data issue +- checking session state early when debugging + +--- + +# 14. Time handling and dual-boot issue insight +A separate development issue was discovered related to system time mismatch in a Windows/Linux dual-boot environment. + +Although not an app architecture feature directly, it affected development by causing: +- failed requests +- misleading network/auth behavior + +### Development takeaway +System time correctness matters for: +- authentication +- HTTPS +- tokens +- scheduled features + +This was important context during debugging and implementation. + +--- + +# 15. Notifications and reminders +Assignment creation/updating included work around deadline reminders. + +### Behavior +When an assignment has a valid future deadline: +- a reminder can be scheduled +- previous reminders are updated/cancelled when necessary +- notification IDs are stored through async storage helpers + +### Why this matters architecturally +This means assignment upsert behavior is not only CRUD. It also coordinates: +- persistence +- reminder scheduling +- reminder cleanup + +This is relevant for the final report because it shows that form flows have side effects beyond database writes. + +--- + +# 16. General design principles used across the redesign + +## Principle 1: reflect the true data hierarchy +The UI should match the conceptual model: +- subjects contain assignments +- assignments contain tasks + +## Principle 2: remove redundant top-level structure +Not every data model deserves a top-level tab. + +## Principle 3: keep list screens for browsing +Heavy management actions should live in detail screens. + +## Principle 4: preserve context +The deeper the user goes, the more important parent context becomes. + +## Principle 5: use color as identity, not decoration +Subject colors provide contextual identity without overwhelming the UI. + +## Principle 6: keep primary actions globally consistent +App accent remains the primary action language. + +## Principle 7: reduce duplication +Reusable upsert screens and shared utilities reduce maintenance cost. + +## Principle 8: avoid visual noise +Redundant pills, repeated indicators, and crowded cards were intentionally reduced. + +--- + +# 17. Current architecture summary + +## Tabs +- Dashboard +- Subjects +- Timer + +## Hierarchy +- Subject + - Assignment + - Task + +## Reusable utilities +- date formatting +- subject color mapping +- progress checks +- async storage notification helpers + +## Form strategy +- upsert-style forms for core entities + +## Design system +- NativeWind +- semantic Tailwind tokens +- shared card/pill patterns +- subject color inheritance + +--- + +# 18. Final outcome +The redesign changed the app from a flatter CRUD-style structure into a more coherent hierarchical study workflow. + +The main improvements were: +- better navigation structure +- reduced redundancy +- clearer subject/assignment/task relationships +- stronger contextual design +- less cluttered list screens +- reusable form patterns +- centralized shared helpers +- more polished and consistent UI + +Overall, the app now better reflects its intended purpose as a study productivity tool organized around the academic structure of: +**Subject → Assignment → Task** + +--- + +# 19. Possible items to mention later in the final report +These are likely worth discussing explicitly: + +- why Tasks and Assignments were removed as top-level tabs +- why subject detail and assignment detail were turned into hubs +- why create/edit were merged into upsert patterns +- why a controlled color palette was used instead of arbitrary colors +- why subject color was used for context, not for primary actions +- why duplicated metadata indicators were removed +- why shared date formatting and subject color utilities were extracted +- how preserving hierarchy improved usability +- how debugging/auth issues affected development decisions \ No newline at end of file diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/chris-work-report-timer-2026-04-21.md b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/chris-work-report-timer-2026-04-21.md new file mode 100644 index 0000000..c8a641c --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/chris-work-report-timer-2026-04-21.md @@ -0,0 +1,92 @@ +# Timer Element Work Report + +## #Overview +This note documents the timer work completed by **Chris Sanden** in the Study-Sprint project. + +The git history shows a dedicated timer commit: +- Commit: `d50301cb04837b196110cea43ff15c0493c5fac2` +- Short hash: `d50301c` +- Author: `Chris Sanden ` +- Date: `2026-04-21` +- Message: `First draft of timer element` +- File added: `app/(tabs)/timer.tsx` +- Branch references at inspection time: `timer`, `origin/timer` + +--- + +## #ImplementedFeatures + +### #TimerTab +Created the first draft of a standalone timer screen: +- Added `app/(tabs)/timer.tsx` +- Implemented the timer as its own tab while the final task-start flow is still planned +- Used React Native and Expo tab routing conventions already present in the project + +--- + +### #DurationSelector +Implemented a horizontal animated selector for timer durations: +- Uses `Animated.FlatList` +- Supports snap scrolling with `snapToInterval` +- Shows selectable durations from `1` to `60` +- Uses scaled and faded text animation so the centered duration is emphasized +- Updates the selected duration when scrolling ends + +--- + +### #TimerAnimation +Implemented the first timer start animation: +- Added a circular start button +- Button fades and moves down after the timer starts +- Timer overlay animates into view +- Timer overlay then animates out based on the selected duration +- Uses `Animated.sequence` and `useNativeDriver` + +--- + +## #UserInterface + +The timer screen includes: +- Full-screen dark background +- Red timer overlay +- Large centered duration numbers +- Circular red start button near the bottom of the screen +- Hidden status bar for a focused timer view + +The visual direction is a simple first draft intended to make the timer interaction testable before deeper integration with tasks. + +--- + +## #PlannedIntegration + +The in-code note describes the intended next step: +- Keep the timer as a separate tab initially +- Later open the timer when a user starts a task +- Replace the current duration-number area with task information such as: + - Task name + - Task description +- Potentially add an animated character or visual element if time allows + +--- + +## #GitEvidence + +The work attributed to Chris is supported by this git log entry: + +```text +d50301c Chris Sanden 2026-04-21 First draft of timer element +``` + +The commit added one new file: + +```text +A app/(tabs)/timer.tsx +``` + +The file was later also touched in commit `cb6368a` by `Teodor` on `2026-04-22` as part of broader UI and routing fixes. The original timer implementation documented here is the `d50301c` commit authored by Chris. + +--- + +## #Conclusion + +Chris implemented the first functional timer draft for the application. The work established a standalone timer tab, duration selection, animated start behavior, and a clear path for later connecting the timer to task-start workflows. diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/chris-work-report-timer-2026-04-22.md b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/chris-work-report-timer-2026-04-22.md new file mode 100644 index 0000000..e83478f --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/chris-work-report-timer-2026-04-22.md @@ -0,0 +1,151 @@ +# Timer UI and Countdown Work Report + +## #Overview +Today the standalone timer screen was developed further before wiring it into the task system. + +The main focus was improving the timer interaction and learning how the React Native animation flow works. The timer is still being treated as its own tab for now, with placeholder task data used in place of real task integration. + +--- + +## #ImplementedFeatures + +### #TaskInformationPlaceholder +Added placeholder task information to the timer screen: +- Placeholder task name +- Placeholder task description +- Fade-in animation when the timer starts +- Fade-out animation when the timer finishes + +This prepares the timer UI for the later task integration, where the placeholder values can be replaced by real task data. + +--- + +### #AdjacentTimerFade +Updated the timer duration selector so adjacent numbers fade away when the timer starts: +- The centered selected value remains visible +- Neighboring values fade out during the active timer state +- Neighboring values are intended to fade back in after the timer finishes + +This was implemented by separating the normal picker opacity from the active timer opacity and combining them with `Animated.add` and `Animated.multiply`. + +--- + +### #MeasuredTimerHeight +Started adjusting the timer overlay to use the measured screen/container height: +- Added `containerHeight` +- Added `onLayout` to measure the actual timer screen area +- Updated timer overlay movement to use the measured container height + +This was done because the full window height does not always match the visible tab screen area when headers, tab bars, or safe areas are involved. + +--- + +### #CountdownDisplay +Added countdown display logic: +- Added `timeRemaining` +- Added `selectedIndex` +- Added `formatTime(totalSeconds)` +- Converted the selected timer value into a `MM:SS` display while running +- Added `TIMER_UNIT_IN_SECONDS` so timer values can behave as seconds during development and minutes later + +Current development behavior: +- `TIMER_UNIT_IN_SECONDS = 1` +- Selecting `5` means a 5-second timer + +Planned production behavior: +- `TIMER_UNIT_IN_SECONDS = 60` +- Selecting `5` means a 5-minute timer + +--- + +### #CountdownFadeControl +Started separating countdown visibility from the rest of the timer UI: +- Added `countdownAnimation` +- Added `showCountdownText` +- Began separating the `MM:SS` countdown fade from the button and picker fade +- Fixed the nested animation callback syntax after adding the countdown fade-out flow + +The goal is for the countdown text to fade out first, then for the button and adjacent timer values to fade back in after the countdown is gone. + +--- + +## #LearningNotes + +### #ReactState +Worked with several pieces of state: +- `duration` stores the selected timer value +- `isRunning` tracks whether the timer is active +- `timeRemaining` stores the countdown value +- `selectedIndex` identifies which duration is selected +- `showCountdownText` controls whether the selected item renders as `MM:SS` +- `containerHeight` stores the measured height of the timer screen + +Important distinction: +- State values trigger re-renders when changed +- Animated values drive smooth visual changes without normal React state updates on every animation frame + +--- + +### #Hooks +Clarified where hooks are allowed: +- `useState`, `useRef`, `useEffect`, and `useCallback` must be called inside the component +- Hooks must not be placed inside callbacks, conditionals, loops, or event handlers +- `useEffect` dependency arrays must be inside the `useEffect(...)` call + +One key bug came from an effect without a proper dependency array. Because the countdown updates state every second, the effect ran every second and reset the red overlay position. + +--- + +### #AnimationFlow +The timer now uses multiple animated values: +- `timerAnimation` controls the red overlay movement +- `buttonAnimation` controls the start button and inactive timer value visibility +- `taskDetailsAnimation` controls the placeholder task information +- `countdownAnimation` controls the `MM:SS` countdown visibility + +The main lesson was that one animation value should not control too many unrelated visual states. Separate animation values make it easier to control the order of fade-out and fade-in transitions. + +--- + +## #Verification + +The timer file syntax issue around the end of the `animation` callback was fixed. + +Current lint result: + +```text +npm run lint +exited successfully +``` + +The previous parse error was caused by mismatched closing braces/parentheses near the nested `.start(...)` callbacks at the end of the animation sequence. + +The remaining behavior to confirm is the final transition order: +- `MM:SS` countdown should fade out +- selected text should switch back to the normal timer value while hidden +- adjacent timer values should fade back in +- start button should fade back in + +--- + +## #FilesChanged + +Main file worked on: + +```text +app/(tabs)/timer.tsx +``` + +New note added: + +```text +notes/work-report-timer-2026-04-22.md +``` + +--- + +## #Conclusion + +The timer UI moved from a basic animated duration selector toward a more complete timer experience. It now has placeholder task information, a `MM:SS` countdown concept, measured layout support, and separate animation values for different UI elements. + +The syntax error at the end of the animation callback has been fixed and lint now passes. The remaining immediate work is to finish confirming the final fade-out/fade-in ordering so the countdown disappears cleanly before the picker and start button return. diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/chris-work-report-timer-2026-04-23.md b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/chris-work-report-timer-2026-04-23.md new file mode 100644 index 0000000..6e9df8c --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/chris-work-report-timer-2026-04-23.md @@ -0,0 +1,141 @@ +# Timer Interaction and Cancel Flow Work Report + +## #Overview +Today the standalone timer screen was developed further with a focus on the cancel interaction, countdown reset order, and a progress cue inside the cancel button. + +The main work was not just adding UI pieces, but understanding how the existing React Native `Animated` flow behaves when a timer is started, cancelled, or allowed to finish naturally. The timer is still being treated as its own tab with placeholder task information, but the interaction model is now closer to the intended study-session behavior. + +--- + +## #ImplementedFeatures + +### #CancelButton +Added a dedicated cancel control for the active timer state: +- Added a separate cancel button animation value +- Added a bottom-positioned cancel button that appears only during the running state +- Added reverse handling so the button can be dismissed again when cancelling manually or when the timer finishes + +The main goal was to keep the original large start control as the primary entry point, while giving the active timer state its own secondary exit action. + +--- + +### #CancelProgressCue +Started adding a progress cue directly inside the cancel button: +- Added a separate `cancelProgressAnimation` +- Added an inner animated fill layer inside the cancel button +- Changed the progress direction to move left-to-right inside the button instead of using a full-button opacity fade + +This was done to match the visual language of the main red timer overlay while keeping the progress indicator smaller and more local to the cancel action. + +--- + +### #DurationLocking +Updated the duration selector to stay fixed while the timer is running: +- Added `scrollEnabled={!timerIsRunning}` to the horizontal timer picker +- Added an early return inside `onMomentumScrollEnd` +- Prevented the selected timer duration from changing once a session has started + +This keeps the timer state consistent after the session begins and avoids the picker drifting into a visually different value while the countdown is active. + +--- + +### #CountdownOwnership +Clarified how the countdown interval should be owned and reset: +- Added `countdownRef` +- Added interval clearing before starting a new countdown +- Used the ref-based interval handle so cancel and finish logic can target the active countdown + +This work was needed because countdown behavior becomes unreliable if the code starts new intervals without keeping a consistent reference to the currently running one. + +--- + +### #CancelFlowSequencing +Worked on the ordering of reverse animations during manual cancel: +- Tested separating countdown fade-out from the picker/start-button return +- Investigated why adjacent numbers were reappearing before the countdown text had fully finished reversing +- Traced the problem to both animation timing and the `showCountdownText` render condition + +The important lesson here was that hiding the countdown visually and switching the rendered text back to the normal timer value are related, but not identical, events. + +--- + +## #LearningNotes + +### #AnimatedValueResponsibilities +Today reinforced that each `Animated.Value` should have one clear responsibility: +- `timerAnimation` controls the red overlay position +- `buttonAnimation` controls start-button disappearance and inactive picker return +- `countdownAnimation` controls countdown visibility +- `cancelButtonAnimation` controls the cancel button itself +- `cancelProgressAnimation` controls the left-to-right fill inside the cancel button + +Several visual bugs came from trying to make one animated value carry two different meanings at the same time. + +--- + +### #RenderStateVsAnimationState +A key distinction became clearer during the cancel-flow debugging: +- Animated values control motion and opacity +- Regular React state controls what text/content is actually rendered + +One important example is `showCountdownText`: +- Even if the countdown has visually faded out, the selected timer item still renders `MM:SS` while `showCountdownText` remains `true` +- This means the UI can still appear to be in “countdown mode” even after part of the reverse animation has already completed + +This is why some cancel-order issues were not purely animation problems. + +--- + +### #SequenceVsParallel +The timer work also clarified when `Animated.sequence([...])` and `Animated.parallel([...])` should be used: +- `sequence` is for strict order +- `parallel` is for animations that should run at the same time + +One mistake that surfaced during the progress-button work was placing the long progress-fill animation in a sequence after the main timer animation, which caused the fill to begin only after the timer had already ended. + +--- + +## #CurrentIssue + +The current timer screen still has remaining cancel-flow polish issues around visual timing and overlay cleanup. + +The main issue currently under investigation is the reset order during manual cancel: +- the red timer overlay can still produce a visible flash/jump when the running animation is interrupted +- the adjacent picker numbers and selected countdown text are sensitive to both animation order and `showCountdownText` +- the current implementation needs further refinement so cancel feels deliberate instead of visually noisy + +Current lint result: + +```text +npm run lint +completed with 1 warning +``` + +Current warning: +- unnecessary `showCountdownText` dependency in one `useCallback` + +There are no current lint errors, but the cancel interaction is not yet considered visually finished. + +--- + +## #FilesChanged + +Main file worked on: + +```text +app/(tabs)/timer.tsx +``` + +New note added: + +```text +notes/work-report-timer-2026-04-23.md +``` + +--- + +## #Conclusion + +The timer screen moved further toward a complete active-session interaction today. It now has a dedicated cancel control, a left-to-right progress cue inside that control, a locked duration picker while running, and a clearer separation between countdown ownership and animation ownership. + +The main remaining work is not basic feature addition, but interaction polish. In particular, the cancel sequence still needs refinement so the red overlay, countdown text, and adjacent timer values return in a clean and intentional order. diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/chris-work-report-timer-2026-04-24.md b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/chris-work-report-timer-2026-04-24.md new file mode 100644 index 0000000..317dc5c --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/chris-work-report-timer-2026-04-24.md @@ -0,0 +1,191 @@ +# Timer Focus Mode and Hold-Cancel Work Report + +## #Overview +Today the standalone timer screen was reworked further with a focus on the active sprint layout, countdown ownership, and the hold-to-cancel interaction. + +The main direction was to make the running timer feel more like a focused study state instead of a duration picker that happens to count down. The countdown was moved toward a separate overlay, the task details were given more visual emphasis, and the cancel interaction was changed from a simple button press into a deliberate hold action. + +--- + +## #ImplementedFeatures + +### #CountdownOverlay +Moved the active countdown away from the duration picker: +- Removed the old selected-picker countdown state +- Added a separate countdown overlay using `countdownAnimation` +- Added `focusModeAnimation` so the countdown can move from the central timer area toward the upper-left area +- Kept the picker responsible for duration values only + +This separates two responsibilities that had previously been mixed together: the picker selects a duration, while the overlay shows active countdown time. + +--- + +### #FocusModeLayout +Adjusted the active timer layout to put more attention on the task: +- Moved task details higher and closer to the center of the running screen +- Increased the task title and description size +- Kept task details animated through `taskDetailsAnimation` +- Continued using the red screen overlay as the main visual timer-progress element + +The intent is for the active state to feel more like a study-session spotlight, where the selected task becomes the main focus and the countdown becomes supporting information. + +--- + +### #HoldToCancel +Changed the cancel action into a hold interaction: +- Added `HOLD_TO_CANCEL_MS` +- Added `cancelHoldTimeoutRef` +- Added a hold-completion haptic warning +- Kept the cancel button scale feedback during press +- Changed the label to `Hold to end sprint` + +This makes cancellation more deliberate and reduces the chance of accidentally ending a sprint with a single tap. + +--- + +### #CancelAccelerationExperiment +Implemented the red timer overlay as cancel feedback: +- Added delayed cancel acceleration through `CANCEL_ANIMATION_DELAY_MS` +- Added `cancelHoldAnimationDelayRef` +- Added `cancelAccelStartedRef` to distinguish quick taps from actual hold acceleration +- Split normal timer progress into `progressAnimationRef` +- Added `startProgressAnimation(fromY)` so progress can start or resume from a specific overlay position +- Added `cancelOverlayAnimation` as a temporary visual offset on top of the real timer progress +- Added `getCancelOverlayTarget(...)` to calculate how far the cancel preview should move +- Added a release handoff animation so the cancel offset eases back into the real timer position +- Added clamping so the visual overlay does not move past the finished timer position +- Added easing constants for the cancel delay, release handoff, and timer reset timings + +The goal was for the red overlay to speed toward the finished position during a hold, then return smoothly to the real timer progress if the user releases before the cancel completes. The important change is that cancel preview motion is now layered on top of the real progress instead of directly taking over the main timer animation. + +--- + +### #DurationPickerCleanup +Cleaned up the duration picker after moving countdown ownership out of it: +- Removed selected countdown rendering from the picker item +- Kept picker items rendering plain timer values +- Kept picker values fading out during active timer mode +- Added index clamping when reading the selected duration from `onMomentumScrollEnd` +- Restored `duration` as a dependency of the start callback so the selected picker value is used correctly + +This fixed the earlier issue where the timer could behave as if the selected duration was still the initial value. + +--- + +### #TimerCodeCleanup +Cleaned up the timer screen structure after the interaction behavior was stabilized: +- Renamed the old `animation` callback to `startTimer` +- Renamed unclear animated values like `opacity` and `translateY` to `startButtonOpacity` and `startButtonTranslateY` +- Grouped refs by purpose: animated values, timer/session refs, and cancel-hold refs +- Extracted `clearCountdown`, `clearCancelHoldTimers`, and `stopTimerAnimations` +- Extracted the cancel overlay target calculation into `getCancelOverlayTarget(...)` +- Split the render section into local render helpers for the overlay, start button, cancel button, countdown, duration picker, and task details +- Moved the timer item layout into `styles.timerItem` + +This did not change the screen into a separate hook or split the timer into multiple files. The cleanup stayed local to `timer.tsx` so the current animation work remains easy to inspect. + +--- + +## #LearningNotes + +### #AnimationOwnership +The main lesson today was that an `Animated.Value` should have one clear owner at a time. + +The red overlay now combines two animated values: +- normal timer progress +- hold-to-cancel visual offset + +The normal timer progress is controlled by `timerAnimation`, while cancel preview motion is controlled by `cancelOverlayAnimation`. This avoids stopping the real timer progress just to show the cancel speed-up effect. + +--- + +### #RefsAsMutableState +Several refs were added to track animation and timer ownership: +- `progressAnimationRef` tracks the long-running red overlay progress animation +- `sessionStartedAtRef` tracks the progress timeline used for recovery calculations +- `sessionDurationMsRef` stores the current timer duration in milliseconds +- `cancelHoldTimeoutRef` tracks when hold cancellation should complete +- `cancelHoldAnimationDelayRef` tracks when cancel acceleration should begin +- `cancelAccelStartedRef` tracks whether the red overlay acceleration actually started +- `cancelHoldActiveRef` and `cancelHoldIdRef` prevent stale delayed hold callbacks from taking over after release + +The important distinction is that assigning to `.current` is allowed even when the ref variable itself is declared with `const`. + +--- + +### #CancelOffsetHandoff +The release recovery logic was changed to avoid rewriting the real timer progress: +- keep `timerAnimation` running as the source of real timer progress +- add `cancelOverlayAnimation` on top of it while the cancel button is held +- animate only the cancel offset back to `0` when the hold is released +- keep the visible overlay clamped to the screen height +- tune the release handoff timing with `CANCEL_RELEASE_MS` + +This makes the visual red overlay return to the countdown's real timer position without forcing the main timer animation to stop and restart. + +--- + +## #CurrentState + +The hold-cancel red overlay interaction has been reworked so the cancel preview no longer directly mutates the real timer progress. + +The current implementation: +- keeps the countdown and real timer progress owned by `timerAnimation` +- uses `cancelOverlayAnimation` as a temporary visual offset during hold-to-cancel +- invalidates stale hold callbacks with `cancelHoldIdRef` +- eases the cancel offset back to `0` on release +- keeps the cancel-completion path separate from normal timer completion + +This should make the red overlay speed-up feel connected to the cancel hold while still keeping the timer progress visually aligned with the countdown after release. + +--- + +## #Verification + +Current static checks pass: + +```text +npm run lint +exited successfully +``` + +```text +npx tsc --noEmit +exited successfully +``` + +The hold-cancel handoff was also adjusted based on runtime feedback so the cancel offset eases back more smoothly into the real timer progress. + +--- + +## #FilesChanged + +Main file worked on: + +```text +app/(tabs)/timer.tsx +``` + +New note added: + +```text +notes/work-report-timer-2026-04-24.md +``` + +--- + +## #Conclusion + +The timer screen moved further toward a focused active-sprint experience. The countdown is now separated from the duration picker, task details have more visual weight, and cancel is treated as a deliberate hold action rather than a normal tap. + +The main animation change is that hold-to-cancel now keeps the real timer progress separate from the temporary cancel speed-up effect. The code was also cleaned up so the timer flow is easier to read and continue working on. + +## Problems occuring after writing conclusion +Tried to implement sound by installing expo-audio. This caused the dependency list to update. The diff was massive, and something in the diff caused the entire timer page to break. Logic, animations - the lot. Have reverted back to last known working dependency list, as well as un-refactored a lot of code in an attempt to revert to a functioning state before figuring out that the culprit was dependencies. Need to figure our what is causing the critical failure in the new list. + +## Todo +- Re-refactor to make code cleaner, more readable and easier to maintain. +- Figure out the dependency issues of later dependency lists + +## Conclusion of dependecy saga +There was a mismatch in the nativewind dependency, with my one being ^4.2.3 and the other list being ^4.1.23. This cause my entire timer screen to fail. Animations got borked, buttons not working properly, duration picker only showing 2 indexes... the works. Solution - keepp nativewind dependency to ^4.2.3 diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/chris-work-report-timer-2026-04-25.md b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/chris-work-report-timer-2026-04-25.md new file mode 100644 index 0000000..eb8d9a0 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/chris-work-report-timer-2026-04-25.md @@ -0,0 +1,163 @@ +# Timer Refactor and Verification Work Report + +## #Overview +Today the timer screen was worked on with a narrower goal than yesterday: not new interaction features, but cleanup, readability, and making the existing timer flow easier to understand and maintain. + +This follows directly from yesterday's state. The April 24 note ended with two follow-up items: +- re-refactor the timer code so it becomes easier to read and work on +- keep the dependency situation stable after the NativeWind version mismatch had broken the screen + +Today's work focused on the first of those. The interaction model was kept the same, but the internal structure of `timer.tsx` was cleaned up so the current hold-to-cancel and focus-mode behavior is easier to inspect without splitting the code into hooks or separate files. + +--- + +## #ImplementedFeatures + +### #TimerCodeRefactor +Refactored the timer screen structure inside `app/(tabs)/timer.tsx`: +- renamed the component from `App` to `TimerScreen` +- renamed unclear callbacks such as the old generic start-animation function into `startTimerSession` +- grouped the file more clearly into constants, animated values, refs, derived values, actions, render helpers, and JSX +- renamed vague animated/interpolated values to clearer names such as `startButtonOpacity`, `startButtonTranslateY`, and `pickerOpacity` + +This did not change the screen architecture into multiple files. The cleanup stayed local to the timer file so the animation flow is still easy to inspect in one place. + +--- + +### #CleanupHelpers +Extracted repeated timer cleanup work into small local helpers: +- added `clearCountdownInterval()` +- added `clearCancelHoldTimeouts()` +- added `stopRunningAnimations()` +- added `resetSessionValues()` + +Before this, the same interval, timeout, and animation-reset work was spread across multiple callbacks. Pulling it into helpers makes it easier to follow what happens when a session starts, finishes, or is cancelled. + +--- + +### #RenderStructureCleanup +Cleaned up the render section so it is easier to read: +- moved repeated inline layout styles into named `StyleSheet` entries +- extracted the timer picker item rendering into a local `renderTimerItem(...)` helper +- kept the JSX order aligned with the visible screen layers: overlay, start button, cancel button, countdown, duration picker, and task details + +This mainly improves scanning. The old file worked, but the render section made you jump between inline style objects and animation expressions to understand each layer. + +--- + +### #CommentAndNamingPass +Added a small number of comments only where the code was genuinely hard to follow: +- clarified that `timerAnimation` owns real timer progress +- clarified that `cancelOverlayAnimation` is only a temporary visual offset during hold-to-cancel +- clarified that `startProgressAnimation(fromY)` resumes overlay progress from the current Y position +- clarified why cancel acceleration starts after a short delay + +The aim was not to comment every line, but to explain the parts that are hard to infer just by reading the code. + +--- + +### #StateResetTightening +Made the session cleanup more explicit: +- reset `sessionStartedAtRef` and `sessionDurationMsRef` when a session ends +- reset cancel-hold flags during session cleanup +- made `finishTimer()` explicitly clear the countdown interval before running exit animations +- kept the existing unmount cleanup so intervals, timeouts, and running animations are not left behind if the screen disappears mid-session + +These are small changes, but they make the timer lifecycle more predictable and reduce the amount of stale mutable state left around after finish or cancel paths. + +--- + +## #LearningNotes + +### #ReadableCodeVsNewFeatures +Today's timer work was a good reminder that "more maintainable" does not always mean "more abstract." + +For this screen, the right cleanup level was: +- better names +- smaller local helpers +- clearer grouping +- a few targeted comments + +The wrong cleanup level for the current stage would have been moving the logic into extra hooks or files too early, because that would make it harder to inspect the animation flow while the interaction is still being tuned. + +--- + +### #MutableRefOwnership +The timer file still relies heavily on refs because several parts of the interaction are long-lived and imperative: +- active countdown interval +- running start animation +- running progress animation +- delayed cancel-preview start +- hold-to-cancel completion timeout + +The cleanup made this easier to see by separating refs that hold animated values from refs that track mutable timer/session ownership. + +--- + +## #CurrentState + +Compared with yesterday, the timer interaction model is mostly the same, but the code behind it is more structured. + +The current implementation: +- keeps the red overlay model used yesterday +- keeps `timerAnimation` as the real progress owner +- keeps `cancelOverlayAnimation` as the temporary hold-preview layer +- keeps the delayed hold acceleration and release recovery flow +- keeps all timer logic local to `timer.tsx` +- is now easier to read because repeated cleanup and render logic have been extracted into named local pieces + +This means today's work was mainly a recovery and consolidation pass after yesterday's interaction-heavy changes and the earlier dependency-related breakage. + +--- + +## #Verification + +Today's static checks passed after the refactor: + +```text +npm run lint +exited successfully +``` + +```text +npx tsc --noEmit +exited successfully +``` + +```text +git diff --check -- 'app/(tabs)/timer.tsx' +exited successfully +``` + +There was no new timer commit for today at the time of writing this note. The summary above is based on: +- the current working-tree diff for `app/(tabs)/timer.tsx` +- the verification commands run after the refactor +- yesterday's note and timer history for context + +I did not do a live Expo interaction test inside this note workflow, so runtime behavior is verified statically plus by code review rather than by manually pressing through the UI. + +--- + +## #FilesChanged + +Main file worked on: + +```text +app/(tabs)/timer.tsx +``` + +New note added: + +```text +notes/work-report-timer-2026-04-25.md +``` + +--- + +## #Conclusion + +The main timer work today was not adding new features, but making yesterday's feature-rich timer implementation is easier to continue working on. + +The result is a timer file that keeps the same focus-mode and hold-to-cancel behavior, while being more readable, more structured, and easier to maintain. The biggest improvement is that the important ideas in the file now have clearer names, clearer ownership, and clearer cleanup paths. + +The timer is now considered finished and ready to implement into the rest of the project. \ No newline at end of file diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/chris-work-report-timer-2026-05-01.md b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/chris-work-report-timer-2026-05-01.md new file mode 100644 index 0000000..be75806 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/chris-work-report-timer-2026-05-01.md @@ -0,0 +1,230 @@ +# Task Timer Integration and App Polish Work Report + +## #Overview +Today the timer work moved from being a standalone tab experiment into the actual task workflow. + +The main commit used for this summary is: + +```text +c74062c Implemented timer into task details, uploaded example images for app and centred headers on all screens +``` + +The work focused on connecting the sprint timer to individual tasks, preserving an active sprint locally, cleaning up routing, and polishing the surrounding app presentation. The timer is no longer exposed as a top-level tab. It now belongs to the task details flow where a sprint naturally starts from a selected task. + +--- + +## #ImplementedFeatures + +### #TimerRouteIntegration +Moved the timer route from the tab navigator into the task stack: +- removed the old timer tab from `app/(tabs)/_layout.tsx` +- added `timer` as a screen in `app/task/_layout.tsx` +- moved the timer implementation from `app/(tabs)/timer.tsx` to `app/task/timer.tsx` +- added a `Start Sprint` action from the task details screen +- passed the selected task id into the timer route using `tId` + +This makes the timer part of the task workflow instead of a separate global screen. + +--- + +### #TaskAwareTimer +Updated the timer screen so it can load and display the selected task: +- reads `tId` from route params +- fetches the matching task from Supabase +- shows the task title and description during the sprint +- falls back to generic sprint text if task data is missing + +This replaces the earlier placeholder-task model and makes the sprint screen reflect the actual task being worked on. + +--- + +### #ActiveSprintPersistence +Added local persistence for the current sprint in `lib/asyncStorage.ts`: +- added an `ActiveSprint` type +- added `SaveActiveSprint(...)` +- added `GetActiveSprint()` +- added `RemoveActiveSprint()` +- stores the active task id, sprint duration, and calculated end time + +The timer now saves the sprint end time when a session starts. When the timer screen is reopened for the same task, it can restore the remaining sprint time instead of treating the session as gone. + +--- + +### #TimeBasedCountdown +Changed the countdown ownership toward wall-clock time: +- calculates `endTime` when the sprint starts +- updates remaining time from `Date.now()` +- restores progress from elapsed time when an active sprint is found +- removes the active sprint when it expires or is cancelled + +This is a step toward making the timer more robust when the app is backgrounded or the timer screen is reopened. + +--- + +### #HoldCancelOverlayWork +Continued work on the red hold-to-cancel timer overlay: +- kept `timerAnimation` as the main timer-progress value +- kept `cancelOverlayAnimation` as the temporary hold-preview offset +- added measured overlay height handling through `containerHeight` +- added an offscreen reset position for the red overlay +- added `timerOverlayVisible` so the red overlay can be hidden immediately after manual cancel fires + +The final direction was to stop relying only on moving the red overlay offscreen. The cancel path now also hides the overlay by opacity before the rest of the return animations run. + +--- + +### #HeaderAlignmentPolish +Centered navigation titles across the main app screens: +- dashboard +- subjects +- subject create/edit +- subject details +- assignment create/edit +- assignment details +- task create/edit +- task details +- sprint timer + +This was a small visual consistency pass, but it makes the app feel less uneven between screens. + +--- + +### #ImageAssetUpdate +Updated the app image assets: +- replaced the main icon and splash image files under `assets/images/` +- moved `master.png` into `assets/images/` +- removed the older `assets/study-sprint-image-pack/` copies + +This keeps the active image assets in the folder Expo expects instead of keeping a separate image-pack folder around. + +--- + +## #ProblemsAndSetbacks + +### #CancelOverlayBug +The main setback today was the red hold-to-cancel overlay still being visible after manual cancel. + +Several possible causes were investigated: +- the overlay using `Dimensions.get('window')` instead of the measured container height +- the overlay being clamped to the screen height +- the overlay view being stretched by `StyleSheet.absoluteFillObject` +- the overlay not being moved far enough below the screen + +The first fixes improved the logic but did not remove the visible red bar in runtime feedback. The latest approach adds explicit overlay visibility state so the red timer layer can be hidden directly when cancel completes. + +--- + +### #ManualCancelVsNaturalFinish +Another important clarification was that the problematic path was manual cancel, not the natural "timer reached zero" flow. + +The cancel path has extra moving parts: +- hold delay +- hold completion timeout +- `cancelOverlayAnimation` +- haptic warning +- return animations + +That made the bug harder to reason about than the normal finish path. + +--- + +### #RuntimeConfidence +Static checks passed, but the final visual fix still needs manual runtime confirmation on the device/emulator. + +The timer animation issue is visual and interaction-dependent, so TypeScript and lint can confirm that the code is valid, but they cannot prove that the red overlay is gone in the actual UI. + +--- + +## #CurrentState + +The current unpushed commit has the timer integrated into the task flow. + +The app now supports: +- starting a sprint from task details +- opening the timer as `/task/timer` +- loading the selected task into the sprint screen +- saving active sprint state locally +- restoring active sprint progress from stored end time +- cancelling and clearing active sprint state +- centered headers across the main screens +- updated Expo image assets + +The remaining runtime risk is the red hold-to-cancel overlay. The newest implementation hides the overlay with explicit `timerOverlayVisible` state after manual cancel, but this still needs to be verified by pressing through the cancel flow in the app. + +--- + +## #Verification + +Static checks were run after the timer changes: + +```text +npx tsc --noEmit +exited successfully +``` + +```text +npm run lint +exited successfully with one existing warning +``` + +The lint warning is unrelated to today's timer work: + +```text +app/(tabs)/subjects.tsx +React Hook useCallback has a missing dependency: 'GetSubjects' +``` + +The summary above is based on the unpushed commit diff from: + +```text +origin/timerTask..HEAD +``` + +--- + +## #FilesChanged + +Main timer and task-flow files: + +```text +app/task/timer.tsx +app/task/_layout.tsx +app/task/viewDetailsTask.tsx +lib/asyncStorage.ts +``` + +Navigation polish files: + +```text +app/(tabs)/_layout.tsx +app/(tabs)/index.tsx +app/(tabs)/subjects.tsx +app/assignment/upsertAssignment.tsx +app/assignment/viewDetailsAssignment.tsx +app/subject/upsertSubject.tsx +app/subject/viewDetailsSubject.tsx +app/task/upsertTask.tsx +``` + +Image asset files: + +```text +assets/images/ +assets/study-sprint-image-pack/ +``` + +New note added: + +```text +notes/work-report-timer-2026-05-01.md +``` + +--- + +## #Conclusion + +Today's work moved the timer from an isolated feature into the real task workflow. + +The biggest progress was routing and ownership: a sprint now starts from a task, carries that task id into the timer, displays task details during the sprint, and stores active sprint state locally. The surrounding app also received a small consistency pass through centered headers and updated image assets. + +The main setback was the manual hold-to-cancel red overlay bug. The implementation has gone through several attempts, and the current version now hides the overlay directly after cancel instead of relying only on moving it out of view. The next step is to verify that final visual behavior live in the app. diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/chris-work-report-timer-2026-05-02.md b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/chris-work-report-timer-2026-05-02.md new file mode 100644 index 0000000..4d52938 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/chris-work-report-timer-2026-05-02.md @@ -0,0 +1,282 @@ +# Timer Session Tracking and Dashboard Integration Work Report + +## #Overview +Today the timer work moved beyond local in-memory behavior and into a more durable sprint-session model. + +The main direction was to make sprint time count toward task progress in a safer way, while also surfacing that progress in the app UI. This meant extending the timer flow with database-backed sprint sessions, making task time visible on the task details screen, and continuing the dashboard integration so active or upcoming work is easier to reach. + +The work stayed focused on the timer/task/dashboard path rather than broad app refactoring. + +--- + +## #ImplementedFeatures + +### #SprintSessionPersistence +Moved the timer session model toward a more robust database-backed structure: +- created a `sprint_sessions` table in Supabase +- added a `sessionId` field to the local `ActiveSprint` type in `lib/asyncStorage.ts` +- updated the timer start flow to create a sprint session in the database before entering the running timer state +- kept local `active_sprint` storage as the resume handle, but now tied it to a real database session instead of only a task id and end time + +This changes the active sprint from being only a local timer state into a recordable session that can later be finalized safely. + +--- + +### #TaskTimeTracking +Added task-level study time tracking: +- added `totalTimeInSeconds` to the task model in `lib/types.ts` +- verified that cancelling a sprint updates both `sprint_sessions` and the task total in the database +- verified that expired sessions also finalize correctly and contribute time as expected + +This gives each task a running total of time spent, rather than leaving the timer as a standalone UI action with no durable result on the task itself. + +--- + +### #FinalizeFlowRepair +Adjusted the timer finalize flow so session teardown and restore logic stop fighting each other: +- added a `finalizeSprintSession(...)` path in `app/task/timer.tsx` +- updated natural finish, cancel, and expired restore paths to use the database finalize flow +- removed the local active sprint before the finalize RPC completes so the restore effect does not immediately re-open a just-cancelled timer +- added alerts for sprint-session creation/finalization failures instead of silently leaving the screen in a half-running state + +This fixed the case where cancelling the timer appeared to work visually, but then the sprint popped back open because restore logic still saw a locally active session. + +--- + +### #TimerStartGuarding +Tightened the sprint-start path in the timer screen: +- delayed `setIsRunning(true)` until after the `start_sprint_session` RPC succeeds +- added handling for the returned session id before local sprint state is saved +- added fallback handling for session id shape differences in the RPC response + +Before this, the timer UI could enter a partial running state if the database session failed to start, which made the header change without actually starting the timer animation flow. + +--- + +### #TaskDetailsTimeDisplay +Made the recorded task time visible in the task details screen: +- added a local formatter for tracked time in `app/task/viewDetailsTask.tsx` +- displayed `Time spent: ...` under the existing metadata block on the task details screen + +This is the first direct UI confirmation that the timer is affecting persistent task data rather than only changing temporary timer state. + +--- + +### #DashboardSprintVisibility +Extended the dashboard so it reflects timer/task state more clearly: +- added dashboard support for reading and displaying the current active sprint from local storage +- showed the active sprint task title, description, and remaining time +- added an `Open Sprint` action that links directly back into the running timer + +This gives the user a global way to get back to an already running sprint after navigating away from the timer screen. + +--- + +### #UpcomingDeadlineCards +Added a deadline-based task section to the dashboard: +- added a `Tasks with upcoming deadlines` section to the dashboard state +- fetched active tasks together with their assignment and subject context +- sorted the tasks by assignment deadline in ascending order +- rendered clickable cards that open the relevant task details screen +- updated the metadata line at the bottom of each card to show subject, assignment, and deadline + +This makes the dashboard more useful as a next-action screen instead of only a placeholder when no sprint is running. + +--- + +### #DashboardTaskCompletion +Extended the dashboard task cards so they can directly affect task progress: +- added a `Mark as completed` action to each upcoming task card +- updated the action to write `isCompleted = true` back to the matching task row +- reused `CheckAssignmentCompletion(...)` so assignment completion status stays in sync with task completion +- removed the completed task from the dashboard list immediately after a successful update +- added a confirmation alert before the completion update runs + +This gives the dashboard a lightweight task-management action instead of making it read-only. + +--- + +### #DashboardAndSubjectsHelpFlow +Added a small help/info entry point to explain the app structure more clearly: +- added a help button in the dashboard header +- added the same help/info pattern to the subjects screen +- opened a compact modal that explains the app flow as `Subject -> Assignment -> Task -> Sprint` +- added a clear summary block and a closing action inside the modal + +This gives new users a direct explanation of how the app model fits together without leaving the current screen. + +--- + +### #HeaderAndStylingPolish +Continued local UI cleanup around the dashboard and subjects screens: +- aligned the header actions so help and logout use the same general layout pattern on both screens +- converted the dashboard screen from local `StyleSheet` usage to NativeWind/Tailwind class-based styling +- converted the subjects help/modal block away from `styles.*` references and into NativeWind classes +- kept the visual structure local to the affected screens rather than introducing shared abstractions + +This keeps the dashboard and subjects screens stylistically closer to each other while staying within the current app structure. + +--- + +### #ActiveSprintDashboardFix +Fixed a rendering bug in the dashboard state logic: +- the `Tasks with upcoming deadlines` section had been placed inside the `no active sprint` branch +- when a sprint was active, the upcoming task section disappeared entirely +- moved the upcoming task section out of that conditional so both the active sprint card and upcoming tasks render together + +This keeps the dashboard useful while a sprint is already running instead of hiding the rest of the user's near-term work. + +--- + +## #ProblemsAndSetbacks + +### #QuotedColumnNames +The first major issue today came from the new sprint-session SQL functions using unquoted camelCase column names. + +The database columns used names such as: +- `sessionId` +- `taskId` +- `startedAt` +- `elapsedSeconds` + +Without quotes, Postgres treated these as lowercase names like `sessionid` and `taskid`, which caused RPC failures when starting or finalizing sprint sessions. + +This had to be corrected in the SQL functions before the app-side timer integration could work. + +--- + +### #RowLevelSecurity +The next blocker was row-level security on `sprint_sessions`. + +Even after the SQL functions matched the correct columns, session creation still failed until the insert/select/update permissions allowed authenticated users to work with their own sprint-session rows. + +This was a necessary database-layer fix before the new robust timer flow could be tested end to end. + +--- + +### #CancelRestoreRace +Another significant bug showed up after the new finalize flow was wired in: +- the cancel animation ran +- the timer visually closed +- then the sprint reopened immediately + +The cause was that the restore effect still found `active_sprint` in local storage while the cancel/finalize path was still finishing. Removing the local active sprint earlier in the finalize path fixed that race. + +--- + +### #DashboardListInterpretation +There was also a dashboard-listing issue where the upcoming-deadlines section could appear to only show tasks from one subject. + +The actual cause was not the subject join itself, but the fact that the list had been truncated after sorting. That made the section biased toward whichever subject owned the earliest deadlines in the current data. + +--- + +### #UpcomingTasksVisibilityBug +Another dashboard bug appeared after the active sprint card had been added. + +The issue was not in the Supabase query itself. The problem was that the upcoming-deadlines section was rendered only in the `no active sprint` branch of the dashboard conditional. + +This meant: +- the active sprint card appeared correctly +- the upcoming task data was still loaded +- but the list was hidden whenever a sprint existed + +The fix was to move the upcoming task section outside that conditional so the dashboard can show both at once. + +--- + +## #CurrentState + +The timer/task flow now goes further than yesterday's integration work. + +The app now supports: +- creating a real sprint session in the database when a timer starts +- finalizing sprint sessions on cancel and expiry +- adding tracked session time into `tasks.totalTimeInSeconds` +- showing tracked task time on the task details screen +- reopening the active sprint from the dashboard +- showing upcoming deadline task cards even while a sprint is active +- marking upcoming dashboard tasks as completed with a confirmation step +- opening a help/info modal from both the dashboard and subjects headers +- using NativeWind/Tailwind styling for the dashboard screen and the subjects help modal block + +At this point, the timer is no longer only integrated into the task route. It is now also contributing durable progress data back into the task model and exposing more of that state in surrounding screens. + +--- + +## #Verification + +During today's work, the following behaviors were verified manually through the app plus database inspection: +- sprint creation now succeeds after fixing quoted column names and RLS +- cancelling a sprint updates both `sprint_sessions` and `tasks.totalTimeInSeconds` +- expired sprint finalization also updates the database as expected +- the cancel flow no longer reopens the timer immediately after the close animation + +Static checks were also run during the implementation work: + +```text +npx tsc --noEmit +exited successfully +``` + +```text +npm run lint -- app/task/timer.tsx +exited successfully +``` + +```text +npm run lint -- app/task/viewDetailsTask.tsx +exited successfully +``` + +```text +npm run lint -- app/(tabs)/index.tsx +exited successfully +``` + +```text +npx eslint app/(tabs)/index.tsx +exited successfully +``` + +```text +npx eslint app/(tabs)/subjects.tsx +completed with one existing warning +``` + +The later dashboard/subjects polish work was verified with local static checks and code inspection. The summary above is based on today's working-tree changes plus the live runtime/database checks done while fixing the timer session flow. + +--- + +## #FilesChanged + +Main timer/session files: + +```text +app/task/timer.tsx +lib/asyncStorage.ts +lib/types.ts +``` + +Task details and dashboard files: + +```text +app/task/viewDetailsTask.tsx +app/(tabs)/index.tsx +app/(tabs)/subjects.tsx +lib/progress.ts +``` + +New note added: + +```text +notes/work-report-timer-2026-05-02.md +``` + +--- + +## #Conclusion + +Today's work turned the timer into something closer to a real task-tracking feature instead of only a screen-local countdown. + +The biggest progress was introducing sprint sessions as database-backed records, finalizing them into tracked task time, and then surfacing that state back into the app through task details and the dashboard. The later dashboard follow-up made that surrounding UI more useful by keeping upcoming tasks visible during active sprints, allowing quick task completion from the dashboard itself, and adding a lightweight in-app explanation of the subject/assignment/task/sprint model. diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/chris-work-report-timer-2026-05-03.md b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/chris-work-report-timer-2026-05-03.md new file mode 100644 index 0000000..13bbe75 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/chris-work-report-timer-2026-05-03.md @@ -0,0 +1,392 @@ +# Focus, Dashboard, And Progress Model Work Report + +## #Overview +Today the timer work moved from a sprint-only model toward a more general session flow that can support both focused work and breaks. + +The main goal was to start closing the vision gap around `focus -> break -> continue`, while keeping the implementation local to the existing timer route instead of introducing a larger navigation or state-management rewrite. + +The work therefore covered both app-side session-model changes and the Supabase function updates needed to make the new flow actually start and finalize sessions correctly. + +Later in the same work session, the scope also expanded into the dashboard and the progress presentation on the detail screens so the app better matches the remaining vision-gap plan. + +The scope then expanded one step further into first-time-user friction, so the work also covered a guided onboarding path and clearer empty states for new accounts. + +Later still, the work expanded beyond the app itself into the signup-confirmation path around account creation. That included auth-screen behavior fixes, a shorter guided-setup timer for quick verification, a minimal confirmation landing page for VPS deployment, Caddy routing, and a less boilerplate-looking confirmation email template. + +--- + +## #ImplementedFeatures + +### #GeneralSessionModel +Changed the local timer model from a sprint-specific structure into a more general session structure: +- added `SessionType` in `lib/types.ts` +- introduced the session types: + - `focus` + - `short_break` + - `long_break` +- replaced the old `ActiveSprint` shape with `ActiveSession` in `lib/asyncStorage.ts` +- stored `sessionType` together with `sessionId`, `taskId`, `durationSeconds`, and `endTime` + +This means the active timer is no longer assumed to always be a task-linked focus sprint. + +--- + +### #TimerSessionStartAndRestore +Updated the timer screen so it can start and restore different session types: +- replaced sprint-specific storage calls with `GetActiveSession(...)`, `SaveActiveSession(...)`, and `RemoveActiveSession(...)` +- generalized the timer start path into `startSession(...)` +- passed `p_session_type` into the Supabase `start_sprint_session(...)` RPC +- kept task linkage only for `focus` sessions +- updated the restore logic so a focus session restores by `tId`, while break sessions restore by `sessionType` + +This gives the existing timer screen enough information to behave differently for focus sessions and break sessions without creating a second timer screen. + +--- + +### #DashboardAndTaskIntegration +Updated the surrounding screens so they understand the new active-session shape: +- updated `app/task/viewDetailsTask.tsx` to read the new active session model +- updated `app/(tabs)/index.tsx` so the dashboard card can describe either a focus session or a break session +- made the dashboard open the timer with either a task id or a break-session configuration, depending on what is active + +This keeps the rest of the app aligned with the timer change, instead of leaving the new session model isolated to one file. + +--- + +### #DashboardProgressAndHistory +Extended the dashboard so it works more clearly as a study-activity overview: +- added a compact `Study progress` summary near the top of the dashboard +- showed: + - `Focus sessions today` + - `Minutes today` + - `Minutes this week` +- loaded the summary from `sprint_sessions` instead of from planning data +- added a `Recent sessions` section showing: + - task title when available + - session type + - duration + - final status + - date and time +- added a small `Recently completed tasks` section based on recent task completion updates + +This moved the dashboard closer to the vision requirement that progress should reflect actual study behavior rather than only task structure. + +--- + +### #DashboardLayoutRestructure +Reworked the order of the dashboard sections so the screen reads more clearly as a home surface: +- kept the active-session card at the top when relevant +- placed `Study progress` before the task lists +- moved `Tasks with upcoming deadlines` directly under the progress summary +- pushed `Recent sessions` and `Recently completed tasks` lower as secondary context +- made the lower history area work as a side-by-side layout when screen width allows it +- changed the dashboard body to a scrollable layout so the extra sections still fit without clipping + +The result is a dashboard that moves from orientation, to next action, to history instead of feeling like a stacked report page. + +--- + +### #ConsistentProgressModel +Aligned the progress language across the detail screens so each layer measures one clear thing: +- on the subject details screen, changed the progress label from `Assignment Progress` to `Assignments completed` +- added helper text clarifying that subject progress is based only on completed assignments +- on the assignment details screen, changed the progress label from `Task Progress` to `Tasks completed` +- added helper text clarifying that assignment progress is based only on completed tasks +- on the task details screen, separated completion state from study activity +- added a dedicated `Study activity` block showing: + - tracked focus time from `tasks.totalTimeInSeconds` + - completed focus-session count from `sprint_sessions` +- added an explicit task status label so completion state is not confused with study effort + +This made the meaning of progress more consistent: +- `Subject` now reads as assignment completion +- `Assignment` now reads as task completion +- `Task` now reads as study effort plus completion state +- `Dashboard` now reads as recent study activity + +--- + +### #FirstTimeSetupAndEmptyStates +Added the first guided setup flow so new users are pushed into one clear study path instead of landing in an empty app: +- added a dedicated `app/setup.tsx` route for first-time setup +- changed signup so a newly authenticated user is routed to setup instead of directly to the dashboard +- built the setup flow as a strict sequence: + - create first subject + - create first assignment + - create first task + - start first sprint +- updated the subject, assignment, and task creation screens so they can advance automatically to the next setup step +- removed the setup-breaking success popups between those guided creation steps +- added short auth-screen explanations describing: + - what the app does + - why an account exists + - that study structure and progress follow the user +- added clearer empty states on the dashboard and subjects screen that point the user into guided setup +- tightened the empty-state copy on subject and assignment details so each one points toward the next required object in the hierarchy + +This closes a large part of the first-run friction gap without introducing a separate onboarding system or broader navigation rewrite. + +--- + +### #AuthScreenKeyboardHandling +Adjusted the auth screens so text inputs do not stay buried behind the on-screen keyboard: +- updated `app/login.tsx` so the login content scrolls and shifts upward when the keyboard opens +- updated `app/createUser.tsx` so the entire create-account content block lifts upward with the keyboard instead of only trying to scroll one input into view +- kept the changes local to the auth screens instead of introducing a broader shared keyboard abstraction + +This was aimed specifically at the real usability problem where the password field could end up hidden during login or signup. + +--- + +### #SignupNavigationAndHeaderAlignment +Adjusted the signup screen navigation so it matches the rest of the app more closely: +- removed the temporary in-screen back button experiment from the signup page +- re-enabled the normal stack header for `createUser` in `app/_layout.tsx` +- kept signup navigation on the default app-style back arrow instead of a one-off local control + +This kept the auth flow visually more consistent with the rest of the route stack. + +--- + +### #GuidedSetupFiveSecondSprint +Changed guided setup so the first sprint can be tested almost immediately: +- updated `app/setup.tsx` so the setup flow opens the timer with a fixed `5` second duration +- extended `app/task/timer.tsx` so it can also accept an explicit `durationSeconds` route param +- kept the rest of the timer behavior unchanged, so the setup-specific shortcut still runs through the same session start, storage, and completion flow as normal timers + +This made the first-run path quicker to test without changing the broader timer model back to a special-case setup implementation. + +--- + +### #SignupConfirmationDeployment +Built the first deployable confirmation landing page outside the Expo app: +- added `deploy/signup-confirmation/site/index.html` as a minimal static confirmation page +- added `deploy/signup-confirmation/docker-compose.yml` so the page can be served with `nginx:alpine` +- added a small README for VPS deployment notes and port mapping +- verified the page deployment path together with the external VPS/domain setup already in use + +This created a concrete destination URL for signup confirmation emails instead of leaving the email to resolve into a blank or undefined endpoint. + +--- + +### #CaddyAndEmailConfirmationPolish +Finished the external confirmation flow around signup: +- corrected the Caddy reverse-proxy target from container port `8080` to `80` for the `nginx` confirmation container +- confirmed that the confirmation page then resolved correctly behind the existing Caddy-plus-Docker setup +- replaced the original bare confirmation email body with a cleaner branded HTML email using the existing `{{ .ConfirmationURL }}` placeholder + +This moved the signup confirmation flow from a functional but rough setup into something that is both deployable and presentable. + +--- + +### #PostSessionBreakFlow +Added the first real post-session flow in the timer UI: +- after a completed focus session, the timer now shows: + - `Start short break` + - `Skip break` +- starting the break reopens the same timer route in `short_break` mode +- after a completed short break, the timer now shows: + - `Continue with same task` + - `Back to dashboard` +- passed `returnTaskId` through the route so the timer can return the user to the original task after the break + +This is the first implementation of an actual study loop rather than a timer that simply ends and disappears. + +--- + +### #BreakTimerPresentation +Adjusted the timer UI so break sessions read more clearly: +- added a fixed-duration block for break sessions instead of showing the normal duration picker +- used a fixed 5-minute short-break duration for the first implementation +- kept the focus-session picker unchanged +- made the break start button match the existing `Start Sprint` button styling, but show only `Start` +- removed the bug where picker or pre-start break elements remained visible on top of the running break session + +This keeps the first break flow minimal and visually consistent with the existing timer screen. + +--- + +### #SupabaseFunctionAlignment +Adjusted the Supabase side so the new app flow could actually run: +- updated `start_sprint_session(...)` to accept `p_session_type` +- allowed break sessions to start with `taskId = null` +- aligned the SQL with the real table schema using: + - `sessionId` + - `taskId` + - `userId` + - `sessionType` + - `countedIntoTaskTotal` +- corrected function-return behavior so the app receives the created session id in the shape it expects +- kept finalize logic so only `focus` sessions contribute to `tasks.totalTimeInSeconds` + +Without this database alignment, the app-side session model would compile but still fail when starting real sessions. + +--- + +## #ProblemsAndSetbacks + +### #SchemaMismatch +The main blocker today was that the first SQL version assumed table columns that did not exist in the real Supabase schema. + +The actual `sprint_sessions` table already contained: +- `sessionId` +- `taskId` +- `userId` +- `plannedDuration` +- `startedAt` +- `endedAt` +- `elapsedSeconds` +- `status` +- `countedIntoTaskTotal` +- `sessionType` + +But it did not contain `createdAt` or `updatedAt`, so the first function version failed at runtime. + +--- + +### #FunctionReturnShape +Another blocker was the shape of the return value from `start_sprint_session(...)`. + +Even after the insert worked, the app still showed: +- `Session could not be created.` + +The issue was not the insert itself, but that the returned value shape did not match what `getSessionId(...)` was looking for on the app side. + +This had to be corrected so the RPC returned the created session id in a directly readable object shape. + +--- + +### #PauseUIScreenOverlap +The first version of the break UI had presentation bugs: +- the pause start button text looked cramped and awkward +- pre-start pause UI stayed visible after the break actually started +- picker or fixed-duration elements overlapped the running break session + +This was corrected by hiding pre-start break UI while the timer is running and by reverting the pause start button back to the same visual model as the existing sprint start button. + +--- + +### #ConfirmationRoutePortMismatch +The external signup-confirmation deployment initially failed behind Caddy with `HTTP ERROR 502`. + +The actual issue was not the Docker network arrangement itself, but that the reverse proxy was targeting `signup-confirmation:8080` even though the `nginx` container listens internally on port `80`. + +Changing the upstream target to the real container port fixed the route. + +--- + +## #CurrentState + +The timer flow now goes further than the previous sprint-only model. + +The app now supports: +- starting a `focus` session tied to a task +- starting a `short_break` session with no task linkage +- storing and restoring the active session with its type +- showing a post-focus decision between taking a break or skipping it +- returning from a completed short break into the same task flow or back to the dashboard +- keeping break sessions out of task time totals + +At this point, the app has the first working version of the focus-and-break loop described in the vision plan, even though the cycle logic and long-break offer are not implemented yet. + +The dashboard also now gives a clearer answer to: +- `What have I done today?` +- `What should I work on next?` + +And the detail screens now separate planning completion from study activity more explicitly, which makes the app easier to read without having to infer what each progress bar means. + +For a brand-new user, the app also no longer drops straight into a generic empty state after account creation. There is now a clearer route from signup to: +- first subject +- first assignment +- first task +- first sprint + +That makes the hierarchy feel more guided and less like a blank structure the user has to interpret alone. + +The signup path also now has a more complete confirmation loop around it: +- the auth screens behave more safely when the mobile keyboard opens +- guided setup can launch a very short first sprint for fast verification +- the confirmation email can point to a real public landing page +- that landing page has a working Docker/Caddy deployment path on the VPS +- the email itself no longer looks like a raw boilerplate template + +--- + +## #Verification + +During today's work, the following behaviors were verified through implementation checks and runtime iteration: +- the new session model compiles across timer, dashboard, task details, and local storage +- `start_sprint_session(...)` now succeeds after the Supabase function updates +- the timer can start using the new session-based flow +- break sessions no longer leave the picker or fixed-duration setup visible on top of the running timer +- the dashboard compiles with the new progress-summary, recent-session, and recent-completion sections +- the task details screen compiles with a new `sprint_sessions`-based completed-session count +- the subject and assignment detail screens now label completion metrics more explicitly +- the new guided setup route compiles and links correctly with the subject, assignment, and task creation flow +- the login and signup screens compile after the keyboard-handling adjustments +- the guided setup route now opens the timer with an explicit 5-second fixed duration +- the deployable signup-confirmation page was brought up behind the VPS Caddy setup after correcting the upstream container port from `8080` to `80` +- the confirmation email template was updated to a cleaner HTML version while keeping `{{ .ConfirmationURL }}` as the actual confirmation link placeholder + +Static verification also passed: + +```text +npx tsc --noEmit +exited successfully + +npm run lint +exited with existing warning only in: +- app/task/timer.tsx +``` + +I did not run a live interactive app test for the later dashboard and progress-model changes. That part of the verification is static rather than runtime-confirmed. + +--- + +## #FilesChanged + +Main app files worked on: + +```text +app/task/timer.tsx +app/task/viewDetailsTask.tsx +app/(tabs)/index.tsx +app/(tabs)/subjects.tsx +app/setup.tsx +app/subject/viewDetailsSubject.tsx +app/subject/upsertSubject.tsx +app/assignment/viewDetailsAssignment.tsx +app/assignment/upsertAssignment.tsx +app/task/upsertTask.tsx +app/createUser.tsx +app/login.tsx +app/_layout.tsx +lib/asyncStorage.ts +lib/types.ts +deploy/signup-confirmation/docker-compose.yml +deploy/signup-confirmation/site/index.html +deploy/signup-confirmation/README.md +``` + +New note added: + +```text +notes/work-report-timer-2026-05-03.md +``` + +--- + +## #Conclusion + +The main result today was not just a timer change, but a broader step toward closing the remaining vision gaps around study flow and progress clarity. + +The app now has: +- a session model that can represent both focused work and breaks +- the first concrete `focus -> break -> continue` path from the vision plan +- a dashboard that reflects recent study effort more directly +- detail screens that use more explicit and consistent progress meanings +- a first guided onboarding path that leads a new user from signup to their first workable sprint path +- more usable auth screens when entering credentials on mobile +- a complete basic signup-confirmation flow that now reaches a real deployed landing page and a cleaner confirmation email + +The remaining work in this area is now less about inventing the model from scratch and more about extending, polishing, and live-validating the pieces that are already in place. diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/chris-work-report-timer-2026-05-04.md b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/chris-work-report-timer-2026-05-04.md new file mode 100644 index 0000000..d18c2bf --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/chris-work-report-timer-2026-05-04.md @@ -0,0 +1,196 @@ +# Main Flow Tightening and Timer Duration Picker Work Report + +## #Overview +Today's work focused on the next concrete step in the vision-gap plan after the already completed sections. + +The main goal was to reduce friction in the path from choosing work to actually starting a focus session. That meant tightening the task-level and dashboard-level sprint actions, introducing a consistent default focus duration, and making the timer screen feel faster to enter without removing the older duration-picker path entirely. + +Later in the same work session, the scope narrowed further into the timer screen itself because the reintroduced picker flow behaved incorrectly. That led to a smaller follow-up fix focused specifically on stabilizing the picker state and preventing the screen from resetting while the user scrolls. + +The scope also expanded into the help-flow modal on the dashboard and subjects screens so its explanation of the app structure matches the way the app now actually works. + +After that, one more timer-flow bug surfaced in the post-session overlay itself. A completed break could still reuse the focus-session action menu, which incorrectly offered the user another break instead of only the actions that make sense after a break has ended. + +--- + +## #ImplementedFeatures + +### #DefaultFocusDuration +Introduced a shared default session-duration source for the low-friction focus flow: +- added `lib/sessionDefaults.ts` +- defined: + - `DEFAULT_FOCUS_DURATION_MINUTES` + - `DEFAULT_SHORT_BREAK_DURATION_MINUTES` +- reused those constants across the timer, task details, and dashboard paths + +This removed the need to hardcode the same default duration in multiple places and made the main sprint path more consistent. + +--- + +### #TaskDetailsPrimarySprintAction +Updated the task details screen so `Start Sprint` is the strongest action on the page: +- moved `Start Sprint` out of the lower row of equal-weight controls +- made it the primary full-width action above `Edit` and `Delete` +- added small helper text clarifying that the action starts a `25` minute focus sprint +- updated the task-details start flow so it passes the default focus duration into the timer route +- tightened the active-session replacement alert text so it clearly states what will happen before the current session is replaced + +This makes the task screen push the user more directly toward real study work instead of presenting sprint start as only one option among several management actions. + +--- + +### #DashboardDirectSprintStart +Reduced dashboard-to-timer friction for upcoming tasks: +- added a `Start Sprint` action directly on the `Tasks with upcoming deadlines` cards +- made that action open the timer immediately with the shared default focus duration +- handled the three relevant states: + - no active session + - an expired stored session + - an already running different session that must be explicitly replaced +- renamed the active-session dashboard button from `Open Session` to: + - `Resume Sprint` + - `Resume Break` + +This removed one unnecessary detour where the user had to open task details first before reaching the timer. + +--- + +### #TimerDefaultDurationFlow +Changed the timer entry flow so focus sessions no longer force the user through duration selection before they can begin: +- changed the default focus-session setup to show a fixed default duration first +- kept break sessions on a fixed-duration path as before +- made the start action use the default focus duration immediately unless the user actively chooses a custom one + +This better matches the low-friction part of the vision plan, where starting work should feel immediate rather than configuration-heavy. + +--- + +### #CustomDurationReturnPath +Reintroduced the old duration-picker flow as an explicit optional side path instead of the default: +- added a `Choose a different duration` button on the pre-start focus timer screen +- reopened the old picker presentation only when the route enters an explicit picker mode + +This keeps the faster default path while still preserving the older manual-duration interaction for users who want it, without adding a second reversal action inside the picker itself. + +--- + +### #PostSessionActionClarity +Adjusted the timer completion overlay so the focus-session exit path is more explicit: +- after a completed focus session, the overlay now offers: + - `Start short break` + - `Continue same task` + - `Back to dashboard` +- updated the explanation text so the available next actions are described directly in the overlay copy + +This makes the post-session decision path closer to the plan's requirement that break, continue, and dashboard-return actions should be simple and explicit. + +--- + +### #TimerPickerGlitchFix +Fixed the first version of the restored duration picker after it showed unstable behavior: +- the picker numbers could initially appear blank until the list was scrolled +- the selected duration could snap back incorrectly when scrolling ended +- the cause was that the picker route was being rewritten while the user interacted with the list +- changed picker selection to use local component state instead of route replacement on every scroll stop +- added explicit initial offset restoration on picker open so the visible selection matches the current duration immediately +- kept the route change only for entering or leaving picker mode, not for every intermediate selection + +This made the picker usable again without undoing the lower-friction default entry flow. + +--- + +### #HelpFlowAlignment +Updated the help modal so it matches the current app structure more closely: +- kept the main hierarchy as: + - `Subject` + - `Assignment` + - `Task` + - `Sprint` +- updated the `Sprint` explanation so it now reflects the real post-session flow: + - take a break + - continue the same task + - return to the dashboard +- changed the supporting copy so it explains that the work path now leads into both sprints and breaks instead of only into one focused work session +- added quick-map text clarifying the dashboard's current role: + - resume active session + - start next sprint + - review recent progress +- changed the help CTA on the dashboard from `Start with Subjects` to `Open Subjects` +- changed the help CTA on the subjects screen from `Start with Subjects` to `Close Guide` + +This keeps the help flow aligned with the app's actual current behavior instead of leaving it stuck on an older sprint-only interpretation. + +--- + +### #PostBreakMenuFix +Fixed a timer completion bug where a finished break could still produce the same action menu as a finished focus session: +- the post-session overlay had to know which session type actually just ended +- the previous flow could fall back to local screen state instead of the persisted active session +- this caused a break completion to sometimes be treated like a focus completion +- changed the completion flow so it reads the stored active session before building the post-session prompt +- reused that same session snapshot when finalizing the session in Supabase + +This means the overlay now behaves correctly after a break finishes: +- it does not offer `Start short break` again +- it instead keeps the narrower break-finished path: + - continue with the same task + - go back to the dashboard + +--- + +## #ProblemsAndSetbacks + +### #PickerStateReset +The main issue during this work happened after the older picker screen was reintroduced as an optional path. + +The first implementation reopened the picker route correctly, but it also updated the route params again when scrolling stopped. In practice this caused two visible problems: +- the initial number presentation was unstable +- the selected value could reset unexpectedly after momentum ended + +The fix was to keep picker selection local to `app/task/timer.tsx` while the picker is open, and only use route params to decide whether the picker mode should be shown in the first place. + +### #PostSessionTypeMismatch +Another issue appeared after the post-session focus actions were introduced. + +The completion overlay already had separate UI for `focus` and `break` sessions, but the value used to choose between them was not robust enough. In practice, that made it possible for a finished break to reopen the focus-style menu and incorrectly offer another break. + +The fix was to derive the completed session type from the persisted active session that had actually been running, rather than relying only on the screen's local state at the moment the animation finished. + +--- + +## #CurrentState + +The timer/task/dashboard flow now does more to push the user into focused work with fewer unnecessary steps. + +The app now supports: +- a shared default focus duration for the main sprint path +- a stronger `Start Sprint` action on the task details screen +- direct sprint start from dashboard upcoming-task cards +- clearer `Resume Sprint` and `Resume Break` wording on the dashboard +- a fixed default-duration entry state on the timer screen +- an optional custom-duration picker path instead of a forced picker +- explicit post-focus next actions for break, continue, or dashboard return +- a stable picker implementation that keeps its selected value while the user scrolls +- a corrected break-finished overlay that no longer offers another pause when the completed session was already a break +- a help-flow explanation that now matches the real sprint, break, dashboard, and subjects flow more closely + +At this point, the timer flow is more aligned with the vision requirement that starting work should feel fast, focused, and low-friction rather than like a chain of setup steps. + +--- + +## #Verification + +Static checks were run after the implementation work and after the picker bug fix: + +An additional static check was also run after the post-break menu fix: + +```text +npx tsc --noEmit +exited successfully + +npm run lint +exited successfully + +npx tsc --noEmit +exited successfully +``` diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/chris-work-report-timer-2026-05-05.md b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/chris-work-report-timer-2026-05-05.md new file mode 100644 index 0000000..6e46ede --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/chris-work-report-timer-2026-05-05.md @@ -0,0 +1,307 @@ +# Session Reliability and Break-Cycle Work Report + +## #Overview +Today's work continued from the updated vision-gap plan, with the focus narrowed to the remaining timer and session-state gaps rather than broader feature expansion. + +The first goal was to finish the last missing part of the focus-and-break loop by making the app distinguish between a short break and a long break in a way that matches an actual study cycle instead of using total historical session count. + +After that, the scope shifted into reliability work because the remaining highest-risk issue was not missing UI, but the possibility that local active-session state and recorded session history could drift apart. That led to a review of how the dashboard, setup flow, task details screen, and timer screen each handled expired, cancelled, or replaced sessions. + +Later in the same work session, the focus narrowed again into wording and flow polish on the timer screen. The break and sprint descriptions were rewritten so they better reflect the app's goal of supporting structured study behavior, and two runtime regressions reported after testing were fixed in the timer flow itself. + +After that, the work shifted into the remaining first-time-user gap from the vision plan. The login and tab flows were tightened so incomplete users are routed into guided setup automatically, and the first guided sprint was changed into a short onboarding demo instead of dropping a new user straight into a normal 25-minute timer. + +The final pass of the day was smaller, but still tied to the same product goal. The help modals on the dashboard and subjects screens were rewritten so they explain the focus-session and break rhythm in a more human way instead of sounding like a rigid step list. + +After that, one final navigation-polish pass was added on the tabs layout itself. The bottom tabs were given explicit icons so the app's primary navigation reads faster at a glance and feels less unfinished. + +After the branch work was merged back into `main`, one more cleanup pass was needed. That merge left multiple screen files in a syntactically broken state, so the final work shifted away from feature work and into restoring the current main branch to a usable state before report-focused delivery work. + +--- + +## #ImplementedFeatures + +### #LongBreakCycleCompletion +Finished the missing long-break part of the focus-and-break loop: +- extended the shared session defaults in `lib/sessionDefaults.ts` +- added: + - `DEFAULT_LONG_BREAK_DURATION_MINUTES` + - `FOCUS_SESSIONS_PER_LONG_BREAK` + - `STUDY_CYCLE_IDLE_RESET_MINUTES` +- updated the timer flow so the next break is chosen from a local study-cycle model instead of total historical session count + +The long-break rule now follows a small continuous-cycle interpretation of study flow rather than incorrectly counting unrelated sessions from earlier in the day or from previous days. + +--- + +### #StudyCycleState +Added a small local study-cycle state to support the new break behavior: +- extended `lib/asyncStorage.ts` +- added `StudyCycle` +- added: + - `SaveStudyCycle` + - `GetStudyCycle` + - `RemoveStudyCycle` +- tracked: + - the task tied to the current cycle + - how many focus sessions have been completed in that cycle + - the last completed session type + - the last completion timestamp + +This keeps the long-break offer tied to the current study run instead of to the user's entire database history. + +--- + +### #DynamicBreakPrompt +Updated the timer completion overlay so post-focus actions are based on the actual cycle state: +- expanded the post-session prompt model to include the next break type +- replaced the hardcoded short-break action with a dynamic break action +- updated the overlay text and button label so the user now sees: + - `Start short break` + - or `Start long break` + depending on the current cycle + +This completes the missing loop from the plan where break behavior should feel intentional rather than unfinished. + +--- + +### #SessionLifecycleConsistency +Introduced a shared finalization path for active sessions: +- added `lib/sessionLifecycle.ts` +- introduced `finalizeStoredSession(...)` +- moved repeated session-finalization behavior into one place: + - remove local active-session state + - clear study-cycle state when the final status is not `completed` + - finalize the same `sessionId` in Supabase with: + - `completed` + - `cancelled` + - `expired` + +This reduced the risk that one screen would only clear local storage while another screen properly finalized the database record. + +--- + +### #CrossScreenReliabilityFixes +Applied the shared finalization path across the screens that handle active-session recovery or replacement: +- `app/task/timer.tsx` +- `app/(tabs)/index.tsx` +- `app/task/viewDetailsTask.tsx` +- `app/setup.tsx` + +The updated paths now explicitly finalize sessions when they are: +- expired on reopen +- expired while being observed from the dashboard +- cancelled because the user replaces one active sprint with another + +This closes a real reliability gap where the app could previously lose the active local session while leaving the recorded session in the database unfinalized. + +--- + +### #TimerAndBreakCopyPolish +Rewrote the timer and break descriptions so they better match the product's intended tone: +- updated the pre-start sprint description +- updated the pre-start break description +- updated the focus fallback description on the running timer +- updated the post-focus and post-break explanation copy + +The new wording emphasizes that structured focus and intentional breaks matter for studying, instead of sounding like placeholder or utility-only text. + +--- + +### #ReportedRegressionFixes +Fixed two runtime issues discovered during manual testing after the earlier session-cycle changes: +- after cancelling a focus session, the sprint-duration view could appear visually blank until the user manually dragged the picker +- after completing a long break, `Continue with same task` could route the user back to the dashboard instead of returning to the correct task flow + +The fixes were: +- reinitializing the picker-offset path when the timer returns to a non-running state +- preserving `returnTaskId` inside the stored active-session shape so break sessions keep the correct task context all the way through completion + +--- + +### #OnboardingRoutingGuard +Closed the remaining onboarding-routing gap so incomplete users are pushed into guided setup instead of being left in the dashboard tabs: +- added `lib/setupStatus.ts` +- moved the shared setup-completion rule into one place +- updated: + - `app/login.tsx` + - `app/(tabs)/_layout.tsx` + - `app/(tabs)/index.tsx` + - `app/(tabs)/subjects.tsx` +- setup completion is now checked from the same source in login, tab entry, dashboard, and subjects + +This made the setup flow enforceable instead of depending on the user noticing the guided-setup card in the dashboard. + +--- + +### #FirstSprintDemoFlow +Adjusted the first guided sprint so the first-time experience better matches the low-friction vision goal: +- extended `lib/asyncStorage.ts` +- added: + - `GetSetupSprintDemoUsed` + - `SaveSetupSprintDemoUsed` +- updated `app/task/upsertTask.tsx` and `app/setup.tsx` so the first setup sprint uses: + - `durationSeconds: '5'` + - `onboardingDemo: 'true'` +- updated `app/task/timer.tsx` so that onboarding-demo sprint completion: + - skips the normal session-complete modal + - routes directly to the dashboard + +This keeps the first sprint short enough to demonstrate the flow without locking a new user into a full focus block, while still falling back to the normal focus-session duration after the demo has been used once. + +--- + +### #HelpModalFlowCopy +Updated the help modals on the dashboard and subjects screens so they explain the intended study rhythm more naturally: +- updated: + - `app/(tabs)/index.tsx` + - `app/(tabs)/subjects.tsx` +- rewrote the flow-step descriptions so they feel less mechanical +- added clearer wording about the actual intended loop: + - focus session + - short pause + - focus session again + - longer pause after a few rounds + +This better matches the app's tone and makes the focus/break cycle easier to understand from inside the product itself. + +--- + +### #TabBarIconPolish +Added explicit icons to the bottom-tab navigation so the two primary surfaces are easier to scan: +- updated `app/(tabs)/_layout.tsx` +- reused the existing `MaterialIcons` set already used elsewhere in the app +- assigned: + - `dashboard` to the dashboard tab + - `menu-book` to the subjects tab + +This was a small UI polish pass, but it improves immediate navigation clarity and makes the tab bar feel more intentional instead of placeholder-like. + +--- + +### #MainBranchMergeCleanup +Repaired merge-related breakage after switching back to `main`: +- fixed `app/(tabs)/subjects.tsx` +- fixed `app/subject/viewDetailsSubject.tsx` +- rebuilt `app/task/viewDetailsTask.tsx` into a consistent working version + +The merge had left these files with duplicated blocks, broken hook structure, and invalid JSX. The cleanup work focused on restoring the intended screen behavior rather than changing product scope. + +The result was: +- subjects screen logic restored to a valid loading/setup/render flow +- subject details screen header and progress area reconstructed +- task details screen restored with working context, study activity, and sprint-start actions + +This was not new feature work, but it was necessary delivery work because the main branch was no longer in a reliable edit/test state. + +--- + +## #ProblemsAndSetbacks + +### #SessionTruthDivergence +The main reliability issue uncovered today was not in the timer animation itself, but in how different screens treated expired or replaced sessions. + +Several screens could detect that a stored session was no longer valid, but some of them only removed the local active-session entry instead of also finalizing the matching `sprint_sessions` row in Supabase. That created a risk where the UI and the database could tell different stories about the same session. + +The fix was to stop duplicating that logic screen by screen and route those paths through a shared finalization helper instead. + +### #PostChangeRuntimeRegressions +After the cycle and reliability changes landed, manual testing surfaced two smaller regressions in the timer screen: +- the duration screen could look empty after cancelling a focus session +- the break-return flow lost its task target after a long break + +These were not architectural problems, but they were both important because they affected the user's immediate understanding of the timer flow after interacting with it. + +### #OnboardingFlowMismatch +Manual testing later uncovered a smaller flow mismatch inside guided setup: +- the first task created in setup could still open the timer with the normal 25-minute focus default +- returning to the guided-setup screen afterwards could then launch a different 5-second demo path + +The problem was that task creation in setup and the setup screen itself were using two different timer-entry paths. The fix was to make those paths share the same one-time onboarding-demo rule. + +### #PostMergeCodeBreakage +The final setback of the day came after the branch merge itself rather than from the timer/session work. + +Several files on `main` were left in a partially merged state with duplicated code fragments and broken JSX structure. That meant the next pass could not start from feature verification alone, because basic app screens were no longer parseable. + +The practical fix was to repair those files directly first, then re-run targeted verification on the restored app files before deciding whether any real feature regressions were still present. + +--- + +## #CurrentState + +The timer and session model are now closer to the final intended behavior in the vision-gap plan. + +The app now supports: +- a simple long-break rule tied to the current study cycle +- a local cycle model that avoids counting unrelated older sessions +- a post-focus overlay that correctly offers either a short break or a long break +- a shared session-finalization path used across timer, dashboard, setup, and task-details flows +- better consistency between active local session state and recorded session history +- more intentional sprint and break wording on the timer screen +- preserved task-return context across long-break completion +- corrected timer-screen recovery after cancelling a focus session +- automatic routing into guided setup for incomplete users after login and tab entry +- a one-time onboarding sprint demo that uses a 5-second timer +- direct dashboard routing after the onboarding demo completes, without the normal completion modal +- help modals that explain the study loop in a more natural way +- explicit tab icons that make dashboard and subjects easier to distinguish at a glance +- repaired `main`-branch versions of the subjects, subject-details, and task-details screens after merge corruption + +At this point, the timer/session work is closer to a finished loop, and the first-time-user path is more in line with the intended product vision. The biggest remaining work is now less about feature gaps and more about making sure the final report and final app behavior stay aligned. + +--- + +## #Verification + +Static checks were run after the main implementation work and again after the regression fixes: + +```text +npx tsc --noEmit +exited successfully + +npm run lint +exited successfully + +npx tsc --noEmit +exited successfully + +npm run lint +exited successfully + +npx tsc --noEmit +exited successfully + +npm run lint +exited successfully + +npx tsc --noEmit +exited successfully + +npm run lint +exited successfully +``` + +Manual testing also confirmed most of the intended behavior from today's scope. Two regressions were found during that testing, both inside the timer flow, and both were fixed in the same work session: +- blank sprint-duration state after cancelling a focus session +- incorrect dashboard return after pressing `Continue with same task` following a long break + +Later manual testing also validated the guided-setup flow after the onboarding fixes: +- incomplete users were routed into guided setup instead of landing in dashboard tabs +- the first setup sprint used the intended 5-second demo timer +- after the demo finished, the user was sent directly to the dashboard without seeing the normal session-complete modal + +The final UI pass for the day was lighter and did not change behavior, but the resulting tabs-layout diff was reviewed directly and confirmed to be limited to navigation presentation: +- explicit `MaterialIcons` import in the tabs layout +- `dashboard` icon for the dashboard tab +- `menu-book` icon for the subjects tab + +The final repair pass on `main` was verified separately: +- `npx eslint app/(tabs)/subjects.tsx app/subject/viewDetailsSubject.tsx app/task/viewDetailsTask.tsx` +- `git diff --check` +- no remaining merge markers were found in `app/`, `lib/`, `components/`, or `notes/` + +One broader static check still failed afterwards: +- `npx tsc --noEmit` + +That remaining failure was no longer caused by the repaired app screens. The reported errors were instead in the test setup under `__tests__/`, where Jest/testing-library types and modules were not currently configured in this branch. diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/new-build-guide.md b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/new-build-guide.md new file mode 100644 index 0000000..305b1df --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/new-build-guide.md @@ -0,0 +1,71 @@ +# DevelopmentBuildGuide + +This project uses an **Expo development build** for features that are not fully supported in Expo Go, such as our notification setup. + +--- + +## WhyWeUseThis + +We do **not** use Expo Go for this project when testing notifications or other native features. + +Reason: +- Expo Go has limitations for some native modules +- `expo-notifications` on Android requires a development build for reliable testing +- a development build works like a custom Expo Go app made specifically for this project + +--- + +## #ImportantRule + +You do **not** need to rebuild the APK for every code change. + +### Rebuild is **not needed** for: +- changing React components +- changing screen layouts +- changing styles +- changing Supabase queries +- changing JS/TS functions +- changing form logic +- changing routing logic +- changing notification scheduling logic in JavaScript only + +### Rebuild **is needed** for: +- adding a new native dependency +- removing a native dependency +- changing `app.json` +- changing Expo plugins +- changing Android/iOS permissions +- changing native notification config +- anything that affects the native app shell + +--- + +## OneTimeSetup +Install EAS CLI globally if needed: +npm install -g eas-cli + +Log in to Expo: +eas login + +Install the Expo development client in the project: +npx expo install expo-dev-client + +# BuildTheDevelopmentAPK +Run this command from the project root: +eas build --platform android --profile development + +This sends the build to Expo's cloud build service. + +When the build is finished: + +open the build link +click Install +install the APK on your Android phone or emulator +Do not place the APK inside the project folder. +The APK is something you install on the device, not a source file. + +# DailyWorkflow +After the development build APK is installed: + +Start the project: +npx expo start \ No newline at end of file diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/work-report-2026-04-20.md b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/work-report-2026-04-20.md new file mode 100644 index 0000000..8375de0 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/work-report-2026-04-20.md @@ -0,0 +1,173 @@ +# Task Management Mobile Application – Project Summary + +## Overview +This project is a mobile task management application developed using **React Native (Expo)** with **Supabase** as the backend. The application enables users to create, view, edit, and delete tasks while maintaining secure authentication and session management. + +The system follows a full-stack architecture, integrating frontend UI components with backend database operations and authentication services. + +--- + +## Technologies Used + +### Frontend +- React Native (Expo) +- Expo Router (navigation) +- React Hooks (`useState`, `useEffect`, `useFocusEffect`) + +### Backend +- Supabase (PostgreSQL database + authentication) +- Row Level Security (RLS) for data protection + +### Storage & Security +- Expo SecureStore for persistent session storage + +--- + +## Application Structure + +### Navigation +The app uses **Expo Router** with a combination of: +- **Tab navigation** for main screens +- **Stack navigation** for individual pages + +Main routes: +- `/` → Home (Today view) +- `/tasks` → Task list +- `/createTask` → Create new task +- `/editTask` → Edit existing task +- `/createUser` → Sign up +- `/login` → Login + +--- + +## Authentication System + +The application includes a complete authentication flow: + +- **User Registration** + - Email and password-based signup +- **User Login** + - Credential-based authentication +- **Session Management** + - Persistent sessions using SecureStore +- **Protected Routes** + - Users are redirected if not authenticated +- **Logout** + - Ends session via Supabase + +--- + +## Task Management Features + +### Create Task +Users can: +- Enter title, description, and deadline +- Set completion status using a checkbox +- Save tasks to the database + +### Read Tasks +- Tasks are fetched from Supabase +- Displayed using a `SectionList` +- Categorized into: + - Upcoming Tasks + - Completed Tasks +- Supports manual refresh and auto-refresh on screen focus + +### Update Task +- Existing tasks can be edited +- Fields are pre-filled with current values +- Updates are sent to the database using task ID + +### Delete Task +- Tasks can be deleted with confirmation +- List updates after deletion + +--- + +## User Interface Design + +A centralized styling system (`defaultStyles`) was implemented to ensure consistency across the application. + +### Key UI Components +- Text inputs for forms +- Buttons and pressable elements +- Custom checkbox component +- Sectioned task list +- Activity indicators for loading states + +### UX Features +- Keyboard handling with `KeyboardAvoidingView` +- Tap outside to dismiss keyboard +- Alerts for feedback (success/errors) +- Dynamic headers with actions (refresh, logout) + +--- + +## State Management + +The app uses local state via React Hooks: +- `useState` for form data and UI state +- `useEffect` for lifecycle events +- `useFocusEffect` for refreshing data when screens are focused + +--- + +## Backend Integration + +### Supabase Client +- Configured using environment variables +- Secure session persistence enabled +- Automatic token refresh + +### Database Operations +- `INSERT` → create tasks +- `SELECT` → fetch tasks +- `UPDATE` → edit tasks +- `DELETE` → remove tasks + +### Data Model (Tasks Table) +- `tId` (UUID) +- `title` +- `description` +- `deadline` +- `isCompleted` +- `lastChanged` +- `uId` (user reference) + +--- + +## Security + +- Row Level Security (RLS) ensures users can only access their own tasks +- Queries are filtered using `auth.uid() = uId` +- Update operations require a `WHERE` clause to prevent unintended changes + +--- + +## Challenges and Solutions + +### Routing Issues +- Fixed incorrect relative paths by using absolute routes and parameters + +### Data Binding +- Ensured edit forms are pre-filled by fetching data using task ID + +### Database Errors +- Resolved missing `WHERE` clause in update queries +- Handled invalid date formats + +### UI Layout Problems +- Improved header layout by replacing default buttons with custom components +- Fixed spacing and alignment issues + +--- + +## Conclusion + +The project successfully demonstrates the development of a full-stack mobile application with: +- Secure authentication +- Persistent user sessions +- CRUD operations with a backend database +- Structured navigation and UI design + +The application follows scalable patterns and provides a solid foundation for further enhancements such as improved UI design, additional features, and performance optimizations. \ No newline at end of file diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/work-report-2026-04-21-to-22.md b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/work-report-2026-04-21-to-22.md new file mode 100644 index 0000000..98fa574 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/work-report-2026-04-21-to-22.md @@ -0,0 +1,116 @@ +## #Overview +Today I implemented a full **CRUD system** for the three core entities in the application: +- **Subjects** +- **Assignments** +- **Tasks** + +This includes creating, editing, viewing details, and deleting records, as well as connecting all screens using Expo Router. + +--- + +## #ImplementedFeatures + +### #Subjects +Created full CRUD flow: +- `createSubject.tsx` +- `editSubject.tsx` +- `viewDetailsSubject.tsx` + +**Functionality:** +- Create new subjects +- Edit existing subjects +- View subject details +- Delete subjects + +**Relationships:** +- Subjects act as the top-level entity +- Assignments can optionally be linked to a subject via `sId` +- Subjects are displayed: + - globally (`subjects.tsx`) + - or standalone (`viewDetailsSubjects.tsx`) + +--- + +### #Assignments +Created full CRUD flow: +- `createAssignment.tsx` +- `editAssignment.tsx` +- `viewDetailsAssignment.tsx` + +**Functionality:** +- Create assignments (with optional `sId`) +- Edit assignments +- View assignment details +- Delete assignments + +**Relationships:** +- Assignments can exist: + - linked to a subject (`sId`) + - or standalone (`sId = null`) +- Assignments are displayed: + - globally (`assignments.tsx`) + - or within a subject (`viewDetailsSubject.tsx`) + - or standalone (`viewDetailsAssignment.tsx`) + +--- + +### #Tasks +Created full CRUD flow: +- `createTask.tsx` +- `editTask.tsx` +- `viewDetailsTask.tsx` + +**Functionality:** +- Create tasks +- Edit tasks +- View task details +- Delete tasks + +**Relationships:** +- Tasks are linked to assignments via `aId` +- Tasks are accessed through assignment detail pages +- Assignments are displayed: + - globally (`tasks.tsx`) + - or within an assignment (`viewDetailsAssignment.tsx`) + - or standalone (`viewDetailsTask.tsx`) + +--- + +## #RoutingStructure + +### #TopLevelScreens +- `subjects.tsx` → list of all subjects +- `assignments.tsx` → list of all assignments +- `tasks.tsx` → list of all tasks +- `index.tsx` → pre-existing home screen + +--- + +## #DataModel + +### #Subject +- `sId` +- `title` +- `description` +- `isActive` +- `lastChanged` +- `uId` + +### #Assignment +- `aId` +- `title` +- `description` +- `deadline` +- `isCompleted` +- `lastChanged` +- `uId` +- `sId` + +### #Task +- `tId` +- `title` +- `description` +- `isCompleted` +- `lastChanged` +- `uId` +- `aId` \ No newline at end of file diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/work-report-2026-04-22-progess-bars.md b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/work-report-2026-04-22-progess-bars.md new file mode 100644 index 0000000..25cdf80 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/work-report-2026-04-22-progess-bars.md @@ -0,0 +1,38 @@ +# Progress Tracking (Assignments & Subjects) + +## What was done +- Implemented progress tracking for both assignments and subjects +- Used `Task.isCompleted` as the source of truth +- Synced `Assignment.isCompleted` based on task completion + +## Logic implemented +- Created `CheckAssignmentCompletion(aId)` +- Assignment is marked completed only if all its tasks are completed +- Assignment remains incomplete if: + - Any task is incomplete + - No tasks exist + +## Data handling +- Fetched assignments from Supabase +- Fetched all related tasks using assignment IDs +- Grouped tasks by `aId` into `tasksByAssignment` +- Used grouped data to calculate progress efficiently + +## Progress calculation +- Assignment progress: + - completed tasks / total tasks +- Subject progress: + - completed tasks across all assignments / total tasks + +## UI work +- Added progress bars to: + - Assignment cards + - Subject views +- Used basic inline styling for progress bars +- Fixed layout issues caused by incorrect placement inside `flex-row` +- Moved progress bar into content column to prevent UI breaking + +## Result +- Progress updates dynamically based on task completion +- Assignment completion stays in sync with tasks +- UI correctly displays both assignment and subject progress \ No newline at end of file diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/work-report-2026-04-22.md b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/work-report-2026-04-22.md new file mode 100644 index 0000000..3caec94 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/work-report-2026-04-22.md @@ -0,0 +1,173 @@ +## #Overview + +Implemented a full local notification system for assignment deadlines using Expo Notifications, integrated with Supabase-backed assignment data. + +--- + +## #CoreFeatures + +### #LocalNotifications + +* Integrated `expo-notifications` for scheduling local device notifications +* Configured notification handler for: + + * banner display + * sound + * badge updates +* Notifications trigger even when: + + * app is in background + * app is fully closed + +--- + +### #DeadlineReminderLogic + +* Implemented reminder scheduling based on assignment deadlines +* Default behavior: + + * notify **24 hours before deadline** +* Prevented invalid scheduling: + + * skip if reminder time is in the past + * validate deadline input before scheduling + +--- + +### #AssignmentIntegration + +* Notifications tied directly to assignment lifecycle: + +#### On Create: + +* Insert assignment into Supabase +* Retrieve inserted assignment (`aId`) +* Schedule reminder if not completed + +#### On Edit: + +* Cancel existing scheduled notification +* Update assignment in Supabase +* Schedule new reminder if still active + +#### On Delete: + +* Cancel scheduled notification +* Remove stored notification reference + +--- + +### #NotificationPersistence + +* Stored notification IDs locally using AsyncStorage +* Structure: + + * `assignmentId → notificationId` +* Enables: + + * precise cancellation + * avoiding duplicate notifications + +--- + +### #NotificationCancellation + +* Implemented cancellation flow using: + + * `Notifications.cancelScheduledNotificationAsync(notificationId)` +* Ensures: + + * no duplicate reminders on edit + * no orphan notifications after deletion + +--- + +### #NotificationRouting + +* Implemented navigation on notification tap +* Uses: + + * `Notifications.addNotificationResponseReceivedListener` + * `Notifications.getLastNotificationResponse()` + +#### Behavior: + +* Works when: + + * app is open + * app is in background + * app is launched from notification + +#### Routing: + +* Extract `aId` from `notification.content.data` +* Navigate using Expo Router: + +```ts +router.push({ + pathname: "/assignment/viewDetailsAssignment", + params: { aId } +}); +``` + +--- + +### #AuthIntegration + +* Notification observer only runs when user session exists +* Prevents routing into protected screens when unauthenticated + +--- + +## #ArchitectureDecisions + +### #LocalVsBackend + +* Chose **local notifications only** +* No backend push notifications used +* Rationale: + + * single-user reminders + * simpler implementation + * no need for push tokens or server logic + +--- + +### #DataSeparation + +* Supabase: + + * stores assignment data (source of truth) +* Device (AsyncStorage): + + * stores notification IDs (device-specific state) + +--- + +### #RoutingApproach + +* Used existing static route: + + * `/assignment/viewDetailsAssignment` +* Passed `aId` via params instead of dynamic route `[aId].tsx` +* Keeps current structure intact + +--- + +## #Summary + +A complete local notification system has been implemented with: + +* deadline-based scheduling +* lifecycle-aware updates (create/edit/delete) +* duplicate prevention +* device-level persistence +* deep-link style navigation on tap + +This provides a solid, production-ready foundation for assignment reminders within the app. + + +Interesting sources: +https://docs.expo.dev/versions/latest/sdk/async-storage/ +https://docs.expo.dev/versions/latest/sdk/securestore/ +https://docs.expo.dev/versions/latest/sdk/notifications/ diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/work-report-2026-04-24-to-25.md b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/work-report-2026-04-24-to-25.md new file mode 100644 index 0000000..4ac50bb --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/markdown verisons/work-report-2026-04-24-to-25.md @@ -0,0 +1,71 @@ +# CRUD Testing Summary (React Native + Jest + Supabase) + +## What these tests are about +Tests verify **app behavior**, not Supabase itself. + +They check: +- User interaction works +- Correct database functions are called +- Navigation happens after actions + +--- + +## CRUD Breakdown + +### CREATE +- User inputs data +- `insert()` is called +- App navigates back + +Flow: +User → type → press create → insert() → router.back() + +--- + +### READ +- Data is fetched (`select().eq().single()`) +- State updates +- UI renders correct content + +--- + +### UPDATE +- Existing data is loaded +- User edits input +- `update().eq()` is called with correct values +- Navigation happens + +--- + +### DELETE +- User presses delete +- `Alert.alert()` is triggered +- Confirm button (`onPress`) is manually called in test +- `delete().eq()` runs +- Navigation happens + +--- + +## Why mocking is used +- No real database calls +- Faster tests +- Full control over success/error cases +- No side effects (no real data created/deleted) + +--- + +## Mock rule +The mock must match the real call chain: + +Real: +from → update → eq → select → single + +Mock: +from() → update() → eq() → select() → single() + +If not → errors like: +".select is not a function" + +--- + +https://oss.callstack.com/react-native-testing-library/ diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/architecture-note.pdf b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/architecture-note.pdf new file mode 100644 index 0000000..f821d5c Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/architecture-note.pdf differ diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/chris-work-report-timer-2026-04-21.pdf b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/chris-work-report-timer-2026-04-21.pdf new file mode 100644 index 0000000..24b8696 Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/chris-work-report-timer-2026-04-21.pdf differ diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/chris-work-report-timer-2026-04-22.pdf b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/chris-work-report-timer-2026-04-22.pdf new file mode 100644 index 0000000..5ca5e56 Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/chris-work-report-timer-2026-04-22.pdf differ diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/chris-work-report-timer-2026-04-23.pdf b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/chris-work-report-timer-2026-04-23.pdf new file mode 100644 index 0000000..538c11e Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/chris-work-report-timer-2026-04-23.pdf differ diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/chris-work-report-timer-2026-04-24.pdf b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/chris-work-report-timer-2026-04-24.pdf new file mode 100644 index 0000000..37e4da3 Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/chris-work-report-timer-2026-04-24.pdf differ diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/chris-work-report-timer-2026-04-25.pdf b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/chris-work-report-timer-2026-04-25.pdf new file mode 100644 index 0000000..2a8c169 Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/chris-work-report-timer-2026-04-25.pdf differ diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/chris-work-report-timer-2026-05-01.pdf b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/chris-work-report-timer-2026-05-01.pdf new file mode 100644 index 0000000..9157b3e Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/chris-work-report-timer-2026-05-01.pdf differ diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/chris-work-report-timer-2026-05-02.pdf b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/chris-work-report-timer-2026-05-02.pdf new file mode 100644 index 0000000..6ef5d45 Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/chris-work-report-timer-2026-05-02.pdf differ diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/chris-work-report-timer-2026-05-03.pdf b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/chris-work-report-timer-2026-05-03.pdf new file mode 100644 index 0000000..578f896 Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/chris-work-report-timer-2026-05-03.pdf differ diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/chris-work-report-timer-2026-05-04.pdf b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/chris-work-report-timer-2026-05-04.pdf new file mode 100644 index 0000000..9e7bd41 Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/chris-work-report-timer-2026-05-04.pdf differ diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/chris-work-report-timer-2026-05-05.pdf b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/chris-work-report-timer-2026-05-05.pdf new file mode 100644 index 0000000..72c8c0b Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/chris-work-report-timer-2026-05-05.pdf differ diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/new-build-guide.pdf b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/new-build-guide.pdf new file mode 100644 index 0000000..f452d49 Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/new-build-guide.pdf differ diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/work-report-2026-04-20.pdf b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/work-report-2026-04-20.pdf new file mode 100644 index 0000000..0cbf020 Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/work-report-2026-04-20.pdf differ diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/work-report-2026-04-21-to-22.pdf b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/work-report-2026-04-21-to-22.pdf new file mode 100644 index 0000000..16e998f Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/work-report-2026-04-21-to-22.pdf differ diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/work-report-2026-04-22-progess-bars.pdf b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/work-report-2026-04-22-progess-bars.pdf new file mode 100644 index 0000000..99a036d Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/work-report-2026-04-22-progess-bars.pdf differ diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/work-report-2026-04-22.pdf b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/work-report-2026-04-22.pdf new file mode 100644 index 0000000..b3531cc Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/work-report-2026-04-22.pdf differ diff --git a/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/work-report-2026-04-24-to-25.pdf b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/work-report-2026-04-24-to-25.pdf new file mode 100644 index 0000000..c0f7c5d Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/Appendices/notes/pdf verisons/work-report-2026-04-24-to-25.pdf differ diff --git a/AppDev/ikt205_2026_18_study_sprint/README.md b/AppDev/ikt205_2026_18_study_sprint/README.md new file mode 100644 index 0000000..3f64a13 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/README.md @@ -0,0 +1,23 @@ +# Study Sprint Delivery + +This delivery folder contains the final Study Sprint apk file, report, project vision, source code, demo video, and supporting appendices. + +## Examiner Login Credentials + +We have included `Appendices/examinerCredentials.txt` so the examiner can log in to the app without needing to register and confirm new accounts manually. + +The file contains credentials for two prepared users: + +- **Populated user**: an account with existing subjects, assignments, tasks, completed sprint sessions, and history. This lets the examiner quickly inspect how the app looks and behaves when it has already been used for study planning and focus sessions. +- **Fresh user**: a newly created account with only email confirmation completed. This lets the examiner inspect the first-time user experience without going through registration or email confirmation. + +These accounts are included to make assessment faster and more reliable. The examiner can test both the empty starting state and a realistic in-use state of the application. + +## Included Files + +- `studysprint.apk`: Android application package. +- `report.pdf`: final project report. +- `projectVision.pdf`: project vision document. +- `source/`: application source code. +- `Appendices/`: appendix material including examiner credentials, work notes and commit history. +- `video.mp4`: Demo video of the app and its functions. diff --git a/AppDev/ikt205_2026_18_study_sprint/README.pdf b/AppDev/ikt205_2026_18_study_sprint/README.pdf new file mode 100644 index 0000000..766f0e5 Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/README.pdf differ diff --git a/AppDev/ikt205_2026_18_study_sprint/pdf/projectVision.pdf b/AppDev/ikt205_2026_18_study_sprint/pdf/projectVision.pdf new file mode 100644 index 0000000..b9c0369 Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/pdf/projectVision.pdf differ diff --git a/AppDev/ikt205_2026_18_study_sprint/pdf/report.pdf b/AppDev/ikt205_2026_18_study_sprint/pdf/report.pdf new file mode 100644 index 0000000..0f32fa2 Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/pdf/report.pdf differ diff --git a/AppDev/ikt205_2026_18_study_sprint/projectVision.pdf b/AppDev/ikt205_2026_18_study_sprint/projectVision.pdf new file mode 100644 index 0000000..b9c0369 Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/projectVision.pdf differ diff --git a/AppDev/ikt205_2026_18_study_sprint/report.pdf b/AppDev/ikt205_2026_18_study_sprint/report.pdf new file mode 100644 index 0000000..0f32fa2 Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/report.pdf differ diff --git a/AppDev/ikt205_2026_18_study_sprint/source/.gitignore b/AppDev/ikt205_2026_18_study_sprint/source/.gitignore new file mode 100644 index 0000000..c9e4ffb --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/.gitignore @@ -0,0 +1,196 @@ +# --------------------------- +# Node / Expo / React Native +# --------------------------- +node_modules/ +.expo/ +dist/ +web-build/ +expo-env.d.ts +.metro-health-check* +*.tsbuildinfo + +# Local env files +.env*.local +.env + +# Logs +*.log +npm-debug.* +yarn-debug.* +yarn-error.* + +# macOS +.DS_Store + +# --------------------------- +# Android / React Native native +# Keep /android and /ios ONLY if you commit native code +# Remove these two lines if you want generated native folders ignored +# --------------------------- +.gradle/ +build/ +local.properties +captures/ +.externalNativeBuild/ +.cxx/ +*.aab +*.apk +output-metadata.json +*.hprof +.kotlin/ + +# --------------------------- +# IntelliJ / Android Studio / VS Code +# --------------------------- +*.iml +.idea/ +.vscode/ +misc.xml +deploymentTargetDropDown.xml +render.experimental.xml + +# --------------------------- +# Secrets / signing / platform keys +# --------------------------- +*.jks +*.keystore +*.p8 +*.p12 +*.key +*.pem +*.mobileprovision +google-services.json + +# --------------------------- +# iOS / Android generated native folders +# Ignore these only for Expo managed/prebuild workflow +# Comment them out if you keep native code in repo +# --------------------------- +/android +/ios + +# --------------------------- +# .NET / ASP.NET Core Web API +# --------------------------- +**/bin/ +**/obj/ +**/.vs/ +*.user +*.rsuser +*.suo + +# App settings / local secrets +**/appsettings.Development.json +**/secrets.json + +# EF Core / local DB artifacts +*.db +*.db-shm +*.db-wal +*.sqlite +*.sqlite3 + +# --------------------------- +# Misc +# --------------------------- +*.orig.* +app-example + +# --------------------------- +# Node / Expo / React Native +# --------------------------- +node_modules/ +.expo/ +dist/ +web-build/ +expo-env.d.ts +.metro-health-check* +*.tsbuildinfo + +# Local env files +.env*.local +.env + +# Logs +*.log +npm-debug.* +yarn-debug.* +yarn-error.* + +# macOS +.DS_Store + +# --------------------------- +# Android / React Native native +# Keep /android and /ios ONLY if you commit native code +# Remove these two lines if you want generated native folders ignored +# --------------------------- +.gradle/ +build/ +local.properties +captures/ +.externalNativeBuild/ +.cxx/ +*.aab +*.apk +output-metadata.json +*.hprof +.kotlin/ + +# --------------------------- +# IntelliJ / Android Studio / VS Code +# --------------------------- +*.iml +.idea/ +.vscode/ +misc.xml +deploymentTargetDropDown.xml +render.experimental.xml + +# --------------------------- +# Secrets / signing / platform keys +# --------------------------- +*.jks +*.keystore +*.p8 +*.p12 +*.key +*.pem +*.mobileprovision +google-services.json + +# --------------------------- +# iOS / Android generated native folders +# Ignore these only for Expo managed/prebuild workflow +# Comment them out if you keep native code in repo +# --------------------------- +/android +/ios + +# --------------------------- +# .NET / ASP.NET Core Web API +# --------------------------- +**/bin/ +**/obj/ +**/.vs/ +*.user +*.rsuser +*.suo + +# App settings / local secrets +**/appsettings.Development.json +**/secrets.json + +# EF Core / local DB artifacts +*.db +*.db-shm +*.db-wal +*.sqlite +*.sqlite3 + +# --------------------------- +# Misc +# --------------------------- +*.orig.* +app-example +newDeps/ \ No newline at end of file diff --git a/AppDev/ikt205_2026_18_study_sprint/source/README.md b/AppDev/ikt205_2026_18_study_sprint/source/README.md new file mode 100644 index 0000000..6031dc3 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/README.md @@ -0,0 +1,105 @@ +# Study Sprint + +Study Sprint is a React Native mobile application built with Expo Router. The app helps students organize study work into subjects, assignments, tasks, and timed focus sessions. Users can create an account, structure their course work, start study sprints from individual tasks, take breaks between sessions, and follow progress from the dashboard. + +The application uses Supabase for authentication and persistent data, while Expo/React Native handles the mobile client, navigation, notifications, and local session state. + +## Main Features + +- Email/password sign up and login with Supabase Auth. +- Subject, assignment, and task management. +- Task-based sprint timer with focus sessions and breaks. +- Dashboard for current progress, active sprint state, and upcoming work. +- Local persistence for active session state. +- Jest tests for route guarding and CRUD behavior around subjects, assignments, and tasks. + +## Tech Stack + +- Expo SDK 54 +- React Native 0.81 +- Expo Router +- TypeScript +- Supabase +- NativeWind / Tailwind CSS +- Jest with `jest-expo` + +## Requirements + +Install these before running the project locally: + +- Node.js 20.19.4 or newer +- npm +- Android Studio with an Android emulator, or a physical Android device with USB debugging +- Expo CLI through `npx expo` + +## Install Dependencies + +From the project root: + +```bash +npm install +``` + +The project uses `patch-package`, so `npm install` also applies the local patch in `patches/`. + +## Run Locally With Expo + +Start the Expo development server: + +```bash +npx expo start +``` + +Then choose one of the Expo options: + +- Press `a` to open the app in an Android emulator. +- Scan the QR code with Expo Go on a physical device. +- Press `w` to run the web version for quick UI checks. + +The Android emulator should already be running before pressing `a`. + +## Test and Quality Checks + +Run the Jest test suite: + +```bash +npm test +``` + +Run Expo linting: + +```bash +npm run lint +``` + +Run TypeScript checking: + +```bash +npx tsc --noEmit +``` + +These commands are the expected local checks before delivery. + +## Project Structure + +```text +app/ Expo Router screens and navigation layouts +components/ Shared UI components +constants/ Shared styling and theme constants +hooks/ Shared React hooks +lib/ Supabase client, session lifecycle, progress, storage, and utilities +__tests__/ Jest test files +assets/ App icons, splash assets, and images +patches/ patch-package fixes applied after install +``` + +## Delivery Notes + +For local assessment, the recommended flow is: + +1. Add the required Supabase environment variables. +2. Run `npm install`. +3. Run `npm test`, `npm run lint`, and `npx tsc --noEmit`. +4. Start the app with `npx expo start` and pressing `a` to open the app with your Android Emulator. + +The app is configured as an Expo managed project with generated native folders ignored, so Android/iOS native folders do not need to be committed for normal Expo development. diff --git a/AppDev/ikt205_2026_18_study_sprint/source/Study-Sprint.sln b/AppDev/ikt205_2026_18_study_sprint/source/Study-Sprint.sln new file mode 100644 index 0000000..9a7956d --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/Study-Sprint.sln @@ -0,0 +1,29 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.2.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "backend", "backend", "{1AE8ACA6-933B-BF2A-3671-3E2EAC007D16}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "study-sprint-api", "backend\study-sprint-api\study-sprint-api.csproj", "{1003D4A4-D46B-F75C-EC68-321C2ED62795}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1003D4A4-D46B-F75C-EC68-321C2ED62795}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1003D4A4-D46B-F75C-EC68-321C2ED62795}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1003D4A4-D46B-F75C-EC68-321C2ED62795}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1003D4A4-D46B-F75C-EC68-321C2ED62795}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {1003D4A4-D46B-F75C-EC68-321C2ED62795} = {1AE8ACA6-933B-BF2A-3671-3E2EAC007D16} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {2870106D-D84D-4FC9-A7C9-41F972CCDF07} + EndGlobalSection +EndGlobal diff --git a/AppDev/ikt205_2026_18_study_sprint/source/__tests__/assignment/createAssignment.test.tsx b/AppDev/ikt205_2026_18_study_sprint/source/__tests__/assignment/createAssignment.test.tsx new file mode 100644 index 0000000..71ea709 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/__tests__/assignment/createAssignment.test.tsx @@ -0,0 +1,79 @@ +import UpsertAssignment from "@/app/assignment/upsertAssignment"; +import { supabase } from "@/lib/supabase"; +import { fireEvent, render, waitFor } from "@testing-library/react-native"; +import { router } from "expo-router"; + +const mockSingle = jest.fn(); +const mockSelect = jest.fn(() => ({ single: mockSingle, })); +const mockInsert = jest.fn(() => ({ select: mockSelect, })); + +jest.mock("expo-router", () => ({ + router: { + back: jest.fn(), + replace: jest.fn(), + }, + Stack: { + Screen: () => null, + }, + useLocalSearchParams: () => ({ + sId: "subject-123", + }), +})); + +jest.mock("@/lib/asyncStorage", () => ({ + GetAssignmentNotificationId: jest.fn(() => Promise.resolve()), + SaveAssignmentNotificationId: jest.fn(() => Promise.resolve()), + RemoveAssignmentNotificationId: jest.fn(() => Promise.resolve()), +})); + +jest.mock("expo-notifications", () => ({ + scheduleNotificationAsync: jest.fn(() => Promise.resolve("notification-123")), + SchedulableTriggerInputTypes: { + DATE: "date", + }, +})); + +jest.mock("@/lib/supabase", () => ({ + supabase: { + auth: { + getUser: jest.fn(() => + Promise.resolve({ + data: { user: { id: "user-123" } }, + error: null, + }) + ), + }, + from: jest.fn(() => ({ + insert: mockInsert, + })), + }, +})); + +test("creates an assignment and navigates back", async () => { + mockSingle.mockResolvedValue({ + data: { + aId: "assignment-123", + title: "create a simple test", + uId: "user-123", + }, + error: null, + }); + + const screen = render(); + fireEvent.changeText(screen.getByTestId("assignment-title-input"), "create a simple test"); + fireEvent.press(screen.getByTestId("upsert-assignment-button")); + + await waitFor(() => { + expect(supabase.from).toHaveBeenCalledWith("assignments"); + expect(mockInsert).toHaveBeenCalledWith( + expect.objectContaining({ + title: "create a simple test", + uId: "user-123", + sId: "subject-123", + }) + ); + expect(mockSelect).toHaveBeenCalled(); + expect(mockSingle).toHaveBeenCalled(); + expect(router.back).toHaveBeenCalled(); + }); +}); diff --git a/AppDev/ikt205_2026_18_study_sprint/source/__tests__/assignment/deleteAssignment.test.tsx b/AppDev/ikt205_2026_18_study_sprint/source/__tests__/assignment/deleteAssignment.test.tsx new file mode 100644 index 0000000..44069d4 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/__tests__/assignment/deleteAssignment.test.tsx @@ -0,0 +1,141 @@ +import ViewDetailsAssignment from "@/app/assignment/viewDetailsAssignment"; +import { supabase } from "@/lib/supabase"; +import { fireEvent, render, waitFor } from "@testing-library/react-native"; +import { router } from "expo-router"; +import { Alert } from "react-native"; + +const mockAssignmentSingle = jest.fn(); +const mockAssignmentSelectEq = jest.fn(() => ({ single: mockAssignmentSingle, })); +const mockAssignmentSelect = jest.fn(() => ({ eq: mockAssignmentSelectEq, })); +const mockAssignmentDeleteEq = jest.fn(); +const mockAssignmentDelete = jest.fn(() => ({ eq: mockAssignmentDeleteEq, })); + +const mockTasksSelectEq = jest.fn(); +const mockTasksSelect = jest.fn(() => ({ eq: mockTasksSelectEq })); + +const mockSubjectSingle = jest.fn(); +const mockSubjectSelectEq = jest.fn(() => ({ single: mockSubjectSingle })); +const mockSubjectSelect = jest.fn(() => ({ eq: mockSubjectSelectEq })); + +jest.mock("expo-router", () => ({ + router: { + back: jest.fn(), + replace: jest.fn(), + }, + Stack: { + Screen: () => null, + }, + useLocalSearchParams: () => ({ + aId: "assignment-123", + }), + useFocusEffect: (callback: () => void) => { + const React = require("react"); + React.useEffect(callback, [callback]); + }, +})); + +jest.mock("@/lib/supabase", () => ({ + supabase: { + auth: { + getUser: jest.fn(() => + Promise.resolve({ + data: { user: { id: "user-123" } }, + error: null, + }) + ), + getSession: jest.fn(() => + Promise.resolve({ + data: { + session: { + user: { id: "user-123" }, + }, + }, + }) + ), + onAuthStateChange: jest.fn(() => ({ + data: { + subscription: { + unsubscribe: jest.fn(), + }, + }, + })), + }, + from: jest.fn((table: string) => { + if (table === "assignments") { + return { + select: mockAssignmentSelect, + delete: mockAssignmentDelete, + }; + } + + if (table === "tasks") { + return { + select: mockTasksSelect, + }; + } + + if (table === "subjects") { + return { + select: mockSubjectSelect, + }; + } + + return {}; + }), + }, +})); + +const alertSpy = jest.spyOn(Alert, "alert"); + +test("deletes an assignment and navigates back", async () => { + mockAssignmentSingle.mockResolvedValue({ + data: { + aId: "assignment-123", + title: "create a simple test", + uId: "user-123", + sId: "subject-123" + }, + error: null, + }); + mockTasksSelectEq.mockResolvedValue({ data: [], error: null, }) + mockSubjectSingle.mockResolvedValue({ + data: { + sId: "subject-123", + title: "ikt205g26v", + color: "blue", + }, + error: null, + }); + mockAssignmentDeleteEq.mockResolvedValue({ error: null, }); + + const screen = render(); + + await screen.findByText("create a simple test"); + await screen.findByText("ikt205g26v"); + + fireEvent.press(await screen.findByTestId("delete-assignment-button")); + + expect(alertSpy).toHaveBeenCalledWith( + "Delete Assignment", + "Are you sure you want to delete this assignment?", + expect.any(Array), + ); + + const alertButtons = alertSpy.mock.calls[0]?.[2]; + expect(alertButtons).toBeDefined(); + const confirmDeleteButton = alertButtons?.[1]; + expect(confirmDeleteButton?.onPress).toBeDefined(); + + if (!confirmDeleteButton?.onPress) { + throw new Error("Delete confirmation button missing"); + } + + await confirmDeleteButton.onPress(); + + await waitFor(() => { + expect(supabase.from).toHaveBeenCalledWith("assignments"); + expect(mockAssignmentDelete).toHaveBeenCalled(); + expect(mockAssignmentDeleteEq).toHaveBeenCalledWith("aId", "assignment-123"); + expect(router.back).toHaveBeenCalled(); + }); +}); diff --git a/AppDev/ikt205_2026_18_study_sprint/source/__tests__/assignment/editAssignment.test.tsx b/AppDev/ikt205_2026_18_study_sprint/source/__tests__/assignment/editAssignment.test.tsx new file mode 100644 index 0000000..3bc2ccf --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/__tests__/assignment/editAssignment.test.tsx @@ -0,0 +1,96 @@ +import UpsertAssignment from "@/app/assignment/upsertAssignment"; +import { supabase } from "@/lib/supabase"; +import { fireEvent, render, waitFor } from "@testing-library/react-native"; +import { router } from "expo-router"; + +const mockUpdateSingle = jest.fn(); +const mockUpdateSelect = jest.fn(() => ({ single: mockUpdateSingle, })); +const mockUpdateEq = jest.fn(() => ({ select: mockUpdateSelect, })); +const mockUpdate = jest.fn(() => ({ eq: mockUpdateEq, })); +const mockSingle = jest.fn(); +const mockSelectEq = jest.fn(() => ({ single: mockSingle, })); +const mockSelect = jest.fn(() => ({ eq: mockSelectEq, })); + +jest.mock("expo-router", () => ({ + router: { + back: jest.fn(), + replace: jest.fn(), + }, + Stack: { + Screen: () => null, + }, + useLocalSearchParams: () => ({ + aId: "assignment-123", + sId: "subject-123", + }), + useFocusEffect: (callback: () => void) => callback(), +})); + +jest.mock("@/lib/asyncStorage", () => ({ + GetAssignmentNotificationId: jest.fn(() => Promise.resolve(null)), + SaveAssignmentNotificationId: jest.fn(() => Promise.resolve()), + RemoveAssignmentNotificationId: jest.fn(() => Promise.resolve()), +})); + +jest.mock("expo-notifications", () => ({ + scheduleNotificationAsync: jest.fn(() => Promise.resolve("notification-123")), + SchedulableTriggerInputTypes: { + DATE: "date", + }, +})); + +jest.mock("@/lib/supabase", () => ({ + supabase: { + auth: { + getUser: jest.fn(() => + Promise.resolve({ + data: { user: { id: "user-123" } }, + error: null, + }) + ), + }, + from: jest.fn(() => ({ + select: mockSelect, + update: mockUpdate, + })), + }, +})); + +test("updates an assignment and navigates back", async () => { + mockSingle.mockResolvedValue({ + data: { + aId: "assignment-123", + title: "create a simple test", + uId: "user-123", + sId: "subject-123", + }, + error: null, + }); + mockUpdateSingle.mockResolvedValue({ + data: { + aId: "assignment-123", + title: "create a harder test", + uId: "user-123", + }, + error: null, + }); + + const screen = render(); + fireEvent.changeText(await screen.findByTestId("assignment-title-input"), "create a harder test"); + fireEvent.press(screen.getByTestId("upsert-assignment-button")); + + await waitFor(() => { + expect(supabase.from).toHaveBeenCalledWith("assignments"); + expect(mockSelect).toHaveBeenCalled(); + expect(mockUpdate).toHaveBeenCalledWith( + expect.objectContaining({ + title: "create a harder test", + uId: "user-123", + sId: "subject-123", + }) + ); + expect(mockUpdateEq).toHaveBeenCalledWith("aId", "assignment-123"); + expect(mockUpdateSingle).toHaveBeenCalled(); + expect(router.back).toHaveBeenCalled(); + }); +}); diff --git a/AppDev/ikt205_2026_18_study_sprint/source/__tests__/authGuard.test.tsx b/AppDev/ikt205_2026_18_study_sprint/source/__tests__/authGuard.test.tsx new file mode 100644 index 0000000..4738b5c --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/__tests__/authGuard.test.tsx @@ -0,0 +1,92 @@ +import TabLayout from "@/app/(tabs)/_layout"; +import { getSetupStatus } from "@/lib/setupStatus"; +import { supabase } from "@/lib/supabase"; +import { render, waitFor } from "@testing-library/react-native"; + +jest.mock("expo-router", () => { + const React = require("react"); + const { Text, View } = require("react-native"); + + const MockTabs = ({ children }: { children?: React.ReactNode }) => ( + + tabs + {children} + + ); + + MockTabs.Screen = () => null; + + return { + Redirect: ({ href }: { href: string }) => redirect:{href}, + Tabs: MockTabs, + router: { + push: jest.fn(), + }, + }; +}); + +jest.mock("expo-notifications", () => ({ + getLastNotificationResponse: jest.fn(() => null), + addNotificationResponseReceivedListener: jest.fn(() => ({ + remove: jest.fn(), + })), +})); + +jest.mock("@/lib/setupStatus", () => ({ + getSetupStatus: jest.fn(), +})); + +jest.mock("@/lib/supabase", () => ({ + supabase: { + auth: { + getSession: jest.fn(), + onAuthStateChange: jest.fn(() => ({ + data: { + subscription: { + unsubscribe: jest.fn(), + }, + }, + })), + }, + }, +})); + +beforeEach(() => { + jest.clearAllMocks(); + (getSetupStatus as jest.Mock).mockResolvedValue({ + subjectId: "subject-123", + assignmentId: "assignment-123", + taskId: "task-123", + completedFocusSessions: 1, + currentStep: "sprint", + isSetupComplete: true, + }); +}); + +test("redirects to login if there is no session", async () => { + (supabase.auth.getSession as jest.Mock).mockResolvedValue({ + data: { session: null }, + }); + + const screen = render(); + + await waitFor(() => { + expect(screen.getByText("redirect:/login")).toBeTruthy(); + }); +}); + +test("renders tabs when session exists", async () => { + (supabase.auth.getSession as jest.Mock).mockResolvedValue({ + data: { + session: { + user: { id: "user-123" }, + }, + }, + }); + + const screen = render(); + + await waitFor(() => { + expect(screen.getByText("tabs")).toBeTruthy(); + }); +}); diff --git a/AppDev/ikt205_2026_18_study_sprint/source/__tests__/subject/createSubject.test.tsx b/AppDev/ikt205_2026_18_study_sprint/source/__tests__/subject/createSubject.test.tsx new file mode 100644 index 0000000..22d1d47 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/__tests__/subject/createSubject.test.tsx @@ -0,0 +1,63 @@ +import UpsertSubject from "@/app/subject/upsertSubject"; +import { supabase } from "@/lib/supabase"; +import { fireEvent, render, waitFor } from "@testing-library/react-native"; +import { router } from "expo-router"; + +const mockSingle = jest.fn(); +const mockSelect = jest.fn(() => ({ single: mockSingle })); +const mockInsert = jest.fn(() => ({ select: mockSelect })); + +jest.mock("expo-router", () => ({ + router: { + back: jest.fn(), + replace: jest.fn(), + }, + Stack: { + Screen: () => null, + }, + useLocalSearchParams: () => ({}), +})); + +jest.mock("@/lib/supabase", () => ({ + supabase: { + auth: { + getUser: jest.fn(() => + Promise.resolve({ + data: { user: { id: "user-123" } }, + error: null, + }) + ), + }, + from: jest.fn(() => ({ + insert: mockInsert, + })), + }, +})); + +test("creates a subject and navigates back", async () => { + mockSingle.mockResolvedValue({ + data: { + sId: "subject-123", + title: "ikt205g26v", + uId: "user-123", + }, + error: null, + }); + + const screen = render(); + fireEvent.changeText(screen.getByTestId("subject-title-input"), "ikt205g26v"); + fireEvent.press(screen.getByTestId("upsert-subject-button")); + + await waitFor(() => { + expect(supabase.from).toHaveBeenCalledWith("subjects"); + expect(mockInsert).toHaveBeenCalledWith( + expect.objectContaining({ + title: "ikt205g26v", + uId: "user-123", + }) + ); + expect(mockSelect).toHaveBeenCalled(); + expect(mockSingle).toHaveBeenCalled(); + expect(router.back).toHaveBeenCalled(); + }); +}); diff --git a/AppDev/ikt205_2026_18_study_sprint/source/__tests__/subject/deleteSubject.test.tsx b/AppDev/ikt205_2026_18_study_sprint/source/__tests__/subject/deleteSubject.test.tsx new file mode 100644 index 0000000..909a44b --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/__tests__/subject/deleteSubject.test.tsx @@ -0,0 +1,122 @@ +import ViewDetailsSubject from "@/app/subject/viewDetailsSubject"; +import { supabase } from "@/lib/supabase"; +import { fireEvent, render, waitFor } from "@testing-library/react-native"; +import { router } from "expo-router"; +import { Alert } from "react-native"; + +const mockSubjectSingle = jest.fn(); +const mockSubjectSelectEq = jest.fn(() => ({ single: mockSubjectSingle })); +const mockSubjectSelect = jest.fn(() => ({ eq: mockSubjectSelectEq })); +const mockSubjectDeleteEq = jest.fn(); +const mockSubjectDelete = jest.fn(() => ({ eq: mockSubjectDeleteEq })); + +const mockAssignmentsOrder = jest.fn(); +const mockAssignmentsEq = jest.fn(() => ({ order: mockAssignmentsOrder })); +const mockAssignmentsSelect = jest.fn(() => ({ eq: mockAssignmentsEq })); + +jest.mock("expo-router", () => ({ + router: { + back: jest.fn(), + replace: jest.fn(), + }, + Stack: { + Screen: () => null, + }, + useLocalSearchParams: () => ({ + sId: "subject-123", + }), + useFocusEffect: (callback: () => void) => { + const React = require("react"); + React.useEffect(callback, [callback]); + }, +})); + +jest.mock("@/lib/supabase", () => ({ + supabase: { + auth: { + getUser: jest.fn(() => + Promise.resolve({ + data: { user: { id: "user-123" } }, + error: null, + }) + ), + getSession: jest.fn(() => + Promise.resolve({ + data: { + session: { + user: { id: "user-123" }, + }, + }, + }) + ), + onAuthStateChange: jest.fn(() => ({ + data: { + subscription: { + unsubscribe: jest.fn(), + }, + }, + })), + }, + from: jest.fn((table) => { + if (table === "subjects") { + return { + select: mockSubjectSelect, + delete: mockSubjectDelete, + }; + } + + if (table === "assignments") { + return { + select: mockAssignmentsSelect, + }; + } + + return {}; + }), + }, +})); + +const alertSpy = jest.spyOn(Alert, "alert"); + +test("deletes a subject and navigates back", async () => { + mockSubjectSingle.mockResolvedValue({ + data: { + sId: "subject-123", + title: "ikt205g26v", + uId: "user-123", + }, + error: null, + }); + mockAssignmentsOrder.mockResolvedValue({ data: [], error: null, }) + mockSubjectDeleteEq.mockResolvedValue({ error: null, }); + + const screen = render(); + + await screen.findByText("ikt205g26v"); + + fireEvent.press(await screen.findByTestId("delete-subject-button")); + + expect(alertSpy).toHaveBeenCalledWith( + "Delete Subject", + "Are you sure you want to delete this subject?", + expect.any(Array), + ); + + const alertButtons = alertSpy.mock.calls[0]?.[2]; + expect(alertButtons).toBeDefined(); + const confirmDeleteButton = alertButtons?.[1]; + expect(confirmDeleteButton?.onPress).toBeDefined(); + + if (!confirmDeleteButton?.onPress) { + throw new Error("Delete confirmation button missing"); + } + + await confirmDeleteButton.onPress(); + + await waitFor(() => { + expect(supabase.from).toHaveBeenCalledWith("subjects"); + expect(mockSubjectDelete).toHaveBeenCalled(); + expect(mockSubjectDeleteEq).toHaveBeenCalledWith("sId", "subject-123"); + expect(router.back).toHaveBeenCalled(); + }); +}); diff --git a/AppDev/ikt205_2026_18_study_sprint/source/__tests__/subject/editSubject.test.tsx b/AppDev/ikt205_2026_18_study_sprint/source/__tests__/subject/editSubject.test.tsx new file mode 100644 index 0000000..cac538c --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/__tests__/subject/editSubject.test.tsx @@ -0,0 +1,70 @@ +import UpsertSubject from "@/app/subject/upsertSubject"; +import { supabase } from "@/lib/supabase"; +import { fireEvent, render, waitFor } from "@testing-library/react-native"; +import { router } from "expo-router"; + +const mockUpdateEq = jest.fn(); +const mockUpdate = jest.fn(() => ({ eq: mockUpdateEq, })); +const mockSingle = jest.fn(); +const mockSelectEq = jest.fn(() => ({ single: mockSingle, })); +const mockSelect = jest.fn(() => ({ eq: mockSelectEq, })); + +jest.mock("expo-router", () => ({ + router: { + back: jest.fn(), + replace: jest.fn(), + }, + Stack: { + Screen: () => null, + }, + useLocalSearchParams: () => ({ + sId: "subject-123", + }), + useFocusEffect: (callback: () => void) => callback(), +})); + +jest.mock("@/lib/supabase", () => ({ + supabase: { + auth: { + getUser: jest.fn(() => + Promise.resolve({ + data: { user: { id: "user-123" } }, + error: null, + }) + ), + }, + from: jest.fn(() => ({ + select: mockSelect, + update: mockUpdate, + })), + }, +})); + +test("updates a subject and navigates back", async () => { + mockSingle.mockResolvedValue({ + data: { + sId: "subject-123", + title: "ikt205g26v", + uId: "user-123", + }, + error: null, + }); + mockUpdateEq.mockResolvedValue({ error: null, }); + + const screen = render(); + fireEvent.changeText(await screen.findByTestId("subject-title-input"), "ikt206g26v"); + fireEvent.press(screen.getByTestId("upsert-subject-button")); + + await waitFor(() => { + expect(supabase.from).toHaveBeenCalledWith("subjects"); + expect(mockSelect).toHaveBeenCalled(); + expect(mockUpdate).toHaveBeenCalledWith( + expect.objectContaining({ + title: "ikt206g26v", + uId: "user-123", + }) + ); + expect(mockUpdateEq).toHaveBeenCalledWith("sId", "subject-123"); + expect(router.back).toHaveBeenCalled(); + }); +}); \ No newline at end of file diff --git a/AppDev/ikt205_2026_18_study_sprint/source/__tests__/task/createTask.test.tsx b/AppDev/ikt205_2026_18_study_sprint/source/__tests__/task/createTask.test.tsx new file mode 100644 index 0000000..f75f111 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/__tests__/task/createTask.test.tsx @@ -0,0 +1,73 @@ +import UpsertTask from "@/app/task/upsertTask"; +import { CheckAssignmentCompletion } from "@/lib/progress"; +import { supabase } from "@/lib/supabase"; +import { fireEvent, render, waitFor } from "@testing-library/react-native"; +import { router } from "expo-router"; + +const mockSingle = jest.fn(); +const mockSelect = jest.fn(() => ({ single: mockSingle })); +const mockInsert = jest.fn(() => ({ select: mockSelect })); + +jest.mock("expo-router", () => ({ + router: { + back: jest.fn(), + replace: jest.fn(), + }, + Stack: { + Screen: () => null, + }, + useLocalSearchParams: () => ({ + aId: "assignment-123", + }), +})); + +jest.mock("@/lib/progress", () => ({ + CheckAssignmentCompletion: jest.fn(() => Promise.resolve()), +})); + +jest.mock("@/lib/supabase", () => ({ + supabase: { + auth: { + getUser: jest.fn(() => + Promise.resolve({ + data: { user: { id: "user-123" } }, + error: null, + }) + ), + }, + from: jest.fn(() => ({ + insert: mockInsert, + })), + }, +})); + +test("creates a task and navigates back", async () => { + mockSingle.mockResolvedValue({ + data: { + tId: "task-123", + title: "Read chapter 4", + uId: "user-123", + aId: "assignment-123", + }, + error: null, + }); + + const screen = render(); + fireEvent.changeText(screen.getByTestId("task-title-input"), "Read chapter 4"); + fireEvent.press(screen.getByTestId("upsert-task-button")); + + await waitFor(() => { + expect(supabase.from).toHaveBeenCalledWith("tasks"); + expect(mockInsert).toHaveBeenCalledWith( + expect.objectContaining({ + title: "Read chapter 4", + uId: "user-123", + aId: "assignment-123", + }) + ); + expect(mockSelect).toHaveBeenCalled(); + expect(mockSingle).toHaveBeenCalled(); + expect(CheckAssignmentCompletion).toHaveBeenCalledWith("assignment-123"); + expect(router.back).toHaveBeenCalled(); + }); +}); diff --git a/AppDev/ikt205_2026_18_study_sprint/source/__tests__/task/deleteTask.test.tsx b/AppDev/ikt205_2026_18_study_sprint/source/__tests__/task/deleteTask.test.tsx new file mode 100644 index 0000000..caac2bc --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/__tests__/task/deleteTask.test.tsx @@ -0,0 +1,169 @@ +import ViewDetailsTask from "@/app/task/viewDetailsTask"; +import { CheckAssignmentCompletion } from "@/lib/progress"; +import { supabase } from "@/lib/supabase"; +import { fireEvent, render, waitFor } from "@testing-library/react-native"; +import { router } from "expo-router"; +import { Alert } from "react-native"; + +const mockTaskSingle = jest.fn(); +const mockTaskSelectEq = jest.fn(() => ({ single: mockTaskSingle })); +const mockTaskSelect = jest.fn(() => ({ eq: mockTaskSelectEq })); +const mockTaskDeleteEq = jest.fn(); +const mockTaskDelete = jest.fn(() => ({ eq: mockTaskDeleteEq })); + +const mockAssignmentSingle = jest.fn(); +const mockAssignmentSelectEq = jest.fn(() => ({ single: mockAssignmentSingle })); +const mockAssignmentSelect = jest.fn(() => ({ eq: mockAssignmentSelectEq })); + +const mockSubjectSingle = jest.fn(); +const mockSubjectSelectEq = jest.fn(() => ({ single: mockSubjectSingle })); +const mockSubjectSelect = jest.fn(() => ({ eq: mockSubjectSelectEq })); + +const mockSprintSessionsEqCompleted = jest.fn(); +const mockSprintSessionsEqSessionType = jest.fn(() => ({ eq: mockSprintSessionsEqCompleted })); +const mockSprintSessionsEqUser = jest.fn(() => ({ eq: mockSprintSessionsEqSessionType })); +const mockSprintSessionsEqTask = jest.fn(() => ({ eq: mockSprintSessionsEqUser })); +const mockSprintSessionsSelect = jest.fn(() => ({ eq: mockSprintSessionsEqTask })); + +jest.mock("expo-router", () => ({ + router: { + back: jest.fn(), + replace: jest.fn(), + }, + Stack: { + Screen: () => null, + }, + useLocalSearchParams: () => ({ + tId: "task-123", + }), + useFocusEffect: (callback: () => void) => { + const React = require("react"); + React.useEffect(callback, [callback]); + }, +})); + +jest.mock("@/lib/progress", () => ({ + CheckAssignmentCompletion: jest.fn(() => Promise.resolve()), +})); + +jest.mock("@/lib/supabase", () => ({ + supabase: { + auth: { + getUser: jest.fn(() => + Promise.resolve({ + data: { user: { id: "user-123" } }, + error: null, + }) + ), + getSession: jest.fn(() => + Promise.resolve({ + data: { + session: { + user: { id: "user-123" }, + }, + }, + }) + ), + onAuthStateChange: jest.fn(() => ({ + data: { + subscription: { + unsubscribe: jest.fn(), + }, + }, + })), + }, + from: jest.fn((table: string) => { + if (table === "tasks") { + return { + select: mockTaskSelect, + delete: mockTaskDelete, + }; + } + + if (table === "assignments") { + return { + select: mockAssignmentSelect, + }; + } + + if (table === "subjects") { + return { + select: mockSubjectSelect, + }; + } + + if (table === "sprint_sessions") { + return { + select: mockSprintSessionsSelect, + }; + } + + return {}; + }), + }, +})); + +const alertSpy = jest.spyOn(Alert, "alert"); + +test("deletes a task and navigates back", async () => { + mockTaskSingle.mockResolvedValue({ + data: { + tId: "task-123", + title: "Read chapter 4", + uId: "user-123", + aId: "assignment-123", + }, + error: null, + }); + mockAssignmentSingle.mockResolvedValue({ + data: { + aId: "assignment-123", + title: "create a simple test", + uId: "user-123", + sId: "subject-123", + }, + error: null, + }); + mockSubjectSingle.mockResolvedValue({ + data: { + sId: "subject-123", + title: "ikt205g26v", + color: "blue", + }, + error: null, + }); + mockSprintSessionsEqCompleted.mockResolvedValue({ count: 0, error: null }); + mockTaskDeleteEq.mockResolvedValue({ error: null, }); + + const screen = render(); + + await screen.findByText("Read chapter 4"); + await screen.findByText("ikt205g26v"); + + fireEvent.press(await screen.findByText("Delete")); + + expect(alertSpy).toHaveBeenCalledWith( + "Delete Task", + "Are you sure you want to delete this task?", + expect.any(Array), + ); + + const alertButtons = alertSpy.mock.calls[0]?.[2]; + expect(alertButtons).toBeDefined(); + const confirmDeleteButton = alertButtons?.[1]; + expect(confirmDeleteButton?.onPress).toBeDefined(); + + if (!confirmDeleteButton?.onPress) { + throw new Error("Delete confirmation button missing"); + } + + await confirmDeleteButton.onPress(); + + await waitFor(() => { + expect(supabase.from).toHaveBeenCalledWith("tasks"); + expect(mockTaskDelete).toHaveBeenCalled(); + expect(mockTaskDeleteEq).toHaveBeenCalledWith("tId", "task-123"); + expect(CheckAssignmentCompletion).toHaveBeenCalledWith("assignment-123"); + expect(router.back).toHaveBeenCalled(); + }); +}); diff --git a/AppDev/ikt205_2026_18_study_sprint/source/__tests__/task/editTask.test.tsx b/AppDev/ikt205_2026_18_study_sprint/source/__tests__/task/editTask.test.tsx new file mode 100644 index 0000000..24fe7cc --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/__tests__/task/editTask.test.tsx @@ -0,0 +1,78 @@ +import UpsertTask from "@/app/task/upsertTask"; +import { CheckAssignmentCompletion } from "@/lib/progress"; +import { supabase } from "@/lib/supabase"; +import { fireEvent, render, waitFor } from "@testing-library/react-native"; +import { router } from "expo-router"; + +const mockUpdateEq = jest.fn(); +const mockUpdate = jest.fn(() => ({ eq: mockUpdateEq, })); +const mockSingle = jest.fn(); +const mockSelectEq = jest.fn(() => ({ single: mockSingle, })); +const mockSelect = jest.fn(() => ({ eq: mockSelectEq, })); + +jest.mock("expo-router", () => ({ + router: { + back: jest.fn(), + replace: jest.fn(), + }, + Stack: { + Screen: () => null, + }, + useLocalSearchParams: () => ({ + tId: "task-123", + }), + useFocusEffect: (callback: () => void) => callback(), +})); + +jest.mock("@/lib/progress", () => ({ + CheckAssignmentCompletion: jest.fn(() => Promise.resolve()), +})); + +jest.mock("@/lib/supabase", () => ({ + supabase: { + auth: { + getUser: jest.fn(() => + Promise.resolve({ + data: { user: { id: "user-123" } }, + error: null, + }) + ), + }, + from: jest.fn(() => ({ + select: mockSelect, + update: mockUpdate, + })), + }, +})); + +test("updates a task and navigates back", async () => { + mockSingle.mockResolvedValue({ + data: { + tId: "task-123", + title: "Read chapter 4", + uId: "user-123", + aId: "assignment-123", + }, + error: null, + }); + mockUpdateEq.mockResolvedValue({ error: null, }); + + const screen = render(); + fireEvent.changeText(await screen.findByTestId("task-title-input"), "Read chapter 5"); + fireEvent.press(screen.getByTestId("upsert-task-button")); + + await waitFor(() => { + expect(supabase.from).toHaveBeenCalledWith("tasks"); + expect(mockSelect).toHaveBeenCalled(); + expect(mockUpdate).toHaveBeenCalledWith( + expect.objectContaining({ + title: "Read chapter 5", + uId: "user-123", + aId: "assignment-123", + }) + ); + expect(mockUpdateEq).toHaveBeenCalledWith("tId", "task-123"); + expect(CheckAssignmentCompletion).toHaveBeenCalledWith("assignment-123"); + expect(router.back).toHaveBeenCalled(); + }); +}); \ No newline at end of file diff --git a/AppDev/ikt205_2026_18_study_sprint/source/app.json b/AppDev/ikt205_2026_18_study_sprint/source/app.json new file mode 100644 index 0000000..8097615 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/app.json @@ -0,0 +1,57 @@ +{ + "expo": { + "name": "Study Sprint", + "slug": "Study-Sprint", + "owner": "ikt205g26v-g18", + "version": "1.0.0", + "orientation": "portrait", + "icon": "./assets/images/icon.png", + "scheme": "studysprint", + "userInterfaceStyle": "automatic", + "newArchEnabled": true, + "ios": { + "supportsTablet": true + }, + "android": { + "adaptiveIcon": { + "backgroundColor": "#E6F4FE", + "foregroundImage": "./assets/images/android-icon-foreground.png", + "backgroundImage": "./assets/images/android-icon-background.png", + "monochromeImage": "./assets/images/android-icon-monochrome.png" + }, + "edgeToEdgeEnabled": true, + "predictiveBackGestureEnabled": false, + "package": "com.softsand.studysprint" + }, + "web": { + "output": "static", + "favicon": "./assets/images/favicon.png" + }, + "plugins": [ + "expo-router", + [ + "expo-splash-screen", + { + "image": "./assets/images/splash-icon.png", + "imageWidth": 200, + "resizeMode": "contain", + "backgroundColor": "#ffffff", + "dark": { + "backgroundColor": "#000000" + } + } + ], + "expo-secure-store" + ], + "experiments": { + "typedRoutes": true, + "reactCompiler": true + }, + "extra": { + "router": {}, + "eas": { + "projectId": "2b2ec99b-a2ea-4991-8694-93f9e3d042a3" + } + } + } +} diff --git a/AppDev/ikt205_2026_18_study_sprint/source/app/(tabs)/_layout.tsx b/AppDev/ikt205_2026_18_study_sprint/source/app/(tabs)/_layout.tsx new file mode 100644 index 0000000..0662b8e --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/app/(tabs)/_layout.tsx @@ -0,0 +1,118 @@ +import { getSetupStatus } from "@/lib/setupStatus"; +import { supabase } from "@/lib/supabase"; +import MaterialIcons from "@expo/vector-icons/MaterialIcons"; +import { Session } from "@supabase/supabase-js"; +import * as Notifications from 'expo-notifications'; +import { Redirect, router, Tabs } from "expo-router"; +import { useEffect, useState } from "react"; + +function UseNotificationObserver() { + useEffect(() => { + function redirect(notification: Notifications.Notification) { + const aId = notification.request.content.data?.aId; + + if (typeof aId === 'string') { + router.push({pathname: "/assignment/viewDetailsAssignment", params: { aId }}); + } + } + + const response = Notifications.getLastNotificationResponse(); + if (response?.notification) { + redirect(response.notification); + } + + const subscription = Notifications.addNotificationResponseReceivedListener(response => { + redirect(response.notification); + }); + + return () => { + subscription.remove(); + }; + }, []); +} + +export default function TabLayout() { + const [session, SetSession] = useState(null) + const [loading, SetLoading] = useState(true); + const [setupChecked, setSetupChecked] = useState(false); + const [needsSetup, setNeedsSetup] = useState(false); + + UseNotificationObserver(); + + useEffect(() => { + const loadSession = async () => { + const { data } = await supabase.auth.getSession(); + SetSession(data.session ?? null); + SetLoading(false); + } + loadSession(); + + const { data: sub } = supabase.auth.onAuthStateChange((_event, newSession) => { + SetSession(newSession); + SetLoading(false); + }); + + return () => sub.subscription.unsubscribe(); + }, []); + + useEffect(() => { + const checkSetupStatus = async () => { + if (!session?.user.id) { + setNeedsSetup(false); + setSetupChecked(true); + return; + } + + try { + const setupStatus = await getSetupStatus(session.user.id); + setNeedsSetup(!setupStatus.isSetupComplete); + } catch { + setNeedsSetup(true); + } finally { + setSetupChecked(true); + } + }; + + setSetupChecked(false); + void checkSetupStatus(); + }, [session?.user.id]); + + if (loading || !setupChecked) { + return null; + } + + if (!session) { + return ; + } + + if (needsSetup) { + return ; + } + + return ( + + ( + + ), + }} + /> + ( + + ), + }} + /> + + ); +} diff --git a/AppDev/ikt205_2026_18_study_sprint/source/app/(tabs)/index.tsx b/AppDev/ikt205_2026_18_study_sprint/source/app/(tabs)/index.tsx new file mode 100644 index 0000000..850b511 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/app/(tabs)/index.tsx @@ -0,0 +1,1028 @@ +import { + GetActiveSession, + type ActiveSession, +} from '@/lib/asyncStorage'; +import type { SessionType } from '@/lib/types'; +import { formatDate, formatDateTime } from '@/lib/date'; +import { RegisterForLocalNotificationsAsync } from '@/lib/notifications'; +import { CheckAssignmentCompletion } from '@/lib/progress'; +import { DEFAULT_FOCUS_DURATION_MINUTES } from '@/lib/sessionDefaults'; +import { getSetupStatus } from '@/lib/setupStatus'; +import { finalizeStoredSession } from '@/lib/sessionLifecycle'; +import { supabase } from "@/lib/supabase"; +import MaterialIcons from '@expo/vector-icons/MaterialIcons'; +import { Session } from '@supabase/supabase-js'; +import { Redirect, router, Stack, useFocusEffect } from "expo-router"; +import { useCallback, useEffect, useState } from 'react'; +import { + Alert, + Modal, + Pressable, + ScrollView, + Text, + View, +} from "react-native"; + +type UpcomingDeadlineTask = { + tId: string; + title: string; + description: string; + aId: string; + subjectTitle: string; + assignmentTitle: string; + deadline: string; +}; + +type DashboardProgressSummary = { + completedFocusSessionsToday: number; + minutesStudiedToday: number; + minutesStudiedThisWeek: number; +}; + +type RecentSession = { + sessionId: string; + taskTitle: string | null; + sessionType: SessionType; + elapsedSeconds: number; + status: string; + startedAt: string | null; + endedAt: string | null; +}; + +type RecentlyCompletedTask = { + tId: string; + title: string; + assignmentTitle: string; + lastChanged: string; +}; + +const FLOW_STEPS = [ + { + label: '1', + title: 'Subject', + description: 'Start with the broad area you are studying, like one course or one exam you are preparing for.', + }, + { + label: '2', + title: 'Assignment', + description: 'Inside that, add the bigger piece of work you want to move forward, like a project, a problem set, or revision block.', + }, + { + label: '3', + title: 'Task', + description: 'Then break it down into one task that feels concrete enough to begin without overthinking it.', + }, + { + label: '4', + title: 'Sprint', + description: 'That task is what you bring into a focus session. After a sprint, you take a short pause, then come back to the same kind of focused work. After a few rounds, the app gives you a longer pause so the rhythm still feels sustainable.', + }, +] as const; + +function formatTime(totalSeconds: number) { + const minutes = Math.floor(totalSeconds / 60); + const seconds = totalSeconds % 60; + + return `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; +} + +function getSessionLabel(sessionType: SessionType) { + switch (sessionType) { + case 'short_break': + return 'Short Break'; + case 'long_break': + return 'Long Break'; + default: + return 'Active Sprint'; + } +} + +function formatTrackedMinutes(totalSeconds: number) { + return Math.floor(totalSeconds / 60); +} + +function formatTrackedDuration(totalSeconds: number) { + if (totalSeconds <= 0) { + return '0m'; + } + + const hours = Math.floor(totalSeconds / 3600); + const minutes = Math.floor((totalSeconds % 3600) / 60); + + if (hours === 0) { + return `${minutes}m`; + } + + if (minutes === 0) { + return `${hours}h`; + } + + return `${hours}h ${minutes}m`; +} + +function getSessionStatusLabel(status: string) { + switch (status) { + case 'completed': + return 'Completed'; + case 'cancelled': + return 'Cancelled'; + case 'expired': + return 'Timed out'; + default: + return status; + } +} + +function getStartOfToday() { + const now = new Date(); + return new Date(now.getFullYear(), now.getMonth(), now.getDate()); +} + +function getStartOfWeek() { + const today = getStartOfToday(); + const currentDay = today.getDay(); + const daysSinceMonday = (currentDay + 6) % 7; + + const startOfWeek = new Date(today); + startOfWeek.setDate(today.getDate() - daysSinceMonday); + return startOfWeek; +} + +export default function HomeScreen() { + const [session, SetSession] = useState(null); + const [activeSprint, setActiveSprint] = useState(null); + const [activeSprintTaskTitle, setActiveSprintTaskTitle] = useState(null); + const [activeSprintTaskDesc, setActiveSprintTaskDesc] = useState(null); + const [remainingSeconds, setRemainingSeconds] = useState(0); + const [dashboardSummary, setDashboardSummary] = useState({ + completedFocusSessionsToday: 0, + minutesStudiedToday: 0, + minutesStudiedThisWeek: 0, + }); + const [recentSessions, setRecentSessions] = useState([]); + const [recentlyCompletedTasks, setRecentlyCompletedTasks] = useState([]); + const [upcomingDeadlineTasks, setUpcomingDeadlineTasks] = useState([]); + const [isFlowInfoVisible, setIsFlowInfoVisible] = useState(false); + const [completingTaskId, setCompletingTaskId] = useState(null); + const [subjectCount, setSubjectCount] = useState(0); + const [needsSetup, setNeedsSetup] = useState(null); + + const loadActiveSprint = useCallback(async () => { + const storedSprint = await GetActiveSession(); + + if (!storedSprint) { + setActiveSprint(null); + setActiveSprintTaskTitle(null); + setActiveSprintTaskDesc(null); + setRemainingSeconds(0); + return; + } + + const secondsLeft = Math.max( + 0, + Math.ceil((storedSprint.endTime - Date.now()) / 1000) + ); + + if (secondsLeft <= 0) { + await finalizeStoredSession('expired', storedSprint); + setActiveSprint(null); + setActiveSprintTaskTitle(null); + setActiveSprintTaskDesc(null); + setRemainingSeconds(0); + return; + } + + setActiveSprint(storedSprint); + setRemainingSeconds(secondsLeft); + + if (!storedSprint.taskId) { + setActiveSprintTaskTitle(getSessionLabel(storedSprint.sessionType)); + setActiveSprintTaskDesc('Take the break before you jump into the next focus session.'); + return; + } + + const { data: dbTitle } = await supabase + .from('tasks') + .select('title') + .eq('tId', storedSprint.taskId) + .single(); + + const { data: dbDesc } = await supabase + .from('tasks') + .select('description') + .eq('tId', storedSprint.taskId) + .single(); + + setActiveSprintTaskTitle(dbTitle?.title ?? null); + setActiveSprintTaskDesc(dbDesc?.description); + }, []); + + const loadUpcomingDeadlineTasks = useCallback(async () => { + if (!session?.user.id) { + setUpcomingDeadlineTasks([]); + return; + } + + const { data: tasksData, error: tasksError } = await supabase + .from('tasks') + .select('tId, title, description, aId') + .eq('uId', session.user.id) + .eq('isCompleted', false); + + if (tasksError || !tasksData || tasksData.length === 0) { + setUpcomingDeadlineTasks([]); + return; + } + + const assignmentIds = [...new Set(tasksData.map((task) => task.aId).filter(Boolean))]; + + if (assignmentIds.length === 0) { + setUpcomingDeadlineTasks([]); + return; + } + + const { data: assignmentsData, error: assignmentsError } = await supabase + .from('assignments') + .select('aId, sId, title, deadline') + .in('aId', assignmentIds) + .eq('isCompleted', false); + + if (assignmentsError || !assignmentsData) { + setUpcomingDeadlineTasks([]); + return; + } + + const subjectIds = [...new Set(assignmentsData.map((assignment) => assignment.sId).filter(Boolean))]; + + const { data: subjectsData, error: subjectsError } = await supabase + .from('subjects') + .select('sId, title') + .in('sId', subjectIds); + + if (subjectsError || !subjectsData) { + setUpcomingDeadlineTasks([]); + return; + } + + const now = Date.now(); + const assignmentsById = new Map( + assignmentsData.map((assignment) => [assignment.aId, assignment]) + ); + const subjectsById = new Map( + subjectsData.map((subject) => [subject.sId, subject]) + ); + + const enrichedTasks = tasksData + .map((task) => { + const assignment = assignmentsById.get(task.aId); + + if (!assignment?.deadline) { + return null; + } + + const deadlineTime = new Date(assignment.deadline).getTime(); + + if (Number.isNaN(deadlineTime) || deadlineTime < now) { + return null; + } + + const subject = subjectsById.get(assignment.sId); + + return { + tId: task.tId, + title: task.title, + description: task.description, + aId: task.aId, + subjectTitle: subject?.title ?? 'Unknown Subject', + assignmentTitle: assignment.title, + deadline: assignment.deadline, + } satisfies UpcomingDeadlineTask; + }) + .filter((task): task is UpcomingDeadlineTask => task !== null) + .sort( + (left, right) => + new Date(left.deadline).getTime() - new Date(right.deadline).getTime() + ); + + setUpcomingDeadlineTasks(enrichedTasks); + }, [session?.user.id]); + + const loadDashboardProgress = useCallback(async () => { + if (!session?.user.id) { + setDashboardSummary({ + completedFocusSessionsToday: 0, + minutesStudiedToday: 0, + minutesStudiedThisWeek: 0, + }); + setRecentSessions([]); + setRecentlyCompletedTasks([]); + return; + } + + const startOfToday = getStartOfToday().toISOString(); + const startOfWeek = getStartOfWeek().toISOString(); + + const [ + { data: weeklySessions, error: weeklySessionsError }, + { data: rawRecentSessions, error: recentSessionsError }, + { data: completedTasks, error: completedTasksError }, + { count: fetchedSubjectCount, error: subjectCountError }, + ] = await Promise.all([ + supabase + .from('sprint_sessions') + .select('sessionId, sessionType, elapsedSeconds, status, startedAt, endedAt') + .eq('userId', session.user.id) + .eq('sessionType', 'focus') + .not('endedAt', 'is', null) + .gte('endedAt', startOfWeek), + supabase + .from('sprint_sessions') + .select('sessionId, taskId, sessionType, elapsedSeconds, status, startedAt, endedAt') + .eq('userId', session.user.id) + .not('endedAt', 'is', null) + .order('endedAt', { ascending: false }) + .limit(6), + supabase + .from('tasks') + .select('tId, title, aId, lastChanged') + .eq('uId', session.user.id) + .eq('isCompleted', true) + .order('lastChanged', { ascending: false }) + .limit(3), + supabase + .from('subjects') + .select('sId', { count: 'exact', head: true }) + .eq('uId', session.user.id), + ]); + + if (weeklySessionsError || recentSessionsError || completedTasksError || subjectCountError) { + setDashboardSummary({ + completedFocusSessionsToday: 0, + minutesStudiedToday: 0, + minutesStudiedThisWeek: 0, + }); + setRecentSessions([]); + setRecentlyCompletedTasks([]); + setSubjectCount(0); + return; + } + + setSubjectCount(fetchedSubjectCount ?? 0); + + const weeklySessionRows = weeklySessions ?? []; + const todaySummary = weeklySessionRows.reduce( + (summary, currentSession) => { + const endedAt = currentSession.endedAt ? new Date(currentSession.endedAt) : null; + + if (!endedAt || Number.isNaN(endedAt.getTime())) { + return summary; + } + + const elapsedSeconds = currentSession.elapsedSeconds ?? 0; + + summary.minutesStudiedThisWeek += formatTrackedMinutes(elapsedSeconds); + + if (endedAt >= new Date(startOfToday)) { + summary.minutesStudiedToday += formatTrackedMinutes(elapsedSeconds); + + if (currentSession.status === 'completed') { + summary.completedFocusSessionsToday += 1; + } + } + + return summary; + }, + { + completedFocusSessionsToday: 0, + minutesStudiedToday: 0, + minutesStudiedThisWeek: 0, + } satisfies DashboardProgressSummary + ); + + setDashboardSummary(todaySummary); + + const recentSessionRows = rawRecentSessions ?? []; + const recentTaskIds = [ + ...new Set( + recentSessionRows + .map((recentSession) => recentSession.taskId) + .filter((taskId): taskId is string => Boolean(taskId)) + ), + ]; + + const completedTaskRows = completedTasks ?? []; + const completedAssignmentIds = [ + ...new Set( + completedTaskRows + .map((task) => task.aId) + .filter((assignmentId): assignmentId is string => Boolean(assignmentId)) + ), + ]; + + const [{ data: recentTasks }, { data: completedAssignments }] = await Promise.all([ + recentTaskIds.length > 0 + ? supabase + .from('tasks') + .select('tId, title') + .in('tId', recentTaskIds) + : Promise.resolve({ data: [], error: null }), + completedAssignmentIds.length > 0 + ? supabase + .from('assignments') + .select('aId, title') + .in('aId', completedAssignmentIds) + : Promise.resolve({ data: [], error: null }), + ]); + + const tasksById = new Map((recentTasks ?? []).map((task) => [task.tId, task.title])); + const assignmentsById = new Map( + (completedAssignments ?? []).map((assignment) => [assignment.aId, assignment.title]) + ); + + setRecentSessions( + recentSessionRows.map((recentSession) => ({ + sessionId: recentSession.sessionId, + taskTitle: recentSession.taskId ? (tasksById.get(recentSession.taskId) ?? null) : null, + sessionType: recentSession.sessionType, + elapsedSeconds: recentSession.elapsedSeconds ?? 0, + status: recentSession.status, + startedAt: recentSession.startedAt, + endedAt: recentSession.endedAt, + })) + ); + + setRecentlyCompletedTasks( + completedTaskRows.map((task) => ({ + tId: task.tId, + title: task.title, + assignmentTitle: assignmentsById.get(task.aId) ?? 'Unknown Assignment', + lastChanged: task.lastChanged, + })) + ); + }, [session?.user.id]); + + useEffect(() => { + supabase.auth + .getSession() + .then(({ data }) => SetSession(data.session ?? null)); + + const { data: sub } = supabase.auth.onAuthStateChange( + (_event, newSession) => { + SetSession(newSession); + } + ); + + return () => sub.subscription.unsubscribe(); + }, []); + + useEffect(() => { + if (session) { + RegisterForLocalNotificationsAsync(); + } + }, [session]); + + useEffect(() => { + const loadSetupGate = async () => { + if (!session?.user.id) { + setNeedsSetup(false); + return; + } + + try { + const setupStatus = await getSetupStatus(session.user.id); + setNeedsSetup(!setupStatus.isSetupComplete); + } catch { + setNeedsSetup(true); + } + }; + + setNeedsSetup(null); + void loadSetupGate(); + }, [session?.user.id]); + + useFocusEffect( + useCallback(() => { + void loadActiveSprint(); + void loadDashboardProgress(); + void loadUpcomingDeadlineTasks(); + }, [loadActiveSprint, loadDashboardProgress, loadUpcomingDeadlineTasks]) + ); + + useEffect(() => { + if (!activeSprint) { + return; + } + + const intervalId = setInterval(() => { + const secondsLeft = Math.max( + 0, + Math.ceil((activeSprint.endTime - Date.now()) / 1000) + ); + + setRemainingSeconds(secondsLeft); + + if (secondsLeft <= 0) { + void finalizeStoredSession('expired', activeSprint); + setActiveSprint(null); + setActiveSprintTaskTitle(null); + setActiveSprintTaskDesc(null); + } + }, 1000); + + return () => clearInterval(intervalId); + }, [activeSprint]); + + const handleTaskCompletion = useCallback(async (task: UpcomingDeadlineTask) => { + if (completingTaskId) { + return; + } + + setCompletingTaskId(task.tId); + + const { error } = await supabase + .from('tasks') + .update({ + isCompleted: true, + lastChanged: new Date().toISOString(), + }) + .eq('tId', task.tId); + + if (error) { + setCompletingTaskId(null); + Alert.alert('Task could not be completed, please try again'); + return; + } + + try { + await CheckAssignmentCompletion(task.aId); + } catch { + setCompletingTaskId(null); + Alert.alert('Task was updated, but assignment progress could not be refreshed'); + return; + } + + setUpcomingDeadlineTasks((currentTasks) => + currentTasks.filter((currentTask) => currentTask.tId !== task.tId) + ); + setCompletingTaskId(null); + }, [completingTaskId]); + + const handleStartSprint = useCallback(async (task: UpcomingDeadlineTask) => { + const storedSession = await GetActiveSession(); + + if (!storedSession) { + router.push({ + pathname: '/task/timer', + params: { + tId: task.tId, + durationMinutes: String(DEFAULT_FOCUS_DURATION_MINUTES), + }, + }); + return; + } + + const secondsLeft = Math.ceil((storedSession.endTime - Date.now()) / 1000); + + if (secondsLeft <= 0) { + await finalizeStoredSession('expired', storedSession); + router.push({ + pathname: '/task/timer', + params: { + tId: task.tId, + durationMinutes: String(DEFAULT_FOCUS_DURATION_MINUTES), + }, + }); + return; + } + + if (storedSession.taskId === task.tId) { + router.push({ + pathname: '/task/timer', + params: { + tId: task.tId, + durationMinutes: String(DEFAULT_FOCUS_DURATION_MINUTES), + }, + }); + return; + } + + Alert.alert( + 'Active session in progress', + `End the current session and start a new ${DEFAULT_FOCUS_DURATION_MINUTES} minute sprint on "${task.title}"?`, + [ + { + text: 'Cancel', + style: 'cancel', + }, + { + text: 'Start sprint', + style: 'destructive', + onPress: async () => { + await finalizeStoredSession('cancelled', storedSession); + router.push({ + pathname: '/task/timer', + params: { + tId: task.tId, + durationMinutes: String(DEFAULT_FOCUS_DURATION_MINUTES), + }, + }); + }, + }, + ] + ); + }, []); + + if (session && needsSetup === null) { + return null; + } + + if (needsSetup) { + return ; + } + + return ( + + { + return ( + + setIsFlowInfoVisible(true)} + > + + + + ) + }, + headerRight: () => { + return ( + + await supabase.auth.signOut()} + > + + Logout + + + + ) + }, + }} + /> + + + setIsFlowInfoVisible(false)} + > + + setIsFlowInfoVisible(false)} + /> + + + + + + How work is organized + + + Study flow + + + + setIsFlowInfoVisible(false)} + > + + + + + + The idea is to make getting started feel lighter. You decide what you are studying, narrow it down to one clear task, and then let the app carry you through a simple rhythm of focus and recovery. + + + + {FLOW_STEPS.map((step, index) => ( + + + + {step.label} + + {index < FLOW_STEPS.length - 1 ? ( + + ) : null} + + + + {step.title} + + {step.description} + + + + ))} + + + + + Quick map + + + {'Subject -> Assignment -> Task -> Sprint'} + + + In practice, that usually becomes focus session, short pause, focus session again, and eventually a longer pause when you have done a few solid rounds. + + + + { + setIsFlowInfoVisible(false); + router.push('/subjects'); + }} + > + Open Subjects + + + + + + {subjectCount === 0 ? ( + + + First step + + + Build your first study path + + + Start with one subject, then add one assignment and one task so you + can reach your first sprint without guessing what to do next. + + + router.push('/setup')} + > + + Start Guided Setup + + + + ) : null} + + {activeSprint ? ( + + + {getSessionLabel(activeSprint.sessionType)} + + + {activeSprintTaskTitle ?? 'Selected task'} + + + {' '} + {activeSprintTaskDesc ?? null} + {' '} + + + {formatTime(remainingSeconds)} remaining + + + + router.push({ + pathname: '/task/timer', + params: activeSprint.taskId + ? { tId: activeSprint.taskId } + : { + sessionType: activeSprint.sessionType, + durationMinutes: String(Math.max(1, Math.round(activeSprint.durationSeconds / 60))), + }, + }) + } + > + + {activeSprint.sessionType === 'focus' ? 'Resume Sprint' : 'Resume Break'} + + + + ) : ( + + No active sprint right now. + + )} + + + + Study progress + + + A quick view of today's and this week's focused study effort. + + + + + + Focus sessions today + + + {dashboardSummary.completedFocusSessionsToday} + + + + + + Minutes today + + + {dashboardSummary.minutesStudiedToday} + + + + + + + Minutes this week + + + {dashboardSummary.minutesStudiedThisWeek} + + + + + + + Tasks with upcoming deadlines + + + The next concrete work items that are most likely to matter soon. + + + {upcomingDeadlineTasks.length > 0 ? ( + upcomingDeadlineTasks.map((task) => ( + + router.push({ + pathname: '/task/viewDetailsTask', + params: { tId: task.tId }, + }) + } + > + {task.title} + {task.description ? ( + + {task.description} + + ) : null} + + {task.subjectTitle} • {task.assignmentTitle} • {formatDate(task.deadline)} + + + { + event.stopPropagation(); + void handleStartSprint(task); + }} + > + + Start Sprint + + + + { + event.stopPropagation(); + Alert.alert( + 'Complete task', + 'Mark this task as completed?', + [ + { + text: 'Cancel', + style: 'cancel', + }, + { + text: 'Complete', + onPress: () => { + void handleTaskCompletion(task); + }, + }, + ] + ); + }} + > + + {completingTaskId === task.tId ? 'Completing...' : 'Mark as completed'} + + + + )) + ) : ( + No upcoming task deadlines. + )} + + + + + + Recent sessions + + + The latest recorded sprints and breaks. + + + {recentSessions.length > 0 ? ( + recentSessions.map((recentSession) => ( + + + + + {recentSession.taskTitle ?? getSessionLabel(recentSession.sessionType)} + + + {getSessionLabel(recentSession.sessionType)} • {formatTrackedDuration(recentSession.elapsedSeconds)} + + + + + + {getSessionStatusLabel(recentSession.status)} + + + + + + {formatDateTime(recentSession.endedAt ?? recentSession.startedAt)} + + + )) + ) : ( + No recent sessions yet. + )} + + + + + Recently completed tasks + + + Tasks you have recently finished and moved out of the queue. + + + {recentlyCompletedTasks.length > 0 ? ( + recentlyCompletedTasks.map((task) => ( + + router.push({ + pathname: '/task/viewDetailsTask', + params: { tId: task.tId }, + }) + } + > + {task.title} + {task.assignmentTitle} + + Completed {formatDateTime(task.lastChanged)} + + + )) + ) : ( + No completed tasks yet. + )} + + + + + ); +} diff --git a/AppDev/ikt205_2026_18_study_sprint/source/app/(tabs)/subjects.tsx b/AppDev/ikt205_2026_18_study_sprint/source/app/(tabs)/subjects.tsx new file mode 100644 index 0000000..62d82eb --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/app/(tabs)/subjects.tsx @@ -0,0 +1,411 @@ +import { getSetupStatus } from '@/lib/setupStatus'; +import { SUBJECT_COLORS, type SubjectColor } from '@/lib/subjectColors'; +import { supabase } from '@/lib/supabase'; +import { Subject } from '@/lib/types'; +import MaterialIcons from '@expo/vector-icons/MaterialIcons'; +import { Session } from '@supabase/supabase-js'; +import { Redirect, router, Stack, useFocusEffect } from 'expo-router'; +import { useCallback, useEffect, useState } from 'react'; +import { Alert, Modal, Pressable, ScrollView, Text, View, ActivityIndicator } from 'react-native'; + +const FLOW_STEPS = [ + { + label: '1', + title: 'Subject', + description: 'Start with the broad area you are studying, like one course or one exam you are preparing for.', + }, + { + label: '2', + title: 'Assignment', + description: 'Inside that, add the bigger piece of work you want to move forward, like a project, a problem set, or revision block.', + }, + { + label: '3', + title: 'Task', + description: 'Then break it down into one task that feels concrete enough to begin without overthinking it.', + }, + { + label: '4', + title: 'Sprint', + description: 'That task is what you bring into a focus session. After a sprint, you take a short pause, then come back to the same kind of focused work. After a few rounds, the app gives you a longer pause so the rhythm still feels sustainable.', + }, +] as const; + +export default function Subjects() { + const [subjects, SetSubjects] = useState([]); + const [session, SetSession] = useState(null); + const [isFlowInfoVisible, setIsFlowInfoVisible] = useState(false); + const [needsSetup, setNeedsSetup] = useState(null); + const [isLoading, SetIsLoading] = useState(true); + + const activeSubjects = subjects.filter((subject) => subject.isActive); + const inactiveSubjects = subjects.filter((subject) => !subject.isActive); + + useEffect(() => { + supabase.auth.getSession().then(({ data }) => { + SetSession(data.session ?? null); + }); + + const { data: sub } = supabase.auth.onAuthStateChange( + (_event, newSession) => { + SetSession(newSession); + } + ); + + return () => sub.subscription.unsubscribe(); + }, []); + + useEffect(() => { + const loadSetupGate = async () => { + if (!session?.user.id) { + setNeedsSetup(false); + return; + } + + try { + const setupStatus = await getSetupStatus(session.user.id); + setNeedsSetup(!setupStatus.isSetupComplete); + } catch { + setNeedsSetup(true); + } + }; + + setNeedsSetup(null); + void loadSetupGate(); + }, [session?.user.id]); + + const GetSubjects = useCallback(async () => { + if (!session?.user.id) { + SetIsLoading(false); + return; + } + + SetIsLoading(true); + + const { data, error } = await supabase + .from('subjects') + .select('*') + .eq('uId', session.user.id) + .order('lastChanged', { ascending: false }); + + SetIsLoading(false); + + if (error) { + Alert.alert('Subjects could not be fetched, please try again'); + return; + } + + SetSubjects((data as Subject[]) ?? []); + }, [session?.user.id]); + + useFocusEffect( + useCallback(() => { + if (session) { + void GetSubjects(); + } + }, [GetSubjects, session]) + ); + + if (session && needsSetup === null) { + return null; + } + + if (needsSetup) { + return ; + } + + const RenderSubjectCard = (subject: Subject) => { + const colorKey: SubjectColor = subject.color ?? 'slate'; + const colorSet = SUBJECT_COLORS[colorKey]; + const firstLetter = subject.title?.trim().charAt(0).toUpperCase() || '?'; + + return ( + + router.push({ + pathname: '/subject/viewDetailsSubject', + params: { sId: subject.sId }, + }) + } + > + + + + {firstLetter} + + + + + + {subject.title} + + + + {subject.description || 'No description added.'} + + + + + + + {subject.isActive ? 'Active' : 'Inactive'} + + + + + + ); + }; + if (isLoading) { + return ( + + + + ); + } + + return ( + + ( + + setIsFlowInfoVisible(true)} + > + + + + ), + headerRight: () => ( + + await supabase.auth.signOut()} + > + + Logout + + + + ), + }} + /> + + setIsFlowInfoVisible(false)} + > + + setIsFlowInfoVisible(false)} + /> + + + + + + How work is organized + + + Study flow + + + + setIsFlowInfoVisible(false)} + > + + + + + + The idea is to make getting started feel lighter. You decide what you are studying, narrow it down to one clear task, and then let the app carry you through a simple rhythm of focus and recovery. + + + + {FLOW_STEPS.map((step, index) => ( + + + + + {step.label} + + + {index < FLOW_STEPS.length - 1 ? ( + + ) : null} + + + + + {step.title} + + + {step.description} + + + + ))} + + + + + Quick map + + + {'Subject -> Assignment -> Task -> Sprint'} + + + In practice, that usually becomes focus session, short pause, focus session again, and eventually a longer pause when you have done a few solid rounds. + + + + setIsFlowInfoVisible(false)} + > + Close Guide + + + + + + + {isLoading ? ( + + + + Loading subjects... + + + ) : subjects.length === 0 ? ( + + + No subjects yet + + + Start with one subject so the rest of your study path has a clear + place to live. + + + router.push('/setup')} + > + + Start Guided Setup + + + + ) : ( + + + + Active Subjects + + + + + {activeSubjects.length} + + + + + {activeSubjects.length === 0 ? ( + + + No active subjects + + + Subjects with ongoing work will show up here. + + + ) : ( + activeSubjects.map(RenderSubjectCard) + )} + + + + Inactive Subjects + + + + + {inactiveSubjects.length} + + + + + {inactiveSubjects.length === 0 ? ( + + + No inactive subjects + + + Completed or paused subjects will show up here. + + + ) : ( + inactiveSubjects.map(RenderSubjectCard) + )} + + )} + + {subjects.length > 0 ? ( + router.push('/subject/upsertSubject')} + > + + Create Subject + + + ) : null} + + + ); +} diff --git a/AppDev/ikt205_2026_18_study_sprint/source/app/_layout.tsx b/AppDev/ikt205_2026_18_study_sprint/source/app/_layout.tsx new file mode 100644 index 0000000..da2de38 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/app/_layout.tsx @@ -0,0 +1,16 @@ +import { Stack } from "expo-router"; +import "../global.css"; + +export default function RootLayout() { + return ( + + + + + + + + + + ); +} diff --git a/AppDev/ikt205_2026_18_study_sprint/source/app/assignment/_layout.tsx b/AppDev/ikt205_2026_18_study_sprint/source/app/assignment/_layout.tsx new file mode 100644 index 0000000..7fb96ef --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/app/assignment/_layout.tsx @@ -0,0 +1,10 @@ +import { Stack } from "expo-router"; + +export default function AssignmentLayout() { + return ( + + + + + ); +} \ No newline at end of file diff --git a/AppDev/ikt205_2026_18_study_sprint/source/app/assignment/upsertAssignment.tsx b/AppDev/ikt205_2026_18_study_sprint/source/app/assignment/upsertAssignment.tsx new file mode 100644 index 0000000..284b6f7 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/app/assignment/upsertAssignment.tsx @@ -0,0 +1,378 @@ +import { defaultStyles } from '@/constants/defaultStyles'; +import * as AsyncStorage from '@/lib/asyncStorage'; +import { supabase } from '@/lib/supabase'; +import * as Notifications from 'expo-notifications'; +import { router, Stack, useLocalSearchParams } from 'expo-router'; +import { useEffect, useState } from 'react'; +import { + ActivityIndicator, + Alert, + Keyboard, + KeyboardAvoidingView, + Platform, + Pressable, + ScrollView, + Text, + TextInput, + TouchableWithoutFeedback, + View, +} from 'react-native'; + +export default function UpsertAssignment() { + const { aId, sId: routeSId, flow } = useLocalSearchParams<{ + aId?: string; + sId?: string; + flow?: string; + }>(); + + const isEditMode = Boolean(aId); + const isSetupFlow = flow === 'setup'; + + const [title, SetTitle] = useState(''); + const [description, SetDescription] = useState(''); + const [deadline, SetDeadline] = useState(''); + const [isCompleted, SetIsCompleted] = useState(false); + const [subjectId, SetSubjectId] = useState(routeSId ?? null); + + const [isLoading, SetIsLoading] = useState(isEditMode); + const [isSaving, SetIsSaving] = useState(false); + + useEffect(() => { + if (!isEditMode || !aId) { + SetIsLoading(false); + return; + } + + const loadAssignment = async () => { + SetIsLoading(true); + + const { data, error } = await supabase + .from('assignments') + .select('*') + .eq('aId', aId) + .single(); + + SetIsLoading(false); + + if (error || !data) { + Alert.alert('Assignment could not be loaded, please try again'); + router.back(); + return; + } + + SetTitle(data.title ?? ''); + SetDescription(data.description ?? ''); + SetDeadline(data.deadline ?? ''); + SetIsCompleted(data.isCompleted ?? false); + SetSubjectId(data.sId ?? routeSId ?? null); + }; + + loadAssignment(); + }, [aId, isEditMode, routeSId]); + + const ScheduleDeadlineReminder = async ( + assignmentId: string, + assignmentTitle: string, + assignmentDeadline: string + ) => { + const dl = new Date(assignmentDeadline); + + if (Number.isNaN(dl.getTime())) return null; + + const deadlineReminder = new Date(dl.getTime() - 24 * 60 * 60 * 1000); + + if (deadlineReminder <= new Date()) return null; + + const nId = await Notifications.scheduleNotificationAsync({ + content: { + title: 'Assignment deadline coming up', + body: `${assignmentTitle} is due in 24 hours.`, + data: { aId: assignmentId }, + }, + trigger: { + type: Notifications.SchedulableTriggerInputTypes.DATE, + date: deadlineReminder, + }, + }); + + return nId; + }; + + const updateDeadlineReminder = async ( + assignmentId: string, + assignmentTitle: string, + assignmentDeadline: string, + completed: boolean + ) => { + const existingNotificationId = + await AsyncStorage.GetAssignmentNotificationId(assignmentId); + + if (existingNotificationId) { + try { + await Notifications.cancelScheduledNotificationAsync( + existingNotificationId + ); + } catch {} + await AsyncStorage.RemoveAssignmentNotificationId(assignmentId); + } + + if (completed) return; + + const nId = await ScheduleDeadlineReminder( + assignmentId, + assignmentTitle, + assignmentDeadline + ); + + if (nId) { + await AsyncStorage.SaveAssignmentNotificationId(assignmentId, nId); + } + }; + + const handleSubmit = async () => { + if (title.trim() === '') { + Alert.alert('Title is required!'); + return; + } + + const { data: userData, error: userError } = await supabase.auth.getUser(); + + if (userError || !userData.user) { + router.replace('/login'); + return; + } + + if (!subjectId) { + Alert.alert('Missing subject', 'This assignment is not linked to a subject.'); + return; + } + + SetIsSaving(true); + + const payload = { + title: title.trim(), + description: description.trim(), + deadline: deadline.trim(), + isCompleted, + lastChanged: new Date().toISOString(), + uId: userData.user.id, + sId: subjectId, + }; + + const result = + isEditMode && aId + ? await supabase + .from('assignments') + .update(payload) + .eq('aId', aId) + .select() + .single() + : await supabase.from('assignments').insert(payload).select().single(); + + if (result.error || !result.data) { + SetIsSaving(false); + Alert.alert( + isEditMode + ? 'Assignment could not be updated, please try again' + : 'Assignment could not be created, please try again' + ); + return; + } + + const savedAssignment = result.data; + + await updateDeadlineReminder( + savedAssignment.aId, + savedAssignment.title, + savedAssignment.deadline, + savedAssignment.isCompleted + ); + + SetIsSaving(false); + + if (!isEditMode && isSetupFlow) { + router.replace({ + pathname: '/task/upsertTask', + params: { + aId: savedAssignment.aId, + flow: 'setup', + }, + }); + return; + } + + Alert.alert( + isEditMode + ? 'Assignment successfully updated!' + : 'Assignment successfully created!' + ); + + router.back(); + }; + + const inputClassName = + 'rounded-2xl border border-app-border bg-app-subtle px-4 py-3 text-base text-text-main'; + + const labelClassName = 'mb-2 text-sm font-semibold text-text-secondary'; + + if (isLoading) { + return ( + + + + ); + } + + return ( + <> + + + + + + + + {isEditMode ? 'Edit Assignment' : 'Create Assignment'} + + + {isEditMode + ? 'Update this assignment and keep your subject organized.' + : 'Add a new assignment to keep your subject organized.'} + + + + + + Title + + + + + Description + + + + + Deadline + + + + SetIsCompleted((current) => !current)} + disabled={isSaving} + > + + {isCompleted && ( + + ✓ + + )} + + + + + Mark as completed + + + You can change this later. + + + + + + {isSaving ? ( + + + + {isEditMode ? 'Saving...' : 'Creating...'} + + + ) : ( + + {isEditMode ? 'Save Changes' : 'Create Assignment'} + + )} + + + router.back()} + disabled={isSaving} + > + + Cancel + + + + + + + + ); +} diff --git a/AppDev/ikt205_2026_18_study_sprint/source/app/assignment/viewDetailsAssignment.tsx b/AppDev/ikt205_2026_18_study_sprint/source/app/assignment/viewDetailsAssignment.tsx new file mode 100644 index 0000000..3ce4b44 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/app/assignment/viewDetailsAssignment.tsx @@ -0,0 +1,521 @@ +import { formatDate, formatDateTime } from '@/lib/date'; +import { CheckAssignmentCompletion } from '@/lib/progress'; +import { getSubjectColorSet, type SubjectColor } from '@/lib/subjectColors'; +import { supabase } from '@/lib/supabase'; +import type { Assignment, Task } from '@/lib/types'; +import { Session } from '@supabase/supabase-js'; +import { router, Stack, useFocusEffect, useLocalSearchParams } from 'expo-router'; +import { useCallback, useEffect, useState } from 'react'; +import { ActivityIndicator, Alert, Pressable, SectionList, Text, View } from "react-native"; + + +export default function ViewDetailsAssignment() { + const { aId } = useLocalSearchParams<{ aId: string }>(); + const [assignment, SetAssignment] = useState(null); + const [tasks, SetTasks] = useState([]); + const [session, SetSession] = useState(null); + const [isLoading, SetIsLoading] = useState(false); + const [subjectMeta, setSubjectMeta] = useState({ + title: 'No Subject', + color: 'slate' as SubjectColor, + }); + + const taskSections = [ + { title: "Upcoming Tasks", data: tasks.filter((task) => !task.isCompleted), emptyMessage: "No upcoming tasks" }, + { title: "Completed Tasks", data: tasks.filter((task) => task.isCompleted), emptyMessage: "No completed tasks" }, + ]; + + useEffect(() => { + supabase.auth.getSession().then(({ data }) => SetSession(data.session ?? null)) + const { data: sub } = supabase.auth.onAuthStateChange((_event, newSession) => { + SetSession(newSession) + }) + return () => sub.subscription.unsubscribe() + }, + []) + + const GetAssignment = async (assignmentId: string) => { + SetIsLoading(true); + + const { data, error } = await supabase + .from('assignments') + .select('*') + .eq('aId', assignmentId) + .single(); + + SetIsLoading(false); + + if (error || !data) { + Alert.alert('Assignment could not be fetched, please try again'); + return; + } + + SetAssignment(data); + + if (data.sId) { + SetIsLoading(true); + + const { data: subjectData, error: subjectError } = await supabase + .from('subjects') + .select('title, color') + .eq('sId', data.sId) + .single(); + + SetIsLoading(false); + + if (subjectError || !subjectData) { + setSubjectMeta({ + title: 'Unknown Subject', + color: 'slate' + }); + return; + } + + setSubjectMeta({ + title: subjectData.title ?? 'Unknown Subject', + color: (subjectData.color as SubjectColor | undefined) ?? 'slate' + }); + } + }; + + const GetTasks = async (aId: string) => { + SetIsLoading(true); + + const { data, error } = await supabase.from("tasks").select("*").eq("aId", aId); + + SetIsLoading(false); + + if (error) { + Alert.alert("Tasks could not be fetched, please try again"); + return; + } + + SetTasks(data ?? []); + } + + useFocusEffect( + useCallback(() => { + if (session && aId) { + GetAssignment(aId); + GetTasks(aId); + } + }, [session, aId]) + ); + + const DeleteAssignment = async (aId: string) => { + Alert.alert( + "Delete Assignment", + "Are you sure you want to delete this assignment?", + [ + { + text: "Cancel", + style: "cancel" + }, + { + text: "Delete", + style: "destructive", + onPress: async () => { + const { error } = await supabase.from("assignments").delete().eq("aId", aId); + + if (error) { + Alert.alert("Assignment could not be deleted, please try again"); + return; + } + + Alert.alert("Assignment deleted successfully!"); + + router.back(); + } + } + ] + ) + } + + const DeleteTask = async (tId: string, aId: string) => { + Alert.alert( + "Delete Task", + "Are you sure you want to delete this task?", + [ + { + text: "Cancel", + style: "cancel" + }, + { + text: "Delete", + style: "destructive", + onPress: async () => { + const { error } = await supabase.from("tasks").delete().eq("tId", tId); + + if (error) { + Alert.alert("Task could not be deleted, please try again"); + return; + } + + Alert.alert("Task deleted successfully!"); + + if (aId) { + try { + await CheckAssignmentCompletion(aId); + } catch { + Alert.alert("Failed to update assignment completion state"); + } + } + + GetTasks(aId); + } + } + ] + ) + } + + const ToggleTaskCompletion = async (task: Task) => { + const nextIsCompleted = !task.isCompleted; + + const { error } = await supabase + .from("tasks") + .update({ + isCompleted: nextIsCompleted, + lastChanged: new Date().toISOString(), + }) + .eq("tId", task.tId); + + if (error) { + Alert.alert("Task could not be updated, please try again"); + return; + } + + try { + await CheckAssignmentCompletion(task.aId); + } catch { + Alert.alert("Failed to update assignment completion state"); + } + + await GetTasks(task.aId); + await GetAssignment(task.aId); + } + + const colorSet = getSubjectColorSet(subjectMeta.color); + + const completedTasks = tasks.filter((task) => task.isCompleted).length; + const totalTasks = tasks.length; + const remainingTasks = totalTasks - completedTasks; + + const progress = + totalTasks === 0 + ? 0 + : Math.round((completedTasks / totalTasks) * 100); + + if (isLoading) { + return ( + + + + ); + } + + if (!assignment) { + return ( + + + + + + Assignment not found + + + The assignment could not be loaded. + + + router.back()} + > + Go back + + + + ); + } + + + return ( + + ( + await supabase.auth.signOut()} + > + + Logout + + + ), + }} + /> + + item.tId} + showsVerticalScrollIndicator={false} + stickySectionHeadersEnabled={false} + ListHeaderComponent={ + + + + + + {assignment.title} + + + {assignment.description ? ( + + {assignment.description} + + ) : null} + + + + + + {subjectMeta.title} + + + + + + + Deadline: {formatDate(assignment.deadline) || 'No deadline'} + + + + + + + + Tasks completed + + + + {completedTasks}/{totalTasks} + + + + + + + + + {remainingTasks === 0 + ? 'All tasks complete' + : `${remainingTasks} task${remainingTasks === 1 ? '' : 's'} remaining`} + + + + Based only on completed tasks in this assignment. + + + + Last changed: {formatDateTime(assignment.lastChanged)} + + + + + + + router.push({ + pathname: '../assignment/upsertAssignment', + params: { aId: assignment.aId }, + }) + } + > + Edit + + + DeleteAssignment(assignment.aId)} + > + + Delete + + + + + + + router.push({ + pathname: '../task/upsertTask', + params: { aId: assignment.aId }, + }) + } + > + + Create Task + + + + } + renderSectionHeader={({ section: { title, data } }) => ( + + {title} + + + + {data.length} + + + + )} + renderItem={({ item }) => { + const isOwner = session?.user.id === item.uId; + + return ( + + + router.push({ + pathname: '/task/viewDetailsTask', + params: { tId: item.tId }, + }) + } + > + + + + {item.title} + + + {item.description ? ( + + {item.description} + + ) : null} + + + + + {isOwner && ( + + ToggleTaskCompletion(item)} + > + + {item.isCompleted ? 'Reopen' : 'Complete'} + + + + + router.push({ + pathname: '../task/upsertTask', + params: { tId: item.tId }, + }) + } + > + Edit + + + DeleteTask(item.tId, item.aId)} + > + + Delete + + + + )} + + ); + }} + ListEmptyComponent={ + + + No tasks needed yet + + + Add tasks if this assignment needs smaller steps. + + + } + renderSectionFooter={({ section }) => + section.data.length === 0 ? ( + + + {section.emptyMessage} + + + {tasks.length === 0 + ? 'Create the first task so this assignment turns into one clear next action.' + : 'Tasks for this assignment will show up here.'} + + + ) : ( + + ) + } + /> + + ); +} diff --git a/AppDev/ikt205_2026_18_study_sprint/source/app/createUser.tsx b/AppDev/ikt205_2026_18_study_sprint/source/app/createUser.tsx new file mode 100644 index 0000000..5a2d3af --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/app/createUser.tsx @@ -0,0 +1,213 @@ +import { supabase } from '@/lib/supabase'; +import { router } from 'expo-router'; +import { useEffect, useRef, useState } from 'react'; +import { + Alert, + Animated, + Keyboard, + KeyboardAvoidingView, + KeyboardEvent, + Platform, + Pressable, + ScrollView, + Text, + TextInput, + TouchableWithoutFeedback, + View, +} from 'react-native'; + +export default function CreateUser() { + const [email, SetEmail] = useState(''); + const [password, SetPassword] = useState(''); + const [isLoading, SetIsLoading] = useState(false); + const [isKeyboardVisible, setIsKeyboardVisible] = useState(false); + const scrollViewRef = useRef(null); + const cardLift = useRef(new Animated.Value(0)).current; + + useEffect(() => { + const showEvent = Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow'; + const hideEvent = Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide'; + + const handleKeyboardShow = (event: KeyboardEvent) => { + setIsKeyboardVisible(true); + + const keyboardHeight = event.endCoordinates.height; + const liftAmount = Math.min( + Platform.OS === 'ios' ? keyboardHeight * 0.5 : keyboardHeight * 0.6, + 260 + ); + + Animated.timing(cardLift, { + toValue: -liftAmount, + duration: event.duration ?? 220, + useNativeDriver: true, + }).start(); + }; + + const handleKeyboardHide = () => { + setIsKeyboardVisible(false); + + Animated.timing(cardLift, { + toValue: 0, + duration: 220, + useNativeDriver: true, + }).start(); + }; + + const showSubscription = Keyboard.addListener(showEvent, handleKeyboardShow); + const hideSubscription = Keyboard.addListener(hideEvent, handleKeyboardHide); + + return () => { + showSubscription.remove(); + hideSubscription.remove(); + }; + }, [cardLift]); + + const SignUp = async () => { + if (email.trim() === '' || password.trim() === '') { + Alert.alert('All fields are required!'); + return; + } + + SetIsLoading(true); + + const { data, error } = await supabase.auth.signUp({ + email: email.trim(), + password, + }); + + SetIsLoading(false); + + if (error) { + Alert.alert(error.message, 'User could not be created, please try again'); + return; + } + + if (!data.session) { + Alert.alert( + 'Check your email', + 'Your account was created. Please confirm your email before signing in.' + ); + router.replace('/login'); + return; + } + router.replace('/setup'); + }; + + const inputClassName = + 'rounded-2xl border border-app-border bg-app-subtle px-4 py-3 text-base text-text-main'; + + return ( + + + + + + + Study Sprint + + + + Organize subjects, assignments, and tasks in one calm workflow. + + + + + + Create account + + + Start your next study sprint. + + + + + What this app does + + + Study Sprint helps you move from subject to assignment to task, + then into a focused sprint. + + + Why an account exists + + + Your account keeps that structure and your tracked study + progress attached to you. + + + + + + Email + + + + + + + Password + + + + + + + {isLoading ? 'Creating account...' : 'Create account'} + + + + router.push('/login')} + > + + Already have an account? Log in + + + + + + + + ); +} diff --git a/AppDev/ikt205_2026_18_study_sprint/source/app/login.tsx b/AppDev/ikt205_2026_18_study_sprint/source/app/login.tsx new file mode 100644 index 0000000..13b6726 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/app/login.tsx @@ -0,0 +1,189 @@ +import { getSetupStatus } from "@/lib/setupStatus"; +import { supabase } from "@/lib/supabase"; +import { router } from "expo-router"; +import { useEffect, useRef, useState } from "react"; +import { Alert, Keyboard, KeyboardAvoidingView, KeyboardEvent, Platform, Pressable, ScrollView, Text, TextInput, TouchableWithoutFeedback, View } from "react-native"; + +export default function Login() { + const [email, SetEmail] = useState(''); + const [password, SetPassword] = useState(''); + const [isLoading, SetIsLoading] = useState(false); + const [isKeyboardVisible, setIsKeyboardVisible] = useState(false); + const scrollViewRef = useRef(null); + + useEffect(() => { + const showEvent = Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow'; + const hideEvent = Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide'; + + const handleKeyboardShow = (event: KeyboardEvent) => { + setIsKeyboardVisible(true); + + const keyboardHeight = event.endCoordinates.height; + const offsetBaseline = Platform.OS === 'ios' ? 180 : 140; + const nextScrollOffset = Math.max(0, keyboardHeight - offsetBaseline); + + scrollViewRef.current?.scrollTo({ + y: nextScrollOffset, + animated: true, + }); + }; + + const handleKeyboardHide = () => { + setIsKeyboardVisible(false); + scrollViewRef.current?.scrollTo({ y: 0, animated: true }); + }; + + const showSubscription = Keyboard.addListener(showEvent, handleKeyboardShow); + const hideSubscription = Keyboard.addListener(hideEvent, handleKeyboardHide); + + return () => { + showSubscription.remove(); + hideSubscription.remove(); + }; + }, []); + + const login = async () => { + if(email.trim() === '' || password.trim() === '') { + Alert.alert("All fields are required!"); + return; + } + + SetIsLoading(true); + + const { data, error } = await supabase.auth.signInWithPassword({ + email, + password + }); + + SetIsLoading(false); + + if (error) { + Alert.alert("Login failed, please check your credentials and try again"); + return; + } + + if (!data.user?.id) { + Alert.alert("Login failed, missing user session after sign-in"); + return; + } + + try { + const setupStatus = await getSetupStatus(data.user.id); + router.replace(setupStatus.isSetupComplete ? "/" : "/setup"); + } catch { + router.replace("/setup"); + } + } + + const inputClassName = + 'rounded-2xl border border-app-border bg-app-subtle px-4 py-3 text-base text-text-main' + + return ( + + + + + + Study Sprint + + + + Pick up where you left off. + + + + + + Log in + + + + Continue your study workflow. + + + + + Your study path stays with your account + + + Subjects, assignments, tasks, and tracked sprint progress follow + you after you sign in. + + + + + + Email + + + + + + + Password + + { + scrollViewRef.current?.scrollToEnd({ animated: true }); + }} + /> + + + + + {isLoading ? 'Logging in...' : 'Log in'} + + + + router.push('/createUser')} + > + + Don't have an account? Sign up + + + + + + +); +} diff --git a/AppDev/ikt205_2026_18_study_sprint/source/app/setup.tsx b/AppDev/ikt205_2026_18_study_sprint/source/app/setup.tsx new file mode 100644 index 0000000..fe60ae0 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/app/setup.tsx @@ -0,0 +1,359 @@ +import { + GetActiveSession, + GetSetupSprintDemoUsed, + SaveSetupSprintDemoUsed, + type ActiveSession, +} from '@/lib/asyncStorage'; +import { DEFAULT_FOCUS_DURATION_MINUTES } from '@/lib/sessionDefaults'; +import { getSetupStatus, type SetupStepKey } from '@/lib/setupStatus'; +import { finalizeStoredSession } from '@/lib/sessionLifecycle'; +import { supabase } from '@/lib/supabase'; +import { Session } from '@supabase/supabase-js'; +import { Redirect, Stack, router, useFocusEffect, useLocalSearchParams } from 'expo-router'; +import { useCallback, useEffect, useState } from 'react'; +import { Pressable, ScrollView, Text, View } from 'react-native'; + +type SetupState = { + subjectId: string | null; + assignmentId: string | null; + taskId: string | null; + completedFocusSessions: number; +}; + +const SETUP_STEPS = [ + { + key: 'subject', + title: 'Create your first subject', + description: + 'Start with one course or study area so the rest of the structure has a clear home.', + }, + { + key: 'assignment', + title: 'Create your first assignment', + description: + 'Add one project, exercise set, or exam-prep block inside that subject.', + }, + { + key: 'task', + title: 'Create your first task', + description: + 'Break the assignment into one concrete thing you can actually sit down and do.', + }, + { + key: 'sprint', + title: 'Start your first sprint', + description: + 'Begin one focused study session so the app immediately turns into action instead of setup.', + }, +] as const; + +export default function SetupScreen() { + const { + subjectId: subjectIdParam, + assignmentId: assignmentIdParam, + taskId: taskIdParam, + } = useLocalSearchParams<{ + subjectId?: string; + assignmentId?: string; + taskId?: string; + }>(); + + const [session, setSession] = useState(null); + const [isAuthLoading, setIsAuthLoading] = useState(true); + const [setupState, setSetupState] = useState({ + subjectId: subjectIdParam ?? null, + assignmentId: assignmentIdParam ?? null, + taskId: taskIdParam ?? null, + completedFocusSessions: 0, + }); + const [activeSession, setActiveSession] = useState(null); + + useEffect(() => { + supabase.auth.getSession().then(({ data }) => { + setSession(data.session ?? null); + setIsAuthLoading(false); + }); + + const { data: sub } = supabase.auth.onAuthStateChange((_event, newSession) => { + setSession(newSession); + setIsAuthLoading(false); + }); + + return () => sub.subscription.unsubscribe(); + }, []); + + const loadSetupState = useCallback(async () => { + if (!session?.user.id) { + setSetupState({ + subjectId: null, + assignmentId: null, + taskId: null, + completedFocusSessions: 0, + }); + setActiveSession(null); + return; + } + + const [storedActiveSession, status] = await Promise.all([ + GetActiveSession(), + getSetupStatus(session.user.id), + ]); + + if (storedActiveSession && storedActiveSession.endTime <= Date.now()) { + await finalizeStoredSession('expired', storedActiveSession); + setActiveSession(null); + } else { + setActiveSession(storedActiveSession); + } + + setSetupState({ + subjectId: subjectIdParam ?? status.subjectId, + assignmentId: assignmentIdParam ?? status.assignmentId, + taskId: taskIdParam ?? status.taskId, + completedFocusSessions: status.completedFocusSessions, + }); + }, [assignmentIdParam, session?.user.id, subjectIdParam, taskIdParam]); + + useFocusEffect( + useCallback(() => { + void loadSetupState(); + }, [loadSetupState]) + ); + + const currentStep: SetupStepKey = (() => { + if (!setupState.subjectId) { + return 'subject'; + } + + if (!setupState.assignmentId) { + return 'assignment'; + } + + if (!setupState.taskId) { + return 'task'; + } + + return 'sprint'; + })(); + + const isSetupComplete = + setupState.taskId !== null && setupState.completedFocusSessions > 0; + + const handlePrimaryAction = useCallback(async () => { + if (isSetupComplete) { + router.replace('/'); + return; + } + + if (currentStep === 'subject') { + router.push({ + pathname: '/subject/upsertSubject', + params: { flow: 'setup' }, + }); + return; + } + + if (currentStep === 'assignment' && setupState.subjectId) { + router.push({ + pathname: '/assignment/upsertAssignment', + params: { + sId: setupState.subjectId, + flow: 'setup', + }, + }); + return; + } + + if (currentStep === 'task' && setupState.assignmentId) { + router.push({ + pathname: '/task/upsertTask', + params: { + aId: setupState.assignmentId, + flow: 'setup', + }, + }); + return; + } + + if (!setupState.taskId) { + return; + } + + const freshActiveSession = await GetActiveSession(); + + if (freshActiveSession && freshActiveSession.endTime > Date.now()) { + router.push({ + pathname: '/task/timer', + params: freshActiveSession.taskId + ? { tId: freshActiveSession.taskId } + : { + sessionType: freshActiveSession.sessionType, + durationMinutes: String( + Math.max(1, Math.round(freshActiveSession.durationSeconds / 60)) + ), + }, + }); + return; + } + + if (freshActiveSession) { + await finalizeStoredSession('expired', freshActiveSession); + setActiveSession(null); + } + + const shouldUseDemoSprint = session?.user.id + ? !(await GetSetupSprintDemoUsed(session.user.id)) + : false; + + if (shouldUseDemoSprint && session?.user.id) { + await SaveSetupSprintDemoUsed(session.user.id); + } + + router.push({ + pathname: '/task/timer', + params: shouldUseDemoSprint + ? { + tId: setupState.taskId, + durationSeconds: '5', + onboardingDemo: 'true', + } + : { + tId: setupState.taskId, + durationMinutes: String(DEFAULT_FOCUS_DURATION_MINUTES), + }, + }); + }, [currentStep, isSetupComplete, session?.user.id, setupState]); + + const primaryLabel = isSetupComplete + ? 'Go to dashboard' + : currentStep === 'subject' + ? 'Create first subject' + : currentStep === 'assignment' + ? 'Create first assignment' + : currentStep === 'task' + ? 'Create first task' + : activeSession + ? 'Open active sprint' + : 'Start first sprint'; + + if (isAuthLoading) { + return null; + } + + if (!session) { + return ; + } + + return ( + + ( + await supabase.auth.signOut()} + > + + Logout + + + ), + }} + /> + + + + + First-time setup + + + Build one simple study path + + + You only need one subject, one assignment, one task, and one sprint to + make the app useful. + + + + + {SETUP_STEPS.map((step, index) => { + const isDone = + step.key === 'subject' + ? Boolean(setupState.subjectId) + : step.key === 'assignment' + ? Boolean(setupState.assignmentId) + : step.key === 'task' + ? Boolean(setupState.taskId) + : isSetupComplete; + const isCurrent = !isDone && currentStep === step.key; + + return ( + + + + + {isDone ? '✓' : index + 1} + + + + + + {step.title} + + + {step.description} + + + + + ); + })} + + + + + {isSetupComplete + ? 'You have already completed at least one focus sprint.' + : currentStep === 'sprint' + ? 'The structure is ready. The next step is to actually begin a sprint.' + : 'Follow the next step below. The rest of the app will make more sense once that path exists.'} + + + + + {primaryLabel} + + + + + + ); +} diff --git a/AppDev/ikt205_2026_18_study_sprint/source/app/subject/_layout.tsx b/AppDev/ikt205_2026_18_study_sprint/source/app/subject/_layout.tsx new file mode 100644 index 0000000..57d25b5 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/app/subject/_layout.tsx @@ -0,0 +1,10 @@ +import { Stack } from "expo-router"; + +export default function SubjectLayout() { + return ( + + + + + ); +} \ No newline at end of file diff --git a/AppDev/ikt205_2026_18_study_sprint/source/app/subject/upsertSubject.tsx b/AppDev/ikt205_2026_18_study_sprint/source/app/subject/upsertSubject.tsx new file mode 100644 index 0000000..f4cf861 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/app/subject/upsertSubject.tsx @@ -0,0 +1,366 @@ +import { defaultStyles } from '@/constants/defaultStyles'; +import { SUBJECT_COLOR_KEYS, SUBJECT_COLORS, type SubjectColor } from '@/lib/subjectColors'; +import { supabase } from '@/lib/supabase'; +import type { Subject } from '@/lib/types'; +import { router, Stack, useLocalSearchParams } from 'expo-router'; +import { useEffect, useMemo, useState } from 'react'; +import { + ActivityIndicator, + Alert, + Keyboard, + KeyboardAvoidingView, + Platform, + Pressable, + ScrollView, + Text, + TextInput, + TouchableWithoutFeedback, + View +} from 'react-native'; + + +export default function UpsertSubject() { + const { sId, flow } = useLocalSearchParams<{ sId?: string; flow?: string }>(); + const isEditMode = Boolean(sId); + const isSetupFlow = flow === 'setup'; + + const [title, setTitle] = useState(''); + const [description, setDescription] = useState(''); + const [isActive, setIsActive] = useState(true); + const [color, setColor] = useState('blue'); + + const [isLoading, setIsLoading] = useState(isEditMode); + const [isSaving, setIsSaving] = useState(false); + + useEffect(() => { + if (!isEditMode || !sId) return; + + const loadSubject = async () => { + setIsLoading(true); + + const { data, error } = await supabase + .from('subjects') + .select('*') + .eq('sId', sId) + .single(); + + setIsLoading(false); + + if (error || !data ) { + Alert.alert('Subject could not be loaded, please try again'); + router.back(); + return; + } + + const subject = data as Subject; + + setTitle(subject.title ?? ''); + setDescription(subject.description ?? ''); + setIsActive(subject.isActive ?? true); + setColor(subject.color ?? 'blue'); + }; + + loadSubject(); + }, [isEditMode, sId]); + + const handleSubmit = async () => { + if (title.trim() === '') { + Alert.alert('Title is required!'); + return; + } + + const { data, error: userError } = await supabase.auth.getUser(); + + if (userError || !data.user) { + router.replace('/login'); + return; + } + + setIsSaving(true); + + const payload = { + title: title.trim(), + description : description.trim(), + isActive, + color, + lastChanged: new Date().toISOString(), + uId: data.user.id, + }; + + const result = isEditMode && sId + ? await supabase.from('subjects').update(payload).eq('sId', sId) + : await supabase.from('subjects').insert(payload).select().single(); + + setIsSaving(false); + + if(result.error) { + Alert.alert( + isEditMode + ? 'Subject could not be updated, please try again' + : 'Subject could not be created, please try again' + ); + return; + } + + if (!isEditMode && isSetupFlow && result.data?.sId) { + router.replace({ + pathname: '/assignment/upsertAssignment', + params: { + sId: result.data.sId, + flow: 'setup', + }, + }); + return; + } + + Alert.alert( + isEditMode ? 'Subject updated successfully!' : 'Subject created successfully!' + ); + + router.back(); + }; + + const inputClassName = + 'rounded-2xl border border-app-border bg-app-subtle px-4 py-3 text-base text-text-main'; + + const labelClassName = 'mb-2 text-sm font-semibold text-text-secondary'; + + const selectedColor = useMemo(() => SUBJECT_COLORS[color], [color]); + + if (isLoading) { + return ( + + + + ); + } + + return ( + <> + + + + + + + + {isEditMode ? 'Edit Subject' : 'Create Subject'} + + + {isEditMode? ' Update this subject and keep your study structure organized.' + : 'Add a subject to organize your assignments and study tasks.'} + + + + + + Title + + + + + Description + + + + + Color + + + Preview + + + + + + {title.trim().charAt(0).toUpperCase() || 'S'} + + + + + + {title.trim() || 'Subject Preview'} + + + + {description.trim() || 'This color will be used as the subject card accent.'} + + + + + + + {isActive ? 'Active' : 'Inactive'} + + + + + + + + + {SUBJECT_COLOR_KEYS.map((colorKey) => { + const colorOption = SUBJECT_COLORS[colorKey]; + const isSelected = color === colorKey; + + return ( + setColor(colorKey)} + className="mr-3 mb-3 rounded-2xl border border-app-border bg-app--surface p-2" + style={{ + borderColor: isSelected + ? colorOption.strong + : '#FFFFFF', + }} + > + + + + {colorOption.label} + + + + ); + })} + + + + setIsActive((state) => !state)} + disabled={isSaving} + className={`mb-6 flex-row items-center rounded-2xl border p-4 ${ + isActive + ? 'border-accent bg-accent-soft' + : 'border-app-border bg-app-subtle' + }`} + > + + {isActive && ( + + )} + + + + + Active subject + + + Active subjects appear in your main study workflow. + + + + + + {isSaving ? ( + + + + {isEditMode ? 'Saving...' : 'Creating...'} + + + ) : ( + + {isEditMode ? 'Save Changes' : 'Create Subject'} + + )} + + + router.back()} + disabled={isSaving} + > + + Cancel + + + + + + + + ); +} diff --git a/AppDev/ikt205_2026_18_study_sprint/source/app/subject/viewDetailsSubject.tsx b/AppDev/ikt205_2026_18_study_sprint/source/app/subject/viewDetailsSubject.tsx new file mode 100644 index 0000000..c399c1f --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/app/subject/viewDetailsSubject.tsx @@ -0,0 +1,540 @@ +import { formatDate, formatDateTime } from '@/lib/date'; +import { SUBJECT_COLORS, type SubjectColor } from '@/lib/subjectColors'; +import { supabase } from '@/lib/supabase'; +import type { Assignment } from '@/lib/types'; +import { Session } from '@supabase/supabase-js'; +import { router, Stack, useFocusEffect, useLocalSearchParams } from 'expo-router'; +import { useCallback, useEffect, useState } from 'react'; +import { ActivityIndicator, Alert, Pressable, SectionList, Text, View } from 'react-native'; + +export type Subject = { + sId: string; + title: string; + description: string; + isActive: boolean; + lastChanged: string; + uId: string; + color: SubjectColor; +}; + +export default function ViewDetailsSubject() { + const { sId } = useLocalSearchParams<{ sId: string }>(); + const [subject, SetSubject] = useState(null); + const [assignments, SetAssignments] = useState([]); + const [session, SetSession] = useState(null); + const [isLoading, SetIsLoading] = useState(false); + + const assignmentSections = [ + { + title: 'Active Assignments', + data: assignments.filter((assignment) => !assignment.isCompleted), + emptyMessage: 'No active assignments', + }, + { + title: 'Completed Assignments', + data: assignments.filter((assignment) => assignment.isCompleted), + emptyMessage: 'No completed assignments', + }, + ]; + + useEffect(() => { + supabase.auth.getSession().then(({ data }) => SetSession(data.session ?? null)); + + const { data: sub } = supabase.auth.onAuthStateChange((_event, newSession) => { + SetSession(newSession); + }); + + return () => sub.subscription.unsubscribe(); + }, []); + + const GetSubject = async (subjectId: string) => { + SetIsLoading(true); + + const { data, error } = await supabase + .from('subjects') + .select('*') + .eq('sId', subjectId) + .single(); + + SetIsLoading(false); + + if (error) { + Alert.alert('Subject could not be fetched, please try again'); + return; + } + + SetSubject((data as Subject) ?? null); + }; + + const GetAssignments = async (subjectId: string) => { + SetIsLoading(true); + + const { data, error } = await supabase + .from('assignments') + .select('*') + .eq('sId', subjectId) + .order('deadline', { ascending: true }); + + SetIsLoading(false); + + if (error) { + Alert.alert('Assignments could not be fetched, please try again'); + return; + } + + SetAssignments(data ?? []); + }; + + const ToggleAssignmentCompletion = async (assignment: Assignment) => { + const nextIsCompleted = !assignment.isCompleted; + + const { error } = await supabase + .from('assignments') + .update({ + isCompleted: nextIsCompleted, + lastChanged: new Date().toISOString(), + }) + .eq('aId', assignment.aId); + + if (error) { + Alert.alert('Assignment could not be updated, please try again'); + return; + } + + await GetAssignments(assignment.sId); + await GetSubject(assignment.sId); + }; + + useFocusEffect( + useCallback(() => { + if (!session || !sId) { + return; + } + + SetIsLoading(true); + SetSubject(null); + + Promise.all([GetSubject(sId), GetAssignments(sId)]).finally(() => { + SetIsLoading(false); + }); + }, [session, sId]) + ); + + const DeleteSubject = async (subjectId: string) => { + Alert.alert( + 'Delete Subject', + 'Are you sure you want to delete this subject?', + [ + { + text: 'Cancel', + style: 'cancel', + }, + { + text: 'Delete', + style: 'destructive', + onPress: async () => { + const { error } = await supabase + .from('subjects') + .delete() + .eq('sId', subjectId); + + if (error) { + Alert.alert('Subject could not be deleted, please try again'); + return; + } + + Alert.alert('Subject deleted successfully!'); + router.back(); + }, + }, + ] + ); + }; + + const DeleteAssignment = async (assignmentId: string, subjectId: string) => { + Alert.alert( + 'Delete Assignment', + 'Are you sure you want to delete this assignment?', + [ + { + text: 'Cancel', + style: 'cancel', + }, + { + text: 'Delete', + style: 'destructive', + onPress: async () => { + const { error } = await supabase + .from('assignments') + .delete() + .eq('aId', assignmentId); + + if (error) { + Alert.alert('Assignment could not be deleted, please try again'); + return; + } + + await GetAssignments(subjectId); + await GetSubject(subjectId); + + Alert.alert('Assignment deleted successfully!'); + }, + }, + ] + ); + }; + + const completedAssignments = assignments.filter((assignment) => assignment.isCompleted).length; + const totalAssignments = assignments.length; + const remainingAssignments = totalAssignments - completedAssignments; + + const progress = + assignments.length === 0 + ? 0 + : Math.round((completedAssignments / totalAssignments) * 100); + + if (isLoading) { + return ( + + + + + + + Loading subject... + + + + ); + } + + if (!subject) { + return ( + + + + + + Subject not found + + + The subject could not be loaded. + + + router.back()} + > + + Go back + + + + + ); + } + + const colorKey: SubjectColor = subject.color ?? 'slate'; + const colorSet = SUBJECT_COLORS[colorKey]; + + const firstLetter = subject.title?.trim().charAt(0).toUpperCase() || 'S'; + + return ( + + ( + await supabase.auth.signOut()} + > + + Logout + + + ), + }} + /> + + item.aId} + showsVerticalScrollIndicator={false} + stickySectionHeadersEnabled={false} + ListHeaderComponent={ + + + + + + {firstLetter} + + + + + + {subject.title} + + + {subject.description ? ( + + {subject.description} + + ) : ( + + No description added. + + )} + + + + + + {subject.isActive ? 'Active' : 'Inactive'} + + + + + + + + + Assignment Progress + + + + {completedAssignments}/{totalAssignments} + + + + + + + + + {remainingAssignments === 0 + ? 'All assignments complete' + : `${remainingAssignments} assignment${ + remainingAssignments === 1 ? '' : 's' + } remaining`} + + + + Based only on completed assignments in this subject. + + + + + Last changed: {formatDateTime(subject.lastChanged)} + + + + + router.push({ + pathname: '../subject/upsertSubject', + params: { sId: subject.sId }, + }) + } + > + + Edit + + + + DeleteSubject(subject.sId)} + > + + Delete + + + + + + + router.push({ + pathname: '../assignment/upsertAssignment', + params: { sId: subject.sId }, + }) + } + > + + Add Assignment + + + + } + renderSectionHeader={({ section: { title, data } }) => ( + + {title} + + + + {data.length} + + + + )} + renderItem={({ item }) => { + const isOwner = session?.user.id === item.uId; + + return ( + + + + router.push({ + pathname: '/assignment/viewDetailsAssignment', + params: { aId: item.aId }, + }) + } + > + + + {item.title} + + + {item.description ? ( + + {item.description} + + ) : null} + + + Deadline: {formatDate(item.deadline)} + + + + + + {isOwner && ( + + ToggleAssignmentCompletion(item)} + > + + {item.isCompleted ? 'Reopen' : 'Complete'} + + + + + router.push({ + pathname: '../assignment/upsertAssignment', + params: { aId: item.aId }, + }) + } + > + + Edit + + + + DeleteAssignment(item.aId, item.sId)} + > + + Delete + + + + )} + + ); + }} + ListEmptyComponent={ + + + No assignments yet + + + Add one when this subject has work to track. + + + } + renderSectionFooter={({ section }) => + section.data.length === 0 ? ( + + + {section.emptyMessage} + + + {assignments.length === 0 + ? 'Create the first assignment to give this subject a real study path.' + : 'Assignments for this subject will show up here.'} + + + ) : ( + + ) + } + /> + + ); +} diff --git a/AppDev/ikt205_2026_18_study_sprint/source/app/task/_layout.tsx b/AppDev/ikt205_2026_18_study_sprint/source/app/task/_layout.tsx new file mode 100644 index 0000000..df39d7d --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/app/task/_layout.tsx @@ -0,0 +1,11 @@ +import { Stack } from "expo-router"; + +export default function TaskLayout() { + return ( + + + + + + ); +} \ No newline at end of file diff --git a/AppDev/ikt205_2026_18_study_sprint/source/app/task/timer.tsx b/AppDev/ikt205_2026_18_study_sprint/source/app/task/timer.tsx new file mode 100644 index 0000000..6cc62de --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/app/task/timer.tsx @@ -0,0 +1,1483 @@ +import { + GetActiveSession, + GetStudyCycle, + RemoveStudyCycle, + SaveActiveSession, + SaveStudyCycle, + type ActiveSession, + type StudyCycle, +} from '@/lib/asyncStorage'; +import { + DEFAULT_FOCUS_DURATION_MINUTES, + DEFAULT_LONG_BREAK_DURATION_MINUTES, + DEFAULT_SHORT_BREAK_DURATION_MINUTES, + FOCUS_SESSIONS_PER_LONG_BREAK, + STUDY_CYCLE_IDLE_RESET_MINUTES, +} from '@/lib/sessionDefaults'; +import { finalizeStoredSession } from '@/lib/sessionLifecycle'; +import { supabase } from '@/lib/supabase'; +import type { SessionType, Task } from '@/lib/types'; +import * as Haptics from 'expo-haptics'; +import { router, Stack, useLocalSearchParams } from 'expo-router'; +import * as React from 'react'; +import { + Alert, + Animated, + Dimensions, + Easing, + StatusBar, + StyleSheet, + Text, + TouchableOpacity, + View +} from 'react-native'; + +const { width, height } = Dimensions.get('window'); + +const colors = { + black: '#323F4E', + red: '#F76A6A', + text: '#ffffff', +}; + +const TIMER_OPTIONS = [...Array(13).keys()].map((index) => (index === 0 ? 1 : index * 5)); +const ITEM_SIZE = width * 0.38; +const ITEM_SPACING = (width - ITEM_SIZE) / 2; +const TIMER_UNIT_IN_SECONDS = 60; +const HOLD_TO_CANCEL_MS = 2000; +const CANCEL_ANIMATION_DELAY_MS = 250; +const BUTTON_PRESS_IN_MS = 80; +const BUTTON_PRESS_OUT_MS = 140; +const STUDY_CYCLE_IDLE_RESET_MS = STUDY_CYCLE_IDLE_RESET_MINUTES * 60 * 1000; + +type PostSessionPrompt = { + completedSessionType: SessionType; + returnTaskId: string | null; + nextBreakType: 'short_break' | 'long_break' | null; +}; + +type BreakSessionType = Extract; + +function isBreakSession(sessionType: SessionType): sessionType is BreakSessionType { + return sessionType === 'short_break' || sessionType === 'long_break'; +} + +function isStudyCycleActive(studyCycle: StudyCycle, taskId: string, now: number) { + return studyCycle.taskId === taskId && now - studyCycle.lastCompletedAt <= STUDY_CYCLE_IDLE_RESET_MS; +} + +function formatTime(totalSeconds: number) { + const minutes = Math.floor(totalSeconds / 60); + const seconds = totalSeconds % 60; + + return `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; +} + +function getSessionId(sessionData: unknown) { + if (!sessionData || typeof sessionData !== 'object') { + return null; + } + + const maybeSession = sessionData as { + sessionId?: string; + sessionid?: string; + }; + + return maybeSession.sessionId ?? maybeSession.sessionid ?? null; +} + +function getSessionLabel(sessionType: SessionType) { + switch (sessionType) { + case 'short_break': + return 'Short Break'; + case 'long_break': + return 'Long Break'; + default: + return 'Sprint'; + } +} + +type StartSessionInput = { + sessionType: SessionType; + taskId: string | null; + returnTaskId: string | null; + durationSeconds: number; +}; + +export default function TimerScreen() { + const [containerHeight, setContainerHeight] = React.useState(0); + const duration = DEFAULT_FOCUS_DURATION_MINUTES; + const [timerIsRunning, setIsRunning] = React.useState(false); + const [timerOverlayVisible, setTimerOverlayVisible] = React.useState(false); + const [timeRemaining, setTimeRemaining] = React.useState(0); + const [task, setTask] = React.useState(null); + const [currentSessionType, setCurrentSessionType] = React.useState('focus'); + const [postSessionPrompt, setPostSessionPrompt] = React.useState(null); + const [pickerDuration, setPickerDuration] = React.useState(DEFAULT_FOCUS_DURATION_MINUTES); + + const scrollX = React.useRef(new Animated.Value(0)).current; + const pickerListRef = React.useRef | null>(null); + const timerAnimation = React.useRef(new Animated.Value(0)).current; + const buttonAnimation = React.useRef(new Animated.Value(0)).current; + const taskDetailsAnimation = React.useRef(new Animated.Value(0)).current; + const countdownAnimation = React.useRef(new Animated.Value(0)).current; + const cancelButtonAnimation = React.useRef(new Animated.Value(0)).current; + const pressedButtonAnimation = React.useRef(new Animated.Value(0)).current; + const focusModeAnimation = React.useRef(new Animated.Value(0)).current; + const cancelOverlayAnimation = React.useRef(new Animated.Value(0)).current; + + const countdownRef = React.useRef | null>(null); + const cancelHoldTimeoutRef = React.useRef | null>(null); + const cancelHoldAnimationDelayRef = React.useRef | null>(null); + const runningAnimationRef = React.useRef(null); + const progressAnimationRef = React.useRef(null); + const sessionStartedAtRef = React.useRef(null); + const sessionDurationMsRef = React.useRef(0); + const cancelAccelStartedRef = React.useRef(false); + const cancelHoldCompletedRef = React.useRef(false); + const cancelHoldActiveRef = React.useRef(false); + const cancelHoldIdRef = React.useRef(0); + const cancelHoldStartedAtRef = React.useRef(0); + + const { tId, sessionType: sessionTypeParam, durationMinutes, durationSeconds, returnTaskId, chooseDuration, onboardingDemo } = useLocalSearchParams<{ + tId?: string; + sessionType?: SessionType; + durationMinutes?: string; + durationSeconds?: string; + returnTaskId?: string; + chooseDuration?: string; + onboardingDemo?: string; + }>(); + const isOnboardingDemo = onboardingDemo === 'true'; + const timerOverlayHeight = Math.max(containerHeight, 1); + const timerOverlayOffscreenY = timerOverlayHeight + 1000; + const selectedSessionType: SessionType = sessionTypeParam ?? 'focus'; + const showDurationPicker = + selectedSessionType === 'focus' && + chooseDuration === 'true' && + durationSeconds == null; + const selectedDurationMinutes = React.useMemo(() => { + if (!durationMinutes) { + return null; + } + + const parsedDuration = Number(durationMinutes); + + if (!Number.isFinite(parsedDuration) || parsedDuration <= 0) { + return null; + } + + return parsedDuration; + }, [durationMinutes]); + const selectedDurationSeconds = React.useMemo(() => { + if (!durationSeconds) { + return null; + } + + const parsedDuration = Number(durationSeconds); + + if (!Number.isFinite(parsedDuration) || parsedDuration <= 0) { + return null; + } + + return parsedDuration; + }, [durationSeconds]); + const displayDurationMinutes = React.useMemo(() => { + if (selectedDurationSeconds != null) { + return null; + } + + if (selectedDurationMinutes != null) { + return selectedDurationMinutes; + } + + if (selectedSessionType === 'focus') { + return DEFAULT_FOCUS_DURATION_MINUTES; + } + + return DEFAULT_SHORT_BREAK_DURATION_MINUTES; + }, [selectedDurationMinutes, selectedDurationSeconds, selectedSessionType]); + + React.useEffect(() => { + if (showDurationPicker) { + setPickerDuration(displayDurationMinutes ?? duration); + } + }, [displayDurationMinutes, duration, showDurationPicker]); + + React.useEffect(() => { + if (!showDurationPicker) { + return; + } + + const selectedIndex = Math.max(0, TIMER_OPTIONS.indexOf(pickerDuration)); + const nextOffset = selectedIndex * ITEM_SIZE; + + scrollX.setValue(nextOffset); + + requestAnimationFrame(() => { + pickerListRef.current?.scrollToOffset({ + offset: nextOffset, + animated: false, + }); + }); + }, [pickerDuration, scrollX, showDurationPicker, timerIsRunning]); + + React.useEffect(() => { + if (containerHeight > 0 && !timerIsRunning) { + timerAnimation.setValue(timerOverlayOffscreenY); + } + }, [containerHeight, timerIsRunning, timerAnimation, timerOverlayOffscreenY]); + + React.useEffect(() => { + if (!tId) { + setTask(null); + return; + } + + const fetchTask = async () => { + const {data, error} = await supabase + .from('tasks') + .select('*') + .eq('tId', tId) + .single() + + + if (!error && data) { + setTask(data); + } + }; + fetchTask(); +}, [tId]) + + const pressedButtonScale = pressedButtonAnimation.interpolate({ + inputRange: [0, 1], + outputRange: [1, 0.9], + }); + + const cancelButtonTranslateY = cancelButtonAnimation.interpolate({ + inputRange: [0, 1], + outputRange: [16, 0], + }); + + // Real timer progress comes from timerAnimation. The cancel hold adds a + // temporary visual offset on top so release/cancel logic does not fight the + // underlying progress animation. + const timerOverlayTranslateY = Animated.add( + timerAnimation, + cancelOverlayAnimation + ); + + const countdownTranslateX = focusModeAnimation.interpolate({ + inputRange: [0, 1], + outputRange: [0, -width * 0.3], + }); + + const countdownTranslateY = focusModeAnimation.interpolate({ + inputRange: [0, 1], + outputRange: [0, -height * 0.35], + }); + + const countdownScale = focusModeAnimation.interpolate({ + inputRange: [0, 1], + outputRange: [1, 0.55], + }); + + const startButtonOpacity = buttonAnimation.interpolate({ + inputRange: [0, 1], + outputRange: [1, 0], + }); + + const startButtonTranslateY = buttonAnimation.interpolate({ + inputRange: [0, 1], + outputRange: [0, 200], + }); + + const taskDetailsOpacity = taskDetailsAnimation.interpolate({ + inputRange: [0, 1], + outputRange: [0, 1], + }); + + const taskDetailsTranslateY = taskDetailsAnimation.interpolate({ + inputRange: [0, 1], + outputRange: [20, 0], + }); + + const finalizeSprintSession = React.useCallback(async ( + finalStatus: 'completed' | 'cancelled' | 'expired', + activeSessionOverride?: ActiveSession | null + ) => { + const result = await finalizeStoredSession(finalStatus, activeSessionOverride); + + if (result?.error) { + Alert.alert( + 'Could not finalize sprint session', + result.error.message + ); + } + }, []); + + const clearCountdownInterval = React.useCallback(() => { + if (countdownRef.current) { + clearInterval(countdownRef.current); + countdownRef.current = null; + } + }, []); + + const clearCancelHoldTimeouts = React.useCallback(() => { + if (cancelHoldTimeoutRef.current) { + clearTimeout(cancelHoldTimeoutRef.current); + cancelHoldTimeoutRef.current = null; + } + + if (cancelHoldAnimationDelayRef.current) { + clearTimeout(cancelHoldAnimationDelayRef.current); + cancelHoldAnimationDelayRef.current = null; + } + }, []); + + const stopRunningAnimations = React.useCallback(() => { + runningAnimationRef.current?.stop(); + runningAnimationRef.current = null; + + progressAnimationRef.current?.stop(); + progressAnimationRef.current = null; + + cancelOverlayAnimation.stopAnimation(); + }, [cancelOverlayAnimation]); + + React.useEffect(() => { + return () => { + clearCountdownInterval(); + clearCancelHoldTimeouts(); + stopRunningAnimations(); + }; + }, [clearCancelHoldTimeouts, clearCountdownInterval, stopRunningAnimations]); + + const animateButtonPress = React.useCallback( + (pressed: boolean) => { + Animated.timing(pressedButtonAnimation, { + toValue: pressed ? 1 : 0, + duration: pressed ? BUTTON_PRESS_IN_MS : BUTTON_PRESS_OUT_MS, + useNativeDriver: true, + }).start(); + }, + [pressedButtonAnimation] + ); + + const resetSessionValues = React.useCallback((options?: { preservePostSessionPrompt?: boolean }) => { + sessionStartedAtRef.current = null; + sessionDurationMsRef.current = 0; + cancelHoldActiveRef.current = false; + cancelAccelStartedRef.current = false; + cancelHoldCompletedRef.current = false; + + timerAnimation.setValue(timerOverlayOffscreenY); + cancelOverlayAnimation.setValue(0); + setTimerOverlayVisible(false); + setTimeRemaining(0); + setCurrentSessionType(selectedSessionType); + if (!options?.preservePostSessionPrompt) { + setPostSessionPrompt(null); + } + setIsRunning(false); + }, [cancelOverlayAnimation, selectedSessionType, timerAnimation, timerOverlayOffscreenY]); + + const syncStudyCycleAfterCompletion = React.useCallback( + async ( + completedSessionType: SessionType, + completedTaskId: string | null + ): Promise<'short_break' | 'long_break' | null> => { + const now = Date.now(); + + if (completedSessionType === 'focus') { + if (!completedTaskId) { + await RemoveStudyCycle(); + return 'short_break'; + } + + const currentStudyCycle = await GetStudyCycle(); + const nextCompletedFocusSessions = + currentStudyCycle && isStudyCycleActive(currentStudyCycle, completedTaskId, now) + ? currentStudyCycle.completedFocusSessions + 1 + : 1; + + await SaveStudyCycle({ + taskId: completedTaskId, + completedFocusSessions: nextCompletedFocusSessions, + lastCompletedSessionType: 'focus', + lastCompletedAt: now, + }); + + return nextCompletedFocusSessions % FOCUS_SESSIONS_PER_LONG_BREAK === 0 + ? 'long_break' + : 'short_break'; + } + + if (!isBreakSession(completedSessionType) || !completedTaskId) { + await RemoveStudyCycle(); + return null; + } + + const currentStudyCycle = await GetStudyCycle(); + + if (!currentStudyCycle || !isStudyCycleActive(currentStudyCycle, completedTaskId, now)) { + await RemoveStudyCycle(); + return null; + } + + if (completedSessionType === 'long_break') { + await RemoveStudyCycle(); + return null; + } + + await SaveStudyCycle({ + ...currentStudyCycle, + lastCompletedSessionType: completedSessionType, + lastCompletedAt: now, + }); + + return null; + }, + [] + ); + + const finishTimer = React.useCallback(() => { + clearCountdownInterval(); + const activeSessionPromise = GetActiveSession(); + + Animated.parallel([ + Animated.timing(countdownAnimation, { + toValue: 0, + duration: 200, + useNativeDriver: true, + }), + Animated.timing(focusModeAnimation, { + toValue: 0, + duration: 250, + useNativeDriver: true, + }), + Animated.timing(taskDetailsAnimation, { + toValue: 0, + duration: 300, + useNativeDriver: true, + }), + ]).start(() => { + Animated.parallel([ + Animated.timing(buttonAnimation, { + toValue: 0, + duration: 300, + useNativeDriver: true, + }), + Animated.timing(cancelButtonAnimation, { + toValue: 0, + duration: 300, + useNativeDriver: true, + }), + ]).start(() => { + void (async () => { + const completedSession = await activeSessionPromise; + const completedSessionType = completedSession?.sessionType ?? currentSessionType; + const completedReturnTaskId = + completedSessionType === 'focus' + ? (completedSession?.taskId ?? tId ?? null) + : (completedSession?.returnTaskId ?? returnTaskId ?? null); + const nextBreakType = await syncStudyCycleAfterCompletion( + completedSessionType, + completedReturnTaskId + ); + + if (isOnboardingDemo && completedSessionType === 'focus') { + resetSessionValues(); + void finalizeSprintSession('completed', completedSession); + router.replace('/'); + return; + } + + resetSessionValues({ preservePostSessionPrompt: true }); + setPostSessionPrompt({ + completedSessionType, + returnTaskId: completedReturnTaskId, + nextBreakType, + }); + void finalizeSprintSession('completed', completedSession); + })(); + }); + }); + }, [ + buttonAnimation, + cancelButtonAnimation, + clearCountdownInterval, + countdownAnimation, + currentSessionType, + finalizeSprintSession, + focusModeAnimation, + isOnboardingDemo, + resetSessionValues, + syncStudyCycleAfterCompletion, + taskDetailsAnimation, + returnTaskId, + tId, + ]); + + // This picks up the timer overlay animation from the current Y position and + // runs it to the bottom over the remaining session time. + const startProgressAnimation = React.useCallback( + (fromY: number) => { + const elapsedRatio = fromY / timerOverlayHeight; + const remainingMs = sessionDurationMsRef.current * (1 - elapsedRatio); + + sessionStartedAtRef.current = Date.now() - sessionDurationMsRef.current * elapsedRatio; + timerAnimation.setValue(fromY); + + const progressAnimation = Animated.timing(timerAnimation, { + toValue: timerOverlayHeight, + duration: remainingMs, + useNativeDriver: true, + }); + + progressAnimationRef.current = progressAnimation; + progressAnimation.start(({ finished }) => { + progressAnimationRef.current = null; + + if (!finished) { + return; + } + + finishTimer(); + }); + }, + [finishTimer, timerAnimation, timerOverlayHeight] + ); + + const runStartSequence = React.useCallback(() => { + buttonAnimation.setValue(1); + cancelButtonAnimation.setValue(1); + countdownAnimation.setValue(1); + timerAnimation.setValue(0); + + startProgressAnimation(0); + + const focusAnimation = Animated.parallel([ + Animated.timing(focusModeAnimation, { + toValue: 1, + duration: 450, + useNativeDriver: true, + }), + Animated.timing(taskDetailsAnimation, { + toValue: 1, + duration: 500, + useNativeDriver: true, + }), + ]); + + runningAnimationRef.current = focusAnimation; + focusAnimation.start(() => { + runningAnimationRef.current = null; + }); + }, [ + buttonAnimation, + cancelButtonAnimation, + countdownAnimation, + focusModeAnimation, + startProgressAnimation, + taskDetailsAnimation, + timerAnimation, + ]); + + const startCountdown = React.useCallback( + (endTime: number) => { + clearCountdownInterval(); + + const updateRemainingTime = () => { + const remainingSeconds = Math.max( + 0, + Math.ceil((endTime - Date.now()) / 1000) + ); + + setTimeRemaining(remainingSeconds); + + if (remainingSeconds <= 0) { + clearCountdownInterval(); + } + }; + + updateRemainingTime(); + countdownRef.current = setInterval(updateRemainingTime, 1000); + }, + [clearCountdownInterval] + ); + + React.useEffect(() => { + if (timerIsRunning || containerHeight === 0) { + return; + } + + const restoreSprint = async () => { + const activeSession = await GetActiveSession(); + + if (!activeSession) { + return; + } + + if (activeSession.sessionType === 'focus' && activeSession.taskId !== tId) { + return; + } + + if (activeSession.sessionType !== 'focus' && selectedSessionType !== activeSession.sessionType) { + return; + } + + const remainingMs = activeSession.endTime - Date.now(); + + if (remainingMs <= 0) { + await finalizeSprintSession('expired'); + return; + } + + const totalMs = activeSession.durationSeconds * 1000; + const elapsedMs = totalMs - remainingMs; + const elapsedRatio = Math.max(0, Math.min(elapsedMs / totalMs, 1)); + const restoredY = timerOverlayHeight * elapsedRatio; + + setIsRunning(true); + setTimerOverlayVisible(true); + setCurrentSessionType(activeSession.sessionType); + sessionStartedAtRef.current = Date.now() - elapsedMs; + sessionDurationMsRef.current = totalMs; + + buttonAnimation.setValue(1); + cancelButtonAnimation.setValue(1); + countdownAnimation.setValue(1); + focusModeAnimation.setValue(1); + taskDetailsAnimation.setValue(1); + cancelOverlayAnimation.setValue(0); + + startCountdown(activeSession.endTime); + startProgressAnimation(restoredY); + }; + + void restoreSprint(); + }, [ + buttonAnimation, + cancelButtonAnimation, + cancelOverlayAnimation, + containerHeight, + countdownAnimation, + finalizeSprintSession, + focusModeAnimation, + startCountdown, + startProgressAnimation, + taskDetailsAnimation, + selectedSessionType, + tId, + timerOverlayHeight, + timerIsRunning, + ]); + + const startSession = React.useCallback(async ({ + sessionType, + taskId, + returnTaskId, + durationSeconds, + }: StartSessionInput) => { + if (timerIsRunning || containerHeight === 0) { + return; + } + + if (sessionType === 'focus' && !taskId) { + Alert.alert('Could not start session', 'Focus sessions must be linked to a task.'); + return; + } + + if (sessionType === 'focus' && taskId) { + const currentStudyCycle = await GetStudyCycle(); + const now = Date.now(); + + if (currentStudyCycle && !isStudyCycleActive(currentStudyCycle, taskId, now)) { + await RemoveStudyCycle(); + } + } + + const endTime = Date.now() + durationSeconds * 1000; + const { data: userData, error: userError } = await supabase.auth.getUser(); + + if (userError || !userData.user?.id) { + Alert.alert('Could not start session', 'Missing signed-in user.'); + return; + } + + const { data: sessionData, error: sessionError } = await supabase.rpc('start_sprint_session', { + p_task_id: taskId, + p_user_id: userData.user.id, + p_session_type: sessionType, + p_planned_duration: durationSeconds, + p_started_at: new Date().toISOString(), + }); + + const sessionId = getSessionId(sessionData); + + if (sessionError || !sessionId) { + Alert.alert( + 'Could not start session', + sessionError?.message ?? 'Session could not be created.' + ); + return; + } + + Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success); + setIsRunning(true); + setTimerOverlayVisible(true); + setCurrentSessionType(sessionType); + + taskDetailsAnimation.setValue(0); + countdownAnimation.setValue(0); + cancelOverlayAnimation.setValue(0); + + sessionStartedAtRef.current = Date.now(); + sessionDurationMsRef.current = durationSeconds * 1000; + + void SaveActiveSession({ + sessionId, + sessionType, + taskId, + returnTaskId, + durationSeconds, + endTime, + }); + + startCountdown(endTime); + runStartSequence(); + }, [ + cancelOverlayAnimation, + containerHeight, + countdownAnimation, + runStartSequence, + startCountdown, + taskDetailsAnimation, + timerIsRunning, + ]); + + const startTimerSession = React.useCallback(async () => { + if (selectedSessionType === 'focus' && !tId) { + return; + } + + const totalSeconds = + selectedDurationSeconds ?? + (showDurationPicker ? pickerDuration : (displayDurationMinutes ?? duration)) * TIMER_UNIT_IN_SECONDS; + + await startSession({ + sessionType: selectedSessionType, + taskId: selectedSessionType === 'focus' ? (tId ?? null) : null, + returnTaskId: selectedSessionType === 'focus' ? null : (returnTaskId ?? null), + durationSeconds: totalSeconds, + }); + }, [ + displayDurationMinutes, + duration, + pickerDuration, + selectedDurationSeconds, + selectedSessionType, + showDurationPicker, + startSession, + returnTaskId, + tId, + ]); + + const handleStartBreak = React.useCallback(() => { + const nextBreakType = postSessionPrompt?.nextBreakType ?? 'short_break'; + const durationMinutes = + nextBreakType === 'long_break' + ? DEFAULT_LONG_BREAK_DURATION_MINUTES + : DEFAULT_SHORT_BREAK_DURATION_MINUTES; + + setPostSessionPrompt(null); + router.replace({ + pathname: '/task/timer', + params: { + sessionType: nextBreakType, + durationMinutes: String(durationMinutes), + returnTaskId: postSessionPrompt?.returnTaskId ?? tId ?? undefined, + }, + }); + }, [postSessionPrompt, tId]); + + const handleContinueSameTask = React.useCallback(() => { + if (!postSessionPrompt?.returnTaskId) { + router.replace('/'); + return; + } + + setPostSessionPrompt(null); + router.replace({ + pathname: '/task/timer', + params: { + tId: postSessionPrompt.returnTaskId, + durationMinutes: String(DEFAULT_FOCUS_DURATION_MINUTES), + }, + }); + }, [postSessionPrompt]); + + const handleBackToDashboard = React.useCallback(() => { + setPostSessionPrompt(null); + router.replace('/'); + }, []); + + const handleChooseCustomDuration = React.useCallback(() => { + if (timerIsRunning || selectedSessionType !== 'focus') { + return; + } + + router.replace({ + pathname: '/task/timer', + params: { + tId: tId ?? undefined, + sessionType: 'focus', + chooseDuration: 'true', + durationMinutes: String(displayDurationMinutes ?? duration), + }, + }); + }, [displayDurationMinutes, duration, selectedSessionType, tId, timerIsRunning]); + + const cancelTimer = React.useCallback(() => { + if (!timerIsRunning) { + return; + } + + clearCountdownInterval(); + clearCancelHoldTimeouts(); + void finalizeSprintSession('cancelled'); + + runningAnimationRef.current?.stop(); + runningAnimationRef.current = null; + + progressAnimationRef.current?.stop(); + progressAnimationRef.current = null; + + timerAnimation.stopAnimation(() => { + cancelOverlayAnimation.stopAnimation(() => { + timerAnimation.setValue(timerOverlayOffscreenY); + cancelOverlayAnimation.setValue(0); + setTimerOverlayVisible(false); + + Animated.parallel([ + Animated.timing(cancelButtonAnimation, { + toValue: 0, + duration: 180, + useNativeDriver: true, + }), + Animated.timing(taskDetailsAnimation, { + toValue: 0, + duration: 220, + useNativeDriver: true, + }), + Animated.timing(focusModeAnimation, { + toValue: 0, + duration: 250, + useNativeDriver: true, + }), + Animated.timing(countdownAnimation, { + toValue: 0, + duration: 180, + useNativeDriver: true, + }), + ]).start(() => { + Animated.timing(buttonAnimation, { + toValue: 0, + duration: 220, + useNativeDriver: true, + }).start(() => { + resetSessionValues(); + }); + }); + }); + }); + }, [ + buttonAnimation, + cancelButtonAnimation, + cancelOverlayAnimation, + clearCancelHoldTimeouts, + clearCountdownInterval, + countdownAnimation, + finalizeSprintSession, + focusModeAnimation, + resetSessionValues, + taskDetailsAnimation, + timerAnimation, + timerOverlayOffscreenY, + timerIsRunning, + ]); + + const handleTimerPickerMomentumEnd = React.useCallback( + (event: { nativeEvent: { contentOffset: { x: number } } }) => { + if (timerIsRunning) { + return; + } + + const index = Math.round(event.nativeEvent.contentOffset.x / ITEM_SIZE); + const clampedIndex = Math.max(0, Math.min(index, TIMER_OPTIONS.length - 1)); + const nextDuration = TIMER_OPTIONS[clampedIndex]; + + setPickerDuration(nextDuration); + }, + [timerIsRunning] + ); + + const renderTimerItem = React.useCallback( + ({ item, index }: { item: number; index: number }) => { + const inputRange = [ + (index - 1) * ITEM_SIZE, + index * ITEM_SIZE, + (index + 1) * ITEM_SIZE, + ]; + + const opacity = scrollX.interpolate({ + inputRange, + outputRange: [0.38, 1, 0.38], + }); + + const scale = scrollX.interpolate({ + inputRange, + outputRange: [0.72, 1, 0.72], + }); + + return ( + + + {item} + + + ); + }, + [scrollX] + ); + + const handleCancelHoldStart = React.useCallback(() => { + animateButtonPress(true); + cancelHoldIdRef.current += 1; + + const cancelHoldId = cancelHoldIdRef.current; + cancelHoldActiveRef.current = true; + cancelHoldStartedAtRef.current = Date.now(); + cancelAccelStartedRef.current = false; + cancelHoldCompletedRef.current = false; + + cancelHoldAnimationDelayRef.current = setTimeout(() => { + cancelHoldAnimationDelayRef.current = null; + + if (!cancelHoldActiveRef.current || cancelHoldIdRef.current !== cancelHoldId) { + return; + } + + // The hold starts with normal button feedback. After a short delay, we + // begin the accelerated red overlay preview so quick taps do not cause a + // jolt, while long holds still clearly show that cancel is about to fire. + cancelAccelStartedRef.current = true; + cancelOverlayAnimation.setValue(0); + + const elapsedHoldMs = Date.now() - cancelHoldStartedAtRef.current; + const remainingHoldMs = Math.max(1, HOLD_TO_CANCEL_MS - elapsedHoldMs); + const sessionStartedAt = sessionStartedAtRef.current ?? Date.now(); + const elapsedAtCancelMs = Date.now() + remainingHoldMs - sessionStartedAt; + const expectedProgress = elapsedAtCancelMs / sessionDurationMsRef.current; + const clampedProgress = Math.max(0, Math.min(expectedProgress, 1)); + const expectedYAtCancel = timerOverlayHeight * clampedProgress; + const cancelOffset = Math.max(0, timerOverlayHeight - expectedYAtCancel); + + Animated.timing(cancelOverlayAnimation, { + toValue: cancelOffset, + duration: remainingHoldMs, + easing: Easing.in(Easing.quad), + useNativeDriver: true, + }).start(); + }, CANCEL_ANIMATION_DELAY_MS); + + cancelHoldTimeoutRef.current = setTimeout(() => { + cancelHoldActiveRef.current = false; + cancelHoldIdRef.current += 1; + cancelAccelStartedRef.current = false; + cancelHoldCompletedRef.current = true; + + Haptics.notificationAsync(Haptics.NotificationFeedbackType.Warning); + cancelTimer(); + cancelHoldTimeoutRef.current = null; + }, HOLD_TO_CANCEL_MS); + }, [animateButtonPress, cancelOverlayAnimation, cancelTimer, timerOverlayHeight]); + + const handleCancelHoldEnd = React.useCallback(() => { + animateButtonPress(false); + cancelHoldActiveRef.current = false; + cancelHoldIdRef.current += 1; + + clearCancelHoldTimeouts(); + + if (cancelHoldCompletedRef.current) { + return; + } + + if (!cancelAccelStartedRef.current) { + return; + } + + cancelAccelStartedRef.current = false; + cancelOverlayAnimation.stopAnimation((currentOffset) => { + cancelOverlayAnimation.setValue(currentOffset); + Animated.timing(cancelOverlayAnimation, { + toValue: 0, + duration: 750, + easing: Easing.in(Easing.bounce), + useNativeDriver: true, + }).start(); + }); + }, [animateButtonPress, cancelOverlayAnimation, clearCancelHoldTimeouts]); + + return ( + { + setContainerHeight(event.nativeEvent.layout.height); + }} + > + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: colors.black, + overflow: 'hidden', + }, + timerOverlay: { + position: 'absolute', + top: 0, + left: 0, + right: 0, + backgroundColor: colors.red, + }, + startButtonContainer: { + justifyContent: 'flex-end', + alignItems: 'center', + paddingBottom: 100, + }, + roundButton: { + width: 80, + height: 80, + borderRadius: 80, + backgroundColor: '#beb9a7', + alignItems: 'center', + justifyContent: 'center', + }, + timerPickerWrapper: { + position: 'absolute', + left: 0, + right: 0, + flex: 1, + alignItems: 'center', + }, + timerPickerList: { + flexGrow: 0, + }, + fixedDurationBlock: { + position: 'absolute', + top: height * 0.28, + left: 32, + right: 32, + alignItems: 'center', + }, + fixedDurationLabel: { + color: colors.text, + fontSize: 56, + fontFamily: 'Menlo', + fontWeight: '900', + textAlign: 'center', + }, + fixedDurationDescription: { + color: colors.text, + fontSize: 18, + lineHeight: 26, + marginTop: 16, + textAlign: 'center', + }, + durationPickerLink: { + marginTop: 18, + minHeight: 42, + paddingHorizontal: 18, + alignItems: 'center', + justifyContent: 'center', + borderRadius: 999, + borderWidth: 1, + borderColor: 'rgba(255,255,255,0.24)', + backgroundColor: 'rgba(255,255,255,0.08)', + }, + durationPickerLinkText: { + color: '#F3EBDD', + fontSize: 15, + fontWeight: '700', + textAlign: 'center', + }, + timerPickerContent: { + paddingHorizontal: ITEM_SPACING, + }, + timerOptionItem: { + width: ITEM_SIZE, + justifyContent: 'center', + alignItems: 'center', + }, + timerOptionText: { + fontSize: ITEM_SIZE * 0.8, + fontFamily: 'Menlo', + color: colors.text, + fontWeight: '900', + }, + taskDetails: { + position: 'absolute', + top: height * 0.34, + left: 32, + right: 32, + alignItems: 'center', + }, + taskName: { + color: colors.text, + fontSize: 32, + fontWeight: '800', + textAlign: 'center', + }, + taskDescription: { + color: colors.text, + fontSize: 24, + lineHeight: 32, + marginTop: 20, + textAlign: 'center', + }, + countdownText: { + fontSize: ITEM_SIZE * 0.32, + fontFamily: 'Menlo', + color: colors.text, + fontWeight: '900', + textAlign: 'center', + }, + cancelButtonContainer: { + position: 'absolute', + left: 0, + right: 0, + bottom: 44, + alignItems: 'center', + zIndex: 2, + }, + cancelButton: { + minWidth: 112, + height: 44, + borderRadius: 22, + borderWidth: 1, + borderColor: 'rgba(155, 155, 155, 0.35)', + backgroundColor: '#beb9a7', + alignItems: 'center', + justifyContent: 'center', + paddingHorizontal: 22, + position: 'relative', + overflow: 'hidden', + }, + countdownOverlay: { + position: 'absolute', + top: height / 2.5 , + left: 0, + right: 0, + alignItems: 'center', + }, + postSessionOverlay: { + ...StyleSheet.absoluteFillObject, + backgroundColor: 'rgba(20, 26, 34, 0.94)', + justifyContent: 'center', + paddingHorizontal: 24, + zIndex: 10, + }, + postSessionCard: { + borderRadius: 28, + backgroundColor: '#F7F4EA', + paddingHorizontal: 24, + paddingVertical: 28, + }, + postSessionEyebrow: { + color: '#7A6F5A', + fontSize: 13, + fontWeight: '700', + letterSpacing: 0.8, + textTransform: 'uppercase', + }, + postSessionTitle: { + color: '#323F4E', + fontSize: 30, + fontWeight: '800', + marginTop: 10, + }, + postSessionBody: { + color: '#52606D', + fontSize: 17, + lineHeight: 25, + marginTop: 12, + marginBottom: 24, + }, + postSessionPrimaryButton: { + minHeight: 54, + borderRadius: 18, + backgroundColor: '#323F4E', + alignItems: 'center', + justifyContent: 'center', + paddingHorizontal: 20, + }, + postSessionPrimaryButtonText: { + color: '#FFFFFF', + fontSize: 16, + fontWeight: '800', + }, + postSessionSecondaryButton: { + minHeight: 54, + borderRadius: 18, + borderWidth: 1, + borderColor: '#C2B8A3', + backgroundColor: '#EFE7D8', + alignItems: 'center', + justifyContent: 'center', + paddingHorizontal: 20, + marginTop: 12, + }, + postSessionSecondaryButtonText: { + color: '#323F4E', + fontSize: 16, + fontWeight: '700', + }, + postSessionTertiaryButton: { + minHeight: 48, + alignItems: 'center', + justifyContent: 'center', + marginTop: 10, + }, + postSessionTertiaryButtonText: { + color: '#52606D', + fontSize: 15, + fontWeight: '700', + }, +}); diff --git a/AppDev/ikt205_2026_18_study_sprint/source/app/task/upsertTask.tsx b/AppDev/ikt205_2026_18_study_sprint/source/app/task/upsertTask.tsx new file mode 100644 index 0000000..2727d04 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/app/task/upsertTask.tsx @@ -0,0 +1,298 @@ +import { defaultStyles } from '@/constants/defaultStyles'; +import { SaveSetupSprintDemoUsed } from '@/lib/asyncStorage'; +import { CheckAssignmentCompletion } from '@/lib/progress'; +import { supabase } from '@/lib/supabase'; +import type { Task } from '@/lib/types'; +import { router, Stack, useLocalSearchParams } from 'expo-router'; +import { useEffect, useState } from 'react'; +import { + ActivityIndicator, + Alert, + Keyboard, + KeyboardAvoidingView, + Platform, + Pressable, + ScrollView, + Text, + TextInput, + TouchableWithoutFeedback, + View, +} from 'react-native'; + +export default function UpsertTask() { + const { tId, aId: routeAId, flow } = useLocalSearchParams<{ + tId?: string; + aId?: string; + flow?: string; + }>(); + + const isEditMode = Boolean(tId); + const isSetupFlow = flow === 'setup'; + + const [title, SetTitle] = useState(''); + const [description, SetDescription] = useState(''); + const [isCompleted, SetIsCompleted] = useState(false); + const [assignmentId, SetAssignmentId] = useState(routeAId ?? null); + + const [isLoading, SetIsLoading] = useState(isEditMode); + const [isSaving, SetIsSaving] = useState(false); + + useEffect(() => { + if (!isEditMode || !tId) { + SetIsLoading(false); + return; + } + + const loadTask = async () => { + SetIsLoading(true); + + const { data, error } = await supabase + .from('tasks') + .select('*') + .eq('tId', tId) + .single(); + + SetIsLoading(false); + + if (error || !data) { + Alert.alert('Task could not be loaded, please try again'); + router.back(); + return; + } + + const task = data as Task; + + SetTitle(task.title ?? ''); + SetDescription(task.description ?? ''); + SetIsCompleted(task.isCompleted ?? false); + SetAssignmentId(task.aId ?? routeAId ?? null); + }; + + loadTask(); + }, [isEditMode, tId, routeAId]); + + const handleSubmit = async () => { + if (title.trim() === '') { + Alert.alert('Title is required!'); + return; + } + + const { data, error: userError } = await supabase.auth.getUser(); + + if (userError || !data.user) { + router.replace('/login'); + return; + } + + if (!assignmentId) { + Alert.alert('Missing assignment', 'This task is not linked to an assignment.'); + return; + } + + SetIsSaving(true); + + const payload = { + title: title.trim(), + description: description.trim(), + isCompleted, + lastChanged: new Date().toISOString(), + uId: data.user.id, + aId: assignmentId, + }; + + const result = + isEditMode && tId + ? await supabase.from('tasks').update(payload).eq('tId', tId) + : await supabase.from('tasks').insert(payload).select().single(); + + if (result.error) { + SetIsSaving(false); + Alert.alert( + isEditMode + ? 'Task could not be updated, please try again' + : 'Task could not be created, please try again' + ); + return; + } + + try { + await CheckAssignmentCompletion(assignmentId); + } catch { + SetIsSaving(false); + Alert.alert('Failed to update assignment completion state'); + return; + } + + SetIsSaving(false); + + if (!isEditMode && isSetupFlow && result.data?.tId) { + await SaveSetupSprintDemoUsed(data.user.id); + router.replace({ + pathname: '/task/timer', + params: { + tId: result.data.tId, + durationSeconds: '5', + onboardingDemo: 'true', + }, + }); + return; + } + + Alert.alert( + isEditMode ? 'Task successfully updated!' : 'Task successfully created!' + ); + + router.back(); + }; + + const inputClassName = + 'rounded-2xl border border-app-border bg-app-subtle px-4 py-3 text-base text-text-main'; + + const labelClassName = 'mb-2 text-sm font-semibold text-text-secondary'; + + if (isLoading) { + return ( + + + + ); + } + + return ( + <> + + + + + + + + {isEditMode ? 'Edit Task' : 'Create Task'} + + + {isEditMode + ? 'Update this task and keep your assignment moving forward.' + : 'Add a small step to move this assignment forward.'} + + + + + + Title + + + + + Description + + + + SetIsCompleted((state) => !state)} + disabled={isSaving} + className={`mb-6 flex-row items-center rounded-2xl border p-4 ${ + isCompleted + ? 'border-accent bg-accent-soft' + : 'border-app-border bg-app-subtle' + }`} + > + + {isCompleted && ( + + ✓ + + )} + + + + + Mark as completed + + + You can change this later. + + + + + + {isSaving ? ( + + + + {isEditMode ? 'Saving...' : 'Creating...'} + + + ) : ( + + {isEditMode ? 'Save Changes' : 'Create Task'} + + )} + + + router.back()} + disabled={isSaving} + > + + Cancel + + + + + + + + ); +} diff --git a/AppDev/ikt205_2026_18_study_sprint/source/app/task/viewDetailsTask.tsx b/AppDev/ikt205_2026_18_study_sprint/source/app/task/viewDetailsTask.tsx new file mode 100644 index 0000000..7391c7e --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/app/task/viewDetailsTask.tsx @@ -0,0 +1,468 @@ +import { GetActiveSession } from '@/lib/asyncStorage'; +import { formatDateTime } from '@/lib/date'; +import { CheckAssignmentCompletion } from '@/lib/progress'; +import { DEFAULT_FOCUS_DURATION_MINUTES } from '@/lib/sessionDefaults'; +import { finalizeStoredSession } from '@/lib/sessionLifecycle'; +import { getSubjectColorSet, type SubjectColor } from '@/lib/subjectColors'; +import { supabase } from '@/lib/supabase'; +import type { Task } from '@/lib/types'; +import { Session } from '@supabase/supabase-js'; +import { router, Stack, useFocusEffect, useLocalSearchParams } from 'expo-router'; +import { useCallback, useEffect, useState } from 'react'; +import { ActivityIndicator, Alert, Pressable, Text, View } from 'react-native'; + +function formatTrackedTime(totalSeconds: number) { + if (totalSeconds <= 0) { + return '0m'; + } + + const hours = Math.floor(totalSeconds / 3600); + const minutes = Math.floor((totalSeconds % 3600) / 60); + + if (hours === 0) { + return `${minutes}m`; + } + + if (minutes === 0) { + return `${hours}h`; + } + + return `${hours}h ${minutes}m`; +} + +export default function ViewDetailsTask() { + const { tId } = useLocalSearchParams<{ tId: string }>(); + + const [task, SetTask] = useState(null); + const [session, SetSession] = useState(null); + const [isLoading, SetIsLoading] = useState(false); + const [completedFocusSessions, setCompletedFocusSessions] = useState(0); + const [contextMeta, setContextMeta] = useState({ + subjectTitle: 'No Subject', + assignmentTitle: 'No Assignment', + subjectColor: 'slate' as SubjectColor, + }); + + useEffect(() => { + supabase.auth.getSession().then(({ data }) => SetSession(data.session ?? null)); + + const { data: sub } = supabase.auth.onAuthStateChange((_event, newSession) => { + SetSession(newSession); + }); + + return () => sub.subscription.unsubscribe(); + }, []); + + const loadTaskStudyActivity = useCallback(async (taskId: string, userId: string) => { + const { count, error } = await supabase + .from('sprint_sessions') + .select('sessionId', { count: 'exact', head: true }) + .eq('taskId', taskId) + .eq('userId', userId) + .eq('sessionType', 'focus') + .eq('status', 'completed'); + + if (error) { + setCompletedFocusSessions(0); + return; + } + + setCompletedFocusSessions(count ?? 0); + }, []); + + const GetTask = useCallback(async (taskId: string) => { + SetIsLoading(true); + + const { data, error } = await supabase + .from('tasks') + .select('*') + .eq('tId', taskId) + .single(); + + if (error || !data) { + SetTask(null); + setContextMeta({ + subjectTitle: 'Unknown Subject', + assignmentTitle: 'Unknown Assignment', + subjectColor: 'slate', + }); + setCompletedFocusSessions(0); + SetIsLoading(false); + Alert.alert('Task could not be fetched, please try again'); + return; + } + + SetTask(data); + await loadTaskStudyActivity(taskId, data.uId); + + let nextContextMeta = { + subjectTitle: 'Unknown Subject', + assignmentTitle: 'Unknown Assignment', + subjectColor: 'slate' as SubjectColor, + }; + + if (data.aId) { + const { data: assignmentData, error: assignmentError } = await supabase + .from('assignments') + .select('title, sId') + .eq('aId', data.aId) + .single(); + + if (!assignmentError && assignmentData) { + nextContextMeta.assignmentTitle = assignmentData.title ?? 'Unknown Assignment'; + + if (assignmentData.sId) { + const { data: subjectData, error: subjectError } = await supabase + .from('subjects') + .select('title, color') + .eq('sId', assignmentData.sId) + .single(); + + if (!subjectError && subjectData) { + nextContextMeta = { + subjectTitle: subjectData.title ?? 'Unknown Subject', + assignmentTitle: assignmentData.title ?? 'Unknown Assignment', + subjectColor: (subjectData.color as SubjectColor | undefined) ?? 'slate', + }; + } + } + } + } + + setContextMeta(nextContextMeta); + SetIsLoading(false); + }, [loadTaskStudyActivity]); + + useFocusEffect( + useCallback(() => { + if (session && tId) { + void GetTask(tId); + } + }, [GetTask, session, tId]) + ); + + const handleSprintStart = async () => { + const activeSession = await GetActiveSession(); + + if (!activeSession) { + router.push({ + pathname: '/task/timer', + params: { + tId: task?.tId, + durationMinutes: String(DEFAULT_FOCUS_DURATION_MINUTES), + }, + }); + return; + } + + const secondsLeft = Math.ceil((activeSession.endTime - Date.now()) / 1000); + + if (secondsLeft <= 0) { + await finalizeStoredSession('expired', activeSession); + router.push({ + pathname: '/task/timer', + params: { + tId: task?.tId, + durationMinutes: String(DEFAULT_FOCUS_DURATION_MINUTES), + }, + }); + return; + } + + if (activeSession.taskId === task?.tId) { + router.push({ + pathname: '/task/timer', + params: { + tId: activeSession.taskId ?? undefined, + durationMinutes: String(DEFAULT_FOCUS_DURATION_MINUTES), + }, + }); + return; + } + + Alert.alert( + 'Active session in progress', + `End the current session and start a new ${DEFAULT_FOCUS_DURATION_MINUTES} minute sprint on this task?`, + [ + { text: 'Cancel', style: 'cancel' }, + { + text: 'Start new sprint', + style: 'destructive', + onPress: async () => { + await finalizeStoredSession('cancelled', activeSession); + router.push({ + pathname: '/task/timer', + params: { + tId: task?.tId, + durationMinutes: String(DEFAULT_FOCUS_DURATION_MINUTES), + }, + }); + }, + }, + ] + ); + }; + + const DeleteTask = async (taskId: string) => { + Alert.alert( + 'Delete Task', + 'Are you sure you want to delete this task?', + [ + { + text: 'Cancel', + style: 'cancel', + }, + { + text: 'Delete', + style: 'destructive', + onPress: async () => { + const { error } = await supabase + .from('tasks') + .delete() + .eq('tId', taskId); + + if (error) { + Alert.alert('Task could not be deleted, please try again'); + return; + } + + const aId = task?.aId; + + if (aId) { + try { + await CheckAssignmentCompletion(aId); + } catch { + Alert.alert('Failed to update assignment completion state'); + } + } + + Alert.alert('Task deleted successfully!'); + router.back(); + }, + }, + ] + ); + }; + + const colorSet = getSubjectColorSet(contextMeta.subjectColor); + + if (isLoading) { + return ( + + + + ); + } + + if (!task) { + return ( + + ( + await supabase.auth.signOut()} + > + + Logout + + + ), + }} + /> + + + + Task not found + + + The task could not be loaded. + + + router.back()} + > + + Go back + + + + + ); + } + + const isOwner = session?.user.id === task.uId; + + return ( + + ( + await supabase.auth.signOut()} + > + + Logout + + + ), + }} + /> + + + + + {task.isCompleted ? ( + + ) : null} + + + + + {task.title} + + + {task.description ? ( + + {task.description} + + ) : ( + + No description added. + + )} + + + + + {contextMeta.subjectTitle} + + + + + + {contextMeta.assignmentTitle} + + + + + + Status: {task.isCompleted ? 'Completed' : 'Not completed'} + + + + + + + Study activity + + + This tracks focused work on the task separately from whether the task is marked completed. + + + + + + Focus time + + + {formatTrackedTime(task.totalTimeInSeconds ?? 0)} + + + + + + Completed sessions + + + {completedFocusSessions} + + + + + + + Last changed: {formatDateTime(task.lastChanged)} + + + + + {isOwner ? ( + + + + Start Sprint + + + + + Starts a {DEFAULT_FOCUS_DURATION_MINUTES} minute focus sprint for this task. + + + + + router.push({ + pathname: '/task/upsertTask', + params: { tId: task.tId }, + }) + } + > + + Edit + + + + DeleteTask(task.tId)} + > + + Delete + + + + + ) : null} + + + ); +} diff --git a/AppDev/ikt205_2026_18_study_sprint/source/assets/images/android-icon-background.png b/AppDev/ikt205_2026_18_study_sprint/source/assets/images/android-icon-background.png new file mode 100644 index 0000000..ce57697 Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/source/assets/images/android-icon-background.png differ diff --git a/AppDev/ikt205_2026_18_study_sprint/source/assets/images/android-icon-foreground.png b/AppDev/ikt205_2026_18_study_sprint/source/assets/images/android-icon-foreground.png new file mode 100644 index 0000000..d9eabcf Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/source/assets/images/android-icon-foreground.png differ diff --git a/AppDev/ikt205_2026_18_study_sprint/source/assets/images/android-icon-monochrome.png b/AppDev/ikt205_2026_18_study_sprint/source/assets/images/android-icon-monochrome.png new file mode 100644 index 0000000..bbf65ed Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/source/assets/images/android-icon-monochrome.png differ diff --git a/AppDev/ikt205_2026_18_study_sprint/source/assets/images/favicon.png b/AppDev/ikt205_2026_18_study_sprint/source/assets/images/favicon.png new file mode 100644 index 0000000..a5be21f Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/source/assets/images/favicon.png differ diff --git a/AppDev/ikt205_2026_18_study_sprint/source/assets/images/icon.png b/AppDev/ikt205_2026_18_study_sprint/source/assets/images/icon.png new file mode 100644 index 0000000..d6d20a2 Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/source/assets/images/icon.png differ diff --git a/AppDev/ikt205_2026_18_study_sprint/source/assets/images/master.png b/AppDev/ikt205_2026_18_study_sprint/source/assets/images/master.png new file mode 100644 index 0000000..d6d20a2 Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/source/assets/images/master.png differ diff --git a/AppDev/ikt205_2026_18_study_sprint/source/assets/images/partial-react-logo.png b/AppDev/ikt205_2026_18_study_sprint/source/assets/images/partial-react-logo.png new file mode 100644 index 0000000..66fd957 Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/source/assets/images/partial-react-logo.png differ diff --git a/AppDev/ikt205_2026_18_study_sprint/source/assets/images/react-logo.png b/AppDev/ikt205_2026_18_study_sprint/source/assets/images/react-logo.png new file mode 100644 index 0000000..9d72a9f Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/source/assets/images/react-logo.png differ diff --git a/AppDev/ikt205_2026_18_study_sprint/source/assets/images/react-logo@2x.png b/AppDev/ikt205_2026_18_study_sprint/source/assets/images/react-logo@2x.png new file mode 100644 index 0000000..2229b13 Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/source/assets/images/react-logo@2x.png differ diff --git a/AppDev/ikt205_2026_18_study_sprint/source/assets/images/react-logo@3x.png b/AppDev/ikt205_2026_18_study_sprint/source/assets/images/react-logo@3x.png new file mode 100644 index 0000000..a99b203 Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/source/assets/images/react-logo@3x.png differ diff --git a/AppDev/ikt205_2026_18_study_sprint/source/assets/images/splash-icon.png b/AppDev/ikt205_2026_18_study_sprint/source/assets/images/splash-icon.png new file mode 100644 index 0000000..d6d20a2 Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/source/assets/images/splash-icon.png differ diff --git a/AppDev/ikt205_2026_18_study_sprint/source/babel.config.js b/AppDev/ikt205_2026_18_study_sprint/source/babel.config.js new file mode 100644 index 0000000..7322dc0 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/babel.config.js @@ -0,0 +1,10 @@ +module.exports = function (api) { + api.cache(true); + + return { + presets: [ + ['babel-preset-expo', { jsxImportSource: 'nativewind' }], + 'nativewind/babel', + ], + }; +}; \ No newline at end of file diff --git a/AppDev/ikt205_2026_18_study_sprint/source/components/external-link.tsx b/AppDev/ikt205_2026_18_study_sprint/source/components/external-link.tsx new file mode 100644 index 0000000..883e515 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/components/external-link.tsx @@ -0,0 +1,25 @@ +import { Href, Link } from 'expo-router'; +import { openBrowserAsync, WebBrowserPresentationStyle } from 'expo-web-browser'; +import { type ComponentProps } from 'react'; + +type Props = Omit, 'href'> & { href: Href & string }; + +export function ExternalLink({ href, ...rest }: Props) { + return ( + { + if (process.env.EXPO_OS !== 'web') { + // Prevent the default behavior of linking to the default browser on native. + event.preventDefault(); + // Open the link in an in-app browser. + await openBrowserAsync(href, { + presentationStyle: WebBrowserPresentationStyle.AUTOMATIC, + }); + } + }} + /> + ); +} diff --git a/AppDev/ikt205_2026_18_study_sprint/source/components/haptic-tab.tsx b/AppDev/ikt205_2026_18_study_sprint/source/components/haptic-tab.tsx new file mode 100644 index 0000000..7f3981c --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/components/haptic-tab.tsx @@ -0,0 +1,18 @@ +import { BottomTabBarButtonProps } from '@react-navigation/bottom-tabs'; +import { PlatformPressable } from '@react-navigation/elements'; +import * as Haptics from 'expo-haptics'; + +export function HapticTab(props: BottomTabBarButtonProps) { + return ( + { + if (process.env.EXPO_OS === 'ios') { + // Add a soft haptic feedback when pressing down on the tabs. + Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); + } + props.onPressIn?.(ev); + }} + /> + ); +} diff --git a/AppDev/ikt205_2026_18_study_sprint/source/components/hello-wave.tsx b/AppDev/ikt205_2026_18_study_sprint/source/components/hello-wave.tsx new file mode 100644 index 0000000..5def547 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/components/hello-wave.tsx @@ -0,0 +1,19 @@ +import Animated from 'react-native-reanimated'; + +export function HelloWave() { + return ( + + 👋 + + ); +} diff --git a/AppDev/ikt205_2026_18_study_sprint/source/components/parallax-scroll-view.tsx b/AppDev/ikt205_2026_18_study_sprint/source/components/parallax-scroll-view.tsx new file mode 100644 index 0000000..6f674a7 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/components/parallax-scroll-view.tsx @@ -0,0 +1,79 @@ +import type { PropsWithChildren, ReactElement } from 'react'; +import { StyleSheet } from 'react-native'; +import Animated, { + interpolate, + useAnimatedRef, + useAnimatedStyle, + useScrollOffset, +} from 'react-native-reanimated'; + +import { ThemedView } from '@/components/themed-view'; +import { useColorScheme } from '@/hooks/use-color-scheme'; +import { useThemeColor } from '@/hooks/use-theme-color'; + +const HEADER_HEIGHT = 250; + +type Props = PropsWithChildren<{ + headerImage: ReactElement; + headerBackgroundColor: { dark: string; light: string }; +}>; + +export default function ParallaxScrollView({ + children, + headerImage, + headerBackgroundColor, +}: Props) { + const backgroundColor = useThemeColor({}, 'background'); + const colorScheme = useColorScheme() ?? 'light'; + const scrollRef = useAnimatedRef(); + const scrollOffset = useScrollOffset(scrollRef); + const headerAnimatedStyle = useAnimatedStyle(() => { + return { + transform: [ + { + translateY: interpolate( + scrollOffset.value, + [-HEADER_HEIGHT, 0, HEADER_HEIGHT], + [-HEADER_HEIGHT / 2, 0, HEADER_HEIGHT * 0.75] + ), + }, + { + scale: interpolate(scrollOffset.value, [-HEADER_HEIGHT, 0, HEADER_HEIGHT], [2, 1, 1]), + }, + ], + }; + }); + + return ( + + + {headerImage} + + {children} + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + }, + header: { + height: HEADER_HEIGHT, + overflow: 'hidden', + }, + content: { + flex: 1, + padding: 32, + gap: 16, + overflow: 'hidden', + }, +}); diff --git a/AppDev/ikt205_2026_18_study_sprint/source/components/themed-text.tsx b/AppDev/ikt205_2026_18_study_sprint/source/components/themed-text.tsx new file mode 100644 index 0000000..d79d0a1 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/components/themed-text.tsx @@ -0,0 +1,60 @@ +import { StyleSheet, Text, type TextProps } from 'react-native'; + +import { useThemeColor } from '@/hooks/use-theme-color'; + +export type ThemedTextProps = TextProps & { + lightColor?: string; + darkColor?: string; + type?: 'default' | 'title' | 'defaultSemiBold' | 'subtitle' | 'link'; +}; + +export function ThemedText({ + style, + lightColor, + darkColor, + type = 'default', + ...rest +}: ThemedTextProps) { + const color = useThemeColor({ light: lightColor, dark: darkColor }, 'text'); + + return ( + + ); +} + +const styles = StyleSheet.create({ + default: { + fontSize: 16, + lineHeight: 24, + }, + defaultSemiBold: { + fontSize: 16, + lineHeight: 24, + fontWeight: '600', + }, + title: { + fontSize: 32, + fontWeight: 'bold', + lineHeight: 32, + }, + subtitle: { + fontSize: 20, + fontWeight: 'bold', + }, + link: { + lineHeight: 30, + fontSize: 16, + color: '#0a7ea4', + }, +}); diff --git a/AppDev/ikt205_2026_18_study_sprint/source/components/themed-view.tsx b/AppDev/ikt205_2026_18_study_sprint/source/components/themed-view.tsx new file mode 100644 index 0000000..6f181d8 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/components/themed-view.tsx @@ -0,0 +1,14 @@ +import { View, type ViewProps } from 'react-native'; + +import { useThemeColor } from '@/hooks/use-theme-color'; + +export type ThemedViewProps = ViewProps & { + lightColor?: string; + darkColor?: string; +}; + +export function ThemedView({ style, lightColor, darkColor, ...otherProps }: ThemedViewProps) { + const backgroundColor = useThemeColor({ light: lightColor, dark: darkColor }, 'background'); + + return ; +} diff --git a/AppDev/ikt205_2026_18_study_sprint/source/components/ui/collapsible.tsx b/AppDev/ikt205_2026_18_study_sprint/source/components/ui/collapsible.tsx new file mode 100644 index 0000000..6345fde --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/components/ui/collapsible.tsx @@ -0,0 +1,45 @@ +import { PropsWithChildren, useState } from 'react'; +import { StyleSheet, TouchableOpacity } from 'react-native'; + +import { ThemedText } from '@/components/themed-text'; +import { ThemedView } from '@/components/themed-view'; +import { IconSymbol } from '@/components/ui/icon-symbol'; +import { Colors } from '@/constants/theme'; +import { useColorScheme } from '@/hooks/use-color-scheme'; + +export function Collapsible({ children, title }: PropsWithChildren & { title: string }) { + const [isOpen, setIsOpen] = useState(false); + const theme = useColorScheme() ?? 'light'; + + return ( + + setIsOpen((value) => !value)} + activeOpacity={0.8}> + + + {title} + + {isOpen && {children}} + + ); +} + +const styles = StyleSheet.create({ + heading: { + flexDirection: 'row', + alignItems: 'center', + gap: 6, + }, + content: { + marginTop: 6, + marginLeft: 24, + }, +}); diff --git a/AppDev/ikt205_2026_18_study_sprint/source/components/ui/icon-symbol.ios.tsx b/AppDev/ikt205_2026_18_study_sprint/source/components/ui/icon-symbol.ios.tsx new file mode 100644 index 0000000..9177f4d --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/components/ui/icon-symbol.ios.tsx @@ -0,0 +1,32 @@ +import { SymbolView, SymbolViewProps, SymbolWeight } from 'expo-symbols'; +import { StyleProp, ViewStyle } from 'react-native'; + +export function IconSymbol({ + name, + size = 24, + color, + style, + weight = 'regular', +}: { + name: SymbolViewProps['name']; + size?: number; + color: string; + style?: StyleProp; + weight?: SymbolWeight; +}) { + return ( + + ); +} diff --git a/AppDev/ikt205_2026_18_study_sprint/source/components/ui/icon-symbol.tsx b/AppDev/ikt205_2026_18_study_sprint/source/components/ui/icon-symbol.tsx new file mode 100644 index 0000000..b7ece6b --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/components/ui/icon-symbol.tsx @@ -0,0 +1,41 @@ +// Fallback for using MaterialIcons on Android and web. + +import MaterialIcons from '@expo/vector-icons/MaterialIcons'; +import { SymbolWeight, SymbolViewProps } from 'expo-symbols'; +import { ComponentProps } from 'react'; +import { OpaqueColorValue, type StyleProp, type TextStyle } from 'react-native'; + +type IconMapping = Record['name']>; +type IconSymbolName = keyof typeof MAPPING; + +/** + * Add your SF Symbols to Material Icons mappings here. + * - see Material Icons in the [Icons Directory](https://icons.expo.fyi). + * - see SF Symbols in the [SF Symbols](https://developer.apple.com/sf-symbols/) app. + */ +const MAPPING = { + 'house.fill': 'home', + 'paperplane.fill': 'send', + 'chevron.left.forwardslash.chevron.right': 'code', + 'chevron.right': 'chevron-right', +} as IconMapping; + +/** + * An icon component that uses native SF Symbols on iOS, and Material Icons on Android and web. + * This ensures a consistent look across platforms, and optimal resource usage. + * Icon `name`s are based on SF Symbols and require manual mapping to Material Icons. + */ +export function IconSymbol({ + name, + size = 24, + color, + style, +}: { + name: IconSymbolName; + size?: number; + color: string | OpaqueColorValue; + style?: StyleProp; + weight?: SymbolWeight; +}) { + return ; +} diff --git a/AppDev/ikt205_2026_18_study_sprint/source/constants/defaultStyles.ts b/AppDev/ikt205_2026_18_study_sprint/source/constants/defaultStyles.ts new file mode 100644 index 0000000..ea16586 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/constants/defaultStyles.ts @@ -0,0 +1,105 @@ +import { StyleSheet } from "react-native"; + +export const defaultStyles = StyleSheet.create({ + container: { + flex: 1, + padding: 24, + marginVertical: 4, + marginHorizontal: 4, + }, + buttonContainer: { + flexDirection: "row", + gap: 8, + justifyContent: "center", + marginHorizontal: 4, + marginVertical: 4, + }, + title: { + fontSize: 24, + fontWeight: '700', + textAlign: 'center', + marginVertical: 4, + marginHorizontal: 4, + }, + subtitle: { + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + marginVertical: 4, + marginHorizontal: 4, + }, + body: { + fontSize: 16, + fontWeight: '400', + textAlign: 'left', + marginVertical: 4, + marginHorizontal: 4, + }, + separator: { + height: 1, + backgroundColor: '#000000', + marginVertical: 4, + marginHorizontal: 4, + }, + circularButton: { + width: 40, + height: 40, + borderRadius: 20, + alignItems: 'center', + justifyContent: 'center', + marginVertical: 4, + marginHorizontal: 4, + }, + linkText: { + color: "blue", + textDecorationLine: "underline", + textAlign: "center", + marginVertical: 4, + marginHorizontal: 4, + }, + inputText: { + borderWidth: 1, + borderColor: "#ccc", + borderRadius: 6, + fontSize: 16, + fontWeight: '400', + textAlign: 'left', + marginVertical: 4, + marginHorizontal: 4, + }, + checkboxContainer: { + flexDirection: 'row', + alignItems: 'center', + gap: 8, + marginVertical: 4, + marginHorizontal: 4, + }, + checkbox: { + width: 24, + height: 24, + borderWidth: 2, + borderColor: '#666', + borderRadius: 4, + alignItems: 'center', + justifyContent: 'center', + marginVertical: 4, + marginHorizontal: 4, + }, + checkboxMark: { + fontSize: 14, + fontWeight: '700', + }, + checkboxLabel: { + fontSize: 16, + color: '#111', + marginVertical: 4, + marginHorizontal: 4, + }, + boldBody: { + fontSize: 16, + fontWeight: 'bold', + textAlign: 'left', + marginVertical: 4, + marginHorizontal: 4, + }, +}); \ No newline at end of file diff --git a/AppDev/ikt205_2026_18_study_sprint/source/constants/theme.ts b/AppDev/ikt205_2026_18_study_sprint/source/constants/theme.ts new file mode 100644 index 0000000..f06facd --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/constants/theme.ts @@ -0,0 +1,53 @@ +/** + * Below are the colors that are used in the app. The colors are defined in the light and dark mode. + * There are many other ways to style your app. For example, [Nativewind](https://www.nativewind.dev/), [Tamagui](https://tamagui.dev/), [unistyles](https://reactnativeunistyles.vercel.app), etc. + */ + +import { Platform } from 'react-native'; + +const tintColorLight = '#0a7ea4'; +const tintColorDark = '#fff'; + +export const Colors = { + light: { + text: '#11181C', + background: '#fff', + tint: tintColorLight, + icon: '#687076', + tabIconDefault: '#687076', + tabIconSelected: tintColorLight, + }, + dark: { + text: '#ECEDEE', + background: '#151718', + tint: tintColorDark, + icon: '#9BA1A6', + tabIconDefault: '#9BA1A6', + tabIconSelected: tintColorDark, + }, +}; + +export const Fonts = Platform.select({ + ios: { + /** iOS `UIFontDescriptorSystemDesignDefault` */ + sans: 'system-ui', + /** iOS `UIFontDescriptorSystemDesignSerif` */ + serif: 'ui-serif', + /** iOS `UIFontDescriptorSystemDesignRounded` */ + rounded: 'ui-rounded', + /** iOS `UIFontDescriptorSystemDesignMonospaced` */ + mono: 'ui-monospace', + }, + default: { + sans: 'normal', + serif: 'serif', + rounded: 'normal', + mono: 'monospace', + }, + web: { + sans: "system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif", + serif: "Georgia, 'Times New Roman', serif", + rounded: "'SF Pro Rounded', 'Hiragino Maru Gothic ProN', Meiryo, 'MS PGothic', sans-serif", + mono: "SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace", + }, +}); diff --git a/AppDev/ikt205_2026_18_study_sprint/source/deploy/signup-confirmation/README.md b/AppDev/ikt205_2026_18_study_sprint/source/deploy/signup-confirmation/README.md new file mode 100644 index 0000000..5670acc --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/deploy/signup-confirmation/README.md @@ -0,0 +1,21 @@ +# Signup Confirmation Page + +This serves a very small static confirmation page with `nginx`. + +## Run + +```bash +docker compose up -d +``` + +It will be available on port `8080` on the VPS. + +## Files + +- `docker-compose.yml`: starts `nginx:alpine` +- `site/index.html`: the page shown after email confirmation + +## Notes + +- If you already have a reverse proxy on the VPS, point your domain or subdomain to `http://localhost:8080`. +- If you want this container to bind directly to port `80`, change `8080:80` to `80:80` in `docker-compose.yml`. diff --git a/AppDev/ikt205_2026_18_study_sprint/source/deploy/signup-confirmation/docker-compose.yml b/AppDev/ikt205_2026_18_study_sprint/source/deploy/signup-confirmation/docker-compose.yml new file mode 100644 index 0000000..581b647 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/deploy/signup-confirmation/docker-compose.yml @@ -0,0 +1,14 @@ +networks: + caddy_shared: + external: true +services: + signup-confirmation: + image: nginx:alpine + container_name: study-sprint-signup-confirmation + restart: always + expose: + - "80" + networks: + - caddy_shared + volumes: + - ./site:/usr/share/nginx/html:ro diff --git a/AppDev/ikt205_2026_18_study_sprint/source/deploy/signup-confirmation/site/index.html b/AppDev/ikt205_2026_18_study_sprint/source/deploy/signup-confirmation/site/index.html new file mode 100644 index 0000000..7c35789 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/deploy/signup-confirmation/site/index.html @@ -0,0 +1,75 @@ + + + + + + Study Sprint + + + +
+

Study Sprint

+

Thank you for signing up.

+

Your email has been confirmed. You can now sign in to your account in the Study Sprint app.

+
+ + diff --git a/AppDev/ikt205_2026_18_study_sprint/source/eas.json b/AppDev/ikt205_2026_18_study_sprint/source/eas.json new file mode 100644 index 0000000..697c1cb --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/eas.json @@ -0,0 +1,21 @@ +{ + "cli": { + "version": ">= 18.8.0", + "appVersionSource": "remote" + }, + "build": { + "development": { + "developmentClient": true, + "distribution": "internal" + }, + "preview": { + "distribution": "internal" + }, + "production": { + "autoIncrement": true + } + }, + "submit": { + "production": {} + } +} diff --git a/AppDev/ikt205_2026_18_study_sprint/source/eslint.config.js b/AppDev/ikt205_2026_18_study_sprint/source/eslint.config.js new file mode 100644 index 0000000..5025da6 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/eslint.config.js @@ -0,0 +1,10 @@ +// https://docs.expo.dev/guides/using-eslint/ +const { defineConfig } = require('eslint/config'); +const expoConfig = require('eslint-config-expo/flat'); + +module.exports = defineConfig([ + expoConfig, + { + ignores: ['dist/*'], + }, +]); diff --git a/AppDev/ikt205_2026_18_study_sprint/source/global.css b/AppDev/ikt205_2026_18_study_sprint/source/global.css new file mode 100644 index 0000000..a90f074 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/global.css @@ -0,0 +1,4 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + diff --git a/AppDev/ikt205_2026_18_study_sprint/source/hooks/use-color-scheme.ts b/AppDev/ikt205_2026_18_study_sprint/source/hooks/use-color-scheme.ts new file mode 100644 index 0000000..17e3c63 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/hooks/use-color-scheme.ts @@ -0,0 +1 @@ +export { useColorScheme } from 'react-native'; diff --git a/AppDev/ikt205_2026_18_study_sprint/source/hooks/use-color-scheme.web.ts b/AppDev/ikt205_2026_18_study_sprint/source/hooks/use-color-scheme.web.ts new file mode 100644 index 0000000..7eb1c1b --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/hooks/use-color-scheme.web.ts @@ -0,0 +1,21 @@ +import { useEffect, useState } from 'react'; +import { useColorScheme as useRNColorScheme } from 'react-native'; + +/** + * To support static rendering, this value needs to be re-calculated on the client side for web + */ +export function useColorScheme() { + const [hasHydrated, setHasHydrated] = useState(false); + + useEffect(() => { + setHasHydrated(true); + }, []); + + const colorScheme = useRNColorScheme(); + + if (hasHydrated) { + return colorScheme; + } + + return 'light'; +} diff --git a/AppDev/ikt205_2026_18_study_sprint/source/hooks/use-theme-color.ts b/AppDev/ikt205_2026_18_study_sprint/source/hooks/use-theme-color.ts new file mode 100644 index 0000000..0cbc3a6 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/hooks/use-theme-color.ts @@ -0,0 +1,21 @@ +/** + * Learn more about light and dark modes: + * https://docs.expo.dev/guides/color-schemes/ + */ + +import { Colors } from '@/constants/theme'; +import { useColorScheme } from '@/hooks/use-color-scheme'; + +export function useThemeColor( + props: { light?: string; dark?: string }, + colorName: keyof typeof Colors.light & keyof typeof Colors.dark +) { + const theme = useColorScheme() ?? 'light'; + const colorFromProps = props[theme]; + + if (colorFromProps) { + return colorFromProps; + } else { + return Colors[theme][colorName]; + } +} diff --git a/AppDev/ikt205_2026_18_study_sprint/source/jest.setup.js b/AppDev/ikt205_2026_18_study_sprint/source/jest.setup.js new file mode 100644 index 0000000..649c550 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/jest.setup.js @@ -0,0 +1,4 @@ +jest.mock( + "@react-native-async-storage/async-storage", + () => require("@react-native-async-storage/async-storage/jest/async-storage-mock") +); diff --git a/AppDev/ikt205_2026_18_study_sprint/source/lib/asyncStorage.ts b/AppDev/ikt205_2026_18_study_sprint/source/lib/asyncStorage.ts new file mode 100644 index 0000000..e04a28e --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/lib/asyncStorage.ts @@ -0,0 +1,80 @@ +import AsyncStorage from '@react-native-async-storage/async-storage'; +import type { SessionType } from '@/lib/types'; + +const notificationKey = (aId: string) => `assignment_notification_${aId}`; +const setupSprintDemoKey = (userId: string) => `setup_sprint_demo_${userId}`; +const activeSprintKey = 'active_sprint'; +const studyCycleKey = 'study_cycle'; + +export type ActiveSession = { + sessionId: string; + sessionType: SessionType; + taskId: string | null; + returnTaskId?: string | null; + durationSeconds: number; + endTime: number; +}; + +export type StudyCycle = { + taskId: string; + completedFocusSessions: number; + lastCompletedSessionType: SessionType; + lastCompletedAt: number; +}; + +export async function SaveAssignmentNotificationId(aId: string, notificationId: string) { + await AsyncStorage.setItem(notificationKey(aId), notificationId); +} + +export async function GetAssignmentNotificationId(aId: string) { + return await AsyncStorage.getItem(notificationKey(aId)); +} + +export async function RemoveAssignmentNotificationId(aId: string) { + await AsyncStorage.removeItem(notificationKey(aId)); +} + +export async function SaveActiveSession(activeSession: ActiveSession) { + await AsyncStorage.setItem(activeSprintKey, JSON.stringify(activeSession)); +} + +export async function GetActiveSession() { + const activeSession = await AsyncStorage.getItem(activeSprintKey); + + if (!activeSession) { + return null; + } + + return JSON.parse(activeSession) as ActiveSession; +} + +export async function RemoveActiveSession() { + await AsyncStorage.removeItem(activeSprintKey); +} + +export async function SaveStudyCycle(studyCycle: StudyCycle) { + await AsyncStorage.setItem(studyCycleKey, JSON.stringify(studyCycle)); +} + +export async function GetStudyCycle() { + const studyCycle = await AsyncStorage.getItem(studyCycleKey); + + if (!studyCycle) { + return null; + } + + return JSON.parse(studyCycle) as StudyCycle; +} + +export async function RemoveStudyCycle() { + await AsyncStorage.removeItem(studyCycleKey); +} + +export async function GetSetupSprintDemoUsed(userId: string) { + const value = await AsyncStorage.getItem(setupSprintDemoKey(userId)); + return value === 'true'; +} + +export async function SaveSetupSprintDemoUsed(userId: string) { + await AsyncStorage.setItem(setupSprintDemoKey(userId), 'true'); +} diff --git a/AppDev/ikt205_2026_18_study_sprint/source/lib/date.ts b/AppDev/ikt205_2026_18_study_sprint/source/lib/date.ts new file mode 100644 index 0000000..a21a5fb --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/lib/date.ts @@ -0,0 +1,29 @@ +export const formatDate = (value?: string | null) => { + if (!value) return 'No date'; + + const date = new Date(value); + + if (Number.isNaN(date.getTime())) return value; + + return date.toLocaleDateString(undefined, { + year: 'numeric', + month: 'short', + day: 'numeric', + }); +}; + +export const formatDateTime = (value?: string | null) => { + if (!value) return 'Unknown'; + + const date = new Date(value); + + if (Number.isNaN(date.getTime())) return value; + + return date.toLocaleString(undefined, { + year: 'numeric', + month: 'short', + day: 'numeric', + hour: 'numeric', + minute: '2-digit', + }); +}; \ No newline at end of file diff --git a/AppDev/ikt205_2026_18_study_sprint/source/lib/notifications.ts b/AppDev/ikt205_2026_18_study_sprint/source/lib/notifications.ts new file mode 100644 index 0000000..c03cb9a --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/lib/notifications.ts @@ -0,0 +1,39 @@ +import * as Notifications from 'expo-notifications'; +import { Platform } from 'react-native'; + +Notifications.setNotificationHandler({ + handleNotification: async () => ({ + shouldPlaySound: true, + shouldSetBadge: true, + shouldShowBanner: true, + shouldShowList: true, + }), +}); + +function HandleRegistrationError(errorMessage: string) { + alert(errorMessage); + throw new Error(errorMessage); +} + +export async function RegisterForLocalNotificationsAsync() { + if (Platform.OS === 'android') { + await Notifications.setNotificationChannelAsync('default', { + name: 'default', + importance: Notifications.AndroidImportance.MAX + }); + } + + const { status: existingStatus } = await Notifications.getPermissionsAsync(); + + let finalStatus = existingStatus; + + if (existingStatus !== 'granted') { + const { status } = await Notifications.requestPermissionsAsync(); + finalStatus = status; + } + + if (finalStatus !== 'granted') { + HandleRegistrationError('Permission not granted for local notifications'); + return; + } +} diff --git a/AppDev/ikt205_2026_18_study_sprint/source/lib/progress.ts b/AppDev/ikt205_2026_18_study_sprint/source/lib/progress.ts new file mode 100644 index 0000000..0198d36 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/lib/progress.ts @@ -0,0 +1,15 @@ +import { supabase } from '@/lib/supabase'; + +export async function CheckAssignmentCompletion(aId: string) { + const { data, error } = await supabase.from("tasks").select("tId, isCompleted").eq("aId", aId); + + if (error) throw error; + + const tasks = data ?? []; + + const allCompleted = tasks.length > 0 && tasks.every((task) => task.isCompleted === true); + + const { error: updateError } = await supabase.from("assignments").update({ isCompleted: allCompleted, lastChanged: new Date().toISOString()}).eq("aId", aId); + + if (updateError) throw updateError; +} diff --git a/AppDev/ikt205_2026_18_study_sprint/source/lib/sessionDefaults.ts b/AppDev/ikt205_2026_18_study_sprint/source/lib/sessionDefaults.ts new file mode 100644 index 0000000..d673d25 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/lib/sessionDefaults.ts @@ -0,0 +1,5 @@ +export const DEFAULT_FOCUS_DURATION_MINUTES = 25; +export const DEFAULT_SHORT_BREAK_DURATION_MINUTES = 5; +export const DEFAULT_LONG_BREAK_DURATION_MINUTES = 15; +export const FOCUS_SESSIONS_PER_LONG_BREAK = 4; +export const STUDY_CYCLE_IDLE_RESET_MINUTES = 120; diff --git a/AppDev/ikt205_2026_18_study_sprint/source/lib/sessionLifecycle.ts b/AppDev/ikt205_2026_18_study_sprint/source/lib/sessionLifecycle.ts new file mode 100644 index 0000000..2de8455 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/lib/sessionLifecycle.ts @@ -0,0 +1,37 @@ +import { + GetActiveSession, + RemoveActiveSession, + RemoveStudyCycle, + type ActiveSession, +} from '@/lib/asyncStorage'; +import { supabase } from '@/lib/supabase'; + +export type FinalSessionStatus = 'completed' | 'cancelled' | 'expired'; + +export async function finalizeStoredSession( + finalStatus: FinalSessionStatus, + activeSessionOverride?: ActiveSession | null +) { + const activeSession = activeSessionOverride ?? await GetActiveSession(); + + if (!activeSession) { + return null; + } + + await RemoveActiveSession(); + + if (finalStatus !== 'completed') { + await RemoveStudyCycle(); + } + + const { error } = await supabase.rpc('finalize_sprint_session', { + p_session_id: activeSession.sessionId, + p_final_status: finalStatus, + p_ended_at: new Date().toISOString(), + }); + + return { + activeSession, + error, + }; +} diff --git a/AppDev/ikt205_2026_18_study_sprint/source/lib/setupStatus.ts b/AppDev/ikt205_2026_18_study_sprint/source/lib/setupStatus.ts new file mode 100644 index 0000000..f68e8e3 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/lib/setupStatus.ts @@ -0,0 +1,84 @@ +import { supabase } from '@/lib/supabase'; + +export type SetupStepKey = 'subject' | 'assignment' | 'task' | 'sprint'; + +export type SetupStatus = { + subjectId: string | null; + assignmentId: string | null; + taskId: string | null; + completedFocusSessions: number; + currentStep: SetupStepKey; + isSetupComplete: boolean; +}; + +export async function getSetupStatus(userId: string): Promise { + const [subjectResult, assignmentResult, taskResult, focusSessionResult] = await Promise.all([ + supabase + .from('subjects') + .select('sId') + .eq('uId', userId) + .order('lastChanged', { ascending: false }) + .limit(1) + .maybeSingle(), + supabase + .from('assignments') + .select('aId') + .eq('uId', userId) + .order('lastChanged', { ascending: false }) + .limit(1) + .maybeSingle(), + supabase + .from('tasks') + .select('tId') + .eq('uId', userId) + .order('lastChanged', { ascending: false }) + .limit(1) + .maybeSingle(), + supabase + .from('sprint_sessions') + .select('sessionId', { count: 'exact', head: true }) + .eq('userId', userId) + .eq('sessionType', 'focus') + .eq('status', 'completed'), + ]); + + if (subjectResult.error) { + throw subjectResult.error; + } + + if (assignmentResult.error) { + throw assignmentResult.error; + } + + if (taskResult.error) { + throw taskResult.error; + } + + if (focusSessionResult.error) { + throw focusSessionResult.error; + } + + const subjectId = subjectResult.data?.sId ?? null; + const assignmentId = assignmentResult.data?.aId ?? null; + const taskId = taskResult.data?.tId ?? null; + const completedFocusSessions = focusSessionResult.count ?? 0; + + let currentStep: SetupStepKey = 'sprint'; + + if (!subjectId) { + currentStep = 'subject'; + } else if (!assignmentId) { + currentStep = 'assignment'; + } else if (!taskId) { + currentStep = 'task'; + } + + return { + subjectId, + assignmentId, + taskId, + completedFocusSessions, + currentStep, + isSetupComplete: taskId !== null && completedFocusSessions > 0, + }; +} diff --git a/AppDev/ikt205_2026_18_study_sprint/source/lib/subjectColors.ts b/AppDev/ikt205_2026_18_study_sprint/source/lib/subjectColors.ts new file mode 100644 index 0000000..1ffe774 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/lib/subjectColors.ts @@ -0,0 +1,58 @@ +export type SubjectColor = + | 'blue' + | 'emerald' + | 'amber' + | 'violet' + | 'cyan' + | 'rose' + | 'slate'; + +export const SUBJECT_COLORS: Record< + SubjectColor, + { soft: string; strong: string; label: string } +> = { + blue: { + soft: '#DCEFF5', + strong: '#2F6F88', + label: 'Blue', + }, + emerald: { + soft: '#DDEFE5', + strong: '#2F7D55', + label: 'Emerald', + }, + amber: { + soft: '#F6E8C6', + strong: '#9A6A16', + label: 'Amber', + }, + violet: { + soft: '#E9E2F5', + strong: '#6D4BA3', + label: 'Violet', + }, + cyan: { + soft: '#DDF0EF', + strong: '#287C7A', + label: 'Cyan', + }, + rose: { + soft: '#F4E1DF', + strong: '#9B4A43', + label: 'Rose', + }, + slate: { + soft: '#E8E4DA', + strong: '#52616B', + label: 'Slate', + }, +}; + +export const SUBJECT_COLOR_KEYS = Object.keys( + SUBJECT_COLORS +) as SubjectColor[]; + +export const getSubjectColorSet = (color?: SubjectColor) => { + const colorKey: SubjectColor = color ?? 'slate'; + return SUBJECT_COLORS[colorKey]; +}; \ No newline at end of file diff --git a/AppDev/ikt205_2026_18_study_sprint/source/lib/supabase.ts b/AppDev/ikt205_2026_18_study_sprint/source/lib/supabase.ts new file mode 100644 index 0000000..1089ee8 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/lib/supabase.ts @@ -0,0 +1,36 @@ +import { createClient } from '@supabase/supabase-js'; +import * as SecureStore from 'expo-secure-store'; +import 'react-native-url-polyfill/auto'; + +const supabaseUrl = process.env.EXPO_PUBLIC_SUPABASE_URL! +const supabaseKey = process.env.EXPO_PUBLIC_SUPABASE_PUBLISHABLE_KEY! + +if (!supabaseUrl) { + throw new Error('Missing EXPO_PUBLIC_SUPABASE_URL'); +} + +if (!supabaseKey) { + throw new Error('Missing EXPO_PUBLIC_SUPABASE_PUBLISHABLE_KEY'); +} + +const SecureStoreAdapter = { + getItem: async (key: string) => { + return await SecureStore.getItemAsync(key); + }, + setItem: async (key: string, value: string) => { + await SecureStore.setItemAsync(key, value); + }, + removeItem: async (key: string) => { + await SecureStore.deleteItemAsync(key); + }, +}; + +export const supabase = createClient(supabaseUrl, supabaseKey, { + auth: { + storage: SecureStoreAdapter, + autoRefreshToken: true, + persistSession: true, + detectSessionInUrl: false, + }, +}) + \ No newline at end of file diff --git a/AppDev/ikt205_2026_18_study_sprint/source/lib/types.ts b/AppDev/ikt205_2026_18_study_sprint/source/lib/types.ts new file mode 100644 index 0000000..fcbc7a0 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/lib/types.ts @@ -0,0 +1,35 @@ +import type { SubjectColor } from '@/lib/subjectColors'; + +export type SessionType = 'focus' | 'short_break' | 'long_break'; + +export type Task = { + tId: string; + title: string; + description: string; + isCompleted: boolean; + lastChanged: string; + uId: string; + aId: string; + totalTimeInSeconds: number; +}; + +export type Assignment = { + aId: string; + title: string; + description: string; + deadline: string; + isCompleted: boolean; + lastChanged: string; + uId: string; + sId: string; +}; + +export type Subject = { + sId: string; + title: string; + description: string; + isActive: boolean; + lastChanged: string; + uId: string; + color?: SubjectColor; +}; diff --git a/AppDev/ikt205_2026_18_study_sprint/source/metro.config.js b/AppDev/ikt205_2026_18_study_sprint/source/metro.config.js new file mode 100644 index 0000000..cdb9601 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/metro.config.js @@ -0,0 +1,8 @@ +const { getDefaultConfig } = require('expo/metro-config'); +const { withNativeWind } = require('nativewind/metro'); + +const config = getDefaultConfig(__dirname); + +module.exports = withNativeWind(config, { + input: './global.css', +}); \ No newline at end of file diff --git a/AppDev/ikt205_2026_18_study_sprint/source/nativewind-env.d.ts b/AppDev/ikt205_2026_18_study_sprint/source/nativewind-env.d.ts new file mode 100644 index 0000000..c0d8380 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/nativewind-env.d.ts @@ -0,0 +1,3 @@ +/// + +// NOTE: This file should not be edited and should be committed with your source code. It is generated by NativeWind. \ No newline at end of file diff --git a/AppDev/ikt205_2026_18_study_sprint/source/package-lock.json b/AppDev/ikt205_2026_18_study_sprint/source/package-lock.json new file mode 100644 index 0000000..f856879 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/package-lock.json @@ -0,0 +1,17164 @@ +{ + "name": "study-sprint", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "study-sprint", + "version": "1.0.0", + "hasInstallScript": true, + "dependencies": { + "@expo/vector-icons": "^15.0.3", + "@react-native-async-storage/async-storage": "2.2.0", + "@react-navigation/bottom-tabs": "^7.4.0", + "@react-navigation/elements": "^2.6.3", + "@react-navigation/native": "^7.1.8", + "@supabase/supabase-js": "^2.103.1", + "expo": "~54.0.33", + "expo-constants": "~18.0.13", + "expo-dev-client": "~6.0.20", + "expo-font": "~14.0.11", + "expo-haptics": "~15.0.8", + "expo-image": "~3.0.11", + "expo-linking": "~8.0.11", + "expo-notifications": "~0.32.16", + "expo-router": "~6.0.23", + "expo-secure-store": "~15.0.8", + "expo-splash-screen": "~31.0.13", + "expo-status-bar": "~3.0.9", + "expo-symbols": "~1.0.8", + "expo-system-ui": "~6.0.9", + "expo-web-browser": "~15.0.10", + "nativewind": "^4.2.3", + "patch-package": "^8.0.1", + "react": "19.1.0", + "react-dom": "19.1.0", + "react-native": "0.81.5", + "react-native-gesture-handler": "~2.28.0", + "react-native-reanimated": "~4.1.1", + "react-native-safe-area-context": "~5.6.0", + "react-native-screens": "~4.16.0", + "react-native-url-polyfill": "^3.0.0", + "react-native-web": "~0.21.0", + "react-native-worklets": "0.5.1", + "tailwindcss": "^3.4.19" + }, + "devDependencies": { + "@testing-library/react-native": "^13.3.3", + "@types/jest": "^30.0.0", + "@types/react": "~19.1.0", + "eslint": "^9.25.0", + "eslint-config-expo": "~10.0.0", + "jest": "^29.7.0", + "jest-expo": "^55.0.16", + "patch-package": "^8.0.1", + "react-test-renderer": "19.1.0", + "tailwindcss": "^3.4.19", + "typescript": "~5.9.2" + } + }, + "node_modules/@0no-co/graphql.web": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@0no-co/graphql.web/-/graphql.web-1.2.0.tgz", + "integrity": "sha512-/1iHy9TTr63gE1YcR5idjx8UREz1s0kFhydf3bBLCXyqjhkIc6igAzTOx3zPifCwFR87tsh/4Pa9cNts6d2otw==", + "license": "MIT", + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0" + }, + "peerDependenciesMeta": { + "graphql": { + "optional": true + } + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.6.tgz", + "integrity": "sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-member-expression-to-functions": "^7.28.5", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.28.6", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.28.5.tgz", + "integrity": "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "regexpu-core": "^6.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.8.tgz", + "integrity": "sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "debug": "^4.4.3", + "lodash.debounce": "^4.0.8", + "resolve": "^1.22.11" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", + "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", + "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-wrap-function": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.28.6.tgz", + "integrity": "sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==", + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.28.5", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.6.tgz", + "integrity": "sha512-z+PwLziMNBeSQJonizz2AGnndLsP2DeGHIxDAn+wdHOGuo4Fo1x1HBPPXeE9TAOPHNNWQKCSlA2VZyYyyibDnQ==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", + "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.9.tgz", + "integrity": "sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-proposal-decorators": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.29.0.tgz", + "integrity": "sha512-CVBVv3VY/XRMxRYq5dwr2DS7/MvqPm23cOCjbwNnVrfOqcWlnefua1uUs0sjdKOGjvPUG633o07uWzJq4oI6dA==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-syntax-decorators": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-export-default-from": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.27.1.tgz", + "integrity": "sha512-hjlsMBl1aJc5lp8MoCDEZCiYzlgdRAShOjAfRw6X+GlpLpUPU7c3XNLsKFZbQk/1cRzBlJ7CXg3xJAJMrFa1Uw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-decorators": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.28.6.tgz", + "integrity": "sha512-71EYI0ONURHJBL4rSFXnITXqXrrY8q4P0q006DPfN+Rk+ASM+++IBXem/ruokgBZR8YNEWZ8R6B+rCb8VcUTqA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-default-from": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.28.6.tgz", + "integrity": "sha512-Svlx1fjJFnNz0LZeUaybRukSxZI3KkpApUmIRzEdXC5k8ErTOz0OD0kNrICi5Vc3GlpP5ZCeRyRO+mfWTSz+iQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-flow": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.28.6.tgz", + "integrity": "sha512-D+OrJumc9McXNEBI/JmFnc/0uCM2/Y3PEBG3gfV3QIYkKv5pvnpzFrl1kYCrcHJP8nOeFB/SHi1IHz29pNGuew==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", + "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", + "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", + "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", + "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.0.tgz", + "integrity": "sha512-va0VdWro4zlBr2JsXC+ofCPB2iG12wPtVGTWFx2WLDOM3nYQZZIGP82qku2eW/JR83sD+k2k+CsNtyEbUqhU6w==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-remap-async-to-generator": "^7.27.1", + "@babel/traverse": "^7.29.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.28.6.tgz", + "integrity": "sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-remap-async-to-generator": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.6.tgz", + "integrity": "sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.28.6.tgz", + "integrity": "sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.6.tgz", + "integrity": "sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.6.tgz", + "integrity": "sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-globals": "^7.28.0", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-replace-supers": "^7.28.6", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.28.6.tgz", + "integrity": "sha512-bcc3k0ijhHbc2lEfpFHgx7eYw9KNXqOerKWfzbxEHUGKnS3sz9C4CNL9OiFN1297bDNfUiSO7DaLzbvHQQQ1BQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/template": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", + "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", + "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-flow-strip-types": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.27.1.tgz", + "integrity": "sha512-G5eDKsu50udECw7DL2AcsysXiQyB7Nfg521t2OAJ4tbfTJ27doHLeF/vlI1NZGlLdbb/v+ibvtL1YBQqYOwJGg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-syntax-flow": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", + "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", + "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", + "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.6.tgz", + "integrity": "sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.28.6.tgz", + "integrity": "sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.0.tgz", + "integrity": "sha512-1CZQA5KNAD6ZYQLPw7oi5ewtDNxH/2vuCh+6SmvgDfhumForvs8a1o9n0UrEoBD8HU4djO2yWngTQlXl1NDVEQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.28.6.tgz", + "integrity": "sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.28.6.tgz", + "integrity": "sha512-SJR8hPynj8outz+SlStQSwvziMN4+Bq99it4tMIf5/Caq+3iOc0JtKyse8puvyXkk3eFRIA5ID/XfunGgO5i6w==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.6.tgz", + "integrity": "sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-transform-destructuring": "^7.28.5", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.28.6.tgz", + "integrity": "sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.6.tgz", + "integrity": "sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", + "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.28.6.tgz", + "integrity": "sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.28.6.tgz", + "integrity": "sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.28.0.tgz", + "integrity": "sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.28.6.tgz", + "integrity": "sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-syntax-jsx": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.27.1.tgz", + "integrity": "sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q==", + "license": "MIT", + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.27.1.tgz", + "integrity": "sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.0.tgz", + "integrity": "sha512-FijqlqMA7DmRdg/aINBSs04y8XNTYw/lr1gJ2WsmBnnaNw1iS43EPkJW+zK7z65auG3AWRFXWj+NcTQwYptUog==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.29.0.tgz", + "integrity": "sha512-jlaRT5dJtMaMCV6fAuLbsQMSwz/QkvaHOHOSXRitGGwSpR1blCY4KUKoyP2tYO8vJcqYe8cEj96cqSztv3uF9w==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "babel-plugin-polyfill-corejs2": "^0.4.14", + "babel-plugin-polyfill-corejs3": "^0.13.0", + "babel-plugin-polyfill-regenerator": "^0.6.5", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", + "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.28.6.tgz", + "integrity": "sha512-9U4QObUC0FtJl05AsUcodau/RWDytrU6uKgkxu09mLR9HLDAtUMoPuuskm5huQsoktmsYpI+bGmq+iapDcriKA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", + "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", + "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.6.tgz", + "integrity": "sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", + "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-react": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.28.5.tgz", + "integrity": "sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-transform-react-display-name": "^7.28.0", + "@babel/plugin-transform-react-jsx": "^7.27.1", + "@babel/plugin-transform-react-jsx-development": "^7.27.1", + "@babel/plugin-transform-react-pure-annotations": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.28.5.tgz", + "integrity": "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-typescript": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse--for-generate-function-map": { + "name": "@babel/traverse", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@egjs/hammerjs": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/@egjs/hammerjs/-/hammerjs-2.0.17.tgz", + "integrity": "sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==", + "license": "MIT", + "dependencies": { + "@types/hammerjs": "^2.0.36" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz", + "integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz", + "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@expo/code-signing-certificates": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@expo/code-signing-certificates/-/code-signing-certificates-0.0.6.tgz", + "integrity": "sha512-iNe0puxwBNEcuua9gmTGzq+SuMDa0iATai1FlFTMHJ/vUmKvN/V//drXoLJkVb5i5H3iE/n/qIJxyoBnXouD0w==", + "license": "MIT", + "dependencies": { + "node-forge": "^1.3.3" + } + }, + "node_modules/@expo/config": { + "version": "12.0.13", + "resolved": "https://registry.npmjs.org/@expo/config/-/config-12.0.13.tgz", + "integrity": "sha512-Cu52arBa4vSaupIWsF0h7F/Cg//N374nYb7HAxV0I4KceKA7x2UXpYaHOL7EEYYvp7tZdThBjvGpVmr8ScIvaQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "~7.10.4", + "@expo/config-plugins": "~54.0.4", + "@expo/config-types": "^54.0.10", + "@expo/json-file": "^10.0.8", + "deepmerge": "^4.3.1", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "require-from-string": "^2.0.2", + "resolve-from": "^5.0.0", + "resolve-workspace-root": "^2.0.0", + "semver": "^7.6.0", + "slugify": "^1.3.4", + "sucrase": "~3.35.1" + } + }, + "node_modules/@expo/config-plugins": { + "version": "54.0.4", + "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-54.0.4.tgz", + "integrity": "sha512-g2yXGICdoOw5i3LkQSDxl2Q5AlQCrG7oniu0pCPPO+UxGb7He4AFqSvPSy8HpRUj55io17hT62FTjYRD+d6j3Q==", + "license": "MIT", + "dependencies": { + "@expo/config-types": "^54.0.10", + "@expo/json-file": "~10.0.8", + "@expo/plist": "^0.4.8", + "@expo/sdk-runtime-versions": "^1.0.0", + "chalk": "^4.1.2", + "debug": "^4.3.5", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "resolve-from": "^5.0.0", + "semver": "^7.5.4", + "slash": "^3.0.0", + "slugify": "^1.6.6", + "xcode": "^3.0.1", + "xml2js": "0.6.0" + } + }, + "node_modules/@expo/config-plugins/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@expo/config-types": { + "version": "54.0.10", + "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-54.0.10.tgz", + "integrity": "sha512-/J16SC2an1LdtCZ67xhSkGXpALYUVUNyZws7v+PVsFZxClYehDSoKLqyRaGkpHlYrCc08bS0RF5E0JV6g50psA==", + "license": "MIT" + }, + "node_modules/@expo/config/node_modules/@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/@expo/config/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@expo/devcert": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@expo/devcert/-/devcert-1.2.1.tgz", + "integrity": "sha512-qC4eaxmKMTmJC2ahwyui6ud8f3W60Ss7pMkpBq40Hu3zyiAaugPXnZ24145U7K36qO9UHdZUVxsCvIpz2RYYCA==", + "license": "MIT", + "dependencies": { + "@expo/sudo-prompt": "^9.3.1", + "debug": "^3.1.0" + } + }, + "node_modules/@expo/devcert/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/@expo/devtools": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/@expo/devtools/-/devtools-0.1.8.tgz", + "integrity": "sha512-SVLxbuanDjJPgc0sy3EfXUMLb/tXzp6XIHkhtPVmTWJAp+FOr6+5SeiCfJrCzZFet0Ifyke2vX3sFcKwEvCXwQ==", + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/@expo/env": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@expo/env/-/env-2.0.11.tgz", + "integrity": "sha512-xV+ps6YCW7XIPVUwFVCRN2nox09dnRwy8uIjwHWTODu0zFw4kp4omnVkl0OOjuu2XOe7tdgAHxikrkJt9xB/7Q==", + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "debug": "^4.3.4", + "dotenv": "~16.4.5", + "dotenv-expand": "~11.0.6", + "getenv": "^2.0.0" + } + }, + "node_modules/@expo/fingerprint": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/@expo/fingerprint/-/fingerprint-0.15.5.tgz", + "integrity": "sha512-mdVoAMcux1WlM6kd1RoWiHRNqKqS+J6mKmWQ/BKgeh937S/fcW58EE68O6nc4KDXtWi3PBeNHskOFcgyIuD4hw==", + "license": "MIT", + "dependencies": { + "@expo/spawn-async": "^1.7.2", + "arg": "^5.0.2", + "chalk": "^4.1.2", + "debug": "^4.3.4", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "ignore": "^5.3.1", + "minimatch": "^10.2.2", + "p-limit": "^3.1.0", + "resolve-from": "^5.0.0", + "semver": "^7.6.0" + }, + "bin": { + "fingerprint": "bin/cli.js" + } + }, + "node_modules/@expo/fingerprint/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@expo/fingerprint/node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@expo/fingerprint/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@expo/fingerprint/node_modules/semver": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@expo/image-utils": { + "version": "0.8.13", + "resolved": "https://registry.npmjs.org/@expo/image-utils/-/image-utils-0.8.13.tgz", + "integrity": "sha512-1I//yBQeTY6p0u1ihqGNDAr35EbSG8uFEupFrIF0jd++h9EWH33521yZJU1yE+mwGlzCb61g3ehu78siMhXBlA==", + "license": "MIT", + "dependencies": { + "@expo/require-utils": "^55.0.4", + "@expo/spawn-async": "^1.7.2", + "chalk": "^4.0.0", + "getenv": "^2.0.0", + "jimp-compact": "0.16.1", + "parse-png": "^2.1.0", + "semver": "^7.6.0" + } + }, + "node_modules/@expo/image-utils/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@expo/json-file": { + "version": "10.0.14", + "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-10.0.14.tgz", + "integrity": "sha512-yWwBFywFv+SxkJp/pIzzA416JVYflNUh7pqQzgaA6nXDqRyK7KfrqVzk8PdUfDnqbBcaZZxpzNssfQZzp5KHrA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.20.0", + "json5": "^2.2.3" + } + }, + "node_modules/@expo/metro": { + "version": "54.2.0", + "resolved": "https://registry.npmjs.org/@expo/metro/-/metro-54.2.0.tgz", + "integrity": "sha512-h68TNZPGsk6swMmLm9nRSnE2UXm48rWwgcbtAHVMikXvbxdS41NDHHeqg1rcQ9AbznDRp6SQVC2MVpDnsRKU1w==", + "license": "MIT", + "dependencies": { + "metro": "0.83.3", + "metro-babel-transformer": "0.83.3", + "metro-cache": "0.83.3", + "metro-cache-key": "0.83.3", + "metro-config": "0.83.3", + "metro-core": "0.83.3", + "metro-file-map": "0.83.3", + "metro-minify-terser": "0.83.3", + "metro-resolver": "0.83.3", + "metro-runtime": "0.83.3", + "metro-source-map": "0.83.3", + "metro-symbolicate": "0.83.3", + "metro-transform-plugins": "0.83.3", + "metro-transform-worker": "0.83.3" + } + }, + "node_modules/@expo/metro-config": { + "version": "54.0.15", + "resolved": "https://registry.npmjs.org/@expo/metro-config/-/metro-config-54.0.15.tgz", + "integrity": "sha512-SqIya4VZ9KHM1S9g+xR0A+QKw1Tfs7Gacx6bQNJ98vs4+O7I5+QP5mHZIB0QSZLUV8opiXebHYTiTu+0OAsIUw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.20.0", + "@babel/core": "^7.20.0", + "@babel/generator": "^7.20.5", + "@expo/config": "~12.0.13", + "@expo/env": "~2.0.8", + "@expo/json-file": "~10.0.8", + "@expo/metro": "~54.2.0", + "@expo/spawn-async": "^1.7.2", + "browserslist": "^4.25.0", + "chalk": "^4.1.0", + "debug": "^4.3.2", + "dotenv": "~16.4.5", + "dotenv-expand": "~11.0.6", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "hermes-parser": "^0.29.1", + "jsc-safe-url": "^0.2.4", + "lightningcss": "^1.30.1", + "picomatch": "^4.0.3", + "postcss": "~8.4.32", + "resolve-from": "^5.0.0" + }, + "peerDependencies": { + "expo": "*" + }, + "peerDependenciesMeta": { + "expo": { + "optional": true + } + } + }, + "node_modules/@expo/metro-config/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@expo/metro-runtime": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@expo/metro-runtime/-/metro-runtime-6.1.2.tgz", + "integrity": "sha512-nvM+Qv45QH7pmYvP8JB1G8JpScrWND3KrMA6ZKe62cwwNiX/BjHU28Ear0v/4bQWXlOY0mv6B8CDIm8JxXde9g==", + "license": "MIT", + "dependencies": { + "anser": "^1.4.9", + "pretty-format": "^29.7.0", + "stacktrace-parser": "^0.1.10", + "whatwg-fetch": "^3.0.0" + }, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-dom": "*", + "react-native": "*" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/@expo/osascript": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/@expo/osascript/-/osascript-2.4.3.tgz", + "integrity": "sha512-wbuj3EebM7W9hN/Wp4xTzKd6rQ2zKJzAxkFxkOOwyysLp0HOAgQ4/5RINyoS241pZUX2rUHq7mAJ7pcCQ8U0Ow==", + "license": "MIT", + "dependencies": { + "@expo/spawn-async": "^1.7.2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@expo/package-manager": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/@expo/package-manager/-/package-manager-1.10.5.tgz", + "integrity": "sha512-nCP9Mebfl3jvOr0/P6VAuyah6PAtun+aihIL2zAtuE8uSe94JWkVZ7051i0MUVO+y3gFpBqnr8IIH5ch+VJjHA==", + "license": "MIT", + "dependencies": { + "@expo/json-file": "^10.0.14", + "@expo/spawn-async": "^1.7.2", + "chalk": "^4.0.0", + "npm-package-arg": "^11.0.0", + "ora": "^3.4.0", + "resolve-workspace-root": "^2.0.0" + } + }, + "node_modules/@expo/plist": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.4.8.tgz", + "integrity": "sha512-pfNtErGGzzRwHP+5+RqswzPDKkZrx+Cli0mzjQaus1ZWFsog5ibL+nVT3NcporW51o8ggnt7x813vtRbPiyOrQ==", + "license": "MIT", + "dependencies": { + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.2.3", + "xmlbuilder": "^15.1.1" + } + }, + "node_modules/@expo/prebuild-config": { + "version": "54.0.8", + "resolved": "https://registry.npmjs.org/@expo/prebuild-config/-/prebuild-config-54.0.8.tgz", + "integrity": "sha512-EA7N4dloty2t5Rde+HP0IEE+nkAQiu4A/+QGZGT9mFnZ5KKjPPkqSyYcRvP5bhQE10D+tvz6X0ngZpulbMdbsg==", + "license": "MIT", + "dependencies": { + "@expo/config": "~12.0.13", + "@expo/config-plugins": "~54.0.4", + "@expo/config-types": "^54.0.10", + "@expo/image-utils": "^0.8.8", + "@expo/json-file": "^10.0.8", + "@react-native/normalize-colors": "0.81.5", + "debug": "^4.3.1", + "resolve-from": "^5.0.0", + "semver": "^7.6.0", + "xml2js": "0.6.0" + }, + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/@expo/prebuild-config/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@expo/require-utils": { + "version": "55.0.5", + "resolved": "https://registry.npmjs.org/@expo/require-utils/-/require-utils-55.0.5.tgz", + "integrity": "sha512-U4K/CQ2VpXuwfNGsN+daKmYOt15hCP8v/pXaYH6eut7kdYZo6SfJ1yr67BIcJ+1Gzzs+QzTxswAZChKpXmceyw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.20.0", + "@babel/core": "^7.25.2", + "@babel/plugin-transform-modules-commonjs": "^7.24.8" + }, + "peerDependencies": { + "typescript": "^5.0.0 || ^5.0.0-0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@expo/schema-utils": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/@expo/schema-utils/-/schema-utils-0.1.8.tgz", + "integrity": "sha512-9I6ZqvnAvKKDiO+ZF8BpQQFYWXOJvTAL5L/227RUbWG1OVZDInFifzCBiqAZ3b67NRfeAgpgvbA7rejsqhY62A==", + "license": "MIT" + }, + "node_modules/@expo/sdk-runtime-versions": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@expo/sdk-runtime-versions/-/sdk-runtime-versions-1.0.0.tgz", + "integrity": "sha512-Doz2bfiPndXYFPMRwPyGa1k5QaKDVpY806UJj570epIiMzWaYyCtobasyfC++qfIXVb5Ocy7r3tP9d62hAQ7IQ==", + "license": "MIT" + }, + "node_modules/@expo/spawn-async": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@expo/spawn-async/-/spawn-async-1.7.2.tgz", + "integrity": "sha512-QdWi16+CHB9JYP7gma19OVVg0BFkvU8zNj9GjWorYI8Iv8FUxjOCcYRuAmX4s/h91e4e7BPsskc8cSrZYho9Ew==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@expo/sudo-prompt": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/@expo/sudo-prompt/-/sudo-prompt-9.3.2.tgz", + "integrity": "sha512-HHQigo3rQWKMDzYDLkubN5WQOYXJJE2eNqIQC2axC2iO3mHdwnIR7FgZVvHWtBwAdzBgAP0ECp8KqS8TiMKvgw==", + "license": "MIT" + }, + "node_modules/@expo/vector-icons": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/@expo/vector-icons/-/vector-icons-15.1.1.tgz", + "integrity": "sha512-Iu2VkcoI5vygbtYngm7jb4ifxElNVXQYdDrYkT7UCEIiKLeWnQY0wf2ZhHZ+Wro6Sc5TaumpKUOqDRpLi5rkvw==", + "license": "MIT", + "peerDependencies": { + "expo-font": ">=14.0.4", + "react": "*", + "react-native": "*" + } + }, + "node_modules/@expo/ws-tunnel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@expo/ws-tunnel/-/ws-tunnel-1.0.6.tgz", + "integrity": "sha512-nDRbLmSrJar7abvUjp3smDwH8HcbZcoOEa5jVPUv9/9CajgmWw20JNRwTuBRzWIWIkEJDkz20GoNA+tSwUqk0Q==", + "license": "MIT" + }, + "node_modules/@expo/xcpretty": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@expo/xcpretty/-/xcpretty-4.4.4.tgz", + "integrity": "sha512-4aQzz9vgxcNXFfo/iyNgDDYfsU5XGKKxWxZopw0cVotHiW+U8IJbIxMaxsINs6bHhtkG3StKNPcOrn3eBuxKPw==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/code-frame": "^7.20.0", + "chalk": "^4.1.0", + "js-yaml": "^4.1.0" + }, + "bin": { + "excpretty": "build/cli.js" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@ide/backoff": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@ide/backoff/-/backoff-1.0.0.tgz", + "integrity": "sha512-F0YfUDjvT+Mtt/R4xdl2X0EYCHMMiJqNLdxHD++jDT5ydEFIyqbCHh51Qx2E211dgZprPKhV7sHmnXKpLuvc5g==", + "license": "MIT" + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@isaacs/ttlcache": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@isaacs/ttlcache/-/ttlcache-1.4.1.tgz", + "integrity": "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz", + "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/core/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "devOptional": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/create-cache-key-function": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-29.7.0.tgz", + "integrity": "sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/diff-sequences": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.3.0.tgz", + "integrity": "sha512-cG51MVnLq1ecVUaQ3fr6YuuAOitHK1S4WUJHnsPFE/quQr33ADUx1FfrTCpMCRxvy0Yr9BThKpDjSlcTi91tMA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/get-type": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/pattern": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz", + "integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-regex-util": "30.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/pattern/node_modules/jest-regex-util": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", + "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/reporters/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "devOptional": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@jest/reporters/node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "devOptional": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@jest/reporters/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "devOptional": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nolyfill/is-core-module": { + "version": "1.0.39", + "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", + "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.4.0" + } + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz", + "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.0.tgz", + "integrity": "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", + "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@react-native-async-storage/async-storage": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-2.2.0.tgz", + "integrity": "sha512-gvRvjR5JAaUZF8tv2Kcq/Gbt3JHwbKFYfmb445rhOj6NUMx3qPLixmDx5pZAyb9at1bYvJ4/eTUipU5aki45xw==", + "license": "MIT", + "dependencies": { + "merge-options": "^3.0.4" + }, + "peerDependencies": { + "react-native": "^0.0.0-0 || >=0.65 <1.0" + } + }, + "node_modules/@react-native/assets-registry": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.81.5.tgz", + "integrity": "sha512-705B6x/5Kxm1RKRvSv0ADYWm5JOnoiQ1ufW7h8uu2E6G9Of/eE6hP/Ivw3U5jI16ERqZxiKQwk34VJbB0niX9w==", + "license": "MIT", + "engines": { + "node": ">= 20.19.4" + } + }, + "node_modules/@react-native/babel-plugin-codegen": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.81.5.tgz", + "integrity": "sha512-oF71cIH6je3fSLi6VPjjC3Sgyyn57JLHXs+mHWc9MoCiJJcM4nqsS5J38zv1XQ8d3zOW2JtHro+LF0tagj2bfQ==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.3", + "@react-native/codegen": "0.81.5" + }, + "engines": { + "node": ">= 20.19.4" + } + }, + "node_modules/@react-native/babel-preset": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/babel-preset/-/babel-preset-0.81.5.tgz", + "integrity": "sha512-UoI/x/5tCmi+pZ3c1+Ypr1DaRMDLI3y+Q70pVLLVgrnC3DHsHRIbHcCHIeG/IJvoeFqFM2sTdhSOLJrf8lOPrA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/plugin-proposal-export-default-from": "^7.24.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-default-from": "^7.24.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-transform-arrow-functions": "^7.24.7", + "@babel/plugin-transform-async-generator-functions": "^7.25.4", + "@babel/plugin-transform-async-to-generator": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.25.0", + "@babel/plugin-transform-class-properties": "^7.25.4", + "@babel/plugin-transform-classes": "^7.25.4", + "@babel/plugin-transform-computed-properties": "^7.24.7", + "@babel/plugin-transform-destructuring": "^7.24.8", + "@babel/plugin-transform-flow-strip-types": "^7.25.2", + "@babel/plugin-transform-for-of": "^7.24.7", + "@babel/plugin-transform-function-name": "^7.25.1", + "@babel/plugin-transform-literals": "^7.25.2", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.8", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", + "@babel/plugin-transform-numeric-separator": "^7.24.7", + "@babel/plugin-transform-object-rest-spread": "^7.24.7", + "@babel/plugin-transform-optional-catch-binding": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.8", + "@babel/plugin-transform-parameters": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.24.7", + "@babel/plugin-transform-private-property-in-object": "^7.24.7", + "@babel/plugin-transform-react-display-name": "^7.24.7", + "@babel/plugin-transform-react-jsx": "^7.25.2", + "@babel/plugin-transform-react-jsx-self": "^7.24.7", + "@babel/plugin-transform-react-jsx-source": "^7.24.7", + "@babel/plugin-transform-regenerator": "^7.24.7", + "@babel/plugin-transform-runtime": "^7.24.7", + "@babel/plugin-transform-shorthand-properties": "^7.24.7", + "@babel/plugin-transform-spread": "^7.24.7", + "@babel/plugin-transform-sticky-regex": "^7.24.7", + "@babel/plugin-transform-typescript": "^7.25.2", + "@babel/plugin-transform-unicode-regex": "^7.24.7", + "@babel/template": "^7.25.0", + "@react-native/babel-plugin-codegen": "0.81.5", + "babel-plugin-syntax-hermes-parser": "0.29.1", + "babel-plugin-transform-flow-enums": "^0.0.2", + "react-refresh": "^0.14.0" + }, + "engines": { + "node": ">= 20.19.4" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "node_modules/@react-native/codegen": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.81.5.tgz", + "integrity": "sha512-a2TDA03Up8lpSa9sh5VRGCQDXgCTOyDOFH+aqyinxp1HChG8uk89/G+nkJ9FPd0rqgi25eCTR16TWdS3b+fA6g==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/parser": "^7.25.3", + "glob": "^7.1.1", + "hermes-parser": "0.29.1", + "invariant": "^2.2.4", + "nullthrows": "^1.1.1", + "yargs": "^17.6.2" + }, + "engines": { + "node": ">= 20.19.4" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "node_modules/@react-native/codegen/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@react-native/community-cli-plugin": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.81.5.tgz", + "integrity": "sha512-yWRlmEOtcyvSZ4+OvqPabt+NS36vg0K/WADTQLhrYrm9qdZSuXmq8PmdJWz/68wAqKQ+4KTILiq2kjRQwnyhQw==", + "license": "MIT", + "dependencies": { + "@react-native/dev-middleware": "0.81.5", + "debug": "^4.4.0", + "invariant": "^2.2.4", + "metro": "^0.83.1", + "metro-config": "^0.83.1", + "metro-core": "^0.83.1", + "semver": "^7.1.3" + }, + "engines": { + "node": ">= 20.19.4" + }, + "peerDependencies": { + "@react-native-community/cli": "*", + "@react-native/metro-config": "*" + }, + "peerDependenciesMeta": { + "@react-native-community/cli": { + "optional": true + }, + "@react-native/metro-config": { + "optional": true + } + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@react-native/debugger-frontend": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.81.5.tgz", + "integrity": "sha512-bnd9FSdWKx2ncklOetCgrlwqSGhMHP2zOxObJbOWXoj7GHEmih4MKarBo5/a8gX8EfA1EwRATdfNBQ81DY+h+w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 20.19.4" + } + }, + "node_modules/@react-native/dev-middleware": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.81.5.tgz", + "integrity": "sha512-WfPfZzboYgo/TUtysuD5xyANzzfka8Ebni6RIb2wDxhb56ERi7qDrE4xGhtPsjCL4pQBXSVxyIlCy0d8I6EgGA==", + "license": "MIT", + "dependencies": { + "@isaacs/ttlcache": "^1.4.1", + "@react-native/debugger-frontend": "0.81.5", + "chrome-launcher": "^0.15.2", + "chromium-edge-launcher": "^0.2.0", + "connect": "^3.6.5", + "debug": "^4.4.0", + "invariant": "^2.2.4", + "nullthrows": "^1.1.1", + "open": "^7.0.3", + "serve-static": "^1.16.2", + "ws": "^6.2.3" + }, + "engines": { + "node": ">= 20.19.4" + } + }, + "node_modules/@react-native/dev-middleware/node_modules/ws": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz", + "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==", + "license": "MIT", + "dependencies": { + "async-limiter": "~1.0.0" + } + }, + "node_modules/@react-native/gradle-plugin": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.81.5.tgz", + "integrity": "sha512-hORRlNBj+ReNMLo9jme3yQ6JQf4GZpVEBLxmTXGGlIL78MAezDZr5/uq9dwElSbcGmLEgeiax6e174Fie6qPLg==", + "license": "MIT", + "engines": { + "node": ">= 20.19.4" + } + }, + "node_modules/@react-native/js-polyfills": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.81.5.tgz", + "integrity": "sha512-fB7M1CMOCIUudTRuj7kzxIBTVw2KXnsgbQ6+4cbqSxo8NmRRhA0Ul4ZUzZj3rFd3VznTL4Brmocv1oiN0bWZ8w==", + "license": "MIT", + "engines": { + "node": ">= 20.19.4" + } + }, + "node_modules/@react-native/normalize-colors": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.81.5.tgz", + "integrity": "sha512-0HuJ8YtqlTVRXGZuGeBejLE04wSQsibpTI+RGOyVqxZvgtlLLC/Ssw0UmbHhT4lYMp2fhdtvKZSs5emWB1zR/g==", + "license": "MIT" + }, + "node_modules/@react-navigation/bottom-tabs": { + "version": "7.15.9", + "resolved": "https://registry.npmjs.org/@react-navigation/bottom-tabs/-/bottom-tabs-7.15.9.tgz", + "integrity": "sha512-Ou28A1aZLj5wiFQ3F93aIsrI4NCwn3IJzkkjNo9KLFXsc0Yks+UqrVaFlffHFLsrbajuGRG/OQpnMA1ljayY5Q==", + "license": "MIT", + "dependencies": { + "@react-navigation/elements": "^2.9.14", + "color": "^4.2.3", + "sf-symbols-typescript": "^2.1.0" + }, + "peerDependencies": { + "@react-navigation/native": "^7.2.2", + "react": ">= 18.2.0", + "react-native": "*", + "react-native-safe-area-context": ">= 4.0.0", + "react-native-screens": ">= 4.0.0" + } + }, + "node_modules/@react-navigation/core": { + "version": "7.17.2", + "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-7.17.2.tgz", + "integrity": "sha512-Rt2OZwcgOmjv401uLGAKaRM6xo0fiBce/A7LfRHI1oe5FV+KooWcgAoZ2XOtgKj6UzVMuQWt3b2e6rxo/mDJRA==", + "license": "MIT", + "dependencies": { + "@react-navigation/routers": "^7.5.3", + "escape-string-regexp": "^4.0.0", + "fast-deep-equal": "^3.1.3", + "nanoid": "^3.3.11", + "query-string": "^7.1.3", + "react-is": "^19.1.0", + "use-latest-callback": "^0.2.4", + "use-sync-external-store": "^1.5.0" + }, + "peerDependencies": { + "react": ">= 18.2.0" + } + }, + "node_modules/@react-navigation/elements": { + "version": "2.9.14", + "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-2.9.14.tgz", + "integrity": "sha512-lKqzu+su2pI/YIZmR7L7xdOs4UL+rVXKJAMpRMBrwInEy96SjIFst6QDGpE89Dunnu3VjVpjWfByo9f2GWBHDQ==", + "license": "MIT", + "dependencies": { + "color": "^4.2.3", + "use-latest-callback": "^0.2.4", + "use-sync-external-store": "^1.5.0" + }, + "peerDependencies": { + "@react-native-masked-view/masked-view": ">= 0.2.0", + "@react-navigation/native": "^7.2.2", + "react": ">= 18.2.0", + "react-native": "*", + "react-native-safe-area-context": ">= 4.0.0" + }, + "peerDependenciesMeta": { + "@react-native-masked-view/masked-view": { + "optional": true + } + } + }, + "node_modules/@react-navigation/native": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.2.2.tgz", + "integrity": "sha512-kem1Ko2BcbAjmbQIv66dNmr6EtfDut3QU0qjsVhMnLLhktwyXb6FzZYp8gTrUb6AvkAbaJoi+BF5Pl55pAUa5w==", + "license": "MIT", + "dependencies": { + "@react-navigation/core": "^7.17.2", + "escape-string-regexp": "^4.0.0", + "fast-deep-equal": "^3.1.3", + "nanoid": "^3.3.11", + "use-latest-callback": "^0.2.4" + }, + "peerDependencies": { + "react": ">= 18.2.0", + "react-native": "*" + } + }, + "node_modules/@react-navigation/native-stack": { + "version": "7.14.11", + "resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-7.14.11.tgz", + "integrity": "sha512-1ufBtJ7KbVFlQhXsYSYHqjgkmP30AzJSgW48YjWMQZ3NZGAyYe34w9Wd4KpdebQCfDClPe9maU+8crA/awa6lQ==", + "license": "MIT", + "dependencies": { + "@react-navigation/elements": "^2.9.14", + "color": "^4.2.3", + "sf-symbols-typescript": "^2.1.0", + "warn-once": "^0.1.1" + }, + "peerDependencies": { + "@react-navigation/native": "^7.2.2", + "react": ">= 18.2.0", + "react-native": "*", + "react-native-safe-area-context": ">= 4.0.0", + "react-native-screens": ">= 4.0.0" + } + }, + "node_modules/@react-navigation/routers": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-7.5.3.tgz", + "integrity": "sha512-1tJHg4KKRJuQ1/EvJxatrMef3NZXEPzwUIUZ3n1yJ2t7Q97siwRtbynRpQG9/69ebbtiZ8W3ScOZF/OmhvM4Rg==", + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11" + } + }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.10", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.10.tgz", + "integrity": "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==", + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@supabase/auth-js": { + "version": "2.103.1", + "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.103.1.tgz", + "integrity": "sha512-HsXbSv6AkX7oBqHmbwtE1oUtK0KiWQmA0KeYoEd4SnsZeSmUOe+mNfEyL3mZbBCdgORJuMDoQX2ofvwayV4tdQ==", + "license": "MIT", + "dependencies": { + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/functions-js": { + "version": "2.103.1", + "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.103.1.tgz", + "integrity": "sha512-OlKF1YhKO+zlxEXYct9NcLUFUBuChlt4t85lMYhVrdN8y4lJSBG+zUuqMz/ZrnBviKq43+D3DsIgBu+Vjq51vw==", + "license": "MIT", + "dependencies": { + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/phoenix": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@supabase/phoenix/-/phoenix-0.4.0.tgz", + "integrity": "sha512-RHSx8bHS02xwfHdAbX5Lpbo6PXbgyf7lTaXTlwtFDPwOIw64NnVRwFAXGojHhjtVYI+PEPNSWwkL90f4agN3bw==", + "license": "MIT" + }, + "node_modules/@supabase/postgrest-js": { + "version": "2.103.1", + "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-2.103.1.tgz", + "integrity": "sha512-nZaN1eYcTXoZt+UyFp6PtPWJIIEoL4r9UpfbCT4cTRz5q6B6IGltsSfwdNWq15SrXNyYj5NlJKL8UIDkHrFf0g==", + "license": "MIT", + "dependencies": { + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/realtime-js": { + "version": "2.103.1", + "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.103.1.tgz", + "integrity": "sha512-JxuM0Gju9WlRkXMU/lSE94Fh+euCzc2xM+R6oaA2xeqJD959L2Ignj0mIvshfhJRglQ2GNJgcdPf1o9Xx48XFw==", + "license": "MIT", + "dependencies": { + "@supabase/phoenix": "^0.4.0", + "@types/ws": "^8.18.1", + "tslib": "2.8.1", + "ws": "^8.18.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/realtime-js/node_modules/ws": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", + "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@supabase/storage-js": { + "version": "2.103.1", + "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.103.1.tgz", + "integrity": "sha512-rkbWonWLbfrtVwdVhr9DZI+VV7TVd+j4QlxkPWzepwqx7pWj6bDxOAqTXaQNWR3aPQR6a+zsK1AAc6KGQH1mtA==", + "license": "MIT", + "dependencies": { + "iceberg-js": "^0.8.1", + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/supabase-js": { + "version": "2.103.1", + "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.103.1.tgz", + "integrity": "sha512-mFdjUK+Rw6iQnpTvj9KiGdL3sHo/M6SkT+VQ7w2KzQ9u6V5OM503rXShJBH3L/vVT5vz8FzRrNOfTIyIsTxswg==", + "dependencies": { + "@supabase/auth-js": "2.103.1", + "@supabase/functions-js": "2.103.1", + "@supabase/postgrest-js": "2.103.1", + "@supabase/realtime-js": "2.103.1", + "@supabase/storage-js": "2.103.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@testing-library/react-native": { + "version": "13.3.3", + "resolved": "https://registry.npmjs.org/@testing-library/react-native/-/react-native-13.3.3.tgz", + "integrity": "sha512-k6Mjsd9dbZgvY4Bl7P1NIpePQNi+dfYtlJ5voi9KQlynxSyQkfOgJmYGCYmw/aSgH/rUcFvG8u5gd4npzgRDyg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "jest-matcher-utils": "^30.0.5", + "picocolors": "^1.1.1", + "pretty-format": "^30.0.5", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "jest": ">=29.0.0", + "react": ">=18.2.0", + "react-native": ">=0.71", + "react-test-renderer": ">=18.2.0" + }, + "peerDependenciesMeta": { + "jest": { + "optional": true + } + } + }, + "node_modules/@testing-library/react-native/node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@testing-library/react-native/node_modules/@sinclair/typebox": { + "version": "0.34.49", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.49.tgz", + "integrity": "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@testing-library/react-native/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@testing-library/react-native/node_modules/pretty-format": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.3.0.tgz", + "integrity": "sha512-oG4T3wCbfeuvljnyAzhBvpN45E8iOTXCU/TD3zXW80HA3dQ4ahdqMkWGiPWZvjpQwlbyHrPTWUAqUzGzv4l1JQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@testing-library/react-native/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@tootallnate/once": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.1.tgz", + "integrity": "sha512-HqmEUIGRJ5fSXchkVgR5F7qn48bDBzv0kWj/Kfu5e6uci4UlEeng4331LnBkWffb++Ei3FOVLxo8JJWMFBDMeQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/hammerjs": { + "version": "2.0.46", + "resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.46.tgz", + "integrity": "sha512-ynRvcq6wvqexJ9brDMS4BnBLzmr0e14d6ZJTEShTBWKymQiHwlAyGu0ZPEFI2Fh1U53F7tN9ufClWM5KvqkKOw==", + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "30.0.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-30.0.0.tgz", + "integrity": "sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^30.0.0", + "pretty-format": "^30.0.0" + } + }, + "node_modules/@types/jest/node_modules/@jest/expect-utils": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.3.0.tgz", + "integrity": "sha512-j0+W5iQQ8hBh7tHZkTQv3q2Fh/M7Je72cIsYqC4OaktgtO7v1So9UTjp6uPBHIaB6beoF/RRsCgMJKvti0wADA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/@jest/types": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.3.0.tgz", + "integrity": "sha512-JHm87k7bA33hpBngtU8h6UBub/fqqA9uXfw+21j5Hmk7ooPHlboRNxHq0JcMtC+n8VJGP1mcfnD3Mk+XKe1oSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/pattern": "30.0.1", + "@jest/schemas": "30.0.5", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/@sinclair/typebox": { + "version": "0.34.49", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.49.tgz", + "integrity": "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/jest/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@types/jest/node_modules/ci-info": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@types/jest/node_modules/expect": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.3.0.tgz", + "integrity": "sha512-1zQrciTiQfRdo7qJM1uG4navm8DayFa2TgCSRlzUyNkhcJ6XUZF3hjnpkyr3VhAqPH7i/9GkG7Tv5abz6fqz0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "30.3.0", + "@jest/get-type": "30.1.0", + "jest-matcher-utils": "30.3.0", + "jest-message-util": "30.3.0", + "jest-mock": "30.3.0", + "jest-util": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/jest-message-util": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.3.0.tgz", + "integrity": "sha512-Z/j4Bo+4ySJ+JPJN3b2Qbl9hDq3VrXmnjjGEWD/x0BCXeOXPTV1iZYYzl2X8c1MaCOL+ewMyNBcm88sboE6YWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.3.0", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.3", + "pretty-format": "30.3.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/jest-mock": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.3.0.tgz", + "integrity": "sha512-OTzICK8CpE+t4ndhKrwlIdbM6Pn8j00lvmSmq5ejiO+KxukbLjgOflKWMn3KE34EZdQm5RqTuKj+5RIEniYhog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.3.0", + "@types/node": "*", + "jest-util": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/jest-util": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.3.0.tgz", + "integrity": "sha512-/jZDa00a3Sz7rdyu55NLrQCIrbyIkbBxareejQI315f/i8HjYN+ZWsDLLpoQSiUIEIyZF/R8fDg3BmB8AtHttg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.3.0", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.3" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@types/jest/node_modules/pretty-format": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.3.0.tgz", + "integrity": "sha512-oG4T3wCbfeuvljnyAzhBvpN45E8iOTXCU/TD3zXW80HA3dQ4ahdqMkWGiPWZvjpQwlbyHrPTWUAqUzGzv4l1JQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/jsdom": { + "version": "20.0.1", + "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.1.tgz", + "integrity": "sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/tough-cookie": "*", + "parse5": "^7.0.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.6.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", + "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.19.0" + } + }, + "node_modules/@types/react": { + "version": "19.1.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.17.tgz", + "integrity": "sha512-Qec1E3mhALmaspIrhWt9jkQMNdw6bReVu64mjvhbhq2NFPftLPVr+l1SZgmw/66WwBNpDh7ao5AT6gF5v41PFA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.0.2" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "license": "MIT" + }, + "node_modules/@types/tough-cookie": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.58.2.tgz", + "integrity": "sha512-aC2qc5thQahutKjP+cl8cgN9DWe3ZUqVko30CMSZHnFEHyhOYoZSzkGtAI2mcwZ38xeImDucI4dnqsHiOYuuCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.58.2", + "@typescript-eslint/type-utils": "8.58.2", + "@typescript-eslint/utils": "8.58.2", + "@typescript-eslint/visitor-keys": "8.58.2", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.58.2", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.58.2.tgz", + "integrity": "sha512-/Zb/xaIDfxeJnvishjGdcR4jmr7S+bda8PKNhRGdljDM+elXhlvN0FyPSsMnLmJUrVG9aPO6dof80wjMawsASg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.58.2", + "@typescript-eslint/types": "8.58.2", + "@typescript-eslint/typescript-estree": "8.58.2", + "@typescript-eslint/visitor-keys": "8.58.2", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.58.2.tgz", + "integrity": "sha512-Cq6UfpZZk15+r87BkIh5rDpi38W4b+Sjnb8wQCPPDDweS/LRCFjCyViEbzHk5Ck3f2QDfgmlxqSa7S7clDtlfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.58.2", + "@typescript-eslint/types": "^8.58.2", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.58.2.tgz", + "integrity": "sha512-SgmyvDPexWETQek+qzZnrG6844IaO02UVyOLhI4wpo82dpZJY9+6YZCKAMFzXb7qhx37mFK1QcPQ18tud+vo6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.58.2", + "@typescript-eslint/visitor-keys": "8.58.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.58.2.tgz", + "integrity": "sha512-3SR+RukipDvkkKp/d0jP0dyzuls3DbGmwDpVEc5wqk5f38KFThakqAAO0XMirWAE+kT00oTauTbzMFGPoAzB0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.58.2.tgz", + "integrity": "sha512-Z7EloNR/B389FvabdGeTo2XMs4W9TjtPiO9DAsmT0yom0bwlPyRjkJ1uCdW1DvrrrYP50AJZ9Xc3sByZA9+dcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.58.2", + "@typescript-eslint/typescript-estree": "8.58.2", + "@typescript-eslint/utils": "8.58.2", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.58.2.tgz", + "integrity": "sha512-9TukXyATBQf/Jq9AMQXfvurk+G5R2MwfqQGDR2GzGz28HvY/lXNKGhkY+6IOubwcquikWk5cjlgPvD2uAA7htQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.58.2.tgz", + "integrity": "sha512-ELGuoofuhhoCvNbQjFFiobFcGgcDCEm0ThWdmO4Z0UzLqPXS3KFvnEZ+SHewwOYHjM09tkzOWXNTv9u6Gqtyuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.58.2", + "@typescript-eslint/tsconfig-utils": "8.58.2", + "@typescript-eslint/types": "8.58.2", + "@typescript-eslint/visitor-keys": "8.58.2", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.58.2.tgz", + "integrity": "sha512-QZfjHNEzPY8+l0+fIXMvuQ2sJlplB4zgDZvA+NmvZsZv3EQwOcc1DuIU1VJUTWZ/RKouBMhDyNaBMx4sWvrzRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.58.2", + "@typescript-eslint/types": "8.58.2", + "@typescript-eslint/typescript-estree": "8.58.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.58.2.tgz", + "integrity": "sha512-f1WO2Lx8a9t8DARmcWAUPJbu0G20bJlj8L4z72K00TMeJAoyLr/tHhI/pzYBLrR4dXWkcxO1cWYZEOX8DKHTqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.58.2", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "license": "ISC" + }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", + "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", + "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", + "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", + "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", + "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", + "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", + "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", + "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", + "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", + "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", + "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", + "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", + "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", + "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", + "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", + "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.11" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", + "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", + "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", + "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@urql/core": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@urql/core/-/core-5.2.0.tgz", + "integrity": "sha512-/n0ieD0mvvDnVAXEQgX/7qJiVcvYvNkOHeBvkwtylfjydar123caCXcl58PXFY11oU1oquJocVXHxLAbtv4x1A==", + "license": "MIT", + "dependencies": { + "@0no-co/graphql.web": "^1.0.13", + "wonka": "^6.3.2" + } + }, + "node_modules/@urql/exchange-retry": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@urql/exchange-retry/-/exchange-retry-1.3.2.tgz", + "integrity": "sha512-TQMCz2pFJMfpNxmSfX1VSfTjwUIFx/mL+p1bnfM1xjjdla7Z+KnGMW/EhFbpckp3LyWAH4PgOsMwOMnIN+MBFg==", + "license": "MIT", + "dependencies": { + "@urql/core": "^5.1.2", + "wonka": "^6.3.2" + }, + "peerDependencies": { + "@urql/core": "^5.0.0" + } + }, + "node_modules/@xmldom/xmldom": { + "version": "0.8.13", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.13.tgz", + "integrity": "sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "deprecated": "Use your platform's native atob() and btoa() methods instead", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz", + "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.1.0", + "acorn-walk": "^8.0.2" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", + "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/anser": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/anser/-/anser-1.4.10.tgz", + "integrity": "sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==", + "license": "MIT" + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-timsort": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz", + "integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==", + "license": "MIT" + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", + "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "license": "MIT" + }, + "node_modules/assert": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz", + "integrity": "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "is-nan": "^1.3.2", + "object-is": "^1.1.5", + "object.assign": "^4.1.4", + "util": "^0.12.5" + } + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "license": "MIT", + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.17.tgz", + "integrity": "sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-define-polyfill-provider": "^0.6.8", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", + "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.5", + "core-js-compat": "^3.43.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.8.tgz", + "integrity": "sha512-M762rNHfSF1EV3SLtnCJXFoQbbIIz0OyRwnCmV0KPC7qosSfCO0QLTSuJX3ayAebubhE6oYBAYPrBA5ljowaZg==", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.8" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-react-compiler": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-react-compiler/-/babel-plugin-react-compiler-1.0.0.tgz", + "integrity": "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.26.0" + } + }, + "node_modules/babel-plugin-react-native-web": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/babel-plugin-react-native-web/-/babel-plugin-react-native-web-0.21.2.tgz", + "integrity": "sha512-SPD0J6qjJn8231i0HZhlAGH6NORe+QvRSQM2mwQEzJ2Fb3E4ruWTiiicPlHjmeWShDXLcvoorOCXjeR7k/lyWA==", + "license": "MIT" + }, + "node_modules/babel-plugin-syntax-hermes-parser": { + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.29.1.tgz", + "integrity": "sha512-2WFYnoWGdmih1I1J5eIqxATOeycOqRwYxAQBu3cUu/rhwInwHUg7k60AFNbuGjSDL8tje5GDrAnxzRLcu2pYcA==", + "license": "MIT", + "dependencies": { + "hermes-parser": "0.29.1" + } + }, + "node_modules/babel-plugin-transform-flow-enums": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-enums/-/babel-plugin-transform-flow-enums-0.0.2.tgz", + "integrity": "sha512-g4aaCrDDOsWjbm0PUUeVnkcVd6AKJsVc/MbnPhEotEpkeJQP6b8nzewohQi7+QS8UyPehOhGWn0nOwjvWpmMvQ==", + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-flow": "^7.12.1" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/babel-preset-expo": { + "version": "54.0.10", + "resolved": "https://registry.npmjs.org/babel-preset-expo/-/babel-preset-expo-54.0.10.tgz", + "integrity": "sha512-wTt7POavLFypLcPW/uC5v8y+mtQKDJiyGLzYCjqr9tx0Qc3vCXcDKk1iCFIj/++Iy5CWhhTflEa7VvVPNWeCfw==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/plugin-proposal-decorators": "^7.12.9", + "@babel/plugin-proposal-export-default-from": "^7.24.7", + "@babel/plugin-syntax-export-default-from": "^7.24.7", + "@babel/plugin-transform-class-static-block": "^7.27.1", + "@babel/plugin-transform-export-namespace-from": "^7.25.9", + "@babel/plugin-transform-flow-strip-types": "^7.25.2", + "@babel/plugin-transform-modules-commonjs": "^7.24.8", + "@babel/plugin-transform-object-rest-spread": "^7.24.7", + "@babel/plugin-transform-parameters": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.24.7", + "@babel/plugin-transform-private-property-in-object": "^7.24.7", + "@babel/plugin-transform-runtime": "^7.24.7", + "@babel/preset-react": "^7.22.15", + "@babel/preset-typescript": "^7.23.0", + "@react-native/babel-preset": "0.81.5", + "babel-plugin-react-compiler": "^1.0.0", + "babel-plugin-react-native-web": "~0.21.0", + "babel-plugin-syntax-hermes-parser": "^0.29.1", + "babel-plugin-transform-flow-enums": "^0.0.2", + "debug": "^4.3.4", + "resolve-from": "^5.0.0" + }, + "peerDependencies": { + "@babel/runtime": "^7.20.0", + "expo": "*", + "react-refresh": ">=0.14.0 <1.0.0" + }, + "peerDependenciesMeta": { + "@babel/runtime": { + "optional": true + }, + "expo": { + "optional": true + } + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/badgin": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/badgin/-/badgin-1.2.3.tgz", + "integrity": "sha512-NQGA7LcfCpSzIbGRbkgjgdWkjy7HI+Th5VLxTJfW5EeaAf3fnS+xWQaQOCYiny+q6QSvxqoSO04vCx+4u++EJw==", + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.19", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.19.tgz", + "integrity": "sha512-qCkNLi2sfBOn8XhZQ0FXsT1Ki/Yo5P90hrkRamVFRS7/KV9hpfA4HkoWNU152+8w0zPjnxo5psx5NL3PSGgv5g==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/better-opn": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/better-opn/-/better-opn-3.0.2.tgz", + "integrity": "sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==", + "license": "MIT", + "dependencies": { + "open": "^8.0.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/better-opn/node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "license": "MIT", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/big-integer": { + "version": "1.6.52", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", + "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", + "license": "Unlicense", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bplist-creator": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.1.0.tgz", + "integrity": "sha512-sXaHZicyEEmY86WyueLTQesbeoH/mquvarJaQNbjuOQO+7gbFcDEWqKmcWA4cOTLzFlfgvkiVxolk1k5bBIpmg==", + "license": "MIT", + "dependencies": { + "stream-buffers": "2.2.x" + } + }, + "node_modules/bplist-parser": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.3.1.tgz", + "integrity": "sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA==", + "license": "MIT", + "dependencies": { + "big-integer": "1.6.x" + }, + "engines": { + "node": ">= 5.10.0" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001788", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001788.tgz", + "integrity": "sha512-6q8HFp+lOQtcf7wBK+uEenxymVWkGKkjFpCvw5W25cmMwEDU45p1xQFBQv8JDlMMry7eNxyBaR+qxgmTUZkIRQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/chrome-launcher": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.2.tgz", + "integrity": "sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0" + }, + "bin": { + "print-chrome-path": "bin/print-chrome-path.js" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/chromium-edge-launcher": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/chromium-edge-launcher/-/chromium-edge-launcher-0.2.0.tgz", + "integrity": "sha512-JfJjUnq25y9yg4FABRRVPmBGWPZZi+AQXT4mxupb67766/0UlhG8PAZCz6xzEMXTbW3CsSoE8PcCWA49n35mKg==", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0", + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + } + }, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "license": "MIT" + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", + "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", + "license": "MIT", + "dependencies": { + "restore-cursor": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "devOptional": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", + "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/comment-json": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.6.2.tgz", + "integrity": "sha512-R2rze/hDX30uul4NZoIZ76ImSJLFxn/1/ZxtKC1L77y2X1k+yYu1joKbAtMA2Fg3hZrTOiw0I5mwVMo0cf250w==", + "license": "MIT", + "dependencies": { + "array-timsort": "^1.0.3", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/compression/node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/core-js-compat": { + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.49.0.tgz", + "integrity": "sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/cross-fetch": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz", + "integrity": "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.7.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-in-js-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/css-in-js-utils/-/css-in-js-utils-3.1.0.tgz", + "integrity": "sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A==", + "license": "MIT", + "dependencies": { + "hyphenate-style-name": "^1.0.3" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssom": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", + "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", + "dev": true, + "license": "MIT" + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true, + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/data-urls": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", + "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/data-urls/node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/data-urls/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/data-urls/node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/dedent": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", + "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", + "devOptional": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "license": "Apache-2.0" + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "license": "MIT" + }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/domexception": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", + "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "license": "MIT", + "dependencies": { + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/domexception/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/dotenv": { + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dotenv-expand": { + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-11.0.7.tgz", + "integrity": "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==", + "license": "BSD-2-Clause", + "dependencies": { + "dotenv": "^16.4.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.336", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.336.tgz", + "integrity": "sha512-AbH9q9J455r/nLmdNZes0G0ZKcRX73FicwowalLs6ijwOmCJSRRrLX63lcAlzy9ux3dWK1w1+1nsBJEWN11hcQ==", + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-editor": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/env-editor/-/env-editor-0.4.2.tgz", + "integrity": "sha512-ObFo8v4rQJAE59M69QzwloxPZtd33TpYEIjtKD1rrFDcM1Gd7IkDxEBU+HriziN6HSHQnBJi8Dmy+JWkav5HKA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/error-ex/node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "license": "MIT", + "dependencies": { + "stackframe": "^1.3.4" + } + }, + "node_modules/es-abstract": { + "version": "1.24.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz", + "integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.3.2.tgz", + "integrity": "sha512-HVLACW1TppGYjJ8H6/jqH/pqOtKRw6wMlrB23xfExmFWxFquAIWCmwoLsOyN96K4a5KbmOf5At9ZUO3GZbetAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.2", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.1.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.3.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "iterator.prototype": "^1.1.5", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", + "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "9.39.4", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-expo": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-expo/-/eslint-config-expo-10.0.0.tgz", + "integrity": "sha512-/XC/DvniUWTzU7Ypb/cLDhDD4DXqEio4lug1ObD/oQ9Hcx3OVOR8Mkp4u6U4iGoZSJyIQmIk3WVHe/P1NYUXKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "^8.18.2", + "@typescript-eslint/parser": "^8.18.2", + "eslint-import-resolver-typescript": "^3.6.3", + "eslint-plugin-expo": "^1.0.0", + "eslint-plugin-import": "^2.30.0", + "eslint-plugin-react": "^7.37.3", + "eslint-plugin-react-hooks": "^5.1.0", + "globals": "^16.0.0" + }, + "peerDependencies": { + "eslint": ">=8.10" + } + }, + "node_modules/eslint-config-expo/node_modules/globals": { + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", + "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.10.tgz", + "integrity": "sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.16.1", + "resolve": "^2.0.0-next.6" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz", + "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@nolyfill/is-core-module": "1.0.39", + "debug": "^4.4.0", + "get-tsconfig": "^4.10.0", + "is-bun-module": "^2.0.0", + "stable-hash": "^0.0.5", + "tinyglobby": "^0.2.13", + "unrs-resolver": "^1.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-resolver-typescript" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*", + "eslint-plugin-import-x": "*" + }, + "peerDependenciesMeta": { + "eslint-plugin-import": { + "optional": true + }, + "eslint-plugin-import-x": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", + "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-expo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-expo/-/eslint-plugin-expo-1.0.0.tgz", + "integrity": "sha512-qLtunR+cNFtC+jwYCBia5c/PJurMjSLMOV78KrEOyQK02ohZapU4dCFFnS2hfrJuw0zxfsjVkjqg3QBqi933QA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "^8.29.1", + "@typescript-eslint/utils": "^8.29.1", + "eslint": "^9.24.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "eslint": ">=8.10" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.32.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", + "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.9", + "array.prototype.findlastindex": "^1.2.6", + "array.prototype.flat": "^1.3.3", + "array.prototype.flatmap": "^1.3.3", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.1", + "hasown": "^2.0.2", + "is-core-module": "^2.16.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.1", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.9", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.37.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", + "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.3", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.2.1", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.9", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.1", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.12", + "string.prototype.repeat": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", + "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/execa/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "devOptional": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/expect/node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/expect/node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/expo": { + "version": "54.0.34", + "resolved": "https://registry.npmjs.org/expo/-/expo-54.0.34.tgz", + "integrity": "sha512-XkVHguZZDC8BcTQxHAd14/TQFbDp1Wt0Z/KApO9t68Ll5A127hLCPzU+a9gytfCIiyL/V1IpF1vIcOLKEVAoNQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.20.0", + "@expo/cli": "54.0.24", + "@expo/config": "~12.0.13", + "@expo/config-plugins": "~54.0.4", + "@expo/devtools": "0.1.8", + "@expo/fingerprint": "0.15.5", + "@expo/metro": "~54.2.0", + "@expo/metro-config": "54.0.15", + "@expo/vector-icons": "^15.0.3", + "@ungap/structured-clone": "^1.3.0", + "babel-preset-expo": "~54.0.10", + "expo-asset": "~12.0.13", + "expo-constants": "~18.0.13", + "expo-file-system": "~19.0.22", + "expo-font": "~14.0.11", + "expo-keep-awake": "~15.0.8", + "expo-modules-autolinking": "3.0.25", + "expo-modules-core": "3.0.30", + "pretty-format": "^29.7.0", + "react-refresh": "^0.14.2", + "whatwg-url-without-unicode": "8.0.0-3" + }, + "bin": { + "expo": "bin/cli", + "expo-modules-autolinking": "bin/autolinking", + "fingerprint": "bin/fingerprint" + }, + "peerDependencies": { + "@expo/dom-webview": "*", + "@expo/metro-runtime": "*", + "react": "*", + "react-native": "*", + "react-native-webview": "*" + }, + "peerDependenciesMeta": { + "@expo/dom-webview": { + "optional": true + }, + "@expo/metro-runtime": { + "optional": true + }, + "react-native-webview": { + "optional": true + } + } + }, + "node_modules/expo-application": { + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/expo-application/-/expo-application-7.0.8.tgz", + "integrity": "sha512-qFGyxk7VJbrNOQWBbE09XUuGuvkOgFS9QfToaK2FdagM2aQ+x3CvGV2DuVgl/l4ZxPgIf3b/MNh9xHpwSwn74Q==", + "license": "MIT", + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-asset": { + "version": "12.0.13", + "resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-12.0.13.tgz", + "integrity": "sha512-x/p7WvQUnkn6K43b9eL6SPeq5Vnf1E8BDe9bDrWrvMqzyUvJnUFvl+ctg3034s/+UHe7Ne2pAmc0+yzbl8CrDQ==", + "license": "MIT", + "dependencies": { + "@expo/image-utils": "^0.8.8", + "expo-constants": "~18.0.13" + }, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo-constants": { + "version": "18.0.13", + "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-18.0.13.tgz", + "integrity": "sha512-FnZn12E1dRYKDHlAdIyNFhBurKTS3F9CrfrBDJI5m3D7U17KBHMQ6JEfYlSj7LG7t+Ulr+IKaj58L1k5gBwTcQ==", + "license": "MIT", + "dependencies": { + "@expo/config": "~12.0.13", + "@expo/env": "~2.0.8" + }, + "peerDependencies": { + "expo": "*", + "react-native": "*" + } + }, + "node_modules/expo-dev-client": { + "version": "6.0.20", + "resolved": "https://registry.npmjs.org/expo-dev-client/-/expo-dev-client-6.0.20.tgz", + "integrity": "sha512-5XjoVlj1OxakNxy55j/AUaGPrDOlQlB6XdHLLWAw61w5ffSpUDHDnuZzKzs9xY1eIaogOqTOQaAzZ2ddBkdXLA==", + "license": "MIT", + "dependencies": { + "expo-dev-launcher": "6.0.20", + "expo-dev-menu": "7.0.18", + "expo-dev-menu-interface": "2.0.0", + "expo-manifests": "~1.0.10", + "expo-updates-interface": "~2.0.0" + }, + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-dev-launcher": { + "version": "6.0.20", + "resolved": "https://registry.npmjs.org/expo-dev-launcher/-/expo-dev-launcher-6.0.20.tgz", + "integrity": "sha512-a04zHEeT9sB0L5EB38fz7sNnUKJ2Ar1pXpcyl60Ki8bXPNCs9rjY7NuYrDkP/irM8+1DklMBqHpyHiLyJ/R+EA==", + "license": "MIT", + "dependencies": { + "ajv": "^8.11.0", + "expo-dev-menu": "7.0.18", + "expo-manifests": "~1.0.10" + }, + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-dev-launcher/node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/expo-dev-launcher/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/expo-dev-menu": { + "version": "7.0.18", + "resolved": "https://registry.npmjs.org/expo-dev-menu/-/expo-dev-menu-7.0.18.tgz", + "integrity": "sha512-4kTdlHrnZCAWCT6tZRQHSSjZ7vECFisL4T+nsG/GJDo/jcHNaOVGV5qPV9wzlTxyMk3YOPggRw4+g7Ownrg5eA==", + "license": "MIT", + "dependencies": { + "expo-dev-menu-interface": "2.0.0" + }, + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-dev-menu-interface": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/expo-dev-menu-interface/-/expo-dev-menu-interface-2.0.0.tgz", + "integrity": "sha512-BvAMPt6x+vyXpThsyjjOYyjwfjREV4OOpQkZ0tNl+nGpsPfcY9mc6DRACoWnH9KpLzyIt3BOgh3cuy/h/OxQjw==", + "license": "MIT", + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-file-system": { + "version": "19.0.22", + "resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-19.0.22.tgz", + "integrity": "sha512-l9pgahSc7sJD0bP9vBNeXvZjy8QKDpVHVxWmei/ESQOrzmoj5BidziqLVsyZdxsi+PfdbTtttLTAmddH/JafYA==", + "license": "MIT", + "peerDependencies": { + "expo": "*", + "react-native": "*" + } + }, + "node_modules/expo-font": { + "version": "14.0.11", + "resolved": "https://registry.npmjs.org/expo-font/-/expo-font-14.0.11.tgz", + "integrity": "sha512-ga0q61ny4s/kr4k8JX9hVH69exVSIfcIc19+qZ7gt71Mqtm7xy2c6kwsPTCyhBW2Ro5yXTT8EaZOpuRi35rHbg==", + "license": "MIT", + "dependencies": { + "fontfaceobserver": "^2.1.0" + }, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo-haptics": { + "version": "15.0.8", + "resolved": "https://registry.npmjs.org/expo-haptics/-/expo-haptics-15.0.8.tgz", + "integrity": "sha512-lftutojy8Qs8zaDzzjwM3gKHFZ8bOOEZDCkmh2Ddpe95Ra6kt2izeOfOfKuP/QEh0MZ1j9TfqippyHdRd1ZM9g==", + "license": "MIT", + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-image": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/expo-image/-/expo-image-3.0.11.tgz", + "integrity": "sha512-4TudfUCLgYgENv+f48omnU8tjS2S0Pd9EaON5/s1ZUBRwZ7K8acEr4NfvLPSaeXvxW24iLAiyQ7sV7BXQH3RoA==", + "license": "MIT", + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*", + "react-native-web": "*" + }, + "peerDependenciesMeta": { + "react-native-web": { + "optional": true + } + } + }, + "node_modules/expo-json-utils": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/expo-json-utils/-/expo-json-utils-0.15.0.tgz", + "integrity": "sha512-duRT6oGl80IDzH2LD2yEFWNwGIC2WkozsB6HF3cDYNoNNdUvFk6uN3YiwsTsqVM/D0z6LEAQ01/SlYvN+Fw0JQ==", + "license": "MIT" + }, + "node_modules/expo-keep-awake": { + "version": "15.0.8", + "resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-15.0.8.tgz", + "integrity": "sha512-YK9M1VrnoH1vLJiQzChZgzDvVimVoriibiDIFLbQMpjYBnvyfUeHJcin/Gx1a+XgupNXy92EQJLgI/9ZuXajYQ==", + "license": "MIT", + "peerDependencies": { + "expo": "*", + "react": "*" + } + }, + "node_modules/expo-linking": { + "version": "8.0.11", + "resolved": "https://registry.npmjs.org/expo-linking/-/expo-linking-8.0.11.tgz", + "integrity": "sha512-+VSaNL5om3kOp/SSKO5qe6cFgfSIWnnQDSbA7XLs3ECkYzXRquk5unxNS3pg7eK5kNUmQ4kgLI7MhTggAEUBLA==", + "license": "MIT", + "dependencies": { + "expo-constants": "~18.0.12", + "invariant": "^2.2.4" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo-manifests": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/expo-manifests/-/expo-manifests-1.0.10.tgz", + "integrity": "sha512-oxDUnURPcL4ZsOBY6X1DGWGuoZgVAFzp6PISWV7lPP2J0r8u1/ucuChBgpK7u1eLGFp6sDIPwXyEUCkI386XSQ==", + "license": "MIT", + "dependencies": { + "@expo/config": "~12.0.11", + "expo-json-utils": "~0.15.0" + }, + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-modules-autolinking": { + "version": "3.0.25", + "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-3.0.25.tgz", + "integrity": "sha512-YmHWctJlwvOuLZccg3cOXvSiXVJrPMKl7g2YR0YHWoGL9v2RvcmgaPJWPSLVW+voNEgEPsbo5UmUrAqbnYcBeg==", + "license": "MIT", + "dependencies": { + "@expo/spawn-async": "^1.7.2", + "chalk": "^4.1.0", + "commander": "^7.2.0", + "require-from-string": "^2.0.2", + "resolve-from": "^5.0.0" + }, + "bin": { + "expo-modules-autolinking": "bin/expo-modules-autolinking.js" + } + }, + "node_modules/expo-modules-core": { + "version": "3.0.30", + "resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-3.0.30.tgz", + "integrity": "sha512-a6IrpAn/Jbmwxi9L+hMmXKpNqnkUpoF7WHOpn02rVLyax2J0gB1vvCVE5rNydplEnt41Q6WxQwvcOjZaIkcSUg==", + "license": "MIT", + "dependencies": { + "invariant": "^2.2.4" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo-notifications": { + "version": "0.32.16", + "resolved": "https://registry.npmjs.org/expo-notifications/-/expo-notifications-0.32.16.tgz", + "integrity": "sha512-QQD/UA6v7LgvwIJ+tS7tSvqJZkdp0nCSj9MxsDk/jU1GttYdK49/5L2LvE/4U0H7sNBz1NZAyhDZozg8xgBLXw==", + "license": "MIT", + "dependencies": { + "@expo/image-utils": "^0.8.8", + "@ide/backoff": "^1.0.0", + "abort-controller": "^3.0.0", + "assert": "^2.0.0", + "badgin": "^1.1.5", + "expo-application": "~7.0.8", + "expo-constants": "~18.0.13" + }, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo-router": { + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/expo-router/-/expo-router-6.0.23.tgz", + "integrity": "sha512-qCxVAiCrCyu0npky6azEZ6dJDMt77OmCzEbpF6RbUTlfkaCA417LvY14SBkk0xyGruSxy/7pvJOI6tuThaUVCA==", + "license": "MIT", + "dependencies": { + "@expo/metro-runtime": "^6.1.2", + "@expo/schema-utils": "^0.1.8", + "@radix-ui/react-slot": "1.2.0", + "@radix-ui/react-tabs": "^1.1.12", + "@react-navigation/bottom-tabs": "^7.4.0", + "@react-navigation/native": "^7.1.8", + "@react-navigation/native-stack": "^7.3.16", + "client-only": "^0.0.1", + "debug": "^4.3.4", + "escape-string-regexp": "^4.0.0", + "expo-server": "^1.0.5", + "fast-deep-equal": "^3.1.3", + "invariant": "^2.2.4", + "nanoid": "^3.3.8", + "query-string": "^7.1.3", + "react-fast-compare": "^3.2.2", + "react-native-is-edge-to-edge": "^1.1.6", + "semver": "~7.6.3", + "server-only": "^0.0.1", + "sf-symbols-typescript": "^2.1.0", + "shallowequal": "^1.1.0", + "use-latest-callback": "^0.2.1", + "vaul": "^1.1.2" + }, + "peerDependencies": { + "@expo/metro-runtime": "^6.1.2", + "@react-navigation/drawer": "^7.5.0", + "@testing-library/react-native": ">= 12.0.0", + "expo": "*", + "expo-constants": "^18.0.13", + "expo-linking": "^8.0.11", + "react": "*", + "react-dom": "*", + "react-native": "*", + "react-native-gesture-handler": "*", + "react-native-reanimated": "*", + "react-native-safe-area-context": ">= 5.4.0", + "react-native-screens": "*", + "react-native-web": "*", + "react-server-dom-webpack": "~19.0.4 || ~19.1.5 || ~19.2.4" + }, + "peerDependenciesMeta": { + "@react-navigation/drawer": { + "optional": true + }, + "@testing-library/react-native": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-native-gesture-handler": { + "optional": true + }, + "react-native-reanimated": { + "optional": true + }, + "react-native-web": { + "optional": true + }, + "react-server-dom-webpack": { + "optional": true + } + } + }, + "node_modules/expo-router/node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/expo-router/node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/expo-router/node_modules/@radix-ui/react-presence": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", + "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/expo-router/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/expo-router/node_modules/@radix-ui/react-primitive/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/expo-router/node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz", + "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/expo-router/node_modules/@radix-ui/react-tabs": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz", + "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/expo-router/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/expo-secure-store": { + "version": "15.0.8", + "resolved": "https://registry.npmjs.org/expo-secure-store/-/expo-secure-store-15.0.8.tgz", + "integrity": "sha512-lHnzvRajBu4u+P99+0GEMijQMFCOYpWRO4dWsXSuMt77+THPIGjzNvVKrGSl6mMrLsfVaKL8BpwYZLGlgA+zAw==", + "license": "MIT", + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-server": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/expo-server/-/expo-server-1.0.6.tgz", + "integrity": "sha512-vb5TBtskvEdzYuW79lATXutOEBfW5m6U4EFpNjCVZTnI7S//SAsLQkYEpn+EDfn84m6VQfzSGkIVR6YPaScKFA==", + "license": "MIT", + "engines": { + "node": ">=20.16.0" + } + }, + "node_modules/expo-splash-screen": { + "version": "31.0.13", + "resolved": "https://registry.npmjs.org/expo-splash-screen/-/expo-splash-screen-31.0.13.tgz", + "integrity": "sha512-1epJLC1cDlwwj089R2h8cxaU5uk4ONVAC+vzGiTZH4YARQhL4Stlz1MbR6yAS173GMosvkE6CAeihR7oIbCkDA==", + "license": "MIT", + "dependencies": { + "@expo/prebuild-config": "^54.0.8" + }, + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-status-bar": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/expo-status-bar/-/expo-status-bar-3.0.9.tgz", + "integrity": "sha512-xyYyVg6V1/SSOZWh4Ni3U129XHCnFHBTcUo0dhWtFDrZbNp/duw5AGsQfb2sVeU0gxWHXSY1+5F0jnKYC7WuOw==", + "license": "MIT", + "dependencies": { + "react-native-is-edge-to-edge": "^1.2.1" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo-symbols": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/expo-symbols/-/expo-symbols-1.0.8.tgz", + "integrity": "sha512-7bNjK350PaQgxBf0owpmSYkdZIpdYYmaPttDBb2WIp6rIKtcEtdzdfmhsc2fTmjBURHYkg36+eCxBFXO25/1hw==", + "license": "MIT", + "dependencies": { + "sf-symbols-typescript": "^2.0.0" + }, + "peerDependencies": { + "expo": "*", + "react-native": "*" + } + }, + "node_modules/expo-system-ui": { + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/expo-system-ui/-/expo-system-ui-6.0.9.tgz", + "integrity": "sha512-eQTYGzw1V4RYiYHL9xDLYID3Wsec2aZS+ypEssmF64D38aDrqbDgz1a2MSlHLQp2jHXSs3FvojhZ9FVela1Zcg==", + "license": "MIT", + "dependencies": { + "@react-native/normalize-colors": "0.81.5", + "debug": "^4.3.2" + }, + "peerDependencies": { + "expo": "*", + "react-native": "*", + "react-native-web": "*" + }, + "peerDependenciesMeta": { + "react-native-web": { + "optional": true + } + } + }, + "node_modules/expo-updates-interface": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/expo-updates-interface/-/expo-updates-interface-2.0.0.tgz", + "integrity": "sha512-pTzAIufEZdVPKql6iMi5ylVSPqV1qbEopz9G6TSECQmnNde2nwq42PxdFBaUEd8IZJ/fdJLQnOT3m6+XJ5s7jg==", + "license": "MIT", + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-web-browser": { + "version": "15.0.10", + "resolved": "https://registry.npmjs.org/expo-web-browser/-/expo-web-browser-15.0.10.tgz", + "integrity": "sha512-fvDhW4bhmXAeWFNFiInmsGCK83PAqAcQaFyp/3pE/jbdKmFKoRCWr46uZGIfN4msLK/OODhaQ/+US7GSJNDHJg==", + "license": "MIT", + "peerDependencies": { + "expo": "*", + "react-native": "*" + } + }, + "node_modules/expo/node_modules/@expo/cli": { + "version": "54.0.24", + "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-54.0.24.tgz", + "integrity": "sha512-5xse1bEgnVUBhOrtttc6xTNJVvjyTRavpzuF0/0nuj+312vfSbk7EiRbG+xJ2pW/iZxnhLPJkFCrPYG0nmheAQ==", + "license": "MIT", + "dependencies": { + "@0no-co/graphql.web": "^1.0.8", + "@expo/code-signing-certificates": "^0.0.6", + "@expo/config": "~12.0.13", + "@expo/config-plugins": "~54.0.4", + "@expo/devcert": "^1.2.1", + "@expo/env": "~2.0.8", + "@expo/image-utils": "^0.8.8", + "@expo/json-file": "^10.0.8", + "@expo/metro": "~54.2.0", + "@expo/metro-config": "~54.0.15", + "@expo/osascript": "^2.3.8", + "@expo/package-manager": "^1.9.10", + "@expo/plist": "^0.4.8", + "@expo/prebuild-config": "^54.0.8", + "@expo/schema-utils": "^0.1.8", + "@expo/spawn-async": "^1.7.2", + "@expo/ws-tunnel": "^1.0.1", + "@expo/xcpretty": "^4.3.0", + "@react-native/dev-middleware": "0.81.5", + "@urql/core": "^5.0.6", + "@urql/exchange-retry": "^1.3.0", + "accepts": "^1.3.8", + "arg": "^5.0.2", + "better-opn": "~3.0.2", + "bplist-creator": "0.1.0", + "bplist-parser": "^0.3.1", + "chalk": "^4.0.0", + "ci-info": "^3.3.0", + "compression": "^1.7.4", + "connect": "^3.7.0", + "debug": "^4.3.4", + "env-editor": "^0.4.1", + "expo-server": "^1.0.6", + "freeport-async": "^2.0.0", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "lan-network": "^0.2.1", + "minimatch": "^9.0.0", + "node-forge": "^1.3.3", + "npm-package-arg": "^11.0.0", + "ora": "^3.4.0", + "picomatch": "^4.0.3", + "pretty-bytes": "^5.6.0", + "pretty-format": "^29.7.0", + "progress": "^2.0.3", + "prompts": "^2.3.2", + "qrcode-terminal": "0.11.0", + "require-from-string": "^2.0.2", + "requireg": "^0.2.2", + "resolve": "^1.22.2", + "resolve-from": "^5.0.0", + "resolve.exports": "^2.0.3", + "semver": "^7.6.0", + "send": "^0.19.0", + "slugify": "^1.3.4", + "source-map-support": "~0.5.21", + "stacktrace-parser": "^0.1.10", + "structured-headers": "^0.4.1", + "tar": "^7.5.2", + "terminal-link": "^2.1.1", + "undici": "^6.18.2", + "wrap-ansi": "^7.0.0", + "ws": "^8.12.1" + }, + "bin": { + "expo-internal": "build/bin/cli" + }, + "peerDependencies": { + "expo": "*", + "expo-router": "*", + "react-native": "*" + }, + "peerDependenciesMeta": { + "expo-router": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/expo/node_modules/brace-expansion": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/expo/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/expo/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/expo/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/expo/node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/expo/node_modules/semver": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/expo/node_modules/ws": { + "version": "8.20.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz", + "integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", + "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", + "license": "Apache-2.0" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fbjs": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.5.tgz", + "integrity": "sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==", + "license": "MIT", + "dependencies": { + "cross-fetch": "^3.1.5", + "fbjs-css-vars": "^1.0.0", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^1.0.35" + } + }, + "node_modules/fbjs-css-vars": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz", + "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==", + "license": "MIT" + }, + "node_modules/fbjs/node_modules/promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "license": "MIT", + "dependencies": { + "asap": "~2.0.3" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/filter-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz", + "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-yarn-workspace-root": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz", + "integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "micromatch": "^4.0.2" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, + "node_modules/flow-enums-runtime": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/flow-enums-runtime/-/flow-enums-runtime-0.0.6.tgz", + "integrity": "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==", + "license": "MIT" + }, + "node_modules/fontfaceobserver": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/fontfaceobserver/-/fontfaceobserver-2.3.0.tgz", + "integrity": "sha512-6FPvD/IVyT4ZlNe7Wcn5Fb/4ChigpucKYSvD6a+0iMoLn2inpo711eyIcKjmDtE5XNcgAkSH9uN/nfAeZzHEfg==", + "license": "BSD-2-Clause" + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/freeport-async": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/freeport-async/-/freeport-async-2.0.0.tgz", + "integrity": "sha512-K7od3Uw45AJg00XUmy15+Hae2hOcgKcmN3/EF6Y7i01O0gaqiRx8sUSpsb9+BRNL8RPBrhzPsVfy8q9ADlJuWQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz", + "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/getenv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/getenv/-/getenv-2.0.0.tgz", + "integrity": "sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hermes-estree": { + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.29.1.tgz", + "integrity": "sha512-jl+x31n4/w+wEqm0I2r4CMimukLbLQEYpisys5oCre611CI5fc9TxhqkBBCJ1edDG4Kza0f7CgNz8xVMLZQOmQ==", + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.29.1.tgz", + "integrity": "sha512-xBHWmUtRC5e/UL0tI7Ivt2riA/YBq9+SiYFU7C1oBa/j2jYGlIF9043oak1F47ihuDIxQ5nbsKueYJDRY02UgA==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.29.1" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-proxy-agent/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "devOptional": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/hyphenate-style-name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz", + "integrity": "sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==", + "license": "BSD-3-Clause" + }, + "node_modules/iceberg-js": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/iceberg-js/-/iceberg-js-0.8.1.tgz", + "integrity": "sha512-1dhVQZXhcHje7798IVM+xoo/1ZdVfzOMIc8/rgVSijRK38EDqOJoGula9N/8ZI5RD8QTxNQtK/Gozpr+qUqRRA==", + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/image-size": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.1.tgz", + "integrity": "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==", + "license": "MIT", + "dependencies": { + "queue": "6.0.2" + }, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=16.x" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC" + }, + "node_modules/inline-style-prefixer": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-7.0.1.tgz", + "integrity": "sha512-lhYo5qNTQp3EvSSp3sRvXMbVQTLrvGV6DycRMJ5dm2BLMiJ30wpXKdDdgX+GmJZ5uQMucwRKHamXSst3Sj/Giw==", + "license": "MIT", + "dependencies": { + "css-in-js-utils": "^3.1.0" + } + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz", + "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==", + "license": "MIT" + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bun-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz", + "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.7.1" + } + }, + "node_modules/is-bun-module/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-nan": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", + "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "devOptional": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "devOptional": true, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "devOptional": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "devOptional": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/iterator.prototype": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "devOptional": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-config/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "devOptional": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-diff": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.3.0.tgz", + "integrity": "sha512-n3q4PDQjS4LrKxfWB3Z5KNk1XjXtZTBwQp71OP0Jo03Z6V60x++K5L8k6ZrW8MY8pOFylZvHM0zsjS1RqlHJZQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jest/diff-sequences": "30.3.0", + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "pretty-format": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-diff/node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-diff/node_modules/@sinclair/typebox": { + "version": "0.34.49", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.49.tgz", + "integrity": "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/pretty-format": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.3.0.tgz", + "integrity": "sha512-oG4T3wCbfeuvljnyAzhBvpN45E8iOTXCU/TD3zXW80HA3dQ4ahdqMkWGiPWZvjpQwlbyHrPTWUAqUzGzv4l1JQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-diff/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-jsdom": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.7.0.tgz", + "integrity": "sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/jsdom": "^20.0.0", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0", + "jsdom": "^20.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-expo": { + "version": "55.0.17", + "resolved": "https://registry.npmjs.org/jest-expo/-/jest-expo-55.0.17.tgz", + "integrity": "sha512-LEJJyPBYtr7FzL5DUvnPsWF4ial6h23XQ37ikmqu/HFR4KidFkQ03ht2jsUWUSqmN/KdKeWSesEmbe5AUNZn3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@expo/config": "~55.0.16", + "@expo/json-file": "^10.0.14", + "@jest/create-cache-key-function": "^29.2.1", + "@jest/globals": "^29.2.1", + "babel-jest": "^29.2.1", + "jest-environment-jsdom": "^29.2.1", + "jest-snapshot": "^29.2.1", + "jest-watch-select-projects": "^2.0.0", + "jest-watch-typeahead": "2.2.1", + "json5": "^2.2.3", + "lodash": "^4.17.19", + "react-test-renderer": "19.2.0", + "server-only": "^0.0.1", + "stacktrace-js": "^2.0.2" + }, + "bin": { + "jest": "bin/jest.js" + }, + "peerDependencies": { + "expo": "*", + "react-native": "*", + "react-server-dom-webpack": "~19.0.4 || ~19.1.5 || ~19.2.4" + }, + "peerDependenciesMeta": { + "react-server-dom-webpack": { + "optional": true + } + } + }, + "node_modules/jest-expo/node_modules/@expo/config": { + "version": "55.0.17", + "resolved": "https://registry.npmjs.org/@expo/config/-/config-55.0.17.tgz", + "integrity": "sha512-Y3VaRg7Jllg3MhlUOTQqHm6/dttsqcjYlnS9enhAllZvPUpTHnRA4YPETtUZlxkdMJy6y3UZe986pd/KfJ6OTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@expo/config-plugins": "~55.0.9", + "@expo/config-types": "^55.0.5", + "@expo/json-file": "^10.0.14", + "@expo/require-utils": "^55.0.5", + "deepmerge": "^4.3.1", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "resolve-workspace-root": "^2.0.0", + "semver": "^7.6.0", + "slugify": "^1.3.4" + } + }, + "node_modules/jest-expo/node_modules/@expo/config-plugins": { + "version": "55.0.9", + "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-55.0.9.tgz", + "integrity": "sha512-jLfpxru8dTo7eU0cqeTWuQav7byyjb37eF/mbXl1/3eTBHBvFU1VGxpeKxanUdTQAAjqzH8KGgWb0fWcce+z1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@expo/config-types": "^55.0.5", + "@expo/json-file": "~10.0.14", + "@expo/plist": "^0.5.3", + "@expo/sdk-runtime-versions": "^1.0.0", + "chalk": "^4.1.2", + "debug": "^4.3.5", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "resolve-from": "^5.0.0", + "semver": "^7.5.4", + "slugify": "^1.6.6", + "xcode": "^3.0.1", + "xml2js": "0.6.0" + } + }, + "node_modules/jest-expo/node_modules/@expo/config-types": { + "version": "55.0.5", + "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-55.0.5.tgz", + "integrity": "sha512-sCmSUZG4mZ/ySXvfyyBdhjivz8Q539X1NondwDdYG7s3SBsk+wsgPJzYsqgAG/P9+l0xWjUD2F+kQ1cAJ6NNLg==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-expo/node_modules/@expo/plist": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.5.3.tgz", + "integrity": "sha512-jz5oPcPDd3fygwVxwSwmO6wodTwm0Qa14NUyPy0ka7H8sFmCtNZUI2+DzVe/EXjOhq1FbEjrwl89gdlWYOnVjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + } + }, + "node_modules/jest-expo/node_modules/react": { + "version": "19.2.5", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.5.tgz", + "integrity": "sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-expo/node_modules/react-test-renderer": { + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-19.2.0.tgz", + "integrity": "sha512-zLCFMHFE9vy/w3AxO0zNxy6aAupnCuLSVOJYDe/Tp+ayGI1f2PLQsFVPANSD42gdSbmYx5oN+1VWDhcXtq7hAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "react-is": "^19.2.0", + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.0" + } + }, + "node_modules/jest-expo/node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-expo/node_modules/semver": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.3.0.tgz", + "integrity": "sha512-HEtc9uFQgaUHkC7nLSlQL3Tph4Pjxt/yiPvkIrrDCt9jhoLIgxaubo1G+CFOnmHYMxHwwdaSN7mkIFs6ZK8OhA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "jest-diff": "30.3.0", + "pretty-format": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/@sinclair/typebox": { + "version": "0.34.49", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.49.tgz", + "integrity": "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/jest-matcher-utils/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/pretty-format": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.3.0.tgz", + "integrity": "sha512-oG4T3wCbfeuvljnyAzhBvpN45E8iOTXCU/TD3zXW80HA3dQ4ahdqMkWGiPWZvjpQwlbyHrPTWUAqUzGzv4l1JQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve/node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "devOptional": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-runner/node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "devOptional": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-runtime/node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "devOptional": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-watch-select-projects": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jest-watch-select-projects/-/jest-watch-select-projects-2.0.0.tgz", + "integrity": "sha512-j00nW4dXc2NiCW6znXgFLF9g8PJ0zP25cpQ1xRro/HU2GBfZQFZD0SoXnAlaoKkIY4MlfTMkKGbNXFpvCdjl1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.3.0", + "chalk": "^3.0.0", + "prompts": "^2.2.1" + } + }, + "node_modules/jest-watch-select-projects/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watch-typeahead": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/jest-watch-typeahead/-/jest-watch-typeahead-2.2.1.tgz", + "integrity": "sha512-jYpYmUnTzysmVnwq49TAxlmtOAwp8QIqvZyoofQFn8fiWhEDZj33ZXzg3JA4nGnzWFm1hbWf3ADpteUokvXgFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^6.0.0", + "chalk": "^4.0.0", + "jest-regex-util": "^29.0.0", + "jest-watcher": "^29.0.0", + "slash": "^5.0.0", + "string-length": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "jest": "^27.0.0 || ^28.0.0 || ^29.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/ansi-escapes": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", + "integrity": "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watch-typeahead/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/jest-watch-typeahead/node_modules/char-regex": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-2.0.2.tgz", + "integrity": "sha512-cbGOjAptfM2LVmWhwRFHEKTPkLwNddVmuqYZQt895yXwAsWsXObCG+YN4DGQ/JBtT4GP1a1lPPdio2z413LmTg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/jest-watch-typeahead/node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watch-typeahead/node_modules/string-length": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-5.0.1.tgz", + "integrity": "sha512-9Ep08KAMUn0OadnVaBuRdE2l615CQ508kr0XMadjClfYpdCyvrbFp6Taebo8yyxokQ4viUd/xPPUA4FGgUa0ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^2.0.0", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watch-typeahead/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jimp-compact": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/jimp-compact/-/jimp-compact-0.16.1.tgz", + "integrity": "sha512-dZ6Ra7u1G8c4Letq/B5EzAxj4tLFHL+cGtdpR+PVm4yzPDj+lCk+AbivWt1eOM+ikzkowtyV7qSqX6qr3t71Ww==", + "license": "MIT" + }, + "node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsc-safe-url": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/jsc-safe-url/-/jsc-safe-url-0.2.4.tgz", + "integrity": "sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==", + "license": "0BSD" + }, + "node_modules/jsdom": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz", + "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "abab": "^2.0.6", + "acorn": "^8.8.1", + "acorn-globals": "^7.0.0", + "cssom": "^0.5.0", + "cssstyle": "^2.3.0", + "data-urls": "^3.0.2", + "decimal.js": "^10.4.2", + "domexception": "^4.0.0", + "escodegen": "^2.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.2", + "parse5": "^7.1.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.2", + "w3c-xmlserializer": "^4.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0", + "ws": "^8.11.0", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/jsdom/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jsdom/node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/jsdom/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/jsdom/node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/jsdom/node_modules/ws": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", + "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.3.0.tgz", + "integrity": "sha512-qtYiSSFlwot9XHtF9bD9c7rwKjr+RecWT//ZnPvSmEjpV5mmPOCN4j8UjY5hbjNkOwZ/jQv3J6R1/pL7RwgMsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "isarray": "^2.0.5", + "jsonify": "^0.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", + "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", + "dev": true, + "license": "Public Domain", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/klaw-sync": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.11" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lan-network": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/lan-network/-/lan-network-0.2.1.tgz", + "integrity": "sha512-ONPnazC96VKDntab9j9JKwIWhZ4ZUceB4A9Epu4Ssg0hYFmtHZSeQ+n15nIwTFmcBUKtExOer8WTJ4GF9MO64A==", + "license": "MIT", + "bin": { + "lan-network": "dist/lan-network-cli.js" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lighthouse-logger": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.4.2.tgz", + "integrity": "sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==", + "license": "Apache-2.0", + "dependencies": { + "debug": "^2.6.9", + "marky": "^1.2.2" + } + }, + "node_modules/lighthouse-logger/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/lighthouse-logger/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "license": "MIT", + "dependencies": { + "chalk": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-symbols/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/log-symbols/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "devOptional": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/marky": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/marky/-/marky-1.3.0.tgz", + "integrity": "sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==", + "license": "Apache-2.0" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==", + "license": "MIT" + }, + "node_modules/merge-options": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz", + "integrity": "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==", + "license": "MIT", + "dependencies": { + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/metro": { + "version": "0.83.3", + "resolved": "https://registry.npmjs.org/metro/-/metro-0.83.3.tgz", + "integrity": "sha512-+rP+/GieOzkt97hSJ0MrPOuAH/jpaS21ZDvL9DJ35QYRDlQcwzcvUlGUf79AnQxq/2NPiS/AULhhM4TKutIt8Q==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/core": "^7.25.2", + "@babel/generator": "^7.25.0", + "@babel/parser": "^7.25.3", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.3", + "@babel/types": "^7.25.2", + "accepts": "^1.3.7", + "chalk": "^4.0.0", + "ci-info": "^2.0.0", + "connect": "^3.6.5", + "debug": "^4.4.0", + "error-stack-parser": "^2.0.6", + "flow-enums-runtime": "^0.0.6", + "graceful-fs": "^4.2.4", + "hermes-parser": "0.32.0", + "image-size": "^1.0.2", + "invariant": "^2.2.4", + "jest-worker": "^29.7.0", + "jsc-safe-url": "^0.2.2", + "lodash.throttle": "^4.1.1", + "metro-babel-transformer": "0.83.3", + "metro-cache": "0.83.3", + "metro-cache-key": "0.83.3", + "metro-config": "0.83.3", + "metro-core": "0.83.3", + "metro-file-map": "0.83.3", + "metro-resolver": "0.83.3", + "metro-runtime": "0.83.3", + "metro-source-map": "0.83.3", + "metro-symbolicate": "0.83.3", + "metro-transform-plugins": "0.83.3", + "metro-transform-worker": "0.83.3", + "mime-types": "^2.1.27", + "nullthrows": "^1.1.1", + "serialize-error": "^2.1.0", + "source-map": "^0.5.6", + "throat": "^5.0.0", + "ws": "^7.5.10", + "yargs": "^17.6.2" + }, + "bin": { + "metro": "src/cli.js" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/metro-babel-transformer": { + "version": "0.83.3", + "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.83.3.tgz", + "integrity": "sha512-1vxlvj2yY24ES1O5RsSIvg4a4WeL7PFXgKOHvXTXiW0deLvQr28ExXj6LjwCCDZ4YZLhq6HddLpZnX4dEdSq5g==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "flow-enums-runtime": "^0.0.6", + "hermes-parser": "0.32.0", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/metro-babel-transformer/node_modules/hermes-estree": { + "version": "0.32.0", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.32.0.tgz", + "integrity": "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ==", + "license": "MIT" + }, + "node_modules/metro-babel-transformer/node_modules/hermes-parser": { + "version": "0.32.0", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.32.0.tgz", + "integrity": "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.32.0" + } + }, + "node_modules/metro-cache": { + "version": "0.83.3", + "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.83.3.tgz", + "integrity": "sha512-3jo65X515mQJvKqK3vWRblxDEcgY55Sk3w4xa6LlfEXgQ9g1WgMh9m4qVZVwgcHoLy0a2HENTPCCX4Pk6s8c8Q==", + "license": "MIT", + "dependencies": { + "exponential-backoff": "^3.1.1", + "flow-enums-runtime": "^0.0.6", + "https-proxy-agent": "^7.0.5", + "metro-core": "0.83.3" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/metro-cache-key": { + "version": "0.83.3", + "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.83.3.tgz", + "integrity": "sha512-59ZO049jKzSmvBmG/B5bZ6/dztP0ilp0o988nc6dpaDsU05Cl1c/lRf+yx8m9WW/JVgbmfO5MziBU559XjI5Zw==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/metro-config": { + "version": "0.83.3", + "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.83.3.tgz", + "integrity": "sha512-mTel7ipT0yNjKILIan04bkJkuCzUUkm2SeEaTads8VfEecCh+ltXchdq6DovXJqzQAXuR2P9cxZB47Lg4klriA==", + "license": "MIT", + "dependencies": { + "connect": "^3.6.5", + "flow-enums-runtime": "^0.0.6", + "jest-validate": "^29.7.0", + "metro": "0.83.3", + "metro-cache": "0.83.3", + "metro-core": "0.83.3", + "metro-runtime": "0.83.3", + "yaml": "^2.6.1" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/metro-core": { + "version": "0.83.3", + "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.83.3.tgz", + "integrity": "sha512-M+X59lm7oBmJZamc96usuF1kusd5YimqG/q97g4Ac7slnJ3YiGglW5CsOlicTR5EWf8MQFxxjDoB6ytTqRe8Hw==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "lodash.throttle": "^4.1.1", + "metro-resolver": "0.83.3" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/metro-file-map": { + "version": "0.83.3", + "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.83.3.tgz", + "integrity": "sha512-jg5AcyE0Q9Xbbu/4NAwwZkmQn7doJCKGW0SLeSJmzNB9Z24jBe0AL2PHNMy4eu0JiKtNWHz9IiONGZWq7hjVTA==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "fb-watchman": "^2.0.0", + "flow-enums-runtime": "^0.0.6", + "graceful-fs": "^4.2.4", + "invariant": "^2.2.4", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "nullthrows": "^1.1.1", + "walker": "^1.0.7" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/metro-minify-terser": { + "version": "0.83.3", + "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.83.3.tgz", + "integrity": "sha512-O2BmfWj6FSfzBLrNCXt/rr2VYZdX5i6444QJU0fFoc7Ljg+Q+iqebwE3K0eTvkI6TRjELsXk1cjU+fXwAR4OjQ==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "terser": "^5.15.0" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/metro-resolver": { + "version": "0.83.3", + "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.83.3.tgz", + "integrity": "sha512-0js+zwI5flFxb1ktmR///bxHYg7OLpRpWZlBBruYG8OKYxeMP7SV0xQ/o/hUelrEMdK4LJzqVtHAhBm25LVfAQ==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/metro-runtime": { + "version": "0.83.3", + "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.83.3.tgz", + "integrity": "sha512-JHCJb9ebr9rfJ+LcssFYA2x1qPYuSD/bbePupIGhpMrsla7RCwC/VL3yJ9cSU+nUhU4c9Ixxy8tBta+JbDeZWw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.0", + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/metro-source-map": { + "version": "0.83.3", + "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.83.3.tgz", + "integrity": "sha512-xkC3qwUBh2psVZgVavo8+r2C9Igkk3DibiOXSAht1aYRRcztEZNFtAMtfSB7sdO2iFMx2Mlyu++cBxz/fhdzQg==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.3", + "@babel/traverse--for-generate-function-map": "npm:@babel/traverse@^7.25.3", + "@babel/types": "^7.25.2", + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "metro-symbolicate": "0.83.3", + "nullthrows": "^1.1.1", + "ob1": "0.83.3", + "source-map": "^0.5.6", + "vlq": "^1.0.0" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/metro-symbolicate": { + "version": "0.83.3", + "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.83.3.tgz", + "integrity": "sha512-F/YChgKd6KbFK3eUR5HdUsfBqVsanf5lNTwFd4Ca7uuxnHgBC3kR/Hba/RGkenR3pZaGNp5Bu9ZqqP52Wyhomw==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "metro-source-map": "0.83.3", + "nullthrows": "^1.1.1", + "source-map": "^0.5.6", + "vlq": "^1.0.0" + }, + "bin": { + "metro-symbolicate": "src/index.js" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/metro-transform-plugins": { + "version": "0.83.3", + "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.83.3.tgz", + "integrity": "sha512-eRGoKJU6jmqOakBMH5kUB7VitEWiNrDzBHpYbkBXW7C5fUGeOd2CyqrosEzbMK5VMiZYyOcNFEphvxk3OXey2A==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/generator": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.3", + "flow-enums-runtime": "^0.0.6", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/metro-transform-worker": { + "version": "0.83.3", + "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.83.3.tgz", + "integrity": "sha512-Ztekew9t/gOIMZX1tvJOgX7KlSLL5kWykl0Iwu2cL2vKMKVALRl1hysyhUw0vjpAvLFx+Kfq9VLjnHIkW32fPA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/generator": "^7.25.0", + "@babel/parser": "^7.25.3", + "@babel/types": "^7.25.2", + "flow-enums-runtime": "^0.0.6", + "metro": "0.83.3", + "metro-babel-transformer": "0.83.3", + "metro-cache": "0.83.3", + "metro-cache-key": "0.83.3", + "metro-minify-terser": "0.83.3", + "metro-source-map": "0.83.3", + "metro-transform-plugins": "0.83.3", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/metro/node_modules/hermes-estree": { + "version": "0.32.0", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.32.0.tgz", + "integrity": "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ==", + "license": "MIT" + }, + "node_modules/metro/node_modules/hermes-parser": { + "version": "0.32.0", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.32.0.tgz", + "integrity": "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.32.0" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/napi-postinstall": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", + "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", + "dev": true, + "license": "MIT", + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, + "node_modules/nativewind": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/nativewind/-/nativewind-4.2.3.tgz", + "integrity": "sha512-HglF1v6A8CqBFpXWs0d3yf4qQGurrreLuyE8FTRI/VDH8b0npZa2SDG5tviTkLiBg0s5j09mQALZOjxuocgMLA==", + "license": "MIT", + "dependencies": { + "comment-json": "^4.2.5", + "debug": "^4.3.7", + "react-native-css-interop": "0.2.3" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "tailwindcss": ">3.3.0" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/nested-error-stacks": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.0.1.tgz", + "integrity": "sha512-SrQrok4CATudVzBS7coSz26QRSmlK9TzzoFbeKfcPBUFPjcQM9Rqvr/DlJkOrwI/0KcgvMub1n1g5Jt9EgRn4A==", + "license": "MIT" + }, + "node_modules/node-exports-info": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.0.tgz", + "integrity": "sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array.prototype.flatmap": "^1.3.3", + "es-errors": "^1.3.0", + "object.entries": "^1.1.9", + "semver": "^6.3.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-forge": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.4.0.tgz", + "integrity": "sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==", + "license": "(BSD-3-Clause OR GPL-2.0)", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.37", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.37.tgz", + "integrity": "sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==", + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-package-arg": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.3.tgz", + "integrity": "sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw==", + "license": "ISC", + "dependencies": { + "hosted-git-info": "^7.0.0", + "proc-log": "^4.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm-package-arg/node_modules/semver": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nullthrows": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", + "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==", + "license": "MIT" + }, + "node_modules/nwsapi": { + "version": "2.2.23", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.23.tgz", + "integrity": "sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/ob1": { + "version": "0.83.3", + "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.83.3.tgz", + "integrity": "sha512-egUxXCDwoWG06NGCS5s5AdcpnumHKJlfd3HH06P3m9TEMwwScfcY35wpQxbm9oHof+dM/lVH9Rfyu1elTVelSA==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", + "license": "MIT", + "dependencies": { + "mimic-fn": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-3.4.0.tgz", + "integrity": "sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==", + "license": "MIT", + "dependencies": { + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-spinners": "^2.0.0", + "log-symbols": "^2.2.0", + "strip-ansi": "^5.2.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ora/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ora/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ora/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/ora/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/ora/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/ora/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ora/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ora/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-png": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/parse-png/-/parse-png-2.1.0.tgz", + "integrity": "sha512-Nt/a5SfCLiTnQAjx3fHlqp8hRgTL3z7kTQZzvIMS9uCAepnCyjpdEc6M/sz69WqMBdaDBw9sF1F1UaHROYzGkQ==", + "license": "MIT", + "dependencies": { + "pngjs": "^3.3.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/patch-package": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-8.0.1.tgz", + "integrity": "sha512-VsKRIA8f5uqHQ7NGhwIna6Bx6D9s/1iXlA1hthBVBEbkq+t4kXD0HHt+rJhf/Z+Ci0F/HCB2hvn0qLdLG+Qxlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@yarnpkg/lockfile": "^1.1.0", + "chalk": "^4.1.2", + "ci-info": "^3.7.0", + "cross-spawn": "^7.0.3", + "find-yarn-workspace-root": "^2.0.0", + "fs-extra": "^10.0.0", + "json-stable-stringify": "^1.0.2", + "klaw-sync": "^6.0.0", + "minimist": "^1.2.6", + "open": "^7.4.2", + "semver": "^7.5.3", + "slash": "^2.0.0", + "tmp": "^0.2.4", + "yaml": "^2.2.2" + }, + "bin": { + "patch-package": "index.js" + }, + "engines": { + "node": ">=14", + "npm": ">5" + } + }, + "node_modules/patch-package/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/patch-package/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/patch-package/node_modules/slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", + "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/plist": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz", + "integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==", + "license": "MIT", + "dependencies": { + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + }, + "engines": { + "node": ">=10.4.0" + } + }, + "node_modules/pngjs": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", + "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-import/node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/postcss-js": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.1.1" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pretty-format/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, + "node_modules/proc-log": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", + "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/promise": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", + "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", + "license": "MIT", + "dependencies": { + "asap": "~2.0.6" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/psl": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/lupomontero" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "devOptional": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/qrcode-terminal": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.11.0.tgz", + "integrity": "sha512-Uu7ii+FQy4Qf82G4xu7ShHhjhGahEpCWc3x8UavY3CTcWV+ufmmCtwkr7ZKsX42jdL0kr1B5FKUeqJvAn51jzQ==", + "bin": { + "qrcode-terminal": "bin/qrcode-terminal.js" + } + }, + "node_modules/query-string": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz", + "integrity": "sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==", + "license": "MIT", + "dependencies": { + "decode-uri-component": "^0.2.2", + "filter-obj": "^1.1.0", + "split-on-first": "^1.0.0", + "strict-uri-encode": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/queue": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", + "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", + "license": "MIT", + "dependencies": { + "inherits": "~2.0.3" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", + "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-devtools-core": { + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-6.1.5.tgz", + "integrity": "sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA==", + "license": "MIT", + "dependencies": { + "shell-quote": "^1.6.1", + "ws": "^7" + } + }, + "node_modules/react-dom": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", + "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.26.0" + }, + "peerDependencies": { + "react": "^19.1.0" + } + }, + "node_modules/react-fast-compare": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==", + "license": "MIT" + }, + "node_modules/react-freeze": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/react-freeze/-/react-freeze-1.0.4.tgz", + "integrity": "sha512-r4F0Sec0BLxWicc7HEyo2x3/2icUTrRmDjaaRyzzn+7aDyFZliszMDOgLVwSnQnYENOlL1o569Ze2HZefk8clA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=17.0.0" + } + }, + "node_modules/react-is": { + "version": "19.2.5", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.5.tgz", + "integrity": "sha512-Dn0t8IQhCmeIT3wu+Apm1/YVsJXsGWi6k4sPdnBIdqMVtHtv0IGi6dcpNpNkNac0zB2uUAqNX3MHzN8c+z2rwQ==", + "license": "MIT" + }, + "node_modules/react-native": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.81.5.tgz", + "integrity": "sha512-1w+/oSjEXZjMqsIvmkCRsOc8UBYv163bTWKTI8+1mxztvQPhCRYGTvZ/PL1w16xXHneIj/SLGfxWg2GWN2uexw==", + "license": "MIT", + "dependencies": { + "@jest/create-cache-key-function": "^29.7.0", + "@react-native/assets-registry": "0.81.5", + "@react-native/codegen": "0.81.5", + "@react-native/community-cli-plugin": "0.81.5", + "@react-native/gradle-plugin": "0.81.5", + "@react-native/js-polyfills": "0.81.5", + "@react-native/normalize-colors": "0.81.5", + "@react-native/virtualized-lists": "0.81.5", + "abort-controller": "^3.0.0", + "anser": "^1.4.9", + "ansi-regex": "^5.0.0", + "babel-jest": "^29.7.0", + "babel-plugin-syntax-hermes-parser": "0.29.1", + "base64-js": "^1.5.1", + "commander": "^12.0.0", + "flow-enums-runtime": "^0.0.6", + "glob": "^7.1.1", + "invariant": "^2.2.4", + "jest-environment-node": "^29.7.0", + "memoize-one": "^5.0.0", + "metro-runtime": "^0.83.1", + "metro-source-map": "^0.83.1", + "nullthrows": "^1.1.1", + "pretty-format": "^29.7.0", + "promise": "^8.3.0", + "react-devtools-core": "^6.1.5", + "react-refresh": "^0.14.0", + "regenerator-runtime": "^0.13.2", + "scheduler": "0.26.0", + "semver": "^7.1.3", + "stacktrace-parser": "^0.1.10", + "whatwg-fetch": "^3.0.0", + "ws": "^6.2.3", + "yargs": "^17.6.2" + }, + "bin": { + "react-native": "cli.js" + }, + "engines": { + "node": ">= 20.19.4" + }, + "peerDependencies": { + "@types/react": "^19.1.0", + "react": "^19.1.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-native-css-interop": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/react-native-css-interop/-/react-native-css-interop-0.2.3.tgz", + "integrity": "sha512-wc+JI7iUfdFBqnE18HhMTtD0q9vkhuMczToA87UdHGWwMyxdT5sCcNy+i4KInPCE855IY0Ic8kLQqecAIBWz7w==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.22.15", + "@babel/traverse": "^7.23.0", + "@babel/types": "^7.23.0", + "debug": "^4.3.7", + "lightningcss": "~1.27.0", + "semver": "^7.6.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": ">=18", + "react-native": "*", + "react-native-reanimated": ">=3.6.2", + "tailwindcss": "~3" + }, + "peerDependenciesMeta": { + "react-native-safe-area-context": { + "optional": true + }, + "react-native-svg": { + "optional": true + } + } + }, + "node_modules/react-native-css-interop/node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "license": "Apache-2.0", + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/react-native-css-interop/node_modules/lightningcss": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.27.0.tgz", + "integrity": "sha512-8f7aNmS1+etYSLHht0fQApPc2kNO8qGRutifN5rVIc6Xo6ABsEbqOr758UwI7ALVbTt4x1fllKt0PYgzD9S3yQ==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^1.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.27.0", + "lightningcss-darwin-x64": "1.27.0", + "lightningcss-freebsd-x64": "1.27.0", + "lightningcss-linux-arm-gnueabihf": "1.27.0", + "lightningcss-linux-arm64-gnu": "1.27.0", + "lightningcss-linux-arm64-musl": "1.27.0", + "lightningcss-linux-x64-gnu": "1.27.0", + "lightningcss-linux-x64-musl": "1.27.0", + "lightningcss-win32-arm64-msvc": "1.27.0", + "lightningcss-win32-x64-msvc": "1.27.0" + } + }, + "node_modules/react-native-css-interop/node_modules/lightningcss-darwin-arm64": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.27.0.tgz", + "integrity": "sha512-Gl/lqIXY+d+ySmMbgDf0pgaWSqrWYxVHoc88q+Vhf2YNzZ8DwoRzGt5NZDVqqIW5ScpSnmmjcgXP87Dn2ylSSQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/react-native-css-interop/node_modules/lightningcss-darwin-x64": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.27.0.tgz", + "integrity": "sha512-0+mZa54IlcNAoQS9E0+niovhyjjQWEMrwW0p2sSdLRhLDc8LMQ/b67z7+B5q4VmjYCMSfnFi3djAAQFIDuj/Tg==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/react-native-css-interop/node_modules/lightningcss-freebsd-x64": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.27.0.tgz", + "integrity": "sha512-n1sEf85fePoU2aDN2PzYjoI8gbBqnmLGEhKq7q0DKLj0UTVmOTwDC7PtLcy/zFxzASTSBlVQYJUhwIStQMIpRA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/react-native-css-interop/node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.27.0.tgz", + "integrity": "sha512-MUMRmtdRkOkd5z3h986HOuNBD1c2lq2BSQA1Jg88d9I7bmPGx08bwGcnB75dvr17CwxjxD6XPi3Qh8ArmKFqCA==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/react-native-css-interop/node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.27.0.tgz", + "integrity": "sha512-cPsxo1QEWq2sfKkSq2Bq5feQDHdUEwgtA9KaB27J5AX22+l4l0ptgjMZZtYtUnteBofjee+0oW1wQ1guv04a7A==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/react-native-css-interop/node_modules/lightningcss-linux-arm64-musl": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.27.0.tgz", + "integrity": "sha512-rCGBm2ax7kQ9pBSeITfCW9XSVF69VX+fm5DIpvDZQl4NnQoMQyRwhZQm9pd59m8leZ1IesRqWk2v/DntMo26lg==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/react-native-css-interop/node_modules/lightningcss-linux-x64-gnu": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.27.0.tgz", + "integrity": "sha512-Dk/jovSI7qqhJDiUibvaikNKI2x6kWPN79AQiD/E/KeQWMjdGe9kw51RAgoWFDi0coP4jinaH14Nrt/J8z3U4A==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/react-native-css-interop/node_modules/lightningcss-linux-x64-musl": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.27.0.tgz", + "integrity": "sha512-QKjTxXm8A9s6v9Tg3Fk0gscCQA1t/HMoF7Woy1u68wCk5kS4fR+q3vXa1p3++REW784cRAtkYKrPy6JKibrEZA==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/react-native-css-interop/node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.27.0.tgz", + "integrity": "sha512-/wXegPS1hnhkeG4OXQKEMQeJd48RDC3qdh+OA8pCuOPCyvnm/yEayrJdJVqzBsqpy1aJklRCVxscpFur80o6iQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/react-native-css-interop/node_modules/lightningcss-win32-x64-msvc": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.27.0.tgz", + "integrity": "sha512-/OJLj94Zm/waZShL8nB5jsNj3CfNATLCTyFxZyouilfTmSoLDX7VlVAmhPHoZWVFp4vdmoiEbPEYC8HID3m6yw==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/react-native-css-interop/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/react-native-gesture-handler": { + "version": "2.28.0", + "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.28.0.tgz", + "integrity": "sha512-0msfJ1vRxXKVgTgvL+1ZOoYw3/0z1R+Ked0+udoJhyplC2jbVKIJ8Z1bzWdpQRCV3QcQ87Op0zJVE5DhKK2A0A==", + "license": "MIT", + "dependencies": { + "@egjs/hammerjs": "^2.0.17", + "hoist-non-react-statics": "^3.3.0", + "invariant": "^2.2.4" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/react-native-is-edge-to-edge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/react-native-is-edge-to-edge/-/react-native-is-edge-to-edge-1.3.1.tgz", + "integrity": "sha512-NIXU/iT5+ORyCc7p0z2nnlkouYKX425vuU1OEm6bMMtWWR9yvb+Xg5AZmImTKoF9abxCPqrKC3rOZsKzUYgYZA==", + "license": "MIT", + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/react-native-reanimated": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-4.1.7.tgz", + "integrity": "sha512-Q4H6xA3Tn7QL0/E/KjI86I1KK4tcf+ErRE04LH34Etka2oVQhW6oXQ+Q8ZcDCVxiWp5vgbBH6XcH8BOo4w/Rhg==", + "license": "MIT", + "dependencies": { + "react-native-is-edge-to-edge": "^1.2.1", + "semver": "^7.7.2" + }, + "peerDependencies": { + "react": "*", + "react-native": "0.78 - 0.82", + "react-native-worklets": "0.5 - 0.8" + } + }, + "node_modules/react-native-reanimated/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/react-native-safe-area-context": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.6.2.tgz", + "integrity": "sha512-4XGqMNj5qjUTYywJqpdWZ9IG8jgkS3h06sfVjfw5yZQZfWnRFXczi0GnYyFyCc2EBps/qFmoCH8fez//WumdVg==", + "license": "MIT", + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/react-native-screens": { + "version": "4.16.0", + "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.16.0.tgz", + "integrity": "sha512-yIAyh7F/9uWkOzCi1/2FqvNvK6Wb9Y1+Kzn16SuGfN9YFJDTbwlzGRvePCNTOX0recpLQF3kc2FmvMUhyTCH1Q==", + "license": "MIT", + "dependencies": { + "react-freeze": "^1.0.0", + "react-native-is-edge-to-edge": "^1.2.1", + "warn-once": "^0.1.0" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/react-native-url-polyfill": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/react-native-url-polyfill/-/react-native-url-polyfill-3.0.0.tgz", + "integrity": "sha512-aA5CiuUCUb/lbrliVCJ6lZ17/RpNJzvTO/C7gC/YmDQhTUoRD5q5HlJfwLWcxz4VgAhHwXKzhxH+wUN24tAdqg==", + "license": "MIT", + "dependencies": { + "whatwg-url-without-unicode": "8.0.0-3" + }, + "peerDependencies": { + "react-native": "*" + } + }, + "node_modules/react-native-web": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.21.2.tgz", + "integrity": "sha512-SO2t9/17zM4iEnFvlu2DA9jqNbzNhoUP+AItkoCOyFmDMOhUnBBznBDCYN92fGdfAkfQlWzPoez6+zLxFNsZEg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.6", + "@react-native/normalize-colors": "^0.74.1", + "fbjs": "^3.0.4", + "inline-style-prefixer": "^7.0.1", + "memoize-one": "^6.0.0", + "nullthrows": "^1.1.1", + "postcss-value-parser": "^4.2.0", + "styleq": "^0.1.3" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/react-native-web/node_modules/@react-native/normalize-colors": { + "version": "0.74.89", + "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.74.89.tgz", + "integrity": "sha512-qoMMXddVKVhZ8PA1AbUCk83trpd6N+1nF2A6k1i6LsQObyS92fELuk8kU/lQs6M7BsMHwqyLCpQJ1uFgNvIQXg==", + "license": "MIT" + }, + "node_modules/react-native-web/node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", + "license": "MIT" + }, + "node_modules/react-native-worklets": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/react-native-worklets/-/react-native-worklets-0.5.1.tgz", + "integrity": "sha512-lJG6Uk9YuojjEX/tQrCbcbmpdLCSFxDK1rJlkDhgqkVi1KZzG7cdcBFQRqyNOOzR9Y0CXNuldmtWTGOyM0k0+w==", + "license": "MIT", + "dependencies": { + "@babel/plugin-transform-arrow-functions": "^7.0.0-0", + "@babel/plugin-transform-class-properties": "^7.0.0-0", + "@babel/plugin-transform-classes": "^7.0.0-0", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.0.0-0", + "@babel/plugin-transform-optional-chaining": "^7.0.0-0", + "@babel/plugin-transform-shorthand-properties": "^7.0.0-0", + "@babel/plugin-transform-template-literals": "^7.0.0-0", + "@babel/plugin-transform-unicode-regex": "^7.0.0-0", + "@babel/preset-typescript": "^7.16.7", + "convert-source-map": "^2.0.0", + "semver": "7.7.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0", + "react": "*", + "react-native": "*" + } + }, + "node_modules/react-native-worklets/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/react-native/node_modules/@react-native/virtualized-lists": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.81.5.tgz", + "integrity": "sha512-UVXgV/db25OPIvwZySeToXD/9sKKhOdkcWmmf4Jh8iBZuyfML+/5CasaZ1E7Lqg6g3uqVQq75NqIwkYmORJMPw==", + "license": "MIT", + "dependencies": { + "invariant": "^2.2.4", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 20.19.4" + }, + "peerDependencies": { + "@types/react": "^19.1.0", + "react": "*", + "react-native": "*" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-native/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/react-native/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/react-native/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/react-native/node_modules/ws": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz", + "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==", + "license": "MIT", + "dependencies": { + "async-limiter": "~1.0.0" + } + }, + "node_modules/react-refresh": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-remove-scroll": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", + "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-test-renderer": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-19.1.0.tgz", + "integrity": "sha512-jXkSl3CpvPYEF+p/eGDLB4sPoDX8pKkYvRl9+rR8HxLY0X04vW7hCm1/0zHoUSjPZ3bDa+wXWNTDVIw/R8aDVw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "react-is": "^19.1.0", + "scheduler": "^0.26.0" + }, + "peerDependencies": { + "react": "^19.1.0" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", + "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "license": "MIT" + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", + "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.2", + "regjsgen": "^0.8.0", + "regjsparser": "^0.13.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.2.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "license": "MIT" + }, + "node_modules/regjsparser": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.1.tgz", + "integrity": "sha512-dLsljMd9sqwRkby8zhO1gSg3PnJIBFid8f4CQj/sXx+7cKx+E7u0PKhZ+U4wmhx7EfmtvnA318oVaIkAB1lRJw==", + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.1.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requireg": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/requireg/-/requireg-0.2.2.tgz", + "integrity": "sha512-nYzyjnFcPNGR3lx9lwPPPnuQxv6JWEZd2Ci0u9opN7N5zUEPIhY/GbL3vMGOr2UXwEg9WwSyV9X9Y/kLFgPsOg==", + "dependencies": { + "nested-error-stacks": "~2.0.1", + "rc": "~1.2.7", + "resolve": "~1.7.1" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/requireg/node_modules/resolve": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz", + "integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==", + "license": "MIT", + "dependencies": { + "path-parse": "^1.0.5" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/resolve": { + "version": "2.0.0-next.6", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.6.tgz", + "integrity": "sha512-3JmVl5hMGtJ3kMmB3zi3DL25KfkCEyy3Tw7Gmw7z5w8M9WlwoPFnIvwChzu1+cF3iaK3sp18hhPz8ANeimdJfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "node-exports-info": "^1.6.0", + "object-keys": "^1.1.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/resolve-workspace-root": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/resolve-workspace-root/-/resolve-workspace-root-2.0.1.tgz", + "integrity": "sha512-nR23LHAvaI6aHtMg6RWoaHpdR4D881Nydkzi2CixINyg9T00KgaJdJI6Vwty+Ps8WLxZHuxsS0BseWjxSA4C+w==", + "license": "MIT" + }, + "node_modules/resolve.exports": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", + "license": "MIT", + "dependencies": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/sax": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/scheduler": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/send/node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serialize-error": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", + "integrity": "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-static/node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/server-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/server-only/-/server-only-0.0.1.tgz", + "integrity": "sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==", + "license": "MIT" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "license": "MIT" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/sf-symbols-typescript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/sf-symbols-typescript/-/sf-symbols-typescript-2.2.0.tgz", + "integrity": "sha512-TPbeg0b7ylrswdGCji8FRGFAKuqbpQlLbL8SOle3j1iHSs5Ob5mhvMAxWN2UItOjgALAB5Zp3fmMfj8mbWvXKw==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/simple-plist": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/simple-plist/-/simple-plist-1.3.1.tgz", + "integrity": "sha512-iMSw5i0XseMnrhtIzRb7XpQEXepa9xhWxGUojHBL43SIpQuDQkh3Wpy67ZbDzZVr6EKxvwVChnVpdl8hEVLDiw==", + "license": "MIT", + "dependencies": { + "bplist-creator": "0.1.0", + "bplist-parser": "0.3.1", + "plist": "^3.0.5" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz", + "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "license": "MIT" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/slugify": { + "version": "1.6.9", + "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.9.tgz", + "integrity": "sha512-vZ7rfeehZui7wQs438JXBckYLkIIdfHOXsaVEUMyS5fHo1483l1bMdo0EDSWYclY0yZKFOipDy4KHuKs6ssvdg==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-on-first": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", + "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, + "node_modules/stable-hash": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", + "integrity": "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/stack-generator": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/stack-generator/-/stack-generator-2.0.10.tgz", + "integrity": "sha512-mwnua/hkqM6pF4k8SnmZ2zfETsRUpWXREfA/goT8SLCV4iOFa4bzOX2nDipWAZFPTjLvQB82f5yaodMVhK0yJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "stackframe": "^1.3.4" + } + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", + "license": "MIT" + }, + "node_modules/stacktrace-gps": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/stacktrace-gps/-/stacktrace-gps-3.1.2.tgz", + "integrity": "sha512-GcUgbO4Jsqqg6RxfyTHFiPxdPqF+3LFmQhm7MgCuYQOYuWyqxo5pwRPz5d/u6/WYJdEnWfK4r+jGbyD8TSggXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "source-map": "0.5.6", + "stackframe": "^1.3.4" + } + }, + "node_modules/stacktrace-gps/node_modules/source-map": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "integrity": "sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stacktrace-js": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stacktrace-js/-/stacktrace-js-2.0.2.tgz", + "integrity": "sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "error-stack-parser": "^2.0.6", + "stack-generator": "^2.0.5", + "stacktrace-gps": "^3.0.4" + } + }, + "node_modules/stacktrace-parser": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.11.tgz", + "integrity": "sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==", + "license": "MIT", + "dependencies": { + "type-fest": "^0.7.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/stream-buffers": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz", + "integrity": "sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==", + "license": "Unlicense", + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/strict-uri-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", + "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/structured-headers": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/structured-headers/-/structured-headers-0.4.1.tgz", + "integrity": "sha512-0MP/Cxx5SzeeZ10p/bZI0S6MpgD+yxAhi1BOQ34jgnMXsCq3j1t6tQnZu+KdlL7dvJTLT3g9xN8tl10TqgFMcg==", + "license": "MIT" + }, + "node_modules/styleq": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/styleq/-/styleq-0.1.3.tgz", + "integrity": "sha512-3ZUifmCDCQanjeej1f6kyl/BeP/Vae5EYkQ9iJfUm/QwZvlgnZzyflqAsAWYURdtea8Vkvswu2GrC57h3qffcA==", + "license": "MIT" + }, + "node_modules/sucrase": { + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/sucrase/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tailwindcss": { + "version": "3.4.19", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", + "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.7", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss/node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tar": { + "version": "7.5.15", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.15.tgz", + "integrity": "sha512-dzGK0boVlC4W5QFuQN1EFSl3bIDYsk7Tj40U6eIBnK2k/8ml7TZ5agbI5j5+qnoVcAA+rNtBml8SEiLxZpNqRQ==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser": { + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.1.tgz", + "integrity": "sha512-vzCjQO/rgUuK9sf8VJZvjqiqiHFaZLnOiimmUuOKODxWL8mm/xua7viT7aqX7dgPY60otQjUotzFMmCB4VdmqQ==", + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/throat": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", + "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tmp": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", + "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "license": "BSD-3-Clause" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "license": "Apache-2.0" + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", + "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ua-parser-js": { + "version": "1.0.41", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.41.tgz", + "integrity": "sha512-LbBDqdIC5s8iROCUjMbW1f5dJQTEFB1+KO9ogbvlb3nm9n4YHa5p4KTvFPWvh2Hs8gZMBuiB1/8+pdfe/tDPug==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "license": "MIT", + "bin": { + "ua-parser-js": "script/cli.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici": { + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.25.0.tgz", + "integrity": "sha512-ZgpWDC5gmNiuY9CnLVXEH8rl50xhRCuLNA97fAUnKi8RRuV4E6KG31pDTsLVUKnohJE0I3XDrTeEydAXRw47xg==", + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, + "node_modules/undici-types": { + "version": "7.19.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", + "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", + "license": "MIT" + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", + "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", + "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unrs-resolver": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", + "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "napi-postinstall": "^0.3.0" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-android-arm-eabi": "1.11.1", + "@unrs/resolver-binding-android-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-x64": "1.11.1", + "@unrs/resolver-binding-freebsd-x64": "1.11.1", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", + "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-musl": "1.11.1", + "@unrs/resolver-binding-wasm32-wasi": "1.11.1", + "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", + "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", + "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-latest-callback": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.2.6.tgz", + "integrity": "sha512-FvRG9i1HSo0wagmX63Vrm8SnlUU3LMM3WyZkQ76RnslpBrX694AdG4A0zQBx2B3ZifFA0yv/BaEHGBnEax5rZg==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz", + "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "devOptional": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz", + "integrity": "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==", + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vaul": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vaul/-/vaul-1.1.2.tgz", + "integrity": "sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-dialog": "^1.1.1" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" + } + }, + "node_modules/vaul/node_modules/@radix-ui/react-dialog": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz", + "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/vaul/node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", + "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/vaul/node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", + "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/vaul/node_modules/@radix-ui/react-portal": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/vaul/node_modules/@radix-ui/react-presence": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", + "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/vaul/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/vaul/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/vlq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz", + "integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==", + "license": "MIT" + }, + "node_modules/w3c-xmlserializer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", + "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/warn-once": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/warn-once/-/warn-once-0.1.1.tgz", + "integrity": "sha512-VkQZJbO8zVImzYFteBXvBOZEl1qL175WH8VmZcxF2fZAoudNhNDvHi+doCaAEdU2l2vtcIwa2zn0QK5+I1HQ3Q==", + "license": "MIT" + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-fetch": { + "version": "3.6.20", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==", + "license": "MIT" + }, + "node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/whatwg-url-without-unicode": { + "version": "8.0.0-3", + "resolved": "https://registry.npmjs.org/whatwg-url-without-unicode/-/whatwg-url-without-unicode-8.0.0-3.tgz", + "integrity": "sha512-HoKuzZrUlgpz35YO27XgD28uh/WJH4B0+3ttFqRo//lmq+9T/mIOJ6kqmINI9HpUpz1imRC/nR/lxKpJiv0uig==", + "license": "MIT", + "dependencies": { + "buffer": "^5.4.3", + "punycode": "^2.1.1", + "webidl-conversions": "^5.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/whatwg-url-without-unicode/node_modules/webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.20", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", + "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wonka": { + "version": "6.3.6", + "resolved": "https://registry.npmjs.org/wonka/-/wonka-6.3.6.tgz", + "integrity": "sha512-MXH+6mDHAZ2GuMpgKS055FR6v0xVP3XwquxIMYXgiW+FejHQlMGlvVRZT4qMCxR+bEo/FCtIdKxwej9WV3YQag==", + "license": "MIT" + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xcode": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/xcode/-/xcode-3.0.1.tgz", + "integrity": "sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==", + "license": "Apache-2.0", + "dependencies": { + "simple-plist": "^1.1.0", + "uuid": "^7.0.3" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12" + } + }, + "node_modules/xml2js": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.0.tgz", + "integrity": "sha512-eLTh0kA8uHceqesPqSE+VvO1CDDJWMwlQfB6LuN6T8w6MaDJ8Txm8P7s5cHD0miF0V+GGTZrDQfxPZQVsur33w==", + "license": "MIT", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xml2js/node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "license": "MIT", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", + "license": "MIT", + "engines": { + "node": ">=8.0" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", + "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/AppDev/ikt205_2026_18_study_sprint/source/package.json b/AppDev/ikt205_2026_18_study_sprint/source/package.json new file mode 100644 index 0000000..f3dabf0 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/package.json @@ -0,0 +1,71 @@ +{ + "name": "study-sprint", + "main": "expo-router/entry", + "version": "1.0.0", + "scripts": { + "start": "expo start", + "reset-project": "node ./scripts/reset-project.js", + "postinstall": "patch-package", + "android": "expo run:android", + "ios": "expo run:ios", + "web": "expo start --web", + "lint": "expo lint", + "test": "jest" + }, + "dependencies": { + "@expo/vector-icons": "^15.0.3", + "@react-native-async-storage/async-storage": "2.2.0", + "@react-navigation/bottom-tabs": "^7.4.0", + "@react-navigation/elements": "^2.6.3", + "@react-navigation/native": "^7.1.8", + "@supabase/supabase-js": "^2.103.1", + "expo": "~54.0.33", + "expo-constants": "~18.0.13", + "expo-dev-client": "~6.0.20", + "expo-font": "~14.0.11", + "expo-haptics": "~15.0.8", + "expo-image": "~3.0.11", + "expo-linking": "~8.0.11", + "expo-notifications": "~0.32.16", + "expo-router": "~6.0.23", + "expo-secure-store": "~15.0.8", + "expo-splash-screen": "~31.0.13", + "expo-status-bar": "~3.0.9", + "expo-symbols": "~1.0.8", + "expo-system-ui": "~6.0.9", + "expo-web-browser": "~15.0.10", + "nativewind": "^4.2.3", + "patch-package": "^8.0.1", + "react": "19.1.0", + "react-dom": "19.1.0", + "react-native": "0.81.5", + "react-native-gesture-handler": "~2.28.0", + "react-native-reanimated": "~4.1.1", + "react-native-safe-area-context": "~5.6.0", + "react-native-screens": "~4.16.0", + "react-native-url-polyfill": "^3.0.0", + "react-native-web": "~0.21.0", + "react-native-worklets": "0.5.1", + "tailwindcss": "^3.4.19" + }, + "devDependencies": { + "@testing-library/react-native": "^13.3.3", + "@types/jest": "^30.0.0", + "@types/react": "~19.1.0", + "eslint": "^9.25.0", + "eslint-config-expo": "~10.0.0", + "jest": "^29.7.0", + "jest-expo": "^55.0.16", + "patch-package": "^8.0.1", + "react-test-renderer": "19.1.0", + "tailwindcss": "^3.4.19", + "typescript": "~5.9.2" + }, + "private": true, + "jest": { + "preset": "jest-expo", + "setupFiles": [ + "/jest.setup.js" + ] + } +} diff --git a/AppDev/ikt205_2026_18_study_sprint/source/patches/metro-config+0.83.3.patch b/AppDev/ikt205_2026_18_study_sprint/source/patches/metro-config+0.83.3.patch new file mode 100644 index 0000000..3785f56 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/patches/metro-config+0.83.3.patch @@ -0,0 +1,28 @@ +diff --git a/node_modules/metro-config/src/loadConfig.js b/node_modules/metro-config/src/loadConfig.js +index 7ac9d88..4a424c3 100644 +--- a/node_modules/metro-config/src/loadConfig.js ++++ b/node_modules/metro-config/src/loadConfig.js +@@ -76,6 +76,9 @@ const resolve = (filePath) => { + const possiblePath = path.resolve(process.cwd(), filePath); + return isFile(possiblePath) ? possiblePath : filePath; + }; ++ ++const { pathToFileURL } = require("url"); ++ + async function resolveConfig(filePath, cwd) { + const configPath = + filePath != null +@@ -289,7 +292,12 @@ async function loadConfigFile(absolutePath) { + } + } catch (e) { + try { +- const configModule = await import(absolutePath); ++ const importPath = ++ process.platform === "win32" ++ ? pathToFileURL(absolutePath).href ++ : absolutePath; ++ ++ const configModule = await import(importPath); + config = await configModule.default; + } catch (error) { + let prefix = `Error loading Metro config at: ${absolutePath}\n`; diff --git a/AppDev/ikt205_2026_18_study_sprint/source/scripts/reset-project.js b/AppDev/ikt205_2026_18_study_sprint/source/scripts/reset-project.js new file mode 100644 index 0000000..51dff15 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/scripts/reset-project.js @@ -0,0 +1,112 @@ +#!/usr/bin/env node + +/** + * This script is used to reset the project to a blank state. + * It deletes or moves the /app, /components, /hooks, /scripts, and /constants directories to /app-example based on user input and creates a new /app directory with an index.tsx and _layout.tsx file. + * You can remove the `reset-project` script from package.json and safely delete this file after running it. + */ + +const fs = require("fs"); +const path = require("path"); +const readline = require("readline"); + +const root = process.cwd(); +const oldDirs = ["app", "components", "hooks", "constants", "scripts"]; +const exampleDir = "app-example"; +const newAppDir = "app"; +const exampleDirPath = path.join(root, exampleDir); + +const indexContent = `import { Text, View } from "react-native"; + +export default function Index() { + return ( + + Edit app/index.tsx to edit this screen. + + ); +} +`; + +const layoutContent = `import { Stack } from "expo-router"; + +export default function RootLayout() { + return ; +} +`; + +const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, +}); + +const moveDirectories = async (userInput) => { + try { + if (userInput === "y") { + // Create the app-example directory + await fs.promises.mkdir(exampleDirPath, { recursive: true }); + console.log(`📁 /${exampleDir} directory created.`); + } + + // Move old directories to new app-example directory or delete them + for (const dir of oldDirs) { + const oldDirPath = path.join(root, dir); + if (fs.existsSync(oldDirPath)) { + if (userInput === "y") { + const newDirPath = path.join(root, exampleDir, dir); + await fs.promises.rename(oldDirPath, newDirPath); + console.log(`➡️ /${dir} moved to /${exampleDir}/${dir}.`); + } else { + await fs.promises.rm(oldDirPath, { recursive: true, force: true }); + console.log(`❌ /${dir} deleted.`); + } + } else { + console.log(`➡️ /${dir} does not exist, skipping.`); + } + } + + // Create new /app directory + const newAppDirPath = path.join(root, newAppDir); + await fs.promises.mkdir(newAppDirPath, { recursive: true }); + console.log("\n📁 New /app directory created."); + + // Create index.tsx + const indexPath = path.join(newAppDirPath, "index.tsx"); + await fs.promises.writeFile(indexPath, indexContent); + console.log("📄 app/index.tsx created."); + + // Create _layout.tsx + const layoutPath = path.join(newAppDirPath, "_layout.tsx"); + await fs.promises.writeFile(layoutPath, layoutContent); + console.log("📄 app/_layout.tsx created."); + + console.log("\n✅ Project reset complete. Next steps:"); + console.log( + `1. Run \`npx expo start\` to start a development server.\n2. Edit app/index.tsx to edit the main screen.${ + userInput === "y" + ? `\n3. Delete the /${exampleDir} directory when you're done referencing it.` + : "" + }` + ); + } catch (error) { + console.error(`❌ Error during script execution: ${error.message}`); + } +}; + +rl.question( + "Do you want to move existing files to /app-example instead of deleting them? (Y/n): ", + (answer) => { + const userInput = answer.trim().toLowerCase() || "y"; + if (userInput === "y" || userInput === "n") { + moveDirectories(userInput).finally(() => rl.close()); + } else { + console.log("❌ Invalid input. Please enter 'Y' or 'N'."); + rl.close(); + } + } +); diff --git a/AppDev/ikt205_2026_18_study_sprint/source/source.zip b/AppDev/ikt205_2026_18_study_sprint/source/source.zip new file mode 100644 index 0000000..e69de29 diff --git a/AppDev/ikt205_2026_18_study_sprint/source/tailwind.config.js b/AppDev/ikt205_2026_18_study_sprint/source/tailwind.config.js new file mode 100644 index 0000000..11597db --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/tailwind.config.js @@ -0,0 +1,73 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + './app/**/*.{js,jsx,ts,tsx}', + './components/**/*.{js,jsx,ts,tsx}', + './constants/**/*.{js,jsx,ts,tsx}', + ], + presets: [require('nativewind/preset')], + theme: { + extend: { + colors: { + app: { + bg: '#F7F5EF', + surface: '#FFFFFF', + subtle: '#EFEBE3', + border: '#DDD6C8', + }, + + text: { + main: '#1F2933', + secondary: '#52616B', + muted: '#9AA6B2', + inverse: '#FFFFFF', + }, + + accent: { + DEFAULT: '#3B82A0', + soft: '#DCEFF5', + hover: '#2F6F88', + disabled: '#9CC7D6', + }, + + status: { + success: '#15803D', + warning: '#B7791F', + danger: '#B91C1C', + }, + + subject: { + blue: { + bg: '#DCEFF5', + text: '#2F6F88', + }, + emerald: { + bg: '#DDEFE5', + text: '#2F7D55', + }, + amber: { + bg: '#F6E8C6', + text: '#9A6A16', + }, + violet: { + bg: '#E9E2F5', + text: '#6D4BA3', + }, + cyan: { + bg: '#DDF0EF', + text: '#287C7A', + }, + rose: { + bg: '#F4E1DF', + text: '#9B4A43', + }, + slate: { + bg: '#E8E4DA', + text: '#52616B', + }, + }, + }, + }, + }, + plugins: [], +}; \ No newline at end of file diff --git a/AppDev/ikt205_2026_18_study_sprint/source/tsconfig.json b/AppDev/ikt205_2026_18_study_sprint/source/tsconfig.json new file mode 100644 index 0000000..573ab12 --- /dev/null +++ b/AppDev/ikt205_2026_18_study_sprint/source/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "expo/tsconfig.base", + "compilerOptions": { + "strict": true, + "jsx": "react-native", + "paths": { + "@/*": ["./*"] + } + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ".expo/types/**/*.ts", + "expo-env.d.ts", + "nativewind-env.d.ts" + ] +} \ No newline at end of file diff --git a/AppDev/ikt205_2026_18_study_sprint/studysprint.apk b/AppDev/ikt205_2026_18_study_sprint/studysprint.apk new file mode 100644 index 0000000..a455c8a Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/studysprint.apk differ diff --git a/AppDev/ikt205_2026_18_study_sprint/video.mp4 b/AppDev/ikt205_2026_18_study_sprint/video.mp4 new file mode 100644 index 0000000..966951b Binary files /dev/null and b/AppDev/ikt205_2026_18_study_sprint/video.mp4 differ diff --git a/AppDev/prospectiveTexFiles/chris.tex b/AppDev/prospectiveTexFiles/chris.tex new file mode 100644 index 0000000..db3f43e --- /dev/null +++ b/AppDev/prospectiveTexFiles/chris.tex @@ -0,0 +1,48 @@ +\section{Individual Reports} +\subsection{Christopher Sanden} + +My individual contribution to \textit{Study Sprint} covered several central parts of the project, but the largest part of my work was connected to the timer, session flow, onboarding, and final delivery preparation. The commit history attributes 44 commits to me, including the first timer implementation, later task-flow integration, dashboard and session improvements, break-cycle logic, onboarding refinements, signup-confirmation deployment, test updates, and Android delivery preparation. The most relevant work is supported by the timer work notes from 21 April to 5 May and commits such as \texttt{d50301c}, \texttt{666bdc1}, \texttt{c74062c}, \texttt{b437643}, \texttt{907fa18}, \texttt{245b6db}, \texttt{2bb2ac6}, \texttt{9bb3bb1}, and \texttt{419463e}. + +\vspace{2mm} + +My first major contribution was creating the original timer feature. In commit \texttt{d50301c}, I added the first functional timer screen with duration selection, start behaviour, running timer state, and animated visual feedback. In the following iterations, I developed the timer into a more complete study-session interaction. This included countdown behaviour, measured layout handling, duration locking while a session was running, a deliberate hold-to-cancel flow, and cleanup of the internal timer structure. The timer eventually relied on several separate kinds of state, including selected duration, running state, countdown text, layout height, progress animation, and cancellation state. Separating these concerns was important because the timer later had to survive routing changes, cancellation, recovery, and integration with persistent session data. + +\vspace{2mm} + +A key part of this work was making the timer maintainable enough to become a core product feature rather than a fragile prototype. In commit \texttt{666bdc1}, I refactored the timer code by extracting repeated cleanup logic, grouping refs by responsibility, and making the render structure match the visible screen layers more closely. This was especially important because the timer used intervals, timeouts, animation refs, and cancellation flags. Keeping those responsibilities clear made the later integration work safer and easier to reason about. + +\vspace{2mm} + +The most important product-level change I made was moving the timer into the actual task workflow. In commit \texttt{c74062c}, I moved the timer from the tab navigator into the task stack and made it open from a selected task. The timer could then receive a task id, load the matching task from Supabase, display task information during the sprint, and preserve an active sprint locally through an end time. This changed the timer from a generic utility into a study-session feature tied directly to the user's planned work, which better matched the product vision. + +\vspace{2mm} + +I also extended the timer into a more durable session model. In commit \texttt{b437643}, I connected active local sprint state to database-backed sprint sessions and added task-level study-time tracking. This meant that completed, expired, or cancelled sessions could contribute elapsed time back to the relevant task instead of only changing temporary UI state. I also handled failure cases around session creation, finalisation, cancellation, and restore behaviour so the local timer state and stored session history would not drift apart. + +\vspace{2mm} + +My work also affected the dashboard and progress experience. I added support for reopening active sprints from the dashboard, showing remaining session time, displaying upcoming deadline tasks with subject and assignment context, and marking tasks as completed from dashboard cards. I also fixed a dashboard issue where upcoming tasks disappeared whenever an active sprint existed. These changes made the dashboard more useful as a daily study overview instead of only being a static landing page. + +\vspace{2mm} + +Later in the project, I worked on the focus-and-break cycle. I introduced shared session defaults in \texttt{lib/sessionDefaults.ts} so focus duration, short breaks, long breaks, and long-break frequency could be reused consistently across the timer, task details, and dashboard. I also implemented a local study-cycle model so the app could decide whether the next break should be short or long based on the current continuous study run rather than unrelated historical sessions. This made the session flow closer to a real study rhythm: focus, break, continue the same task, or return to the dashboard. + +\vspace{2mm} + +As the session flow became more connected to the rest of the app, I added a shared lifecycle helper in \texttt{lib/sessionLifecycle.ts}. This centralised how active sessions are finalised when they expire, are replaced, or are cleared from other screens. This was one of my more important reliability contributions because it reduced duplicated logic across the timer, dashboard, task details, and setup flow, and lowered the risk of the UI and database recording different versions of the same session. + +\vspace{2mm} + +I also contributed to the first-time-user and account-confirmation flow. In commit \texttt{907fa18}, I added a guided setup route that helps new users create their first subject, assignment, and task before starting a sprint. Later, in commit \texttt{9bb3bb1}, I added shared setup-completion logic in \texttt{lib/setupStatus.ts} so incomplete users are routed into setup more consistently. I also changed the first setup sprint into a short demo timer, making the first interaction easier to test and understand. + +\vspace{2mm} + +Outside the app itself, I improved the signup confirmation loop. I added a small static confirmation page under \texttt{deploy/signup-confirmation}, served through \texttt{nginx} with Docker Compose and hosted on my VPS behind the existing reverse-proxy setup. I also corrected the Caddy routing target so the page resolved correctly, and customised the Supabase confirmation email into a cleaner HTML email while keeping the required confirmation-link placeholder. This made account creation feel more complete and presentable from signup through email confirmation. + +\vspace{2mm} + +Toward the end of the project, I contributed to verification and delivery preparation. I used TypeScript checks, linting, manual runtime testing, and database inspection during timer and session work, because interaction-heavy behaviour could not be fully verified by static checks alone. I also updated the test setup and several test files in commit \texttt{419463e} so they matched the newer logic across auth, subject, assignment, and task flows. Finally, I adjusted the Android package name in \texttt{app.json} to match Google Play Console expectations and added the APK artifact for delivery. + +\vspace{2mm} + +Overall, my contribution was broad, but it was tied together by one main goal: making the app feel like a coherent study tool rather than a set of separate screens. I worked on the timer, task integration, session persistence, dashboard visibility, break-cycle behaviour, onboarding, signup confirmation, testing, and Android delivery. Strategically, this strengthened the parts of the project most closely connected to the product vision: helping users move from planning study work to actually starting and tracking focused study sessions. diff --git a/AppDev/prospectiveTexFiles/conclusion.tex b/AppDev/prospectiveTexFiles/conclusion.tex new file mode 100644 index 0000000..e8094bf --- /dev/null +++ b/AppDev/prospectiveTexFiles/conclusion.tex @@ -0,0 +1,19 @@ +\section{Conclusion} + +The goal of \textit{Study Sprint} was to create a focused mobile application that helps students organise academic work and move more easily into structured study sessions. The final product addresses this goal by combining subjects, assignments, tasks, timed focus sessions, breaks, progress tracking, reminders, and persistence into one connected workflow. + +\vspace{2mm} + +The project shows that the value of the application lies mainly in how these parts work together. A planner alone would not solve the problem of starting focused work, and a timer alone would not help the user decide what to study. By linking study sessions directly to tasks, the app makes the transition from planning to action more concrete. This supports the original product vision, where simplicity, low friction, reliability, and realistic scope were more important than building a broad productivity platform. + +\vspace{2mm} + +During development, the application also became more coherent through several important refinements. The screen structure was aligned more closely with the hierarchy of \textit{Subject $\rightarrow$ Assignment $\rightarrow$ Task}, the timer flow was implemented around the task workflow as originally intended, and session reliability was improved through more consistent lifecycle handling. The final design also supports several usability principles, including visible system status, familiar student-oriented concepts, consistent interaction patterns, and a low-friction default path into study sessions. + +\vspace{2mm} + +There are still limitations. The project remained intentionally narrow in scope, and some behaviour, especially around timer interaction, onboarding, notifications, and break handling, depended heavily on manual verification. The product is also still best understood as a proof-of-concept rather than a production service, especially because it depends on Supabase free-tier limits and does not yet include a larger automated testing strategy, advanced analytics, calendar integration, or richer cross-device behaviour. In addition, the lack of formal time sheets and a formal ticket-tracking system weakened the precision of the process documentation, even though the group could still document work through the report, source control, communication, meetings, and development history. + +\vspace{2mm} + +Overall, \textit{Study Sprint} can be considered a successful result within the constraints of the project. It delivers a working and coherent study-support application that reflects the original vision more clearly than the early prototype. The final result is not the largest possible productivity app, but it is a focused solution that connects planning, studying, breaks, and progress in a way that is useful for the intended student user. diff --git a/AppDev/prospectiveTexFiles/discussion.tex b/AppDev/prospectiveTexFiles/discussion.tex new file mode 100644 index 0000000..f3b72e7 --- /dev/null +++ b/AppDev/prospectiveTexFiles/discussion.tex @@ -0,0 +1,106 @@ +\section{Discussion} + +The development of Study Sprint shows both the strengths and limitations of building a small productivity application around one tightly scoped user problem. The project did not aim to compete with broad commercial productivity platforms on feature count. Instead, it aimed to reduce the gap between planning study work and actually starting it. In that sense, the most important question is not whether the app includes many features, but whether the implemented features support one coherent and dependable study flow. + +\vspace{2mm} + +Overall, the final result suggests that the project moved substantially closer to that goal over time. The strongest improvement was not the addition of one isolated feature, but the gradual alignment between planning structure, timer behaviour, session persistence, progress visibility, and onboarding. Earlier versions of the app already contained the core building blocks, but later revisions made those parts reflect the original product direction more clearly and work more convincingly as one product rather than as loosely connected components. + +\subsection{Strength of the Hierarchy-Driven Product Model} + +One of the clearest lessons from the project was that the application's underlying hierarchy mattered more than first assumed. The conceptual model of \textit{Subject $\rightarrow$ Assignment $\rightarrow$ Task} was not only a database relationship but also an important usability principle. When assignments and tasks were exposed too much as standalone top-level concepts, the app became flatter, more repetitive, and less clear. Important context was lost, and the user could more easily lose track of what a specific task belonged to. + +\vspace{2mm} + +Restructuring the app around that hierarchy improved both navigation and meaning. Subjects became the natural entry point into academic content, while assignments and tasks became progressively deeper parts of the same flow. This made the product feel more intentional and better aligned with its actual purpose. In discussion terms, this supports the broader argument that architectural clarity in a small application is not only a technical concern but also a user-experience concern. + +\subsection{Why Task-Linked Study Sessions Were Important} + +Another important outcome was that the final implementation came to reflect one of the project's original intentions more accurately: the timer was always meant to support concrete study tasks rather than function as a detached utility. This reflects one of the central ideas behind the project, namely that planning and focused work should support each other directly. A generic timer can measure time, but it does not necessarily help the user decide what to work on. By contrast, a task-linked sprint flow makes the act of starting a session more concrete and meaningful in the context of study work. + +\vspace{2mm} + +This also strengthens the product's unique value relative to broader productivity tools. Study Sprint does not attempt to replace general-purpose planners or offer advanced analytics. Its strength lies instead in the connection between defining study structure and beginning focused work quickly. From that perspective, the later timer-related revisions should not be understood as a change in product direction, but as a process of bringing the implementation into better alignment with the intended identity of the app. + +\subsection{Reliability as a Central Product Requirement} + +Reliability also became one of the most important concerns during development. This was especially visible in the timer and session lifecycle. Once the app began storing active sessions, supporting break cycles, and recovering state across screens, inconsistencies between local state and stored session data became a real product risk. A timer-based application quickly loses credibility if it cannot be trusted to reflect the user's actual study activity. + +\vspace{2mm} + +For that reason, the later work on shared session finalisation, active-session recovery, and break-cycle logic was highly significant. These changes may seem less visible than larger UI changes, but they directly support one of the most important, critical product attributes identified earlier in the report: reliability. In practical terms, this means that some of the most valuable work in the project was not the addition of new features, but the correction of weak interactions between existing features. + +\subsection{Tradeoffs in Persistence and Scope} + +The chosen persistence model also represents a clear tradeoff. Supabase was used for durable user data such as subjects, assignments, tasks, and recorded sessions, while local device storage was used for temporary or device-specific state, such as active-session recovery, study-cycle continuity, and notification identifiers. This was a pragmatic and appropriate design for the scope of the project. + +\vspace{2mm} + +The benefit of this split is that it keeps the app practical without introducing unnecessary backend complexity. At the same time, it also creates a boundary that must be handled carefully. When one part of the app depends on local control state and another part depends on backend records, consistency problems can arise if the transition between them is not carefully managed. The later reliability fixes suggest that this tradeoff was acceptable, but only when paired with more explicit lifecycle handling. + +\subsection{Usability, Onboarding, and Low-Friction Design} + +The project also highlights that usability problems in small applications often arise from friction rather than from missing functionality. In this case, several later revisions focused on making the main study flow easier to enter: guided setup was strengthened, default sprint durations were made easier to accept immediately, and help flows were adjusted so that the intended rhythm of focus and breaks became easier to understand. + +\vspace{2mm} + +These changes support the original product vision well. The main goal of the app was not to maximise customisation or feature depth, but to help users move quickly from intention to action. The discussion that follows from this is that a low-friction default path can be more valuable than a more flexible but slower interaction model, especially in a study-orientated application where hesitation and setup overhead directly work against the product's purpose. + +\vspace{2mm} + +The claim that the application has a low-friction and intuitive design can also be supported through Nielsen's usability heuristics. Nielsen's heuristics are broad principles for interaction design and are commonly used to evaluate whether an interface is likely to be understandable, predictable, and usable \cite{nielsenheuristics}. Study Sprint was never formally tested through a complete heuristic evaluation with several reviewers, but several of the final design decisions align closely with these principles. + +\vspace{2mm} + +First, the app supports \textit{visibility of system status} by showing the active timer state, study session progress, completion ratios, and recent activity. This helps users understand what is currently happening and what progress has been made. Second, the app follows \textit{match between system and the real world} by organising academic work through familiar student concepts such as subjects, assignments, and tasks. Third, \textit{user control and freedom} are both supported through options such as cancelling active sessions, editing created entities, and ease of navigation. + +\vspace{2mm} + +The design also follows \textit{consistency and standards} by reusing cards, pills, action buttons, spacing, and upsert-based forms across similar screens. \textit{Recognition rather than recall} is supported by keeping the parent context visible as users move through the hierarchy, for example, by showing subject and assignment context on deeper task screens. The default sprint flow also supports \textit{flexibility and efficiency of use} because users can start quickly with a sensible default duration while still having the option to choose alternative durations when needed. + +\vspace{2mm} + +The app follows \textit{aesthetic and minimalist design} by reducing top-level navigation, removing redundant assignment and task tabs, and limiting progress indicators to screens where they provide useful context. Help and documentation are supported through onboarding and lightweight help flows that explain the intended study rhythm without requiring the user to read a large manual. Together, these design choices support the argument that the interface was intentionally shaped to be understandable and low-friction, although a full user test would still be needed to validate this with real users. + +\subsection{Limitations of the Project} + +Despite the strengths of the final result, the project also has clear limitations. First, the scope remained relatively narrow. This was intentional and appropriate, but it still means that the product does not attempt to cover many surrounding needs that broader productivity platforms address, such as advanced analytics, collaboration, calendar integration, or richer cross-device notification infrastructure. This area would likely be the projects next development path, given a bigger development window. + +\vspace{2mm} + +Second, the development process remained strongly iterative until late in the project. That was useful for improving the product, but it also meant that some parts of the application changed several times before reaching a more stable form. In report terms, this suggests that the project succeeded more as a process of refinement than as a case of implementing a fully settled design from the start. + +\vspace{2mm} + +Third, the testing picture appears mixed. The report includes structured tests for important CRUD and guard behaviour, together with repeated use of linting, TypeScript checks, manual testing, and development-build verification. Even so, not all important qualities of the app were verified in the same way. Interaction-heavy behaviour such as timer flow, break handling, onboarding transitions, and notification timing depended heavily on manual validation. This is understandable for the project scope, but it still represents a limitation compared to a larger and more thoroughly automated testing strategy. + +\vspace{2mm} + +Fourth, the current state of the project is dependent on Supabase and their free-tier rate limits. One obvious concern is the rate of emails being limited to 2 per hour, meaning that within any given hourly timeframe, only two new accounts can be registered due to the requirement of a confirmed email address before a user can log in. This is also an area of expansion for the project; however, the group decided to forego the cost of a subscription, given that the app, in its current state, is used as a proof-of-concept rather than an actual avenue of business. + +\subsection{Documentation Lapses} + +A further limitation was that the group did not maintain formal time sheets throughout the project. The requirement for time sheets was discovered late, after a vast majority of the product development had been completed. As a result, the group cannot provide a detailed and reliable hour-by-hour record of the work process. + +\vspace{2mm} + +This weakens the documentation of workload distribution and makes it harder to evaluate the exact amount of time spent. However, the group has still documented the development process through the method section, collaboration description, implementation history, testing section, and final product outcome. The work was also supported by regular communication, meetings, source control activity, and shared report writing. Member contributions can be roughly estimated given the git commit history of each member, although this does not provide a realistic estimate of time spent. Group members also wrote daily work summary notes to document the work that had been carried out and the current state of the development branch at the time of writing. This makes it possible to determine workload distribution based on additions to the codebase. Hourly distribution, however, is difficult to estimate given only work notes and commit history. + +\vspace{2mm} + +The group also did not keep any formal ticket list using a Scrum based system. The reasoning was that the app had such limited scope that deploying a full-scale ticket tracking system was deemed to add more complexity to the project than it would alleviate. Given that the planned features for the app were meant to be few but of high quality, the group had no issues staying on top of what each member was working on at any given time, nor did it introduce difficulties in keeping track of future work. With the added benefit of writing work summary notes, the group can also reliably prove the work and contributions of each member. In short; the lack of a full-scale ticket tracking system did not hinder the project in any capacity. +\clearpage + +A further limitation was that the group did not maintain formal time sheets throughout the project. The requirement for time sheets was discovered late, after a vast majority of the product development had been completed. As a result, the group cannot provide a detailed and reliable hour-by-hour record of the work process. + +\vspace{2mm} + +This weakens the documentation of workload distribution and makes it harder to evaluate the exact amount of time spent. However, the group has still documented the development process through the method section, collaboration description, implementation history, testing section, and final product outcome. The work was also supported by regular communication, meetings, source control activity, and shared report writing. Member contributions can be roughly estimated given the git commit history of each member, although this does not provide a realistic estimate of time spent. Group members also wrote daily work summary notes to document the work that had been carried out and the current state of the development branch at the time of writing. This makes it possible to determine workload distribution based on additions to the codebase. Hourly distribution, however, is difficult to estimate given only work notes and commit history. + +\subsection{Overall Evaluation} + +Taken as a whole, Study Sprint appears successful primarily because the project stayed disciplined about its central problem. The strongest parts of the final application are those where structure, study sessions, breaks, reminders, and progress all reinforce the same user goal. The weaker parts are not signs that the project lacked ambition, but reminders that even a small mobile product becomes complex once reliability, persistence, and user flow are treated seriously. + +\vspace{2mm} + +The most important discussion outcome is therefore that the project demonstrates the value of coherence over breadth. Study Sprint became stronger when the team removed redundancy, tightened the hierarchy, linked sessions to real tasks, and refined the timer lifecycle until it better supported dependable use. That does not mean the application is complete in every sense, but it does mean that the final result reflects its stated product vision more clearly than the earlier prototype versions did. diff --git a/AppDev/prospectiveTexFiles/introduction.tex b/AppDev/prospectiveTexFiles/introduction.tex new file mode 100644 index 0000000..8769d4c --- /dev/null +++ b/AppDev/prospectiveTexFiles/introduction.tex @@ -0,0 +1,95 @@ +\section{Introduction} + +This report presents the development of \textit{Study Sprint}, a mobile productivity application designed to help students organise academic work and turn that structure into focused study sessions. The core idea behind the application is to reduce the gap between intending to study and actually starting. Instead of treating planning, timing and progress as separate concerns, Study Sprint connects subjects, assignments, tasks, timed focus sessions, breaks and visible progress into one lightweight workflow. + +\vspace{2mm} + +The motivation for the project came from a common frustration with existing study and productivity applications. Many such applications are either too broad, too feature-heavy or too abstract for students who simply want to organise what they need to study and begin working with as little friction as possible. In many cases, users are forced through unnecessary setup, presented with too many unrelated features, or given timer tools that are disconnected from the work they are supposed to support. Study Sprint was developed as a response to that problem. + +\vspace{2mm} + +The project therefore focused on a small but coherent feature set. The goal was not to create the most advanced productivity application, but to create one that is easy to understand, fast to use and reliable in practice. This meant prioritising a clear study hierarchy, low-friction navigation, task-linked study sessions, break handling and progress visibility over broader functionality that would have increased the complexity without adding equal value to the intended user. + +\vspace{2mm} + +The conceptual background for the app was also influenced by the Pomodoro technique, where focused work intervals are separated by short breaks. This was relevant because the project aimed to support concentration, reduce study friction, and make it easier for users to turn vague study intentions into concrete work sessions. Recent review literature also suggests that structured Pomodoro-style intervals can improve focus, reduce fatigue, and support sustained task performance in demanding learning contexts \cite{pomodoro_scoping_review}. + +\vspace{2mm} + +From a development perspective, the project followed an iterative approach. Early prototypes were used to explore structure, interaction and timer behaviour before the application was gradually refined through implementation, testing and revision. Several parts of the application, especially the timer flow and session handling, changed significantly over time as practical issues were discovered and resolved. This process helped move the product from a simple prototype toward a more complete and reliable study tool. +\clearpage + + +\subsection{Product Vision} + +The complete project vision is included in Appendix~\ref{appendix:projectvision}. The following section summarises the most important parts of that vision and shows how they shaped the direction of the product. + +\subsection{Target customer} + +The primary target group for Study Sprint is students in higher education who want a simple and structured way to organise study work, start focused work sessions and keep track of their progress \cite{projectvision}. + +\vspace{2mm} + +A secondary target group includes other learners, such as upper secondary students, as well as users who rely on timed work sessions for productivity in non-academic contexts. Even so, the application is mainly designed around student needs, since that is the clearest and most relevant use case for the project. + +\subsubsection{Customer needs} + +Study Sprint is intended to address a small set of practical needs that repeatedly appear in student work: + +\begin{itemize} + \item better focus during study sessions through timed work periods and breaks, + \item simple planning and organisation through subjects, assignments, and tasks, + \item motivation through visible progress and recorded study activity, + \item low friction, so users can understand the app quickly and begin studying without unnecessary setup. +\end{itemize} + +These needs are closely related. A study timer becomes more useful when it is connected to real tasks, and planning becomes more meaningful when it leads directly into focused work. + +\subsubsection{Critical Product Attributes} + +The most important product attribute for Study Sprint is simplicity. The application should be intuitive enough that a user can understand the main study flow almost immediately. A user should be +able to move from creating structure to starting a study session without confusion or unnecessary decision-making. + +\vspace{2mm} + +Reliability is also critical. Since the application depends heavily on timed study sessions and progress tracking, it must handle active sessions, completion, cancellation, breaks, and saved +progress in a dependable way. If the timer flow feels unstable or if recorded study activity becomes inconsistent, the application quickly loses its usefulness. + +\vspace{2mm} + +A third important attribute is a clear and focused user interface. The design does not need to be visually complex, but it should feel complete, deliberate, and easy to navigate. Since the app is +intended to reduce procrastination rather than add friction, fast and understandable interaction is especially important. + +\vspace{2mm} + +Finally, scope control is an important product attribute in itself. A smaller and more polished application is more valuable for this project than a broader solution with too many unfinished or +weakly integrated features. A successful version of Study Sprint therefore includes structured planning, task-linked study sessions, break handling, progress visibility, and persistence, while +avoiding feature expansion that would dilute the product's main purpose. + +\subsubsection{Unique Seeling Points} + +Study Sprint enters a crowded space of Pomodoro apps, study planners, habit trackers, and general productivity tools such as Forest, Focus To-Do, and Todoist. These applications often provide useful +functionality, but many of them are either too broad, too feature-heavy, or too focused on premium features and generalized productivity workflows \cite{projectvision}. + +\vspace{2mm} + +Compared to these alternatives, Study Sprint aims to be more focused and more student-oriented. Rather than trying to include every possible productivity feature, it combines only the features most relevant to the intended workflow: subject structure, assignments, tasks, timed focus sessions, breaks, and visible progress. + +\vspace{2mm} + +The main unique selling point of Study Sprint is therefore not feature quantity, but feature connection. The application links planning and studying more directly than a simple timer app, while +remaining much lighter and more focused than broader productivity platforms. This makes it easier for a student to decide what to study, begin working quickly, and see meaningful progress afterward. + +\subsubsection{Target Time-frame and Budget} + +The target time-frame for Study Sprint was the duration of the project period, ending in early May. Because this work was carried out alongside other courses, assignments, and exams, the project had +to be planned with a strong focus on the effort-to-value ratio rather than feature ambition. + +\clearpage + +For that reason, the team aimed to establish a working prototype early and then use the remaining time on refinement, reliability, usability, and report work. A realistic development path was to +first define the product structure and screen flow, then implement the core planning hierarchy, timer functionality, session persistence, break flow, and progress tracking, before focusing on testing and polish \cite{projectvision}. + +\vspace{2mm} + +The financial budget for the project was expected to be minimal. The application was developed using free or low-cost tools and frameworks, with time being the main practical constraint. This made it especially important to avoid unnecessary complexity and to concentrate on the parts of the application that contributed most directly to the intended study experience. diff --git a/AppDev/prospectiveTexFiles/method.tex b/AppDev/prospectiveTexFiles/method.tex new file mode 100644 index 0000000..e140983 --- /dev/null +++ b/AppDev/prospectiveTexFiles/method.tex @@ -0,0 +1,71 @@ +\section{Method} + +The development of \textit{Study Sprint} followed a practical and iterative project method. Rather than treating the application as a fixed specification that could be implemented in one pass, the team worked from a product vision, built early versions of the core functionality, and then refined the solution as weaknesses became clearer through use, testing, and discussion. + +\vspace{2mm} + +This approach fit the nature of the project well. The main challenge was not only to implement isolated features, but to shape a small mobile product that felt coherent, reliable, and easy to use in practice. Because of that, the method had to support both technical implementation and repeated revision of structure, flow, and scope. + +\subsection{Vision-Driven and Scope-Conscious Development} + +The project vision functioned as the main strategic starting point for the work. It defined the target users, the most important customer needs, and the product attributes that mattered most for success. In particular, simplicity, reliability, low friction, and realistic scope were treated as guiding constraints throughout the project \cite{projectvision}. + +\vspace{2mm} + +This had a direct effect on development priorities. Features that supported the core study flow were given precedence, while ideas that would broaden the product without strengthening its main purpose were deprioritized or excluded. That is also why the report separates requirements into must-have, should-have, could-have, and will-not-have categories. This prioritization made it easier to protect the project from feature growth and to keep effort focused on the parts of the application that contributed most directly to the intended user experience. + +\subsection{Iterative Prototyping and Refinement} + +The practical development process was iterative. Early work focused on establishing the underlying structure of the app, including navigation, CRUD support for subjects, assignments, and tasks, and the first timer-related flows. These early versions were useful for confirming that the main ideas were technically possible, but they also revealed architectural and usability problems that were not obvious at the planning stage. + +\vspace{2mm} + +One clear example was the relationship between the app's conceptual data model and its screen structure. The intended hierarchy was always \textit{Subject $\rightarrow$ Assignment $\rightarrow$ Task}, but earlier versions exposed assignments and tasks too much as top-level concepts. As the app was used and reviewed, this was recognized as a source of redundancy, weak context, and unnecessary navigation complexity. The architecture was therefore revised so that the interface reflected the actual hierarchy more clearly. + +\vspace{2mm} + +The same pattern appeared in the timer and session logic. Initial timer behaviour was gradually replaced by a more complete session model with focus sessions, breaks, persistence, and safer finalization rules. Several parts of the timer flow changed more than once as practical issues were discovered, especially around routing, active-session recovery, break handling, and reliability. In that sense, prototyping was not only used to create a first version, but also as a way to expose where the product model was still too weak or too rough. + +\subsection{Incremental Delivery of Core Features} + +The implementation was carried out in layers rather than as one large build phase. A basic feature foundation was established first, followed by increasingly product-specific refinement. + +\vspace{2mm} + +At an early stage, the work concentrated on basic entity management and data flow, such as creating, editing, viewing, and deleting subjects, assignments, and tasks. After that, the project moved further toward the product's intended identity by adding progress tracking, local reminders, more structured navigation, and task-linked study sessions. Later work focused more strongly on reducing friction in the main study flow, improving onboarding, and making the timer and break cycle more robust. + +\vspace{2mm} + +This incremental method helped reduce risk. A simple but working baseline could be established first, after which the team could decide which refinements actually improved the product and which ideas were unnecessary within the project's time constraints. + +\subsection{Testing, Verification, and Revision} + +Testing in this project was not treated as something that only happened at the end. Instead, verification and revision were interwoven with development. When new functionality was added, the result was checked, weaknesses were identified, and the implementation was adjusted before the project moved further. + +\vspace{2mm} + +The notes show two main forms of verification. The first was manual testing of the app's actual behaviour, especially in flows where user interaction and timing mattered. This was particularly important for the timer, break handling, onboarding flow, routing, and notification behaviour. The second was technical verification through static checks such as linting and TypeScript compilation, which helped detect invalid code, inconsistent types, and integration mistakes before further changes were added. + +\vspace{2mm} + +This combination was necessary because the project contains both logic-heavy and interaction-heavy features. Static checks can confirm that the codebase is structurally valid, but they cannot on their own confirm that a timed session flow feels correct or that screen transitions behave as intended. Manual testing was therefore especially important whenever reliability, usability, or flow clarity were central concerns. For native-dependent functionality such as notifications, a development build was also used instead of relying only on Expo Go, since that gave more realistic behaviour during testing. + +\subsection{Collaboration and Work Organization} + +The work was organized as a collaborative group project with regular meetings, shared responsibility, and ongoing task distribution. According to the project vision and group contract, the group planned to meet weekly to review progress, divide work, and discuss problems as they appeared. Discord functioned as the main communication channel between meetings, making it easier to adjust responsibilities when needed. + +\vspace{2mm} + +Because the project remained relatively limited in scope, with a small team and a fairly small number of central features, the group did not use a heavier Scrum-oriented project management setup with dedicated ticket tools such as Taiga. In practice, many tasks were easier to define, discuss, and reprioritize through regular meetings and direct communication than through maintaining a formal backlog with only a few active items. This reduced unnecessary administrative overhead and made the work organization more appropriate for the actual scale of the project. + +\vspace{2mm} + +Version control and shared documentation were important parts of the method. GitHub was used to manage source code and changes over time, while notes and work reports were used to document completed work, encountered problems, and follow-up decisions. This created a lightweight but useful development trail that supported both collaboration and report writing. + +\subsection{Why This Method Was Appropriate} + +An important reason for choosing this style of method was that \textit{Study Sprint} is a product where usability, flow, and reliability matter at least as much as raw feature count. A more rigid process could have described the intended system early, but it would have been less useful for improving the real experience of moving from planning work to starting a study session. + +\vspace{2mm} + +The iterative and scope-conscious method therefore matched the project well. It allowed the team to begin with a workable prototype, identify weaknesses through repeated review and testing, and gradually move the application toward a more coherent and dependable final form without losing control of scope. diff --git a/AppDev/prospectiveTexFiles/solution.tex b/AppDev/prospectiveTexFiles/solution.tex new file mode 100644 index 0000000..9d3bfab --- /dev/null +++ b/AppDev/prospectiveTexFiles/solution.tex @@ -0,0 +1,84 @@ +\section{Solution} + +The final solution developed for \textit{Study Sprint} is a mobile productivity application that combines lightweight planning, task-based study sessions, breaks, and visible progress in one workflow. The purpose of the solution was to help students move more easily from deciding what to study to actually starting focused work. + +\vspace{2mm} + +Rather than functioning only as a timer or only as a planning tool, the application connects the two. A user can create academic structure, choose a concrete task, begin a timed study sprint, continue through short or long breaks, and return to an overview that shows both recent activity and broader progress. + +\vspace{2mm} + +This product direction was influenced by the Pomodoro technique, where work is divided into focused intervals separated by breaks. That background was relevant because the goal of the project was not simply to count time, but to support a more sustainable and actionable study rhythm. Review literature on Pomodoro-style study intervals suggests that structured work-and-break cycles can improve focus, reduce fatigue, and support sustained performance in demanding learning situations \cite{pomodoro_scoping_review}. For that reason, the final app was built around the idea that planning and focused study should be tightly connected rather than treated as separate tools. + +\subsection{Main Components of the Solution} + +The solution consists of four closely connected parts: + +\begin{itemize} + \item a planning system for subjects, assignments, and tasks, + \item a task-linked timer flow with focus sessions and breaks, + \item a dashboard for overview, progress, and quick actions, + \item persistent storage and supporting logic for user data, active sessions, and reminders. +\end{itemize} + +These parts are intended to support one continuous study flow. The user should be able to define what to work on, start working without unnecessary setup, continue through breaks when appropriate, and return to a screen that still gives a clear sense of what has been done and what remains. + +\subsection{Planning and Study Structure} + +The planning part of the solution gives the user a structured way to organize academic work through subjects, assignments, and tasks. This allows larger and more abstract study obligations to be broken down into smaller actionable units. In practice, this matters because focused work sessions are easier to begin when the user is working from a clearly defined task rather than from a vague intention such as ``study more'' or ``work on the course''. + +\vspace{2mm} + +This means that the planning system is not only included for bookkeeping. It plays a direct role in the app's main purpose by making it easier to convert study plans into concrete sprint starts. + +\subsection{Task-Linked Sprint and Break Flow} + +The most central part of the solution is the timer flow. In the final app, a sprint is started from a task, not from a detached timer utility. This ties focused work directly to a chosen piece of study content and makes the session feel like part of the planning workflow rather than a separate feature beside it. + +\vspace{2mm} + +The timer supports focus sessions as well as short and long breaks. In the final version of the app, the default timing model follows a familiar Pomodoro-style rhythm: + +\begin{itemize} + \item a default focus session of 25 minutes, + \item a default short break of 5 minutes, + \item a default long break of 15 minutes after four completed focus sessions. +\end{itemize} + +These default values were chosen because they match the common Pomodoro model closely enough to feel familiar, while still fitting the project's broader goal of low-friction study support. The point was not to claim that one exact timing pattern is universally optimal, but to provide a sensible default that helps the user begin immediately without having to configure the session first. + +\vspace{2mm} + +At the same time, the app was not designed as a rigid timer. The solution still allows alternative session durations when needed. This was important because flexibility matters in real study situations, but the default path was intentionally kept simple so that customization would not become a barrier to getting started. + +\subsection{Dashboard, Progress, and Guided Flow} + +The dashboard acts as the application's overview and next-action screen. Instead of functioning only as a static home page, it gives the user a way to resume an active session, start a sprint from relevant tasks, and review recent study activity. This makes the dashboard part of the working flow rather than only a summary screen. + +\vspace{2mm} + +The solution also includes visible progress indicators and recent-activity summaries so that study effort is easier to interpret over time. This supports motivation and orientation by showing not only what the user planned, but also what they have actually completed or spent time on. + +\vspace{2mm} + +To reduce friction further, the app also includes guided setup and lightweight help flows. These parts of the solution are especially important for first-time users, since they make the main structure and intended study rhythm easier to understand before the app contains much user-created content. + +\subsection{Persistence and Supporting Functionality} + +The solution uses Supabase as the main backend for stored user data such as subjects, assignments, tasks, and recorded session information. This provides persistence beyond a single app instance and gives the app a clearer basis for authenticated, user-specific data. + +\vspace{2mm} + +At the same time, local storage is used for state that is more device- and interaction-specific, such as active-session recovery, study-cycle continuity, and some reminder-related information. This division is useful because not all app state serves the same role. Some data belongs to the durable academic structure, while other data belongs to the immediate behaviour of the app on the device. + +\vspace{2mm} + +The solution also includes local assignment reminders through notifications. This extends the application beyond passive planning by helping users notice approaching deadlines without requiring a more complex push-notification infrastructure. + +\subsection{Why This Solution Fits the Product Goal} + +The final solution fits the goals of the project because it remains focused on a small set of connected features rather than trying to become a broad productivity platform. Planning, sprint starts, breaks, reminders, and progress tracking all support the same main objective: helping students begin meaningful study work with less friction and maintain that work through a clearer rhythm of effort and recovery. + +\vspace{2mm} + +In that sense, the main strength of \textit{Study Sprint} is not feature quantity, but feature connection. A timer alone does not help the user decide what to study, and a planner alone does not help the user begin. The solution developed here is intended to bridge that gap in a lightweight and student-oriented way. diff --git a/AppDev/texFiles/architecuralDesign.tex b/AppDev/texFiles/architecuralDesign.tex new file mode 100644 index 0000000..67bca3d --- /dev/null +++ b/AppDev/texFiles/architecuralDesign.tex @@ -0,0 +1,192 @@ +\section{Architectural Design and Philosophy} + +\subsection{Overview} +Study Sprint was designed around a clear hierarchical productivity model: + +\begin{center} +\textbf{Subject $\rightarrow$ Assignment $\rightarrow$ Task} +\end{center} + +\vspace{2mm} + +This hierarchy became the foundation for how navigation and screen-level interaction was handled. The design aimed to make the application intuitive, reduce redundancy, and to make sure the interface reflected the actual the hierarchy in addition to the back-end database structure. + +\vspace{2mm} + +The goal for the design was to create an application that feels calm, minimal, and easy to understand. The architecture emphasizes context, structure, and progressive disclosure. + +\subsection{Architectural Motivation} + +The initial structure of the application that I was given treated several related entities as if they were independent. Subjects, assignments, and tasks were all exposed on the top-level I'm guessing this made basic CRUD operations easier to test while developing the back-end. In any case t his did not match the product model. This version of the code created several problems: + +\begin{itemize} + \item tasks could appear without sufficient assignment or subject context, + \item assignments felt detached from their parent subjects, + \item the interface duplicated information across multiple screens, + \item the difference between assignments and tasks are nuanced +\end{itemize} + +To fix this, the application was restructured so that the architecture of the interface matched the architecture of the data. + +\subsection{Navigation Architecture} +The top-level navigation was simplified into three tabs, and in the final product, two tabs. + +\begin{itemize} + \item \textbf{Dashboard} + \item \textbf{Subjects} + \item \textbf{Timer}, now directly integrated into the Task-level +\end{itemize} + +This was a deliberate decision. The application in its initial state risked becoming too flat by exposing assignments and tasks as separate top-level tabs. However, assignments and tasks are not standalone concepts. + +\vspace{2mm} + +The new tab structure gives each destination a distinct role: + +\begin{itemize} + \item \textbf{Dashboard} acts as an overview screen for cross-cutting information + \item \textbf{Subjects} acts as the primary entry point into the study hierarchy +\end{itemize} + +\subsection{Hierarchy-Driven Screen Design} +The screen flow follows the actual logical structure of the application: + +\begin{itemize} + \item the \textbf{Subjects} screen presents all subjects, + \item the \textbf{Subject Details} screen acts as the hub for a single subject and its assignments, + \item the \textbf{Assignment Details} screen acts as the hub for a single assignment and its tasks, + \item the \textbf{Task Details} screen focuses on one task while preserving its parent context. +\end{itemize} + +This means that users move deeper into the structure through meaningful parent-child relationships rather than through disconnected CRUD pages. + +\subsection{Hub-Based Detail Screens} +A major architectural choice was to turn detail pages into \emph{management hubs} instead of simple read-only detail views. + +\subsubsection{Subject Details as a Hub} +The subject details screen was designed to serve as the central management hub for a subject. It contains: + +\begin{itemize} + \item subject summary information, + \item status and metadata, + \item actions such as edit and delete, + \item action for creating assignments, + \item assignment sections organized by completion state. +\end{itemize} + +This supports a structured flow where the users naturally move from a subject, into an assignment, and then into the tasks that make it actionable. + +\subsection{Reduction of Redundancy} +One of the main architectural design principles was the removal of unnecessary duplication + +\subsubsection{Removal of Top-Level Assignment and Task Navigation} +Assignments and tasks were removed from the tab bar because they did not function as top-level concepts in practice. Their meaning depends on the parent hierarchy. Keeping them as top-level tabs only worsens the contextual clarity and created repeated list views that duplicated information already available deeper in the hierarchy. + +\subsubsection{Reduction of Inline Management Controls} +List screens were simplified so that entity cards primarily function as entry points rather than control panels. For example subject cards no longer contain too many management actions such as inline edit, delete, or progress-heavy UI. Those actions were moved into the corresponding hub screens. + +\vspace{2mm} + +This follows a simple principle: browsing screens should prioritize selection and orientation, while detail screes should prioritize management. + +\subsection{Reusable Upsert-Based Form Design} +Another architectural decision was to reduce duplication in entity creation and editing workflows. + +Originally, create and edit flows existed as separate screens even when they used close to identical fields, validation control, and layout. This increased maintenance overhead and produced repeated code. + +\vspace{2mm} + +To improve this, the application moved toward an \textbf{upsert-based form architecture}. In this pattern, a single screen handles both creation and editing: + +\begin{itemize} + \item if no id is present, the form works in create mode, + \item if an id is present, the form loads existing data and works in edit mode +\end{itemize} + +This was implemented for core entity forms such as subjects, assignments, and tasks. The benefit is that validation, styling, and layout remain consistent while avoiding unnecessary duplication of screen logic. + +\subsection{Shared Utility Extraction} +As the design progressed, common patterns were extracted into globally shared utility modules. + +\subsubsection{Date Formatting} +Date and timestamp rendering was centralized in a shared formatting utility. This replaced raw database timestamps with user-friendly display values and ensured consistency across subject, assignment, and task screens. + +\subsubsection{Subject Color System} +A dedicated subject color utility was introduced to centralize: + +\begin{itemize} + \item the available subject color palette, + \item the type definition for valid subject colors, + \item the mapping between a subject color key and its visual values, + \item helper logic for retrieving the correct visual accent set. +\end{itemize} + +This avoided repeated color logic and ensured that subject styling remained consistent across the hierarchy. + +\subsection{Design Philosophy} +The architectural design was strongly influenced by a clear philosophy. The UI was intentionally shaped by the following principles. + +\subsubsection{Calm over visual noise} +The interface was designed to feel calm and discreet. The goal was not to make everything look awesome, but to make structure understandable and interaction obvious. This led to a restrained card-based UI, reduced redundancy, and fewer competing visual accents. + +\subsubsection{Hierarchy over flatness} +The interface should communicate the real structure of the application. The design preserves parent-child relationships instead of flattening all the entities. This improves orientation and helps the user understand where they are in the study workflow. + +\subsubsection{Context over abstraction} +The deeper the user moves into the hierarchy, the more important context becomes. For this reason assignment screens display subject context, and task screens display subject context, and task screens display both subject and assignment context. This prevents the user from losing track of where a specific item belongs. + +\subsubsection{Consistency over novelty} +The design favors repeated, understandable patterns over excessive variation. Pills, card, spacing, and stable action buttons are reused deliberately so that the application feels predictable. Primary actions continue to use the app-level accent, while subject colors are used for contextual identity. + +\subsubsection{Identity through controlled color} +Subjects were given user-selectable accent colors from a predefined palette. This creates a stronger sense of identity without overwhelming the interface. The subject color is inherited by related assignment and task screens, visually reinforcing the branch structure of the hierarchy. + +\vspace{2mm} + +This color is not used for everything. A key design rule was maintained: + +\begin{itemize} + \item \textbf{app accent color} = primary actions, + \item \textbf{subject color} = contextual identity. +\end{itemize} + +This distinction keeps the interaction language stable while still giving each subject a recognizable visual signature. + +\subsection{Card-Based Interface Design} +The design used a consistent card-based layout. Cards were used to group related information and actions. This supports readability and imporoves structure. + +Each card is designed to: +\begin{itemize} + \item present on conceptual unit, + \item reduce visual clutter, + \item support quick scanning, + \item separate context from action. +\end{itemize} + +Subject cards emphasize browing and selection. Detail cards emphasize context and management. This distinction was important in making the UI feel more intentional. + +\subsubsection{Progress Representation} +Progress indicators were intentionally limited to screens where they carry structural meaning. Rather than showing progress everywhere, progress was only shown on screens such as subject and assignment details. + +Progress is represented using both: + +\begin{itemize} + \item a visual progress bar, + \item a numeric completion ratio such as \texttt{x / y}, + \item remaining assignments/tasks text. +\end{itemize} + +This makes progress easier to interpret than a bar alone and avoids ambiguity. + +\subsection{Outcome} +The final architecture now emphasizes: +\begin{itemize} + \item clear hierarchy, + \item reduced redundancy, + \item stronger contextual awareness, + \item reusable form patterns, + \item shared utility logic, + \item cleaner, calmer interaction design. +\end{itemize} + +As a result, the interface now accurately reflects the study workflow and provides an overall better foundation for usability and maintainability. \ No newline at end of file diff --git a/AppDev/texFiles/conclusion.tex b/AppDev/texFiles/conclusion.tex new file mode 100644 index 0000000..47c04f1 --- /dev/null +++ b/AppDev/texFiles/conclusion.tex @@ -0,0 +1 @@ +\section{Conclusion} \ No newline at end of file diff --git a/AppDev/texFiles/discussion.tex b/AppDev/texFiles/discussion.tex new file mode 100644 index 0000000..c277d16 --- /dev/null +++ b/AppDev/texFiles/discussion.tex @@ -0,0 +1 @@ +\section{Discussion} \ No newline at end of file diff --git a/AppDev/texFiles/groupDeclaration .tex b/AppDev/texFiles/groupDeclaration .tex new file mode 100644 index 0000000..9d08e32 --- /dev/null +++ b/AppDev/texFiles/groupDeclaration .tex @@ -0,0 +1,57 @@ +\large{\bf{Mandatory group declaration}} \\ +{\small \hbadness=10000 +Each student is responsible for familiarizing themselves with what constitutes permitted aids, guidelines for the use of these, and rules regarding the use of sources. The declaration is intended to make students aware of their responsibility and of the consequences that cheating may entail. A missing declaration does not exempt students from their responsibility. +\begin{center} +\begin{tabular}{ |p{1cm}|p{11.5cm}|p{1cm}|} + \hline + 1. & We hereby declare that our submission is our own work, and that we have not used other sources or received any other assistance than what is mentioned in the submission. & Yes \\ + \hline + 2. & \textbf{We further declare that this submission:} + \begin{itemize} + \item Has not been used for another examination at another department/university/university college in Norway or abroad. + \item Does not refer to the work of others without this being stated. + \item Does not refer to our own previous work without this being stated. + \item Has all references listed in the bibliography. + \item Is not a copy, duplicate, or transcript of another person's work or submission. + + \end{itemize}& Yes \\ + \hline + 3. & We are aware that breaches of the above are to be regarded as cheating and may result in annulment of the examination and exclusion from universities and university colleges in Norway, cf. the Universities and Colleges Act §§4-7 and 4-8 and the Examination Regulations §§ 31. + & Yes \\ + \hline + 4. & We are aware that all submitted assignments may be checked for plagiarism. + & Yes \\ + \hline + 5. & We are aware that the University of Agder will handle all cases where there is suspicion of cheating according to the university college's guidelines for handling cases of cheating. + & Yes \\ + \hline + 6. & We have familiarized ourselves with the rules and guidelines for the use of sources and references on the library's webpages. + & Yes \\ + \hline + 7. & We have, by majority, agreed that the effort within the group is noticeably different and therefore wish to be assessed individually. +Ordinarily, all participants in the project are assessed collectively. + & No \\ + \hline +\end{tabular} +\end{center}} + +\bigskip + +\large{\bf{Publication agreement}} \\ +{\small \hbadness=10000 Authorization for electronic publication of the assignment +The author(s) hold the copyright to the assignment. This means, among other things, the exclusive right to make the work available to the public (Copyright Act. §2). +\\ +Assignments that are exempt from public disclosure or are subject to a duty of confidentiality/confidential will not be published. +\begin{center} +\begin{tabular}{ |p{13cm}|p{1cm}|} +\hline +We hereby grant the University of Agder a royalty-free right to make the assignment available for electronic publication: & No \\ +\hline +Is the assignment restricted (confidential)? & Yes \\ +\hline +Is the assignment exempt from public disclosure? & Yes \\ +\hline +\end{tabular} +\end{center} +} +\newpage \ No newline at end of file diff --git a/AppDev/texFiles/implementation.tex b/AppDev/texFiles/implementation.tex new file mode 100644 index 0000000..96bc6bd --- /dev/null +++ b/AppDev/texFiles/implementation.tex @@ -0,0 +1,126 @@ +\section{Implementation} + +The implementation of Study Sprint was carried out as a gradual refinement of both product structure and technical behaviour. Rather than building every feature as an isolated part, the work focused on making the different parts of the application support one coherent study flow. This meant that navigation, CRUD functionality, timer behaviour, persistence, progress tracking, notifications, and onboarding all had to be made to work together as parts of the same product. + +\vspace{2mm} + +The application was implemented using React Native with Expo on the frontend and Supabase as the main backend for authentication and persistent user data. In practice, this gave the project a relatively fast development workflow while still allowing the application to move beyond a purely local prototype. At the same time, some state was intentionally kept local on the device, especially when that state was closely tied to temporary interaction flow +rather than long-term user data. + +\subsection{Core Data and CRUD Implementation} + +A large early part of the implementation focused on establishing the application's core academic structure through subjects, assignments, and tasks. These three entities form the conceptual hierarchy of the product: + +\begin{center} +\textbf{Subject $\rightarrow$ Assignment $\rightarrow$ Task} +\end{center} + +\vspace{2mm} + +This structure was implemented through full CRUD support for each level. Users can create, edit, view, and delete subjects, assignments, and tasks, and the entities are linked together through their parent-child relationships. Subjects act as the top-level organisational unit, assignments belong to subjects, and tasks belong to assignments. + +\vspace{2mm} + +An important implementation decision was to move away from separate create and edit screens wherever the form structure was nearly identical. Instead, the project used upsert-style screens for the main entities. In this pattern, the same screen handles both creation and editing, depending on whether an existing id is passed into the route. This reduced duplicated form logic and made it easier to keep validation, styling, and layout consistent across related flows. +\clearpage + +\subsection{Navigation and Screen-Structure Implementation} + +As the project developed, it became clear that the original screen structure did not reflect the intended product model strongly enough. Earlier versions exposed subjects, assignments, and tasks too much as parallel top-level concepts, even though they were not conceptually independent. This created duplicated views, weaker context, and a flatter structure than intended. + +\vspace{2mm} + +To address this, the implementation shifted toward a hierarchy-driven navigation model. Subjects became the main entry point into academic content, while assignments and tasks were accessed through their parent screens instead of being treated as separate top-level browsing areas. Subject details, assignment details, and task details were each implemented more as management hubs than as static detail pages. This made it easier to preserve context and reduced unnecessary navigation noise. + +\vspace{2mm} + +The dashboard remained a cross-cutting overview screen. As development progressed, the timer was eventually integrated into the task flow as originally intended, instead of functioning as a detached utility page. This was an important decision, as the product goal was not merely to provide a timer, but to connect focused work directly to actual study tasks. + +\subsection{Timer, Session Flow, and Break Handling} + +The timer implementation developed significantly over time. Earlier versions focused mainly on starting and cancelling sessions, but later iterations expanded the flow into a more complete model with linked tasks, persistent active-session recovery, break handling, and safer finalisation rules. + +\vspace{2mm} + +A major implementation step was to move the timer into the real task workflow. Instead of starting a generic timer in isolation, the user starts a sprint from a specific task. This makes the session part of the study structure rather than a separate feature beside it. The timer was therefore implemented to receive task context, display relevant task information, and preserve that context when moving between focus sessions and breaks. + +\clearpage + +The final timer flow supports focus sessions, short breaks, and long breaks. Shared session defaults were introduced so that common durations could be reused consistently across the app. This reduced hardcoded duplication and helped align task-start, dashboard-start, and timer-entry behaviour. At the same time, the implementation kept room for alternative durations when needed, so that the timer would not become too rigid in practice. A total time window of 1 - 60 minutes was chosen based on the research material suggesting that shorter sessions with frequent breaks were the most beneficial \cite{cirillo_pomodoro_2018, pomodoro_scoping_review}. + +\vspace{2mm} + +Another important refinement was the implementation of a small local study-cycle model for break logic. Rather than deciding long breaks based on total historical sessions, the application tracks the current study cycle more narrowly. This makes the break flow behave more like a real continuous work rhythm and avoids misleading long-break prompts based on unrelated earlier activity. + +\subsection{Persistence and Session Reliability} + +Persistence in the project was implemented through a combination of Supabase and local device storage. Supabase was used for durable user-specific data such as subjects, assignments, tasks, and recorded session information. Local storage was used for more temporary or interaction-sensitive state, such as active-session recovery, study-cycle continuity, and notification identifiers. + +\vspace{2mm} + +This split was a deliberate implementation decision. Not all state in the application serves the same purpose. Academic structure and recorded session history belong in persistent backend storage, while temporary control state related to the current device session is better handled locally for faster and simpler recovery. + +\vspace{2mm} + +As the timer flow became more central to the app, reliability problems in session handling became more important. Different screens could detect expired, cancelled, or replaced sessions, but earlier implementations risked treating those cases inconsistently. To reduce that risk, session-finalization logic was moved into a shared lifecycle helper. This ensured that active local session state and stored session records were handled more consistently when sessions ended, expired, or were replaced. + +\vspace{2mm} + +This part of the implementation was especially important because the usefulness of the app depends heavily on users being able to trust the timer and recorded study activity. If local UI state and stored session history drift apart, the core study flow becomes less dependable. + +\subsection{Progress Tracking and Visual Feedback} + +The application also required implementation work around progress tracking so that planning and studying would feel meaningfully connected. Task completion was used as the main source of truth, and this was then used to calculate assignment-level and subject-level progress. + +\vspace{2mm} + +To support this, related tasks were grouped and evaluated so that progress could be displayed in a more understandable way. This included both visual progress bars and simple completion ratios. The implementation intentionally limited these indicators to screens where they were structurally useful, such as subject and assignment detail screens, instead of placing them aggressively throughout the app. + +\vspace{2mm} + +This choice was partly technical and partly design-orientated. From a technical side, it required consistent progress calculation based on task state. From a product perspective, it reduced visual clutter and kept browsing views calmer while still making progress visible where it mattered most. + +\subsection{Notifications and Reminder Logic} + +Another practical implementation area was assignment reminders through local notifications. These were implemented using Expo Notifications and were tied directly to assignment deadlines. The reminder logic schedules notifications for valid upcoming deadlines and updates or cancels them when assignments are edited or deleted. + +\vspace{2mm} + +An important implementation detail here was that notification identifiers were stored locally on the device rather than in the backend. This made reminder clean-up and rescheduling easier while keeping the reminder system lightweight. The project, therefore, avoided a more complex push-notification architecture since that would have added scope without being necessary for the intended use case. + +\vspace{2mm} + +Because notification behaviour depends on native capabilities, this part of the project was tested through an Expo development build rather than relying only on Expo Go. That made the implementation more realistic and gave better confidence in behaviour on Android devices. + +\subsection{Android Internal Testing and Delivery Preparation} + +Toward the end of the project, the application was also prepared for internal testing through Google Play Console. This required uploading the Android app bundle, configuring an internal test track, adding at least one tester email address, and publishing the internal test so that testers could gain access to the application. + +\vspace{2mm} + +After the internal test was published, Google Play Console provided a direct link to the app listing in Google Play. At this stage, the listing used a temporary name and was not publicly searchable. Access was limited to users with the link and the configured tester access. This made it possible to test the distribution flow in a more realistic way without treating the application as a full public release. + +\vspace{2mm} + +This step was part of the practical delivery work rather than the product solution itself. It helped confirm that the application could be packaged, uploaded, and distributed through the expected Android testing channel, which was important for validating the project as more than a local development prototype. +\clearpage + +\subsection{Onboarding and Low-Friction Flow Improvements} + +Later implementation work focused more strongly on reducing friction for first-time users and making the main study flow easier to enter. This included guided setup behaviour, clearer help flows, faster sprint-start paths, and more direct routing from dashboard and task screens into the timer. + +\vspace{2mm} + +One specific refinement was to make the default sprint flow faster by presenting a sensible default focus duration immediately instead of forcing the user through a configuration step every time. A custom-duration path was still preserved, but it became an optional side path rather than the default interaction. + +\vspace{2mm} + +The onboarding flow was also adjusted so that incomplete users are routed into setup more consistently, and the first guided sprint was shortened to a small demo session rather than a full, normal-length focus block. This was done to support the product goal that the app should be understandable and usable quickly, without making the first interaction feel unnecessarily heavy. + +\subsection{Implementation Outcome} + +In implementation terms, the final application became much more than a basic CRUD prototype. The main technical result was a mobile application where planning structure, task ownership, timed study sessions, breaks, reminders, progress tracking, and persistence all support the same study workflow. + +\vspace{2mm} + +Several of the most important implementation choices were therefore not about adding more features, but about improving coherence between features that already existed. The shift toward hierarchy-driven navigation, task-linked timers, shared lifecycle handling, limited but meaningful progress feedback, and lower-friction session starts all helped move the application closer to its intended product identity. diff --git a/AppDev/texFiles/introduction.tex b/AppDev/texFiles/introduction.tex new file mode 100644 index 0000000..8e96be7 --- /dev/null +++ b/AppDev/texFiles/introduction.tex @@ -0,0 +1,96 @@ +\section{Introduction} + +This report presents the development of \textit{Study Sprint}, a mobile productivity application designed to help students organise academic work and turn that structure into focused study sessions. The core idea behind the application is to reduce the gap between intending to study and actually starting. Instead of treating planning, timing and progress as separate concerns, Study Sprint connects subjects, assignments, tasks, timed focus sessions, breaks and visible progress into one lightweight workflow. + +\vspace{2mm} + +The motivation for the project came from a common frustration with existing study and productivity applications. Many such applications are either too broad, too feature-heavy or too abstract for students who simply want to organise what they need to study and begin working with as little friction as possible. In many cases, users are forced through unnecessary setup, presented with too many unrelated features, or given timer tools that are disconnected from the work they are supposed to support. Study Sprint was developed as a response to that problem. + +\vspace{2mm} + +The project therefore focused on a small but coherent feature set. The goal was not to create the most advanced productivity application, but to create one that is easy to understand, fast to use and reliable in practice. This meant prioritising a clear study hierarchy, low-friction navigation, task-linked study sessions, break handling and progress visibility over broader functionality that would have increased the complexity without adding equal value to the intended user. + +\vspace{2mm} + +The conceptual background for the app was also influenced by the Pomodoro technique, where focused work intervals are separated by short breaks. This was relevant because the project aimed to support concentration, reduce study friction, and make it easier for users to turn vague study intentions into concrete work sessions. Recent review literature also suggests that structured Pomodoro-style intervals can improve focus, reduce fatigue, and support sustained task performance in demanding learning contexts \cite{cirillo_pomodoro_2018, pomodoro_scoping_review}. + +\vspace{2mm} + +From a development perspective, the project followed an iterative approach. Early prototypes were used to explore structure, interaction and timer behaviour before the application was gradually refined through implementation, testing and revision. Several parts of the application, especially the timer flow and session handling, changed significantly over time as practical issues were discovered and resolved. This process helped move the product from a simple prototype toward a more complete and reliable study tool. +\clearpage + + +\subsection{Product Vision} + +The complete project vision is included in Appendix~\ref{appendix:projectvision}. The following section summarises the most important parts of that vision and shows how they shaped the direction of the product. + +\subsection{Target customer} + +The primary target group for Study Sprint is students in higher education who want a simple and structured way to organise study work, start focused work sessions and keep track of their progress \cite{projectvision}. + +\vspace{2mm} + +A secondary target group includes other learners, such as upper secondary students, as well as users who rely on timed work sessions for productivity in non-academic contexts. Even so, the application is mainly designed around student needs, since that is the clearest and most relevant use case for the project. + +\subsubsection{Customer needs} + +Study Sprint is intended to address a small set of practical needs that repeatedly appear in student work: + +\begin{itemize} + \item better focus during study sessions through timed work periods and breaks, + \item simple planning and organisation through subjects, assignments, and tasks, + \item motivation through visible progress and recorded study activity, + \item low friction, so users can understand the app quickly and begin studying without unnecessary setup. +\end{itemize} + +These needs are closely related. A study timer becomes more useful when it is connected to real tasks, and planning becomes more meaningful when it leads directly into focused work. + +\subsubsection{Critical Product Attributes} + +The most important product attribute for Study Sprint is simplicity. The application should be intuitive enough that a user can understand the main study flow almost immediately. A user should be +able to move from creating structure to starting a study session without confusion or unnecessary decision-making. + +\clearpage + +Reliability is also critical. Since the application depends heavily on timed study sessions and progress tracking, it must handle active sessions, completion, cancellation, breaks, and saved +progress in a dependable way. If the timer flow feels unstable or if recorded study activity becomes inconsistent, the application quickly loses its usefulness. + +\vspace{2mm} + +A third important attribute is a clear and focused user interface. The design does not need to be visually complex, but it should feel complete, deliberate, and easy to navigate. Since the app is +intended to reduce procrastination rather than add friction, fast and understandable interaction is especially important. + +\vspace{2mm} + +Finally, scope control is an important product attribute in itself. A smaller and more polished application is more valuable for this project than a broader solution with too many unfinished or +weakly integrated features. A successful version of Study Sprint therefore includes structured planning, task-linked study sessions, break handling, progress visibility, and persistence, while +avoiding feature expansion that would dilute the product's main purpose. + +\subsubsection{Unique Seeling Points} + +Study Sprint enters a crowded space of Pomodoro apps, study planners, habit trackers, and general productivity tools such as Forest, Focus To-Do, and Todoist. These applications often provide useful +functionality, but many of them are either too broad, too feature-heavy, or too focused on premium features and generalized productivity workflows \cite{projectvision}. + +\vspace{2mm} + +Compared to these alternatives, Study Sprint aims to be more focused and more student-oriented. Rather than trying to include every possible productivity feature, it combines only the features most relevant to the intended workflow: subject structure, assignments, tasks, timed focus sessions, breaks, and visible progress. + +\vspace{2mm} + +The main unique selling point of Study Sprint is therefore not feature quantity, but feature connection. The application links planning and studying more directly than a simple timer app, while +remaining much lighter and more focused than broader productivity platforms. This makes it easier for a student to decide what to study, begin working quickly, and see meaningful progress afterward. +\clearpage + +\subsubsection{Target Time-frame and Budget} + +The target time-frame for Study Sprint was the duration of the project period, ending in early May. Because this work was carried out alongside other courses, assignments, and exams, the project had +to be planned with a strong focus on the effort-to-value ratio rather than feature ambition. + +\clearpage + +For that reason, the team aimed to establish a working prototype early and then use the remaining time on refinement, reliability, usability, and report work. A realistic development path was to +first define the product structure and screen flow, then implement the core planning hierarchy, timer functionality, session persistence, break flow, and progress tracking, before focusing on testing and polish \cite{projectvision}. + +\vspace{2mm} + +The financial budget for the project was expected to be minimal. The application was developed using free or low-cost tools and frameworks, with time being the main practical constraint. This made it especially important to avoid unnecessary complexity and to concentrate on the parts of the application that contributed most directly to the intended study experience. diff --git a/AppDev/texFiles/method.tex b/AppDev/texFiles/method.tex new file mode 100644 index 0000000..44b82f4 --- /dev/null +++ b/AppDev/texFiles/method.tex @@ -0,0 +1,73 @@ +\section{Method} + +The development of Study Sprint followed a practical and iterative project method. Rather than treating the application as a fixed specification that could be implemented in one pass, the team worked from a product vision, built early versions of the core functionality, and then refined the solution as weaknesses became clearer through use, testing, and discussion. + +\vspace{2mm} + +This approach fit the nature of the project well. The main challenge was not only to implement isolated features, but to shape a small mobile product that felt coherent, reliable, and easy to use in practice. Because of that, the method had to support both technical implementation and repeated revision of structure, flow, and scope. + +\subsection{Vision-Driven and Scope-Conscious Development} + +The project vision functioned as the main strategic starting point for the work. It defined the target users, the most important customer needs, and the product attributes that mattered most for success. In particular, simplicity, reliability, low friction, and realistic scope were treated as guiding constraints throughout the project \cite{projectvision}. + +\vspace{2mm} + +This had a direct effect on development priorities. Features that supported the core study flow were given precedence, while ideas that would broaden the product without strengthening its main purpose were de-prioritised or excluded. That is also why the report separates requirements into must-have, should-have, could-have, and will-not-have categories. This prioritisation made it easier to protect the project from feature growth and to keep effort focused on the parts of the application that contributed most directly to the intended user experience. +\clearpage + + +\subsection{Iterative Prototyping and Refinement} + +The practical development process was iterative. Early work focused on establishing the underlying structure of the app, including navigation, CRUD support for subjects, assignments, and tasks, and the first timer-related flows. These early versions were useful for confirming that the main ideas were technically possible, but they also revealed architectural and usability problems that were not obvious at the planning stage. + +\vspace{2mm} + +One clear example was the relationship between the app's conceptual data model and its screen structure. The intended hierarchy was always \textit{Subject $\rightarrow$ Assignment $\rightarrow$ Task}, but earlier versions exposed assignments and tasks too much as top-level concepts. As the app was used and reviewed, this was recognised as a source of redundancy, weak context, and unnecessary navigation complexity. The architecture was therefore revised so that the interface reflected the actual hierarchy more clearly. + +\vspace{2mm} + +The same pattern appeared in the timer and session logic. Initial timer behaviour was gradually replaced by a more complete session model with focus sessions, breaks, persistence, and safer finalisation rules. Several parts of the timer flow changed more than once as practical issues were discovered, especially around routing, active-session recovery, break handling, and reliability. In that sense, prototyping was not only used to create a first version, but also as a way to expose where the product model was still too weak or too rough. + +\subsection{Incremental Delivery of Core Features} + +The implementation was carried out in layers rather than as one large build phase. A basic feature foundation was established first, followed by increasingly product-specific refinement. + +\vspace{2mm} + +At an early stage, the work concentrated on basic entity management and data flow, such as creating, editing, viewing, and deleting subjects, assignments, and tasks. After that, the project moved further toward the product's intended identity by adding progress tracking, local reminders, more structured navigation, and task-linked study sessions. Later work focused more strongly on reducing friction in the main study flow, improving onboarding, and making the timer and break cycle more robust. + +\vspace{2mm} + +This incremental method helped reduce risk. A simple but working baseline could be established first, after which the team could decide which refinements actually improved the product and which ideas were unnecessary within the project's time constraints. + +\subsection{Testing, Verification, and Revision} + +Testing in this project was not treated as something that only happened at the end. Instead, verification and revision were interwoven with development. When new functionality was added, the result was checked, weaknesses were identified, and the implementation was adjusted before the project moved further. + +\vspace{2mm} + +The notes show two main forms of verification. The first was manual testing of the app's actual behaviour, especially in flows where user interaction and timing mattered. This was particularly important for the timer, break handling, onboarding flow, routing, and notification behaviour. The second was technical verification through static checks such as linting and TypeScript compilation, which helped detect invalid code, inconsistent types, and integration mistakes before further changes were added. + +\vspace{2mm} + +This combination was necessary because the project contains both logic-heavy and interaction-heavy features. Static checks can confirm that the codebase is structurally valid, but they cannot on their own confirm that a timed session flow feels correct or that screen transitions behave as intended. Manual testing was therefore especially important whenever reliability, usability, or flow clarity were central concerns. For native-dependent functionality such as notifications, a development build was also used instead of relying only on Expo Go, since that gave more realistic behaviour during testing. + +\subsection{Collaboration and Work Organisation} + +The work was organised as a collaborative group project with regular meetings, shared responsibility, and ongoing task distribution. According to the project vision and group contract, the group planned to meet weekly to review progress, divide work, and discuss problems as they appeared. Discord functioned as the main communication channel between meetings, making it easier to adjust responsibilities when needed. + +\vspace{2mm} + +Because the project remained relatively limited in scope, with a small team and a fairly small number of central features, the group did not use a heavier Scrum-oriented project management setup with dedicated ticket tools such as Taiga. In practice, many tasks were easier to define, discuss, and re-prioritise through regular meetings and direct communication than through maintaining a formal backlog with only a few active items. This reduced unnecessary administrative overhead and made the work organisation more appropriate for the actual scale of the project. + +\clearpage + +Version control and shared documentation were important parts of the method. GitHub was used to manage source code and changes over time, while notes and work reports were used to document completed work, encountered problems, and follow-up decisions. This created a lightweight but useful development trail that supported both collaboration and report writing. + +\subsection{Why This Method Was Appropriate} + +An important reason for choosing this style of method was that Study Sprint is a product where usability, flow, and reliability matter at least as much as raw feature count. A more rigid process could have described the intended system early, but it would have been less useful for improving the real experience of moving from planning work to starting a study session. + +\vspace{2mm} + +The iterative and scope-conscious method therefore matched the project well. It allowed the team to begin with a workable prototype, identify weaknesses through repeated review and testing, and gradually move the application toward a more coherent and dependable final form without losing control of scope. diff --git a/AppDev/texFiles/requirements.tex b/AppDev/texFiles/requirements.tex new file mode 100644 index 0000000..532a9a4 --- /dev/null +++ b/AppDev/texFiles/requirements.tex @@ -0,0 +1,97 @@ +\section{Requirements} + +Requirements are critical for measuring the success of the project. They are both the team's guidelines for the project and determine what users can expect from the product. + +\vspace{2mm} + +Requirements will be divided into two main parts, those being functional and non-functional requirements. Functional requirements define what the system should do, whereas non-functional requirements define how the system should perform \cite{geeksforgeeks_functional_nonfunctional_requirements}. Beyond that, functional/non-functional requirements will both be split into 4 subcategories. "Must have", "Should have", "Could have" and "Will not have" requirements. + + + +\subsection{Functional Requirements} + +\subsubsection{Must Have} + +\begin{itemize} + \item[FR1:] Users must be able to create, edit, delete and view subjects + \item[FR2:] Users must be able to create, edit, delete and view assignments + \item[FR3:] Users must be able to create, edit, delete and view tasks + \item[FR4:] Users must be able to start and cancel timed study sessions + \item[FR5:] Users must be prompted to take breaks after timed study sessions + \item[FR6:] The app must connect a study session to a specific task + \item[FR7:] Subjects, assignments, tasks and study sessions must persist between app instances to avoid losing data + \item[FR8:] Tracking of studying progress +\end{itemize} + + + +\subsubsection{Should Have} + +\begin{itemize} + \item[FR9:] Ability to set assignments and tasks as completed/not completed + \item[FR10:] Ability to set subjects as active/inactive + \item[FR11:] Notifications for important events + \item[FR12:] Users should be able to cancel active study session +\end{itemize} + + + +\subsubsection{Could Have} + +\begin{itemize} + \item[FR13:] Authentication could be set up to allow for cross device persistence and greater safety + \item[FR14:] Users could be able to customize break and study session durations + \item[FR15:] Users could be able to pause study sessions +\end{itemize} + + + +\subsubsection{Will Not Have} + +\begin{itemize} + \item[FR-W1:] Study groups will not be included, as this was deemed too large in scope for the simple design philosophy of the project + \item[FR-W2:] Calendar integration will not be included + \item[FR-W4:] Advanced analytics will not be included +\end{itemize} + + + +\subsection{Non-Functional Requirements} + +\subsubsection{Must Have} + +\begin{itemize} + \item[NFR1:] The project must have a functional UI where elements do not overlap and do not become unreachable + \item[NFR2:] The UI must be easy to understand / low friction + \item[NFR3:] Project must be open source on GitHub + \item[NFR4:] Simple navigation between screens + \item[NFR5:] Timer must be reliable at tracking time during study sessions and breaks +\end{itemize} + + + +\subsubsection{Should Have} + +\begin{itemize} + \item[NFR6:] Loading states between different pages being rendered + \item[NFR7:] Page not found / error pages if something were to go wrong during interaction with, for example storage/database + \item[NFR8:] A custom UI style + \item[NFR9:] App should be prepped and ready for android deployment, and should be published on the Google Play Store if time allows for it +\end{itemize} + + + +\subsubsection{Could Have} + +\begin{itemize} + \item[NFR10:] Display daily motivational quotes to encourage users to study +\end{itemize} + + + +\subsubsection{Will Not Have} + +\begin{itemize} + \item[NFR-W1:] Advanced animations + \item[NFR-W2:] Be published on App Store +\end{itemize} \ No newline at end of file diff --git a/AppDev/texFiles/solution.tex b/AppDev/texFiles/solution.tex new file mode 100644 index 0000000..fb1d4cd --- /dev/null +++ b/AppDev/texFiles/solution.tex @@ -0,0 +1,87 @@ +\section{Solution} + +The final solution developed for Study Sprint is a mobile productivity application that combines lightweight planning, task-based study sessions, breaks, and visible progress into a single workflow. The purpose of the solution was to help students move more easily from deciding what to study to actually starting focused and efficient work. + +\vspace{2mm} + +Rather than functioning only as a timer, or as a planning tool, the application connects the two. A user can create academic structure, chose a concrete task, begin a timed study sprint, continue through short or long breaks, and return to an overview that shows both recent activity and broader progress. + +\vspace{2mm} + +This product direction was influenced by the Pomodoro technique, where work is divided into focused intervals separated by breaks. That background was relevant because the goal of the project was not simply to count time, but to support a more sustainable and actionable study rhythm. Upon reviewing literature on Pomodoro-style study intervals, we found consistent suggestions that structured work-and-break cycles can improve focus, reduce fatigue, and support sustained performance in demanding learning situations \cite{cirillo_pomodoro_2018, pomodoro_scoping_review}. For that reason, the final app was built around the idea that planning and focused study should be tightly connected rather than treated as separate tools. + +\subsection{Main Components of the Solution} + +The solution consists of four closely connected parts; + +\begin{itemize} + \item a planning system for subjects, assignments, and tasks, + \item a task-linked timer flow with focus sessions and breaks, + \item a dashboard for overview, progress, and quick actions, + \item persistent storage and supporting logic for user data, active sessions, and reminders. +\end{itemize} + +These parts are intended to support one continuous study flow. The user should be able to define what to work on, start working without unnecessary setup, continue through breaks when appropriate, and return to a screen that still gives a clear sense of what has been done and what remains. + +\subsection{Planning and Study Structure} + +The planning part of the solution gives the user a structured way to organise academic work through subjects, assignments, and tasks. This allows larger and more abstract study obligations to be broken down into smaller, more digestible units. In practice, this matters because focused work sessions are easier to begin when the user is working from a clearly defined task rather than from a vague intention such as "study more" or "work on the course". + +\vspace{2mm} + +This means that the planning system is not only included for book-keeping. It plays a direct and central role in the app's main purpose by making it easier to convert study plans into concrete sprint starts. + +\subsection{Task-Linked Sprint and Break Flow} + +The most central part of the solution is the timer flow. In the final app, a sprint is started from a task, not from a detached timer utility. This ties focused work directly to a chosen piece of study content and makes the session feel like part of the planning workflow rather than a separate feature beside it. + +\vspace{2mm} + +The timer supports focus sessions as well as short and long breaks. In the final version of the app, the default timing model follows a familiar Pomodoro-style rhythm; + +\begin{itemize} + \item a default focus session of 25 minutes, + \item a default short break of 5 minutes, + \item a default long break of 15 minutes upon completing four focus sessions. +\end{itemize} + +These default values were chosen because they match the common Pomodoro model closely enough to feel familiar, whilst still fitting the project's broader goal of low-friction study support. The point was not to claim that one exact timing is universally optimal, but rather to provide a sensible default that helps the user begin immediately without having to configure the session first. + +\vspace{2mm} + +At the same time, the app was not designed as a rigid timer. The solution still allows for alternative session durations when needed. This was important because flexibility matters in real study situations, but the default path was intentionally kept simple so that customisation would not become a barrier to getting started. +\clearpage + +\subsection{Dashboard, Progress, and Guided Flow} + +The dashboard acts as the application's overview and next-action screen. Instead of functioning only as a static home page, it gives the user a way to resume an active session, start a sprint from upcoming tasks, and review recent study activity. This makes the dashboard part of the workflow rather than merely a simple summary screen. + +\vspace{2mm} + +The solution also includes visible progress indicators and recent-activity summaries so that study effort is easier to interpret over time. This supports motivation and orientation by showing not only what the user planned, but also what they have actually completed or spent time on. + +\vspace{2mm} + +To reduce friction further, the app also includes a guided setup and lightweight help flows. These parts of the solution are especially important for first-time users, as they make the main structure and intended study rhythm easier to understand before the app contains much user-created content. + +\subsection{Persistence and Supporting Functionality} + +The solution uses Supabase as the main backend for stored user data such as subjects, assignments, tasks, and recorded session information. This provides persistence beyond a single app instance and gives the app a clearer basis for authenticated, user-specific data. + +\vspace{2mm} + +At the same time, local storage is used for state that is more device- and interaction-specific, such as active-session recovery, study-cycle continuity, and some reminder-related information. This division is useful because not all app state serves the same role. Some data belongs to the durable academic structure, while other data belongs to the immediate behaviour of the app on the device. + +\vspace{2mm} + +The solution also includes local assignment reminders through notifications. This extends the application beyond passive planning by helping users notice approaching deadlines without requiring a more complex push-notification infrastructure. +\clearpage + +\subsection{Why This Solution Fits the Product Goal} + +The final solution fits the goals of the project because it remains focused on a small set of connected features rather than trying to become a broad productivity platform. Planning, sprint starts, breaks, reminders, and progress tracking all support the same main objective: helping students begin meaningful study work with less friction and maintain that work through a clearer rhythm of effort and recovery. + +\vspace{2mm} + +In that sense, the main strength of Study Sprint is not the quantity of features, but the connection between them. A timer alone does not help the user decide what to study, and a planner alone does not help the user begin. The solution developed here is intended to bridge that gap in a lightweight and student-orientated way. + diff --git a/AppDev/texFiles/summary.tex b/AppDev/texFiles/summary.tex new file mode 100644 index 0000000..1408808 --- /dev/null +++ b/AppDev/texFiles/summary.tex @@ -0,0 +1 @@ +\section*{Summary} \ No newline at end of file diff --git a/AppDev/texFiles/testing.tex b/AppDev/texFiles/testing.tex new file mode 100644 index 0000000..53f79cd --- /dev/null +++ b/AppDev/texFiles/testing.tex @@ -0,0 +1,96 @@ +\section{Testing} + +For the testing section of this project, the group focused mostly on creating tests that verify CRUD behaviour of subjects, assignments and tasks + an auth guard test. The reason that these specific tests were chosen is because they are core to the requirements while also being relatively obvious on how they should be set up. + +\vspace{2mm} + +An important note for all of these tests is that the tests should not actually interact with elements like \texttt{expo-router}, \texttt{asyncStorage}, \texttt{expo-notifications} or API's like \texttt{supabase}. Instead, they should be mocked/simulated using \texttt{jest.mock}. +% forklare hvorfor de mockes, og ikke tester direkte med UI? + + + +\subsection{Subject Tests} + +\subsubsection{Create Subject Test} + +For the Create Subject test, the goal was to verify that a new subject can be created through the creation branch of the \texttt{handleSubmit} function in \texttt{upsertSubject.tsx}. Since this component normally relies on \texttt{supabase} and \texttt{expo-router}, these have to be mocked using \texttt{jest.mock}. + +\vspace{2mm} + +The test mocks \texttt{supabase.auth.getUser} so that a fake authenticated user exists for the test. This is important because the row level policy implemented in supabase for creating subjects requires authentication, meaning the test needs to simulate a logged in user. The supabase insert chain is also mocked, meaning one call to \texttt{insert}, one to \texttt{select}, and one to \texttt{single}. With this chain the test can simulate the supabase command used in the component. + +\vspace{2mm} + +For the actual test logic, the test starts by mocking a resolved value for \texttt{single}. This represents a successful database response after creating the subject. The test then renders the actual \texttt{UpsertSubject} component. Then it fills in the title field to pass the requirement that title must not be empty and presses the submit button. At this point it waits for asynchronous logic to finish. + +\vspace{2mm} + +Finally, the test defines its expectations. It expects \texttt{supabase.from} to have been called with \texttt{subjects}, which confirms that the correct table was targeted. Then it expects the mocked \texttt{insert} to have been called with an object containing the subject title and authenticated user id. Next, it expects the mocked \texttt{select} and \texttt{single} to have been called, completing the insert chain. Finally, it expects \texttt{router.back}, which confirms that the user would be routed back upon subject creation. If all these expectations pass, the test passes. + + + +\subsubsection{Update Subject Test} + +For the Update Subject test, the goal was to verify that an already existing subject can be updated through the update branch of the \texttt{handleSubmit} function in \texttt{upsertSubject.tsx}. Since this component normally relies on \texttt{supabase} and \texttt{expo-router}, these have to be mocked using \texttt{jest.mock}. + +\vspace{2mm} + +The test mocks \texttt{supabase.auth.getUser} so that a fake authenticated user exists for the test. This is important because the row level policy implemented in supabase for updating subjects requires authentication, meaning the test needs to simulate a logged in user. The test also mocks \texttt{useLocalSearchParams} so that the component receives an existing subject id. This makes the component behave as if it is updating an existing subject rather than creating a new one. The supabase update and select chains are also mocked. For update this means one call to \texttt{update}, and one to \texttt{eq} and for select this means one call to \texttt{select}, one to \texttt{eq} and one to \texttt{single}. With these chains the test can simulate the supabase commands used in the component. + +\vspace{2mm} + +For the actual test logic, the test starts by mocking a resolved value for \texttt{single}. This represents a successful database response after selecting the subject. It also mocks a resolved value for the update chain \texttt{eq}. This represents no errors upon submitting the update. The test then renders the actual \texttt{UpsertSubject} component. Then it verifies that the title field is filled in to pass the requirement that title must not be empty and presses the submit button. At this point it waits for asynchronous logic to finish. + +\vspace{2mm} + +Finally, the test defines its expectations. It expects \texttt{supabase.from} to have been called with \texttt{subjects}, which confirms that the correct table was targeted. Then it expects the mocked \texttt{select} to have been called. After that it expects the mocked \texttt{update} to have been called with an object containing the subject title and authenticated user id. Next, it expects the mocked update chain \texttt{eq} to have been called with a subject id, completing the update chain. Finally, it expects \texttt{router.back}, which confirms that the user would be routed back upon the subject update. If all these expectations pass, the test passes. + + + +\subsubsection{Delete Subject Test} + +. + + + +\subsection{Assignment Tests} + +\subsubsection{Create Assignment Test} + +. + + + +\subsubsection{Update Assignment Test} + +. + + + +\subsubsection{Delete Assignment Test} + +. + + + +\subsection{Task Tests} + +\subsubsection{Create Task Test} + +. + + + +\subsubsection{Update Task Test} + +. + + + +\subsubsection{Delete Task Test} + +. + + + +\subsection{Auth Guard Test} diff --git a/MA179/Kræsjkurs-Delprøve-5.pdf b/MA179/Kræsjkurs-Delprøve-5.pdf new file mode 100644 index 0000000..e9a6bbd Binary files /dev/null and b/MA179/Kræsjkurs-Delprøve-5.pdf differ diff --git a/MA179/Linear Algebra and Its Applications 5th Edition.pdf b/MA179/Linear Algebra and Its Applications 5th Edition.pdf new file mode 100644 index 0000000..5267275 Binary files /dev/null and b/MA179/Linear Algebra and Its Applications 5th Edition.pdf differ diff --git a/MA179/Ma179-eksamen-H20-ml.pdf b/MA179/Ma179-eksamen-H20-ml.pdf new file mode 100644 index 0000000..626fd77 Binary files /dev/null and b/MA179/Ma179-eksamen-H20-ml.pdf differ diff --git a/MA179/Ma179-eksamen-H21-mL.pdf b/MA179/Ma179-eksamen-H21-mL.pdf new file mode 100644 index 0000000..1ca5bc8 Binary files /dev/null and b/MA179/Ma179-eksamen-H21-mL.pdf differ diff --git a/MA179/Ma179-eksamen-V20-ml.pdf b/MA179/Ma179-eksamen-V20-ml.pdf new file mode 100644 index 0000000..d6eb9c6 Binary files /dev/null and b/MA179/Ma179-eksamen-V20-ml.pdf differ diff --git a/MA179/Ma179-eksamen-V21-mL.pdf b/MA179/Ma179-eksamen-V21-mL.pdf new file mode 100644 index 0000000..30697af Binary files /dev/null and b/MA179/Ma179-eksamen-V21-mL.pdf differ diff --git a/MA179/Oppgaver-lsn.pdf b/MA179/Oppgaver-lsn.pdf new file mode 100644 index 0000000..26d5f0b Binary files /dev/null and b/MA179/Oppgaver-lsn.pdf differ diff --git a/MA179/Oppgaver.pdf b/MA179/Oppgaver.pdf new file mode 100644 index 0000000..23bfe66 Binary files /dev/null and b/MA179/Oppgaver.pdf differ diff --git a/MA179/calculus-a-complete-course-10_compress.pdf b/MA179/calculus-a-complete-course-10_compress.pdf new file mode 100644 index 0000000..39bb17a --- /dev/null +++ b/MA179/calculus-a-complete-course-10_compress.pdf @@ -0,0 +1,130890 @@ +%PDF-1.4 % +13337 0 obj <> endobj xref 13337 1436 0000000016 00000 n +0000092360 00000 n +0000093085 00000 n +0000093133 00000 n +0000093270 00000 n +0000093428 00000 n +0000093586 00000 n +0000093744 00000 n +0000094273 00000 n +0000095482 00000 n +0000095803 00000 n +0000095877 00000 n +0000095967 00000 n +0000097553 00000 n +0000098763 00000 n +0000098855 00000 n +0000098930 00000 n +0000099046 00000 n +0000099083 00000 n +0000099163 00000 n +0000099219 00000 n +0000128864 00000 n +0000129196 00000 n +0000129268 00000 n +0000129374 00000 n +0000129467 00000 n +0000190711 00000 n +0000192806 00000 n +0000194134 00000 n +0000195191 00000 n +0000195506 00000 n +0000195861 00000 n +0000258847 00000 n +0000260950 00000 n +0000262278 00000 n +0000270735 00000 n +0000270778 00000 n +0000276068 00000 n +0000276111 00000 n +0000277074 00000 n +0000277117 00000 n +0000287322 00000 n +0000287365 00000 n +0000297231 00000 n +0000297274 00000 n +0000297354 00000 n +0000297470 00000 n +0000297807 00000 n +0000297887 00000 n +0000298014 00000 n +0000298285 00000 n +0000300189 00000 n +0000370502 00000 n +0001564640 00000 n +0001564704 00000 n +0001564784 00000 n +0001564865 00000 n +0001564958 00000 n +0001565006 00000 n +0001565142 00000 n +0001565189 00000 n +0001565266 00000 n +0001565343 00000 n +0001565507 00000 n +0001565554 00000 n +0001565639 00000 n +0001565726 00000 n +0001565867 00000 n +0001565914 00000 n +0001566055 00000 n +0001566208 00000 n +0001566379 00000 n +0001566426 00000 n +0001566567 00000 n +0001566709 00000 n +0001566874 00000 n +0001566921 00000 n +0001567036 00000 n +0001567187 00000 n +0001567361 00000 n +0001567408 00000 n +0001567548 00000 n +0001567700 00000 n +0001567849 00000 n +0001567896 00000 n +0001568046 00000 n +0001568200 00000 n +0001568347 00000 n +0001568394 00000 n +0001568538 00000 n +0001568694 00000 n +0001568848 00000 n +0001568895 00000 n +0001569031 00000 n +0001569185 00000 n +0001569354 00000 n +0001569401 00000 n +0001569535 00000 n +0001569710 00000 n +0001569867 00000 n +0001569914 00000 n +0001570064 00000 n +0001570235 00000 n +0001570396 00000 n +0001570443 00000 n +0001570595 00000 n +0001570748 00000 n +0001570925 00000 n +0001570972 00000 n +0001571127 00000 n +0001571282 00000 n +0001571458 00000 n +0001571505 00000 n +0001571662 00000 n +0001571828 00000 n +0001571996 00000 n +0001572043 00000 n +0001572187 00000 n +0001572320 00000 n +0001572496 00000 n +0001572543 00000 n +0001572668 00000 n +0001572834 00000 n +0001572994 00000 n +0001573041 00000 n +0001573199 00000 n +0001573352 00000 n +0001573510 00000 n +0001573557 00000 n +0001573696 00000 n +0001573855 00000 n +0001573999 00000 n +0001574046 00000 n +0001574188 00000 n +0001574329 00000 n +0001574498 00000 n +0001574545 00000 n +0001574677 00000 n +0001574844 00000 n +0001575001 00000 n +0001575048 00000 n +0001575184 00000 n +0001575353 00000 n +0001575501 00000 n +0001575548 00000 n +0001575697 00000 n +0001575842 00000 n +0001575996 00000 n +0001576043 00000 n +0001576205 00000 n +0001576354 00000 n +0001576500 00000 n +0001576547 00000 n +0001576696 00000 n +0001576842 00000 n +0001576950 00000 n +0001576997 00000 n +0001577103 00000 n +0001577150 00000 n +0001577258 00000 n +0001577305 00000 n +0001577410 00000 n +0001577457 00000 n +0001577555 00000 n +0001577602 00000 n +0001577701 00000 n +0001577746 00000 n +0001577847 00000 n +0001577892 00000 n +0001577997 00000 n +0001578042 00000 n +0001578143 00000 n +0001578188 00000 n +0001578298 00000 n +0001578342 00000 n +0001578389 00000 n +0001578487 00000 n +0001578582 00000 n +0001578750 00000 n +0001578797 00000 n +0001578898 00000 n +0001578998 00000 n +0001579173 00000 n +0001579220 00000 n +0001579349 00000 n +0001579452 00000 n +0001579612 00000 n +0001579659 00000 n +0001579756 00000 n +0001579874 00000 n +0001580037 00000 n +0001580084 00000 n +0001580177 00000 n +0001580276 00000 n +0001580444 00000 n +0001580491 00000 n +0001580578 00000 n +0001580672 00000 n +0001580719 00000 n +0001580824 00000 n +0001580871 00000 n +0001580968 00000 n +0001581015 00000 n +0001581130 00000 n +0001581177 00000 n +0001581224 00000 n +0001581271 00000 n +0001581378 00000 n +0001581425 00000 n +0001581531 00000 n +0001581578 00000 n +0001581703 00000 n +0001581750 00000 n +0001581863 00000 n +0001581910 00000 n +0001581957 00000 n +0001582004 00000 n +0001582124 00000 n +0001582171 00000 n +0001582310 00000 n +0001582357 00000 n +0001582467 00000 n +0001582514 00000 n +0001582561 00000 n +0001582608 00000 n +0001582718 00000 n +0001582765 00000 n +0001582812 00000 n +0001582859 00000 n +0001582992 00000 n +0001583039 00000 n +0001583086 00000 n +0001583133 00000 n +0001583242 00000 n +0001583289 00000 n +0001583409 00000 n +0001583456 00000 n +0001583568 00000 n +0001583615 00000 n +0001583725 00000 n +0001583772 00000 n +0001583819 00000 n +0001583866 00000 n +0001583951 00000 n +0001584079 00000 n +0001584126 00000 n +0001584235 00000 n +0001584282 00000 n +0001584329 00000 n +0001584376 00000 n +0001584499 00000 n +0001584589 00000 n +0001584733 00000 n +0001584780 00000 n +0001584877 00000 n +0001584979 00000 n +0001585151 00000 n +0001585198 00000 n +0001585292 00000 n +0001585399 00000 n +0001585552 00000 n +0001585599 00000 n +0001585691 00000 n +0001585786 00000 n +0001585833 00000 n +0001585952 00000 n +0001585999 00000 n +0001586046 00000 n +0001586093 00000 n +0001586199 00000 n +0001586246 00000 n +0001586378 00000 n +0001586425 00000 n +0001586472 00000 n +0001586519 00000 n +0001586658 00000 n +0001586705 00000 n +0001586847 00000 n +0001586894 00000 n +0001587023 00000 n +0001587070 00000 n +0001587186 00000 n +0001587233 00000 n +0001587280 00000 n +0001587327 00000 n +0001587439 00000 n +0001587486 00000 n +0001587533 00000 n +0001587580 00000 n +0001587699 00000 n +0001587795 00000 n +0001587842 00000 n +0001587963 00000 n +0001588010 00000 n +0001588057 00000 n +0001588104 00000 n +0001588198 00000 n +0001588288 00000 n +0001588465 00000 n +0001588512 00000 n +0001588603 00000 n +0001588728 00000 n +0001588886 00000 n +0001588933 00000 n +0001589033 00000 n +0001589131 00000 n +0001589287 00000 n +0001589334 00000 n +0001589445 00000 n +0001589552 00000 n +0001589721 00000 n +0001589768 00000 n +0001589871 00000 n +0001589971 00000 n +0001590090 00000 n +0001590137 00000 n +0001590309 00000 n +0001590356 00000 n +0001590451 00000 n +0001590579 00000 n +0001590727 00000 n +0001590774 00000 n +0001590880 00000 n +0001590993 00000 n +0001591148 00000 n +0001591195 00000 n +0001591298 00000 n +0001591391 00000 n +0001591539 00000 n +0001591586 00000 n +0001591688 00000 n +0001591812 00000 n +0001591859 00000 n +0001591963 00000 n +0001592010 00000 n +0001592117 00000 n +0001592164 00000 n +0001592211 00000 n +0001592258 00000 n +0001592368 00000 n +0001592415 00000 n +0001592522 00000 n +0001592569 00000 n +0001592616 00000 n +0001592663 00000 n +0001592807 00000 n +0001592854 00000 n +0001592901 00000 n +0001592948 00000 n +0001593073 00000 n +0001593120 00000 n +0001593167 00000 n +0001593214 00000 n +0001593326 00000 n +0001593373 00000 n +0001593505 00000 n +0001593552 00000 n +0001593599 00000 n +0001593646 00000 n +0001593693 00000 n +0001593740 00000 n +0001593787 00000 n +0001593834 00000 n +0001593948 00000 n +0001593995 00000 n +0001594042 00000 n +0001594089 00000 n +0001594201 00000 n +0001594248 00000 n +0001594351 00000 n +0001594398 00000 n +0001594445 00000 n +0001594492 00000 n +0001594560 00000 n +0001594607 00000 n +0001594654 00000 n +0001594767 00000 n +0001594857 00000 n +0001595011 00000 n +0001595058 00000 n +0001595147 00000 n +0001595316 00000 n +0001595363 00000 n +0001595479 00000 n +0001595592 00000 n +0001595742 00000 n +0001595789 00000 n +0001595906 00000 n +0001595997 00000 n +0001596178 00000 n +0001596225 00000 n +0001596322 00000 n +0001596425 00000 n +0001596596 00000 n +0001596643 00000 n +0001596731 00000 n +0001596817 00000 n +0001596864 00000 n +0001596911 00000 n +0001596958 00000 n +0001597084 00000 n +0001597131 00000 n +0001597246 00000 n +0001597293 00000 n +0001597340 00000 n +0001597387 00000 n +0001597501 00000 n +0001597548 00000 n +0001597674 00000 n +0001597721 00000 n +0001597768 00000 n +0001597815 00000 n +0001597952 00000 n +0001597999 00000 n +0001598046 00000 n +0001598093 00000 n +0001598140 00000 n +0001598253 00000 n +0001598300 00000 n +0001598413 00000 n +0001598460 00000 n +0001598507 00000 n +0001598554 00000 n +0001598664 00000 n +0001598772 00000 n +0001598819 00000 n +0001598866 00000 n +0001598913 00000 n +0001599016 00000 n +0001599106 00000 n +0001599259 00000 n +0001599306 00000 n +0001599398 00000 n +0001599514 00000 n +0001599669 00000 n +0001599716 00000 n +0001599825 00000 n +0001599915 00000 n +0001600071 00000 n +0001600118 00000 n +0001600223 00000 n +0001600380 00000 n +0001600427 00000 n +0001600543 00000 n +0001600646 00000 n +0001600813 00000 n +0001600860 00000 n +0001600946 00000 n +0001601056 00000 n +0001601215 00000 n +0001601262 00000 n +0001601349 00000 n +0001601497 00000 n +0001601544 00000 n +0001601646 00000 n +0001601771 00000 n +0001601924 00000 n +0001601971 00000 n +0001602068 00000 n +0001602228 00000 n +0001602275 00000 n +0001602390 00000 n +0001602482 00000 n +0001602529 00000 n +0001602635 00000 n +0001602682 00000 n +0001602729 00000 n +0001602776 00000 n +0001602823 00000 n +0001602939 00000 n +0001602986 00000 n +0001603108 00000 n +0001603155 00000 n +0001603293 00000 n +0001603340 00000 n +0001603387 00000 n +0001603434 00000 n +0001603481 00000 n +0001603528 00000 n +0001603575 00000 n +0001603711 00000 n +0001603758 00000 n +0001603902 00000 n +0001603949 00000 n +0001603996 00000 n +0001604043 00000 n +0001604090 00000 n +0001604137 00000 n +0001604184 00000 n +0001604289 00000 n +0001604336 00000 n +0001604383 00000 n +0001604430 00000 n +0001604563 00000 n +0001604610 00000 n +0001604726 00000 n +0001604773 00000 n +0001604820 00000 n +0001604867 00000 n +0001604965 00000 n +0001605012 00000 n +0001605059 00000 n +0001605159 00000 n +0001605249 00000 n +0001605409 00000 n +0001605456 00000 n +0001605540 00000 n +0001605670 00000 n +0001605717 00000 n +0001605886 00000 n +0001605933 00000 n +0001606043 00000 n +0001606171 00000 n +0001606326 00000 n +0001606373 00000 n +0001606476 00000 n +0001606572 00000 n +0001606729 00000 n +0001606776 00000 n +0001606874 00000 n +0001606972 00000 n +0001607019 00000 n +0001607066 00000 n +0001607113 00000 n +0001607225 00000 n +0001607272 00000 n +0001607319 00000 n +0001607366 00000 n +0001607413 00000 n +0001607460 00000 n +0001607507 00000 n +0001607554 00000 n +0001607601 00000 n +0001607677 00000 n +0001607724 00000 n +0001607771 00000 n +0001607879 00000 n +0001607969 00000 n +0001608078 00000 n +0001608125 00000 n +0001608291 00000 n +0001608338 00000 n +0001608432 00000 n +0001608523 00000 n +0001608675 00000 n +0001608722 00000 n +0001608826 00000 n +0001608939 00000 n +0001609111 00000 n +0001609158 00000 n +0001609273 00000 n +0001609389 00000 n +0001609544 00000 n +0001609591 00000 n +0001609706 00000 n +0001609838 00000 n +0001610003 00000 n +0001610050 00000 n +0001610159 00000 n +0001610269 00000 n +0001610316 00000 n +0001610428 00000 n +0001610475 00000 n +0001610583 00000 n +0001610630 00000 n +0001610677 00000 n +0001610724 00000 n +0001610842 00000 n +0001610889 00000 n +0001611012 00000 n +0001611059 00000 n +0001611106 00000 n +0001611153 00000 n +0001611265 00000 n +0001611312 00000 n +0001611430 00000 n +0001611477 00000 n +0001611524 00000 n +0001611571 00000 n +0001611691 00000 n +0001611738 00000 n +0001611785 00000 n +0001611832 00000 n +0001611940 00000 n +0001611987 00000 n +0001612034 00000 n +0001612081 00000 n +0001612185 00000 n +0001612232 00000 n +0001612361 00000 n +0001612408 00000 n +0001612518 00000 n +0001612565 00000 n +0001612678 00000 n +0001612725 00000 n +0001612772 00000 n +0001612819 00000 n +0001612898 00000 n +0001612945 00000 n +0001612992 00000 n +0001613087 00000 n +0001613177 00000 n +0001613322 00000 n +0001613369 00000 n +0001613470 00000 n +0001613557 00000 n +0001613737 00000 n +0001613784 00000 n +0001613901 00000 n +0001614024 00000 n +0001614185 00000 n +0001614232 00000 n +0001614328 00000 n +0001614439 00000 n +0001614582 00000 n +0001614629 00000 n +0001614706 00000 n +0001614873 00000 n +0001614920 00000 n +0001615012 00000 n +0001615123 00000 n +0001615284 00000 n +0001615331 00000 n +0001615417 00000 n +0001615524 00000 n +0001615642 00000 n +0001615689 00000 n +0001615736 00000 n +0001615868 00000 n +0001615915 00000 n +0001615962 00000 n +0001616009 00000 n +0001616127 00000 n +0001616174 00000 n +0001616221 00000 n +0001616268 00000 n +0001616315 00000 n +0001616410 00000 n +0001616457 00000 n +0001616504 00000 n +0001616551 00000 n +0001616598 00000 n +0001616645 00000 n +0001616759 00000 n +0001616806 00000 n +0001616924 00000 n +0001616971 00000 n +0001617113 00000 n +0001617160 00000 n +0001617207 00000 n +0001617254 00000 n +0001617373 00000 n +0001617420 00000 n +0001617467 00000 n +0001617514 00000 n +0001617608 00000 n +0001617702 00000 n +0001617749 00000 n +0001617860 00000 n +0001617907 00000 n +0001617954 00000 n +0001618001 00000 n +0001618106 00000 n +0001618196 00000 n +0001618364 00000 n +0001618411 00000 n +0001618504 00000 n +0001618592 00000 n +0001618769 00000 n +0001618816 00000 n +0001618921 00000 n +0001619031 00000 n +0001619206 00000 n +0001619253 00000 n +0001619360 00000 n +0001619463 00000 n +0001619614 00000 n +0001619661 00000 n +0001619778 00000 n +0001619883 00000 n +0001619930 00000 n +0001619977 00000 n +0001620024 00000 n +0001620071 00000 n +0001620118 00000 n +0001620165 00000 n +0001620212 00000 n +0001620332 00000 n +0001620379 00000 n +0001620426 00000 n +0001620473 00000 n +0001620592 00000 n +0001620639 00000 n +0001620686 00000 n +0001620733 00000 n +0001620818 00000 n +0001620920 00000 n +0001620967 00000 n +0001621091 00000 n +0001621138 00000 n +0001621239 00000 n +0001621286 00000 n +0001621406 00000 n +0001621453 00000 n +0001621576 00000 n +0001621623 00000 n +0001621722 00000 n +0001621769 00000 n +0001621892 00000 n +0001621939 00000 n +0001621986 00000 n +0001622033 00000 n +0001622127 00000 n +0001622217 00000 n +0001622391 00000 n +0001622438 00000 n +0001622533 00000 n +0001622632 00000 n +0001622809 00000 n +0001622856 00000 n +0001622969 00000 n +0001623064 00000 n +0001623225 00000 n +0001623272 00000 n +0001623394 00000 n +0001623496 00000 n +0001623642 00000 n +0001623689 00000 n +0001623801 00000 n +0001623895 00000 n +0001624065 00000 n +0001624112 00000 n +0001624215 00000 n +0001624324 00000 n +0001624495 00000 n +0001624542 00000 n +0001624635 00000 n +0001624765 00000 n +0001624914 00000 n +0001624961 00000 n +0001625053 00000 n +0001625155 00000 n +0001625202 00000 n +0001625331 00000 n +0001625378 00000 n +0001625425 00000 n +0001625472 00000 n +0001625587 00000 n +0001625634 00000 n +0001625741 00000 n +0001625788 00000 n +0001625932 00000 n +0001625979 00000 n +0001626026 00000 n +0001626073 00000 n +0001626120 00000 n +0001626167 00000 n +0001626305 00000 n +0001626352 00000 n +0001626399 00000 n +0001626446 00000 n +0001626570 00000 n +0001626617 00000 n +0001626664 00000 n +0001626711 00000 n +0001626832 00000 n +0001626879 00000 n +0001626926 00000 n +0001626973 00000 n +0001627020 00000 n +0001627067 00000 n +0001627188 00000 n +0001627235 00000 n +0001627355 00000 n +0001627402 00000 n +0001627507 00000 n +0001627554 00000 n +0001627601 00000 n +0001627648 00000 n +0001627733 00000 n +0001627780 00000 n +0001627827 00000 n +0001627910 00000 n +0001628000 00000 n +0001628158 00000 n +0001628205 00000 n +0001628289 00000 n +0001628411 00000 n +0001628583 00000 n +0001628630 00000 n +0001628729 00000 n +0001628826 00000 n +0001628938 00000 n +0001628985 00000 n +0001629136 00000 n +0001629183 00000 n +0001629276 00000 n +0001629361 00000 n +0001629524 00000 n +0001629571 00000 n +0001629659 00000 n +0001629765 00000 n +0001629907 00000 n +0001629954 00000 n +0001630048 00000 n +0001630142 00000 n +0001630189 00000 n +0001630311 00000 n +0001630358 00000 n +0001630474 00000 n +0001630521 00000 n +0001630568 00000 n +0001630615 00000 n +0001630740 00000 n +0001630787 00000 n +0001630834 00000 n +0001630881 00000 n +0001630988 00000 n +0001631035 00000 n +0001631082 00000 n +0001631129 00000 n +0001631176 00000 n +0001631223 00000 n +0001631330 00000 n +0001631377 00000 n +0001631490 00000 n +0001631537 00000 n +0001631660 00000 n +0001631707 00000 n +0001631754 00000 n +0001631801 00000 n +0001631920 00000 n +0001631967 00000 n +0001632074 00000 n +0001632121 00000 n +0001632220 00000 n +0001632267 00000 n +0001632314 00000 n +0001632361 00000 n +0001632454 00000 n +0001632580 00000 n +0001632627 00000 n +0001632674 00000 n +0001632721 00000 n +0001632843 00000 n +0001632959 00000 n +0001633006 00000 n +0001633143 00000 n +0001633190 00000 n +0001633318 00000 n +0001633365 00000 n +0001633486 00000 n +0001633533 00000 n +0001633664 00000 n +0001633711 00000 n +0001633836 00000 n +0001633883 00000 n +0001633930 00000 n +0001633977 00000 n +0001634092 00000 n +0001634226 00000 n +0001634273 00000 n +0001634390 00000 n +0001634437 00000 n +0001634565 00000 n +0001634612 00000 n +0001634718 00000 n +0001634765 00000 n +0001634878 00000 n +0001634925 00000 n +0001635048 00000 n +0001635095 00000 n +0001635205 00000 n +0001635252 00000 n +0001635299 00000 n +0001635346 00000 n +0001635451 00000 n +0001635541 00000 n +0001635726 00000 n +0001635773 00000 n +0001635883 00000 n +0001635977 00000 n +0001636152 00000 n +0001636199 00000 n +0001636298 00000 n +0001636422 00000 n +0001636584 00000 n +0001636631 00000 n +0001636762 00000 n +0001636868 00000 n +0001637046 00000 n +0001637093 00000 n +0001637198 00000 n +0001637313 00000 n +0001637360 00000 n +0001637466 00000 n +0001637513 00000 n +0001637560 00000 n +0001637607 00000 n +0001637721 00000 n +0001637768 00000 n +0001637869 00000 n +0001637916 00000 n +0001637963 00000 n +0001638010 00000 n +0001638130 00000 n +0001638177 00000 n +0001638224 00000 n +0001638271 00000 n +0001638404 00000 n +0001638451 00000 n +0001638550 00000 n +0001638597 00000 n +0001638644 00000 n +0001638691 00000 n +0001638804 00000 n +0001638851 00000 n +0001638985 00000 n +0001639032 00000 n +0001639161 00000 n +0001639208 00000 n +0001639344 00000 n +0001639391 00000 n +0001639438 00000 n +0001639485 00000 n +0001639585 00000 n +0001639632 00000 n +0001639679 00000 n +0001639787 00000 n +0001639877 00000 n +0001640030 00000 n +0001640077 00000 n +0001640173 00000 n +0001640278 00000 n +0001640450 00000 n +0001640497 00000 n +0001640596 00000 n +0001640713 00000 n +0001640907 00000 n +0001640954 00000 n +0001641053 00000 n +0001641171 00000 n +0001641320 00000 n +0001641367 00000 n +0001641464 00000 n +0001641564 00000 n +0001641723 00000 n +0001641770 00000 n +0001641861 00000 n +0001642015 00000 n +0001642062 00000 n +0001642169 00000 n +0001642300 00000 n +0001642417 00000 n +0001642464 00000 n +0001642511 00000 n +0001642558 00000 n +0001642605 00000 n +0001642652 00000 n +0001642699 00000 n +0001642746 00000 n +0001642866 00000 n +0001642913 00000 n +0001643037 00000 n +0001643084 00000 n +0001643188 00000 n +0001643235 00000 n +0001643282 00000 n +0001643329 00000 n +0001643456 00000 n +0001643503 00000 n +0001643550 00000 n +0001643597 00000 n +0001643709 00000 n +0001643756 00000 n +0001643891 00000 n +0001643938 00000 n +0001643985 00000 n +0001644032 00000 n +0001644079 00000 n +0001644126 00000 n +0001644208 00000 n +0001644304 00000 n +0001644351 00000 n +0001644454 00000 n +0001644501 00000 n +0001644548 00000 n +0001644595 00000 n +0001644688 00000 n +0001644778 00000 n +0001644936 00000 n +0001644983 00000 n +0001645087 00000 n +0001645202 00000 n +0001645352 00000 n +0001645399 00000 n +0001645508 00000 n +0001645662 00000 n +0001645709 00000 n +0001645826 00000 n +0001645930 00000 n +0001646092 00000 n +0001646139 00000 n +0001646232 00000 n +0001646361 00000 n +0001646527 00000 n +0001646574 00000 n +0001646700 00000 n +0001646797 00000 n +0001646952 00000 n +0001646999 00000 n +0001647109 00000 n +0001647223 00000 n +0001647415 00000 n +0001647462 00000 n +0001647541 00000 n +0001647588 00000 n +0001647635 00000 n +0001647682 00000 n +0001647729 00000 n +0001647862 00000 n +0001647909 00000 n +0001647956 00000 n +0001648003 00000 n +0001648050 00000 n +0001648097 00000 n +0001648197 00000 n +0001648244 00000 n +0001648291 00000 n +0001648338 00000 n +0001648385 00000 n +0001648432 00000 n +0001648479 00000 n +0001648588 00000 n +0001648635 00000 n +0001648741 00000 n +0001648788 00000 n +0001648835 00000 n +0001648882 00000 n +0001648970 00000 n +0001649017 00000 n +0001649064 00000 n +0001649167 00000 n +0001649257 00000 n +0001649431 00000 n +0001649478 00000 n +0001649577 00000 n +0001649674 00000 n +0001649786 00000 n +0001649833 00000 n +0001650005 00000 n +0001650052 00000 n +0001650152 00000 n +0001650330 00000 n +0001650377 00000 n +0001650493 00000 n +0001650610 00000 n +0001650760 00000 n +0001650807 00000 n +0001650854 00000 n +0001650901 00000 n +0001650948 00000 n +0001650995 00000 n +0001651042 00000 n +0001651089 00000 n +0001651197 00000 n +0001651244 00000 n +0001651362 00000 n +0001651409 00000 n +0001651538 00000 n +0001651585 00000 n +0001651632 00000 n +0001651679 00000 n +0001651797 00000 n +0001651903 00000 n +0001651950 00000 n +0001652074 00000 n +0001652121 00000 n +0001652168 00000 n +0001652215 00000 n +0001652308 00000 n +0001652398 00000 n +0001652563 00000 n +0001652610 00000 n +0001652705 00000 n +0001652816 00000 n +0001652982 00000 n +0001653029 00000 n +0001653143 00000 n +0001653239 00000 n +0001653388 00000 n +0001653435 00000 n +0001653521 00000 n +0001653675 00000 n +0001653722 00000 n +0001653831 00000 n +0001653934 00000 n +0001653981 00000 n +0001654028 00000 n +0001654075 00000 n +0001654122 00000 n +0001654169 00000 n +0001654216 00000 n +0001654335 00000 n +0001654382 00000 n +0001654516 00000 n +0001654563 00000 n +0001654671 00000 n +0001654718 00000 n +0001654827 00000 n +0001654874 00000 n +0001654921 00000 n +0001654968 00000 n +0001655085 00000 n +0001655132 00000 n +0001655266 00000 n +0001655313 00000 n +0001655360 00000 n +0001655407 00000 n +0001655541 00000 n +0001655657 00000 n +0001655704 00000 n +0001655829 00000 n +0001655876 00000 n +0001655923 00000 n +0001655970 00000 n +0001656087 00000 n +0001656177 00000 n +0001656357 00000 n +0001656404 00000 n +0001656494 00000 n +0001656589 00000 n +0001656701 00000 n +0001656748 00000 n +0001656916 00000 n +0001656963 00000 n +0001657058 00000 n +0001657221 00000 n +0001657268 00000 n +0001657367 00000 n +0001657547 00000 n +0001657594 00000 n +0001657698 00000 n +0001657792 00000 n +0001657839 00000 n +0001657886 00000 n +0001657933 00000 n +0001657980 00000 n +0001658027 00000 n +0001658132 00000 n +0001658179 00000 n +0001658284 00000 n +0001658331 00000 n +0001658438 00000 n +0001658485 00000 n +0001658532 00000 n +0001658579 00000 n +0001658727 00000 n +0001658774 00000 n +0001658904 00000 n +0001658951 00000 n +0001658998 00000 n +0001659045 00000 n +0001659153 00000 n +0001659255 00000 n +0001659302 00000 n +0001659426 00000 n +0001659473 00000 n +0001659520 00000 n +0001659567 00000 n +0001659674 00000 n +0001659791 00000 n +0001659976 00000 n +0001660023 00000 n +0001660117 00000 n +0001660240 00000 n +0001660399 00000 n +0001660446 00000 n +0001660538 00000 n +0001660666 00000 n +0001660847 00000 n +0001660894 00000 n +0001660993 00000 n +0001661091 00000 n +0001661233 00000 n +0001661280 00000 n +0001661382 00000 n +0001661481 00000 n +0001661528 00000 n +0001661626 00000 n +0001661673 00000 n +0001661720 00000 n +0001661767 00000 n +0001661887 00000 n +0001661934 00000 n +0001662061 00000 n +0001662108 00000 n +0001662155 00000 n +0001662202 00000 n +0001662314 00000 n +0001662361 00000 n +0001662479 00000 n +0001662526 00000 n +0001662573 00000 n +0001662620 00000 n +0001662745 00000 n +0001662792 00000 n +0001662839 00000 n +0001662886 00000 n +0001662997 00000 n +0001663044 00000 n +0001663091 00000 n +0001663138 00000 n +0001663231 00000 n +0001663278 00000 n +0001663325 00000 n +0001663410 00000 n +0001663500 00000 n +0001663691 00000 n +0001663738 00000 n +0001663860 00000 n +0001663971 00000 n +0001664144 00000 n +0001664191 00000 n +0001664301 00000 n +0001664406 00000 n +0001664585 00000 n +0001664632 00000 n +0001664745 00000 n +0001664838 00000 n +0001665002 00000 n +0001665049 00000 n +0001665144 00000 n +0001665239 00000 n +0001665286 00000 n +0001665392 00000 n +0001665439 00000 n +0001665563 00000 n +0001665610 00000 n +0001665729 00000 n +0001665776 00000 n +0001665823 00000 n +0001665870 00000 n +0001665917 00000 n +0001665964 00000 n +0001666011 00000 n +0001666058 00000 n +0001666105 00000 n +0001666152 00000 n +0001666261 00000 n +0001666308 00000 n +0001666422 00000 n +0001666469 00000 n +0001666516 00000 n +0001666563 00000 n +0001666610 00000 n +0001666709 00000 n +0001666843 00000 n +0001667029 00000 n +0001667076 00000 n +0001667199 00000 n +0001667295 00000 n +0001667433 00000 n +0001667480 00000 n +0001667527 00000 n +0001667652 00000 n +0001667699 00000 n +0001667835 00000 n +0001667882 00000 n +0001667985 00000 n +0001668032 00000 n +0001668176 00000 n +0001668223 00000 n +0001668359 00000 n +0001668406 00000 n +0001668453 00000 n +0001668500 00000 n +0001668620 00000 n +0001668667 00000 n +0001668777 00000 n +0001668824 00000 n +0001668945 00000 n +0001668992 00000 n +0001669108 00000 n +0001669155 00000 n +0001669202 00000 n +0001669249 00000 n +0001669354 00000 n +0001669481 00000 n +0001669528 00000 n +0001669656 00000 n +0001669703 00000 n +0001669750 00000 n +0001669797 00000 n +0001669901 00000 n +0001670015 00000 n +0001670181 00000 n +0001670228 00000 n +0001670326 00000 n +0001670488 00000 n +0001670535 00000 n +0001670614 00000 n +0001670777 00000 n +0001670824 00000 n +0001670919 00000 n +0001671044 00000 n +0001671203 00000 n +0001671250 00000 n +0001671347 00000 n +0001671457 00000 n +0001671504 00000 n +0001671619 00000 n +0001671666 00000 n +0001671779 00000 n +0001671826 00000 n +0001671873 00000 n +0001671920 00000 n +0001672045 00000 n +0001672092 00000 n +0001672203 00000 n +0001672250 00000 n +0001672297 00000 n +0001672344 00000 n +0001672391 00000 n +0001672438 00000 n +0001672555 00000 n +0001672602 00000 n +0001672649 00000 n +0001672696 00000 n +0001672801 00000 n +0001672901 00000 n +0001672948 00000 n +0001673057 00000 n +0001673104 00000 n +0001673238 00000 n +0001673285 00000 n +0001673332 00000 n +0001673379 00000 n +0001673480 00000 n +0001673527 00000 n +0001673629 00000 n +0001673676 00000 n +0001673779 00000 n +0001673826 00000 n +0001673928 00000 n +0001673975 00000 n +0001674076 00000 n +0001674123 00000 n +0001674224 00000 n +0001674271 00000 n +0001674372 00000 n +0001674419 00000 n +0001674520 00000 n +0001674567 00000 n +0001674668 00000 n +0001674715 00000 n +0001674816 00000 n +0001674863 00000 n +0001674964 00000 n +0001675011 00000 n +0001675112 00000 n +0001675159 00000 n +0001675260 00000 n +0001675307 00000 n +0001675408 00000 n +0001675455 00000 n +0001675556 00000 n +0001675603 00000 n +0001675704 00000 n +0001675751 00000 n +0001675851 00000 n +0001675898 00000 n +0001675998 00000 n +0001676045 00000 n +0001676145 00000 n +0001676192 00000 n +0001676292 00000 n +0001676339 00000 n +0001676439 00000 n +0001676486 00000 n +0001676586 00000 n +0001676633 00000 n +0001676733 00000 n +0001676780 00000 n +0001676880 00000 n +0001676927 00000 n +0001677027 00000 n +0001677074 00000 n +0001677121 00000 n +0001677169 00000 n +0001677261 00000 n +0001677309 00000 n +0001677401 00000 n +0001677449 00000 n +0001677541 00000 n +0001677589 00000 n +0001677681 00000 n +0001677729 00000 n +0001677821 00000 n +0001677869 00000 n +0001677961 00000 n +0001678009 00000 n +0001678101 00000 n +0001678149 00000 n +0001678241 00000 n +0001678289 00000 n +0001678381 00000 n +0001678429 00000 n +0001678521 00000 n +0001678569 00000 n +0001678661 00000 n +0001678709 00000 n +0001678801 00000 n +0001678848 00000 n +0001678940 00000 n +0001678987 00000 n +0001679079 00000 n +0001679126 00000 n +0001679218 00000 n +0001679265 00000 n +0001679357 00000 n +0001679404 00000 n +0001679496 00000 n +0001679543 00000 n +0001679635 00000 n +0001679682 00000 n +0001679774 00000 n +0001679821 00000 n +0001679913 00000 n +0001679960 00000 n +0001680052 00000 n +0001680099 00000 n +0001680191 00000 n +0001680238 00000 n +0001680285 00000 n +0000029027 00000 n +trailer <]/Prev 28661509>> startxref 0 %%EOF 14772 0 obj <>stream +h|x{\Te3`6q@A9 DxhFBjpKC5 *"`jhP ` )P +?}P@UR|j`:32`ꢓRFYє`DY~B?(Eu!i]v19+TΔCݢfkG&2-fR$=T$PS'iyJV!OS59UrZhǀS@12hH naP $5B"il@+#mP.9G (­Ձ."^YN{ۑ7FՆ8eAI\8&="u͵ Y. +:ŏ8I@^:o/HCh%] +%:h7J#Hx9!sr:5De ”XTHB@dE}+WZ 5"(#ZƱ7w*C6FV= Fq<;Rs% 4k'5D$ +t`ZDFN$u&p2DPB븬Dpt׳jHD x;cq}&&"_ǕAH œlī%‡d D("${A(JĔH5)85A}c+j?rA-Ϸ`Jk !C:`v5gS7 ⋑NCx+ǃo2qn1q&qDkۜ}9g\^^)];5"C7ۉudp<2.AqNn,xnjf&}H,R+,cj#ۮic"ۆ@$&MF d` +tQx82;bP3}t(Qîڄ +1|:&sQbKc.-ռZrqY*nfrvphCp:UW]*J!_?61:a?قvB+Y Yx%@!g}, +R $T䉬!!K +D| b%Ňs@> 0ATh 7F+"Bi4<}fnyyÉ|2إ F?-'@= Ok~}U4H,kI;`(gMx +|,C\Lr iR dOdff$C#o}[sf]pPLu\VЭ_7"ʿA֏VJ}"F+Em~ρ̜)LTK3g3Sh# gK}dS;BZ-n6p}A3=*t'yXaL>.tQ<(>#?`+"6 Y\P0=IdQ#ǜN$K%:s8.?;@v>f+wO֔-p:֌@6@Q(z1Oť!jݛ:|jrdƱTc1N1z0X42׍$gs Ң +'X ȯ`lt{y`m2YXb[{ ^ 9q8*8Mjw& `f78g# +u{&y. Xn yJLD%`㊫. >]]cI%DFq >j{cZ +N g= دD#&4jdGX& X?p71>AZ7@ D((ݎIHp^WiB;&B׊-н%Q輳ra N9%hF Xc_Bp̻BNDqis$ Y|`?GԊFȯ[3IKj3K&A=NU 5 +3h!otA>HFK$:@^?')Al2 2Cg jHM@$CI*[3@ Њ)/Wdx `88i.']#Saeq0WEFʐM(Xd#i$R+ dX/7ۉWsd2( +m i1Pot2ΟLN܊fZPeA g,DڍR}"8؞U}'7 BoEp5RGxA4 +"=+NA"HǷI6#0JLO(p +Hw`ft=`,]8ᅄ5 +AvdO=>Bs&͂bt٩V!4 jQHX%J;y?HaH9&: +VS. ŏt(qšIrC ̝i .x\׶B 7n˭]EZ'ƼqU; NY<#;S;ByCNwC' /<#2#9E~}/h E,ҶvK6ho:J} >foyeunךW_#Zؒݙ?1˭EӖ+&;EKCn v^:{e֛/"PsaŽ[V=L5;^7s߻tmНKY[j#lQN.8_uPO6l^鍫n +zfdbkm~ʉ(8K9eO{e\kY޻'GTk4|{rO;΋2)>n]GͶw;* ۑ:.7^ܧ?x݆m|(TS룆=5;_/XverPwvɆ~ݗq({_m²nAXn&~Q;+Zq2ͭ#{Ϛ{/,PÚ}i|-2+О:K|+W6Mtp }oĭo5wEUЕc}W80rmI~`^Ӫ>ͽrоm!YG^'{JmpV{_l X1Y͑naC;DĜkE!&~.޷ּ0}֛7v,8КiI"8u^Ck*~tSez}-w)%[^OW6eՕٳ_uS}SѦ*:ծWYG-HXpIE|Ȳo;5ʶ]ڊ8"{ڻq[ 7j_1mpIkSΛms4;w~\iHdv\<UUv1{n)7]8i-"6(-k/m\rmjK%!mnΨǽe@{m=;vmJ'C2$(po'WPrB=O>)]d` D]pHTnH|!5J#U +uk1SPjZMWMUX<H`F¤sSx~[TeExanb4o0wGWF$r4a4{S`#52A \c4=*M$}OJqBI|˨ORgkDZbI^j'ޣ*&㪌7rIVJ_JJETu9Lx'JU|5ss1 +fTinz& UI%2Q _}%DTi1mI !>S[+M ;SqzY<:AtB]F<1$3'4I4Ϊ_o5>ݍ2)hwpAI39o(pѺxiΊ p۟8װG iTO0xvwoBjJȂZbdRb4w쨻-FԑTKZ_^Ĥ7݆busa0 FLw6)7օ$|5KXt ^eTj(%Xc].UX".麘c8S~9Z˄˲"n^ M +P>谐\P[/`œh^skd:w1N; }<օ,)<aiPh<xK>UwRƣr$]-ǠN۳QN'IÇ'mMEķ%eMc /YAjS@mfTAp;tm:rP CÖ0mQps)iށ3ӂ!񙴩CCXh3O<aGa=Q#muMm'-K%UyQ4l^O4*MY!\]M:Xcj-ZZXPH: H1r>oKORF + MƍfH&u +Ng--q 0z碠\7~f@xqΒ)Fߜ˘a2)odz:Z״xI 2}[P#8+M+VM{F`SDTFJ_v>u*ڍhy|gvHzK? l( ۉ1S9fC$7OK#~AC\ơ(|?lDtP#H?uWkϳ:f(Bk^^V HufzpSto7e'VeIVNe&n7[`e+~jH.$/U E 1]|KR =]WԐLj!4ىC{YԩMzcԚ1$y+)?Kd)$O+v(+Jº:soc(gzF m]gލ3tTCso +(a1sAHfDtH _vk@[k,d+f@TU#aܾb.,XѦˢN>C 4) ت'YP)(P 6{'?fcU#e*M.i)w?1~FKe;]1`D`o5NIGOjˉ3D8*.IhmsE;cm,'dY`FuLO'32R9b />o,J8E]fl$H)9~U?Jnϒ]Xa\+"n{_a5 AF]>puwwWG+ZI]!ߝjyϠy)3@,_fS⣾뻮/ދĎ0fǼB< +xC}lBT֗Ȩ /SS*jcoR/>Id p*lw^_$_IWỎ1ڨY O[$/)ӼSK_8CٛXkI[;0,>|GZ%+Ni'S\ߤo}3]{oo&yT58Ԋ Q[ Mp'_r׋x+q"|}2 bfi̐Mc }c}}SpP?.u߳GU!8$KCwR TԂ!#ԂqJƥ,۱/6Y fl*3tj( ߊuCiU8nY$oñfŝ{>A1]1A%Y(Duvo?-y˨)}3JmYo_l3kߑfT3R/' EĿ| *j@ԺUcs脣yH) Ѽ-o -gzLUAG(bOY1vN'U┊@)O [ 5JRuסVJPD%p^U^[bLBkw.NEЍi%mDX]0!);p̔}_$#cpGw.(-~ꂺm+ȼok$, *(´PiCj;͆cQn5SnA3*k0!7Q?)AL:-zI`A0b؋fjJ:_KBɨf38'2E,\LuH%>)#JΘԩl>+z]S\Q=b8bJRm*>h'd92ק{w ¥E/Ux-~/* +ND7L[EqYϘc=-fiJl=a#%힫OXp2P_@g+|RSC5Slcg +ny?c92kN%69Ŝ'o9A oN͡42\'s97hߑVs x9B#ol}y62ؼn " .)ML%Atuhif2&$$& "cR IQZ{oqgY}Z[}vG5oXxY-{}#ak̙*(L>?5Ϊ<{P(6 +[+yZS҂mb`.0>75SѮ%f*m gk"4-1 +EHI2(0FT )tcQHn)TG-F̼g!zOȌLM5/5+E@sHkdFm$]ۥg+x6I¡ld`̤XOrX- +!W/r68U^n[aÈ){H*Ī *y(%D0ybઓ,kԡgʍ xQMrg괚.=N$13Um+ӓH;yD8g"Y. ?D8D &g2|1j(YL*6)eGktOjaUOk>3OI@r vzkPj@#&+T%Уt.v~u7.0UH{k? ћgijRBǚVp-/9%Zl6TZ>rړ%a&OI}q|ȤAj*eQZ(;DMpjHJrhJ"i5躖t*iK~;+#sx63Pb8[Ek<9XjR5hHZNNk<%XyZ01($%p,A#\$?a"Z}aIIf܎-9!%xx#! +(o} = TaLE\@U9q@3bbwdG)!Tp ,.'>U<)1 s4v2tìѭs +OJ&9fֱI̡LhiwV %ԌRSPXD TagTpF.#<ƿt7R3Vd*:BM<"_-ˎ,~{0A^F[i;&s %+m-D:UFB㙺Ău&58'v5)A2 mpO. fҦ̟-tÊ7WCXgAn,vvNHFJy)#2£ #*) J 2p_ăfVgͬcX8C}Ԋ+l7(sWq*ѕ;! b5ZZ912+JB[l#L39],ƬgXh9#6vc!Bb8iB$R:Kms#œF$R¶N,6ںrSA4`}U"/x>MA| +z*r{ AÏNtJ +, MA\Nsc~ehE~bCrR\a%cOJ+;m3"ؗ1{́J2yFRyOxX^@ {į70MBA:/,ꎞl#.;OD=)A7BbY_V=~h\U +FvL66vVq|_xB}z\KH+\b2#`OH7$wF?\6eW*p\l)fHT0jI]|Cu;] ކZ`yzf_<+LLkpfpd2е ޒ1XKyÞRpw^}(uE(@{o~)E~$_N`SȯO;x'59]עݥE9Gi5ЛyӖ6d;/[CMl],]݄T}`/72skԚ Dz HAGGER[1C vXlrM_t6*4Nq}w] tOZ5}qة)| +EM@*CDAX0ԍFᩥwz^Yi,"(fZ_{ iYvkG`QP9Z/ǹ;֭9fѧw턎: 0IEldut nѮn tgao>x{% 0;5I,;^+{iqNde3A | F8~>Bh- VP^n}+@WanMIE{i:)C\ 0l lp#,:m ]Yu_z1.Sl޸9G7Հъt=ekF|\5u^:+,;A 5"G&ĖjuA=FHjJVCQk[A hQG<ك`NP2UuE͵yFC СiHE[~8F&JIW `(!@lR AgUx $}갂gץ0c՚Q('R^SQ,РkʃGCޔ5GϰoS{ܤ9qCtDƓs1F@z&R!kΙ e)YՀFgHn NXk5MZLPMAUxY?$pt^kIɑEk.n 9{rvzY7aV[s-X<{g_%JRD +095t7V1a& +f7H_ăD˰NawVtfU}lB\ ugx"@45_b&5S02.TM`PF[21t=!Aa(U4 UqXI\,aufSxHi)aӫS!xRMՉuqq/<ӒuРTWؿë%t|tK`Tgp?p׌6اiIrabA\<O0%qN{^~k c+5Y2{3'~HM\WW[, ѷ8/fXϚ"$:?ꙙVr"шH]4?۔(&#TsJhΧ,\$䘿?Z-g ۙ]ĊH F[/K5WyDSBU6K'm3?)u o;8Q]d("+!48vRMG0dL{(<gn]hPuqi1kDnqItdn.;nP|#DX<1y!|py`,%G8KUid0*3G +Y]zNbu~w9D8W>мUQbg3K}TTG<7WG2wOuiSE#i渭G@l`%TDhW|`"j%r:F$'kaUj%`:cj$ $Y85}qDL+y-0 5R̕(~ȇ6#[~y/`(vwK+hL& NjҤl­4Q"٭k'uApo \)YmzN1IVspҋ]=E s,-:o!ai_чN1nZhQo&o;f 3ae@aI-F~GnaL@ Q6FΰK8FZ-wzx6#ٍe- N\L,luJ%a&A^E ,M6 +;s&Q[`ܭ.7@Ծ{ld;݀I^!m?|An|mRAM_(k%U2O{(c+}X6yG6 (d%QK&?{ѩP("/H|鈴u^[7'LgDHlKblx59@10j lH񴮧.}wYW͵x"t5rN0"n֥Lt=[c90|gص= xE, +nІY{~e-s/d$7H;Eud]u &?z67 cfmǨw~29x¨sr)5 HSCRQ\Qږ5,"o@ҷRFDacE-FRo2@;EZ4yנIlRN5}̷;ț;1yYCeTn9r4Z:\Du#/oDjbMR*|(B֭%/ }:&dZT1z"1\$flŸ(/t$*. eps?ccn> ̯ZYcG 9/(:1Zsu53L0ႀn%)rg=|M^lNGDp-L&^~!\p*II-;XRJ9`gs~x}Oů*gDA]]+ +X<[|Lu-ħayrlDaʴ'Եu1&l[L()!Q⌔u/ζ=GpqR8BG?KƸB!3 ]dc)mh{d,SȎ.&4^X&XuۥѮ>SX +xòɴu.VUzG.Z>(=#u>w(N\# 8N ;%dd6Ծu2PYrpdgF75/v!~R]|ɽM@6q+H {Cc-_@-%d S > +--\^iY-^a&3i8mpLm15ޗ8)f#֟Sj=- mKhF||N3?@:Q+i Md:_7۹ViXJ~eY}GL߁IbĶuT'%@W&s>f>IHar./y7MH=1a pTx{|f/Nb4{fVa>Xზ5آ9Z8 P3nKH@BU>IñӐ_zQ_ݥs)Gg!G{-oy7O}ދ}<'㐣#ۍ6%6ϻ]LPd(9Q@e-Hspќ .>i7N7bsDMr0Xrwk,L] ! %BVr9xB>$g<ڼ |( g=yn 洳ǛG}ýBrp~}^6}N/1Ǻ뤮vŶMd߀@H>)RI򅝈廷 ۖ6](zp4:^;aBZ_-Jo .babΔ>l ?c_By僺Q@4r +6US iJu,Z6mzz(;\8|H.-5Sty˖+LDҵ>8黎Ÿ\γ0zb6oe“!Lߙn'91F)Ҋ:w 3Vm[mGVY&D5D9"E4e ~nڧg=-8?;Ƌ0/2<_ :ˈ +,ڼ$& *Y~4[ 'wh~{=\Pip\`)z8{&;CŔ(w2 x4n]ePFkbS_.RIް.:pR"xz;,꤇0ŃRs(#i^&}L݃SQW`n n'X]/f[3}Eu_SO -8iHiYaeo/_|j } +vx +@x ,8-C=1o=Kdx>xm#׏נ#_xSNOz;sVN'-C%jfߤ[{,A[gޗcDzיnyB;c +S"v,ǩhb JO"q hJ=B- +=.N˜f%v\U>~[}|:`f1{ LA$fN{+~:w逅*/\z 9xE, +=^BgΘuYXڋeeih̊~wjkOyL_OBR#O@m;q;UMSN=A?!18y܇ge;;W aQz6MTM?@Ɍc !ۋe@@z;^Slް1?W3/N?kȊԶ ĥ¦6hί'n9_E:y RMRs;сy}S)nAVލ/+]n1Cd,^ޔ>\V0{Ϟ0ۄbKfV2K'MiJbIh}yd < +oJ k95&;`돏AwO7|h?1rID\oid9^n8=K?]8ج>l='Y&c:%Apv(}Ɗ3A禖Jw09C +[9 +!~ 4E+L[/ u- vwMR&SdT˿^j)++STPyTVNK-YgP/cǰչ3>Jr'ns7麾}og&cXl7Ѻ~TVI"xR.#xٷ_@ZU +%(1?c+`o )geϷ-vx?\pj;xo;I2`CzcOg&>=:l' Mī'{ +*&] 2j+K Jo7y۲2Уaݔyd&jĭP-Aޗa]?P{n#4_dhZul<ͱ{9͐:zr\_KsWrNEv\Y&:`S^٬+c_!Em}ēD^2o먎]ԉد2l^B j,Sf4/$]e֍TWOyg[[ȱ?[wn$VM╭.:&F[/H˝:! +iKÄ +}A-s2KMW4k+_9 -oRmT,eb\ ,IN?p[YuJbFqӌU$.6 SۑXpLNf!Bf'UȎ1kJ +c?׬= ?t6|quL~սAERSNw Im׶HQy#A@zzObEk[ThGH(:3iQZ赧/X H[{3w~9Nߵ|>_IEN|MBk< R$A>v.-~Ca:u祖}l]X]=O$ Ž9Fɤ&sUܸu+S㺮yQ)aj\2q2vz{=tǽnS$Be GQu51N}9Z4Z$xs{3g>Ezkvx"ė!q܏ePӵE#H[3(ur6\ќ;dYsO?߲}jq?>WSegsaսI'?D&[nZ}}k[v(حP VF&@WkЇS#72"ɥK5uSz? ywkUDUaR`GjL |B09N> uf^XnK#OeEKZ`Defw~"~OnH)g"?'i;I +)tUz'mtSgV{k\oZ$jS$th+R:_X#_Fe8:&AرnBKƵ?U3pwt`4c?[Ҽ DHGO +bש/SfUt~2 sےo;W/N`D#xȓ?+}K7j:<+&$V2Q.lm6d~v`89CNm3vp!ׁLyP' qOeTǩ%W^!c)X[mE Fc-e I+ٶʌqc}AG8QDK (; 3_Cdy]8Jd8FqDbeV*L߄Eـ,7gvT@4\ʪu/ ͌#٢%Rkbybː[^זPݩ.wvh^_Wf7*w۪vk1;]5źGEg1aT(&*l`>}k~Weaq +F8Faq|Id{ESJcؔ x+vocՖD苽L, Y\޷ /; .@> +=4./e7AIS\I +0;ΆPϳ}ݡf9STɰRܡ8iIJYJPWḚwh k5ƎvP@2`^1*0)`Ms|"\aO@Z9;&ῐA^ZmRƮܚbP(OxKp=VCKQn:B!u{ك+[$}mIhڌP>rlܰos?+j3HUfIB h0j.Xđ/{yXVj4( W=o,|v?IC9!mڻȯtm]Zv6rRKE;z jؗ0ܲ;B;Z$%uW~k*_E}ڶ{gZ <5vYOK˽y + aiKh!- /.kXÐlS HgQk{C9\u2":}X"[^tMvCqKݶj0ocbXz6D$#}hWTλ=;9<ڭMK9Ljju!r P{*z[*p$L}KRGZX0B64QWwtV,HbhҵSeE @leyn5+OlvB]f~vכIb#4]*m{[BC} cȒ"j (3M|"of$A4Qm6Ky52.nwLKP/d4,L*V p$]rEflͺu.jDiY>,%L抛Zq7`Q̧K&('B&x%2(tŎ_? O޹ǁd8baT?Ԁ &dU!&Vu]zD.<تq_{'5{ +^.DtMje95g[^[~jU~'z?'DSN];}.1OE4C]5-3%4uqMة@ 7SBu}.xcWjǑsšߘGOKr V?J8tW9ݧA NXqI-)h~\kfuq,(-<}rZQD*8%NenŃyG\xCWQˏ(~ڀ贯 -4#b%+)™PNel o~!cS2]7dtoO/=۪۟ (\)R ;l{pYZ+yvծRcR p`yi~ޠjO'-K3 +-o!5~ncgc"ۃO.l\{ph5o{ŽD"?{MГA~ݔ \m詷x$Smc]LRRꏚϠY7'hPAjY?n[x \f8ǘ"8'%]!oped7Qe݄xQ-{eF&ˉ!d;~[bwD2HG~'@ޟ)Ro.տ?txƉs;=NJX +r1'x>V>ޏ:J9HYn8Oިɰ*h7+ X@uX N!fl=eu2haq{]3 P)q`~L5wkjxD1gQpAjkip;y,2Z0H9p*.6^/> |Ǝ2-7D*Ms5':#;^bo8e|ƥ1 +67Vp<_Y0dYTnϺ_17/\rgLIj^.oֳ㋸nxQFcY%.*ޙ(E4mₙ\UG$Įl6kpܐ?Y +_C:u&iUoŎ"](5UьW07]DQb8?m"Ci`U5.ǵeO4¯HF2z49d^.<jZhࢃ8%4bxS4Kσkb]g,j k3OD떮1`kwQ;^I5iBl!~23 *囆g)粫{gCbRςd 1*>kxWs+F5˻faL21]{Y +Ϸrn~2QdQ4koµD1X_ MEϛ)x{u07[h711!Zȱ~ +RᢩfV53 O(,eegDL(DkȖ 'Iw5ɥ^MSPiE}FN~[μ,~7uQ_yЋuP2Ma + S'3eտHK̛U;͆kq8Чb7Y1Cgo+< ܬo](sVHpPa]A+1mpл.jpa͛NE<^a>cMn&Cf!"Ǝ[팧Kǡ,9+qVVR>*h&J!Ơuu|͸ `Iȏ8$}\G}1qaW0qF;jc~0GyTJ-+NQ=e=lVm7!s,#tGf:!$!жhwctc닚{qų0Շ }f_ۺaLYMp+;*̉Qa7bi^ v&j G_,mS-Yيb5M9dsJPj=rN=BDX砷bW#S1DFiME}޲nE;0 ^\,HcD8^,e&ZhTdHP3QjTT [/7::!:uWdfXY +Cunf @JнWmao)ϡX{-ٛeL=ȢZL̺4vWZfHfY:DuB؈`h(qinXSJvDa4xꕿZ SHD1lUMFx* +[<b B +./׎Wqq$yҘ#2x' +y]Dި10?6֏+BGد  +1*ȀDEjVB $z +p\:X"K}=b{&[!~5 ǹmNI:o~``"Is*F%%8y0y0p&TqQZRSH T M%{7`rNy3 +-< +FGJ efTYv[9v ?Qz5Z Wѳr 3yr +&njT 0Eڗaܱ9}wIIWč:cO0jU/vim?,ؤ%#o#'{,Ψ ȫD'kz $I rL^%2,i<4 +x3:GO0KH4 + Co)VFJ }H-=ףhq)7 LHm__CS( ܟN<"R\3;ѵk0[儆v+NCFC6A3Aqvq<;ͨ'Þ$iP)2evdXSpW&7kڃx]w`=ҫLFn$BȌ5Ȇ4Itz1':ft^`3aL2opӷ/& `F +{"ytLSݣ`S!}Y,'>o1-@fx4]QLJ膭{b ZNqAw"lgH/lbM}:>.2-IԨ_`od[¸1ƑNԔNj.Wwu xa%f дHMo:ub=+Ey ]x~0 h@ƺ$N ,bfmƼ{ +՗XsGP8Oo +#4Bʾ][#AiR/\h՗J +[PB>DF9"I5}Lc_$%@!֎xiAN9ߎݩ1jIektHN!%;{x%vLb^z0.QJiDoKpLx){md+mY2sLFDR^Ƶ%Τ.i# +IKY)^3Ȍ>GyG|qZj+Xܚ { +k^^Kdx#Ǯi8nJ:1q6PGzx\(G&IJx~e[jS-vvP +X6\ՆI2x{,(_x) MS;5QkN׼s$L.x9.|Y+*㷀6}{kQ߃zVDW`R#j;ΙGG:|؝Ԍ_ȜGm/tVeOŁ!Wi-ϸ`0ǯlFɟڢv+'ɟ̤5֠NvA Oi"Fʻxh @+mc$)^OF2$s%EI$WHs=Y+i+nQ폺cmu$?IŅLG5UC*p|sӺʷm ȽKT*WNvw<*kbHV)*; ++0i#d ڷ:$jSb'CWl:5x2,prD JAΉXjcFe S(N^W/kL5r .? WܽmUJ|Pmܢx.eDҜg]* +B5o`e!QFeY K~`!gQ+<3&h5C7sBft_Ԩl`QbHi xj{zǸG5}hؑ(KXTTԱ@$a0,AǺm/"ED%@ UlڢB|ա;w{o ~}y.fxW'0D\TdL\`g-YБ,c`)߬R?:. n@/(`0 ՈANڋ&+hpJTQ6_-ݤD=;a>Γtbw@Ig#'zy6ImC#V=HrNe1یOy¸8 +Q"A|*cI4|+=HDEhE-[}٬v-$eBg_P?_Qԋl"D4 xVw#Wc&2Š6L~؀4h\ :FN?h/bkvX;p(@Q!<4n8R |<38=Z^%oT'ka;ͩw^2h1"g +D*XOlWwrr@VEۡFNh'yITtWf%b҂$i[30/EΞz9uQMY'\o"/ҧ9rPpJ7Xg"R.y;IǭU {^&:sV^-r[OrPJ\b sKK."|Ϊ3(?9`+Mkv13~Dkȓ3}nS@G +*TOAmFx!hrFC${ fY#?JvIlc$/d@/v'IWf> + 8  K +ӈkC'_Tyj3% u0 +FSOʷYlɨl%8bHnԣ48WlsU#ݥj$T#iD(BFЏT$Q2!_Ր w$T]*/3gYW@P1qIpYX0w$/y>QvADø=0zF@x]=Zm|Ьh,S5ވ~%0uxlcH ˦ဘd,~M)m?<ås*]9JC`Ս @A%1lEWi?[tYWzظ +P/1Ndk)u0X8Wh6\ڐi @)Bd~ ȱcmIL#†W!GU uɨ1vtGʫȇ7Bs}AMyF$pt?]7BW <^RԢ\P~@ѷyE{I D(l~~Qsf -m[έl!#DDgajDrm19kCM3RǫeܟH$-"Iɟ >Hq溱?󃹛=Q+ 2dQdf6^Rv$_u$>aȔ 葙|wL *¡01d.m5{lBWR4eqU0FށP`ӡSĬ! u'5(G8s@&%]ffg6Fm 'iu|xθz))ޛJ!9NJIR"Z2s̿Gh +Y(z gpI_ 4) aZ&N_,NWaZ}1!h_\]DU'6s=~nSPD!8㣭o)/ *,;]M 3_0Oz ުFǨ&&H5*WWb1klsFN:@;"%|?rJT* j}#x.JrQ$`lE H3u ptfW=458Rs4 + B&TǴD-ku`[cZVjB]+ވz9êQzᰖa̿T Πz-֬;/1"+MJZ.>d߷vhb͋^ #rJYF& uAPaSQ$w8&aӇ aWgs )TJֵvp΋pnq6;bbJ7DVp8W{\)|p۷+0B9pe`k{I @xǬόgSvnbHx),C8;x$-,LW<%NMmQ 1ko*Q{ + lu03y<#sZ~8획1l-=< *bnF5';?|=L({S@.tꄣBQL|̬j|C &u|"-0aČ+ +Z[j-,(Rl00pKP شS{[30f'2lmiHhOC-UFY!/8ݶ=*I y<̩$ 9+ ^I"JŤt$C8쏹K#'#6Ħzz',b9b0Juqͺ̃m7#&` +*31pyK|V|*@`/`׬TbS +O@F^qF-- #=K*l}Q_B8f~$&1&k&U;Lc?ieco3{=%O+uUB$*$jUY9~,x+g8e[WwPb{Bܦ}޼C +g;EwuI8N pěEPd%53LmV= Y犑O0e b&9Ia - 8hK3U$[a\F0kz_􇡆t a'vI}xm }$^;hc+_$uc "e 2̳!p .WNN>=}0k EV"^"Ҏ:w!+!ہ3[{tCX_A&K* O%Bx9 +`VÛ:DNH{9-8 A +Wi[?xy<-"`]sj;ȗHŋV<7y7L0fS5NjR%x(tCpΰۉKbPSKB0jgKGY U /vXE6\qt;ꭋb4WmA.MWkk2C\=qa vݟ\.O7د د +5w#Bp&<-9Ja]Ep'q#VlP.@cAKA E<%#qpL+]̓ E2p::> n(N 41;%Q"HZ o;p6)XHքҲN&]aޔ( v{G+%)iGdѦWYl(Qqk(bZ xe`sK;0V׹t!T/ +~3m^|Ó퓚/TksB)jFLa`ѾmC̈d?8q³s =%M>.S?6D_=ʼI .K khk$V./*eHL#wז.&,W㲰d DYm~k9G,)3 D8 +P;oxB;ܬ')07u`F bPf Ap<>-'۾=BVr~`Nh:}2p AeKahN'Q^Pj#Zs1-qː/0 23zL">Lp+UH\~߷_dKő +<"Ji+oL'y.I%.l .fC(F6Qcd'~K_p-8x?F$)v̫?nVdn7EIVK1&3D.1OG:*EX| G)P>#r RO4ԤdIVsϺ-[ZCX7ơneaCx]өD{o!<_$ ]mۭ׾ ʴm7}q9Q?ƹ H֢ %z䀴}EnTRȷFJN++e*^75:_?ܭ)[RGC %9`Q3rK 9 +=_Y~j)HZnѨPN +L 'a7pNL_\q;lfb93l\!6Fs(ފ2+V̓lVE.هJzʱxܦ0+jrY@ FT[ Eۍ CBB o/IwRH劃9O^w"守ݬqmN\AIusr ixR~<(ORA`dK6:PՈ*cjw7X.&O^:od龽BmGt[մduBHuJh284*hsdJ`/Sg`XZ&E ڝ30 +ʨDqz>k#qZ"ֽ/rSZ8 j/\&"%PU8əevRgS~ˌ넻p"K^HzoV~_(Ƿ +3cL./1^ߍT~ (/ uY{ ;t,B6XjIdoaxܾAnVPf*mjM::/o۟(-E=4CWc&p].މ Q';O#H7+)C߁$..!?̕L[(T)ÐZΐm䈬f u4~ s+7XI10D8CDQƦoUeow"Hݬ5YNkJ:['{ވSR[21.sz{ ),u;eG΅إ:Mymw9?S`K9SM:7iS*O RU?Fqh1>x%]fzYzXW:&EtL"F R2IU!3miP]|؇Ѳ0,Ew[NjKγ;Ν+-Z=0ɺ~?&Uv>|yoDcyh݌稆RZ_ EutYس)Ξ+ ߣ_'d <7heIv +5gk;r?O\ydIANP!g$ͧN_ٟfq6Gߡu$ob46@1xQ_ %y=}iN!b"ܤHO[^-VhArzƚ${8AE/]9;5%NI _{N:}9y͸Pb<"+7ʟ̊|j[ ++0_)lԌoɼB"۫u;c7~:R4?@S1?B4x-:t?9pa/Iՠ.7^p4E I3)^?Hj}^rZ~Gz]h͙x7' YCs]9mG*_D2 Vyΰo7HL5Z?ϔ[<2RN /EPFsP1P A!ٌq2N"+_]3A#uMa>ub'ͧ^9\맒^3odc{nE?J[\"7dAL \焩ӿ%h*ī EpLx'*Ћfk]暖P3 ~_ͧ53! mF]hoL-ּgG*0=5-;}$y~̺zt2!a^K Ug+գ =s}l}9Fɰ +-a0G?ջϴ$sT(+{;S ̟dO+2K^X *B썛nQ:_.PY Ǐȑ +^LoՒBE +gݖ)\=]m[mϓͿ]!OsHH2<>KC ̢۟k Qө$ä <|:Dq'jQQfpg0%lVckf^s/V}/*~ ڨ݁HddPJ]C 14!goL+rL"vZH +1Obg:=e5](()5{Ԫ!oDL%Qі˛ /$&Ο/ǭ8yε,?C_$ik.`dF~ff}HY]&DB"*#ݍg>8˝:DMQCh!>5q$3s=`FDxdu%9ޣ92vC|{Oj]?xTrdd@ +r◠_B%3HbLR-Qb!KOTm^n^#QjͼcGCX[Ċ*ۍKr[$%S5+>x$ lA^:` 8Uz0x5L>7rzO +P4CU? -s"X}-'7 6~O 2Aj\4#%9sji '=|k_oNv3cG=TU8z 랭Y;t՗e[Y&gy(=RHVJ +Om B5&\`zVBLK1~Z7lP^%x.g=6Y o9GejA[zdt2u<8FW5W7Ț3W K=vN.ĩ">KXڣ:KT ^.Z{#5|7ݼeua`.>3maùܭ:ɋv+̾/+{$ 9v1/'_[3ɃGSʮS8[/1 s+8;d+zGpA枢8u;g9y4$1i̹ f8|tlnC6ZnjF1Ta ,|\3fݱ`J1%L+l[[Oq<^ +ǷOkK b҂WhqT_{p}Y7e1We]yт؃;x(qڌߚO`tQ/ﺱg>qp9ႁP}.-6;BX'^ŢclEzǹ5ܿ/1yNtU@7X' =-gmZZN ++&D)|A03a2f1)7 OVdb(S%<8Nө3d:2WP&YB e3!+&"#(˿:{oR$lU杬}KvSt[30ʮ =.%֏ z#V-gb3>9`]r!așxҫ;?FJUܕy?)wO*Lx'!!Z:ln + złF)| M!6t+F.D"G|$TT R&PLp=ʜ0 "C]ms)Up$PYMG&fu5˺(&@W~[e{'u} EL쭜aNTV1Sqot`QzI=L\1< +d[m h%`;Q(jۣۓ8|R)skTz%Xr8,qY 8N]aoQ[ +YHǥ;Ls +4 quC-& ES̞`m7iP.ƎwbWrf 18-!۵bU ` +Z +2t6KoߐጓZ!VH -= c/rE#lZ'L!dC5a.ED:nȤum,F3w}aXY%ߘVȝ粞{&%sbi)` +Aݏy"#)>MEt+ +Ta|wövPbZ*m|{f2@׋{l;bd.9B@ghI("s(mH.FS~G8{;A/ +191G 숌)v" ?e`[¶[pFp (ulGX_y|\&>B+DDM+0U"D+Q#In)gpid[}=0Hvő ]~_3_1,H FÇ8&j7w^bɽ̿;.BQMB'IO*KO gN${~8˸¬]pbmNVkg*~-᠘b8+iyZ#K$E16kÞ?||_5UtVm6lުMLZ0ds$(-Y~Vr&FWf8y_+ݧ~-8Ѣ{'VYǰÃ́v'r\JBByӸ_ X] \ )\kwFse`F*U …@ 2h0`,EAA\@`(Q `#QrqT+ `kP.z$Zַ:gJG "AM|kS~w-d٘WAfq[rm.'voer*fnGOInj7xY^.i1آ:-s]]WܴYU')M򵍲:qpDA=v8iMʈ4f֓¬ŎPtdB AKs:¯c\Wm5,3X )`8)̞K3%[Td%?/*j1S$F&.|/FN,pj+M˴pCGdҋ< >KA/d̦_R *fJw +a JzW`h4dž2'WFXlͽl䟤HⰑor8R ;S"F&*ph =gɀw`Ic7T:2N+\5 +lYlgA@k͹(im$RQi8R),b@f!gI10_1c3oY`<NE}J.{O߲KAV岲lץE`j "na +C,+EX©*/*a4hç@CIk_ǽ6SaZi3Ry84j͂{/Qߨ*\bV*:(bR_3]1H4%Ct[ouE1ʫ8Cff))MznBEB @G=qJ9FٍҜcv_ɰMrFj@&CuDtKח)#Ic-)>2Ei*I:ld9Eso $PH] +ήD*Y tm&sXMFу0Pߨ9Xg,H)X{)D]rVS8GVѯERe%z.X2 +tBE 4wJ*.H^C ,@k:'dOa%-xQ|S,Ca 1 ;HWNd55 = d3r*}؃C8 RycH +^ VX!P7y LhX-7iTvܸ +Ώ +7d5jkUv ݍ#mL[FG"Ay  VqAb RfQUG?{uƒ^Yg&xD/&J CWa%_T5|sͼ #sC%u{hC4,ǔVtq`/Hݠ[Մ:T0:6kgV#P6#ό}H_R'nZnb\9 ] [8DZ4 +!s=pt63/Q찣05o}5?)t+@v+cd#.,Bw_<~z{ D²i.{F]wyLT sHM4XV~cNn#=[˦Y\K!궝#]rVn!d:l}k[t9D?2 ,a2JQ!#ķնXإ+Dy`ihYgG4In "HLaLS8'rErSuU + viQ9y_Xx氜tAC*[v@+XgcšX:91P0*Q?xfj~&gN^b4mk16<XhmHC^_ pj-O><}|sūWԡD?$}^of jgNe%g&t $FիVıDyja[y\څVi>oM3$!]!\hY!:V0Sz0aCGE7=9LG_=kN+-Gqi(ax}@2dy-$}7,_]dۻ24\Y2fa0簜Li䍭>=qY*3G}oZ*,Z5r1$YpJ +^euNdg"Pא@x#60Xz"Tqb5K-B35RzNZ]A:Nd(I|[j`ytn2FTEEuR +9"F޼BDPrӹrs3F]'LaٲfuЁԉP}f>q XI''$5ò"5 +YTa qԀkjJ!J:`\(u5XL842ubF]zTyQ$c?k+K]#"Y4O%7["n9ZT[sDB}̷TzGY]$}b1y h,/*j9"yQ$ѷ-ƀ޺F ٿƂa!,9~ZVwzϺ:*n- 6\!7SC%d7fBXyu)O:NZ OFq(wWc6m\Hz3A4Vn CmI=lyب[eX5K]ŋa,*fCķ#i-j[<'M~]=˞Ѣɪ ;Ce0 4#Wcy* >{p_ƀ9[>ID66muZRѣpP#TV -9N+?:bZxI%QTt] GypB|xz c{kSX$شUsߨ+sg:x-s~0,d nK#o6 +q6H&hDuSyR ycu +WoLUl7'f_ G"o/Q+zX762WJ/$%/uԨ_PsR̹ܜ#Fn>4i-ٛ^ =+36 +sj{L,\ 8g<Yuz;ot +zqx/!}kT ΘH3qNS%7V}Z nk2μKnq~iz޲Om03< =^ujjwO{Y+S~8W,?v}R$Z-cD}f~p8 B }iRw :a7:úbe|OLN$po$LԾ}kGL0 n~3Xz{?:s]%o;p]YzyG [,;슭4tǽCEiNkY 'm[y8?G^gMxVs^e%O#bVf\fv1;I)>A,lP;1z$& "azy|TtV5!q?<;0ʤUI_c#y_m7's[wk.y'zMGCtLtl6f-pF$CVsWf~Pk[cBC{7ޅrs+}:(赟o9,E| yLS@wvǎ_}m͞ݭ1 dդ_“y=J_ <":Չ %D|`xɹayP1WT;oj}P^8|]ՠqf~ +3Wc[kREQO?>!syi}Ļ7=vj=щw\c>)OPj6Nd9Kx}U0NNk>>i5p=:+_ 6meT+ε +8j"v`^"wOZx:*s}=\U ,BNKyrV"L|:<Qx vОN,uwWYk Xʴ񮍦S9P L,݇Gс. ldžG+}5dp9ķ)Uߖ`}I{k`o Z@dŵaYs{%d^c4]ɹ; GJw#)~P81PK>فYطo 1s"R]lk}|^aooaAnj C_ɌH+W7C}UdR*";5)-5.Xb?BcjLm[N74YԍV|0CU֙DB\ '!!ґ -j+TK~3J^7x=e j0q>5M1|A[&$0ayZ.%d)i HZ&QߑrΠa#"0e,&kB֍xSxF(āʬLt@L嶟~틮!iJdPOy6YRs^V6;7𐀼X@G>@LVBbC ";@_V:Um0Zs+KUB2~F[D/MUR. +N$Ӂ;?*iSG[U(F]Y?SߒDaPu– +s&;$btSQQ[M]*j-4Jh4rw.w? +|o2; }saQ3jߛx A]&;O?FoLꙭ +,d&0_(Tzՙ R>^%ی؋b˿"r-LIѾ㚹:dDY:Gں|zs;f7c#C:%ϟIkDVG~n {9'೨6嫰^6=TB ݆ 54?#z`tfۨ67SFÞxu:l=Y _hos)=z˟VazY=G'Jb1~OA(Skk?Co2`L2 jɷ(ϔ GI=O*mU]egbDGB9M,=F ]/uGtAGAsrC+q޵ +HHiw }f<,$u&WyVTnEV=1$oC䨦wCBGd2zM{cӓOV3qZt 4*a(EPY1BR +qnчоkz+#/j[Cak\.ѝs }zZXN%csQs)sbW_4:aa4fpβ^JDI "Ĩ8 R\|z2JmOc(}$aKνzLP.#@HRZ)뽞_k .|7:7I:MP ,+ޤZS_OrF5*،wC!cyy$+o69i>%]mfamкX,҃\ Q\|!~RŻMÙ21­ЋVw>X)PߣoCq][ovh>l52=1Du#Ui 0aNRjH0  qRlDV4m AG| +bp%پQy!d$({NʁBqŇd?w|4C{:lN[!EVA؆ Y/>_ Qgj AF vq*"~)JwfƔGLe?`$ȫUoa(~_=FIh0 !aa@* YVQj]@lM*2oh*q+}jW>LQj\H#pց:/BeYnrΜF*.IHGe޹+wpIњ@Bpi$4c;~{7b~r=%ә,>6C,2evkَe'0j71U z<:ӂfʢyly2g8omg칪̅MlYlǐJHbQ:ɺ.7vvT6VC5#'gZWoLQcYD/LnemK uU|4XVXc`նFi:d6c3"9mSze5HalCڢ=3u$ &ATxFyCNbaMe'2=Ԓɫ.&6iE/ovbL8ʲYOXUbר`Rk"rBgj+"Y* 6ESt]բIS{k +x$[j|JJK6,TĢ8%2eAB2dmL"5Km ҄^jEyԋY^K`gAv8MK,FkgkD7UdFo2:B% +3Y~ YFqRu,U`> ז|Xg:O\;5GLeUl;5qQ\e-5j"Q0Cb]4wZ`ɰKWy*94!7KU܇,SdsPScxdD1l " !$4 >@#jEtq*ܝjkDFH;z/2d&rdfxVPr"wT'lNtΖתt$q! @o#,сۈL _'֙c* Uo5UCJW;1E" +S2WXDO\yc l4`JI^AZi%If Kձ2f\dꙄB=>(& Q\܇mH@iͱ0RPm"k4JYFҩX0&r HxJbWnkwҹk̊w6 r%Az-5chL_ok'7kmUjնi*d,EFaUtk@ږ+ADbn&aT3h>vbMAa!Qj*3JVwW/8?3 jgkjA8KiìH7C4!UERz@^%Z5rdPB꧲3zD'%rJ}QmWuRX9T!4mtN[#v:D)Ԋ"tEss G!5YKDYMyFY26L "d/H:0-ĒR +QOE"0\,w҅qRԀ?5y#9<+ C_Z=V֤ʉ@IQĆR%d}%)k9ů-Ub Д_Y()΂f̅n{P LEQ bWonZ/@屓m/w7x%g7NuDJ$g\6rKv^leC]PʒYDlx6׺^@qz^.C2cpSe7WӁiH}&KfzCe7E1~(_j"%]$I+[+[ȵQe&kt8Ы}o ψH!B) fa@}C%Jrru՟?e?l~`:8|~;\(db" 5[P`ݥx1Y9\qSp( + +Wt.k)CrB>sMypr  ;z>>rY`^~ϙt1`.) gL < +]EGB?wz_2 s 1A $'a0.25_ڌ0>B +GST`],_rP7Ο':c@aPD?Z_\kH*_PqTu33ܚͥiIP ͅJ;Rp[I @ Z P ȩPXЀE+".PT X\T 7 TQ<3ݝ|#|ff;w=B5 ba&^~Hv-B) ?]PB/ i~Ǫ+#mM1՛P4K<ߗG\Y.o5ݻdaq$w~V;DYl@s*oT{_tOi >۔2FJMkR7 `$T4뺬@6p iqH$/Hwm2ǡ'm^K2lhZlB=p׿> +rjS䯘l; JM|s8 &NR _GN2$/ #ZiH&8V5v%-qlNduP յ$+Gh7{3/jK^Yd +/1>-o(ϼKhcH9[7,c& %aew6pJ.Zs3 ao  *:RҾ}+!XRtmc2;= ++kx˧M{LFmo0VX{&/ +eWfYh z?xS[{i{Z=-?(yZȷ},֦⃖t;XY0WK.2|wY~q "+,ۛ dI@,DKҲ޺!9ifZ}E{$2qH CK01PvA;_r_Gze‰[:MC~Cv.6L0-*0|!< 04ȳ(\wdm&e}^w(Fgjgg4Lk~]:/ǩtnM?z;%EM^@ط餁nk n䕇hۊh Y\@zYtؚWkZRͫ6Fֶ;}vޕ;fYoQwAGHmB7SlIIK'O9jVJO)y'ηyp(Xbq9Ɂ>4=ds0`a`uWY +$@Fؤa&(+F(m3z T~ +ZBJQT)?䈡_~7HVb6w`XQ@LQݱi\l1+Dv@>0ʕmZ8 #Io:rx(8YiYB_C2"zj}vP'F(P3+ׄRsπb2/T\^ɝʿϓd=Y6C2l']G4 3`{n`-}Q̓r'm6($^@iв]r.־̯YZIcyYG@5ͦ,Ȯ!#vHH$bnMW @jeNs/&heTFk @Wr=IZ'g̒i6?xgDgw4ORRcvÈgrN wp3H5S'SS %f[y W#`@qN};-yTIR[ 0z +ѝXeN2w7-s'U$A:;j +5,sj=3dǝT+4tȲt%Wm@[;9E-jN1ɞ!|K7dɒ\SVp\׌ɴGQI*d&< *,ϣ {V'P'm1FwK +l[߫-> SFJj!gEMUvz8-ս*,zNqTb\E/gD%%RVcaYy8QFܩߪP63v,dJ Grʖ\ކݛiImsI|Q]DFfoV+If3Q<}v@ Ał;Wi Vvt2sG4VM)}PbO|-)I. ]̥r,(y% 3Ժa<&NU!FA{9pZ. AZ˘-[rJ5T#.E_kh)NU&] Xxnb +]d(Yae^WBҾ72Ƿ#d%s0Yt~lG!+[ּ)-^Sxoz +H}Ti@I@t3Nc&e䜓AC<^~ 79qUbfz̼NϏEWs?kzC89WoF®d(9?\BEO7Rsd^yq[?YA5q!%ҩ”g^Ըi!"8 _ǫ[JΠ1/wH-f9f/ +GG(^m=Uvr0l qZDk\ƚ LM~MTϿ1f|gdq_qM"Ӵ.py'%C Omq8#kw7&[^<>d0'mٸɂoV\ǎCUQfgѨØz>W1fn(t(fADN +{?a/Îq*d;ғI,>ðsFTU%ȝ'r V:U =~;-S}TE1NhZST?Macybf HRpo#aqf7 z%o(Up%bXH?xC!ur +䜳(~>O!St4OF0^ˎXLEqlGPI3W6 =r_byOdIĤA,,\EZI%.To[d:lj#ix;ʼ$\D8 HvXs謎gCdJf嘷#$z3ұGNqU{u"k?vK#wHq٦ԒêYbM:I]5 +F?<ۏ W]@\ @~-iMJAg2$ 9*5^XLwBL\&cN)stQ;Nv1% gԆD>X_l؞`"/5}P˲X|oBv^ s2$o}Ai!E +NZ6+e")7Lw!t,0"c<{6byk}2K\ҁa +j!Iզ̩ +n:w +VRMۿ";>l(= gl6RPS[}$#Pۅ8C͞Oy lP2yxN-t{'̚oc +0 IXth,\ ;IcW˧J1&LX -8-%yxpIx}\b>s!j'7Ow6ܷFw,%Ja'td.o~9MWnYz{I,,pj⩘U=kw\Ȃ3`fJ8(\@Fvac[O)J #At#F#{ (3äX6h!ELvݻ]wx8r:^[4:Z' 28W%*r်ya2MnHZ/{1::OQl"mkL+&tf,CßYrɃp?NU!#/E) ̡VfWa%9ubnl6M&bu{D^V`m# %o'@D K_’v@ewrznqYwP"dђ(Iρ95L{9y{Z)&e{9$K6V8oM0q b T͓廻{&FtDa[Dpd0k+>:G+[g@@%?렻HGN̟r'G]YZY v,KI))b$⃨ a^E){~eu"[3֕a)KNl[2h 0.~[0MP# fV=0C7HM,1 )NZ?dת6Q7OSͮv$xpO eϪNxYgbboP CX-&lc/t1,'62v;o6<@yVſủ,SRe$$-Hk29-!9ڴKzy.b做ׁVgb -%'_ׄ>:-۬O]T[p?i9|^` L%Fi.VV<|I 9d*&jRx½lo4FnF2o +mJIt+$I*{qYGUgՐ19 h%Oc˅[c 4)ttj4TD\%r7m  醀UB\)xcv[\ψ+f9.72?jF>c׳^'^8)?!_Yy!s)_n]3ɛ(~x)cZ,6zCxpDhQ\;"fl^"\H[BH=d\-~+o#ǝTOvhğPE(G:ǝ 'W3&ht`!=A97,n8{%E<ڪ " G#e1}uE>lsYc8iʅ˪(vN:0Ѩ/^*7Wa&Ԕ'E g9#bjm2XmC섡]ezl /W9~%ZV;X4W罣|eB"X~P7 ++[Bsw{I1]WJO]zSO)ڼeKH+?AMZ޼>H?$kKKgkaWԗKVٺGDĔ;x +b1,nUcwNި7vO+|0zw~eSp&Hu7;^'v{oSױcN=nq6X/_h ;Ƽa%© D0Jn1GĪ #y![e[sUZ>* gVlls=j}a;\ Whx+[ƞV-{/ց҃qtvw_Qo,xJ_k5SV-ՏF~zZvHCoƊ +oÊmjIvvvx#R.?Zq^s'W/~trQ}FL<)y/Q/h CIҳyBc%)_I_NVi*`z"|k!Up +=CVI\x> ֢<޲OtTOC쬕x7fuh +ٟ;Ř9Mj/od%*>K֩w#z+v9{أ}uٚعO0 ^JW/_WODL cU.K,^uXC{ +w>/,SKqCGd>C$UqF;௙r](#3"+oT ԓ0KA)1Ut15GPo_.V'sNBg=;LjW)/3pO:VVbÈIvfP m6o |ϗ+OQc{ڭZe|ov1g{6WK|7]VbߐUcͻb]oM*F0M /o/P6Ѽ-凧Y_cZtR2_}zmōp=oVmovh)l]ύ>y +p?K/{R[pHxZ-{Wce6Mo?# +=6^,mP}߉Y#֑~*)p:jЃ"%mz.vD<]=?-;-V;Y9#p$奛3nAK#59;UX,/j'KOx#c΅%ʿxأF7z~{BG}Y6'nSL'?ln,P.UƚQwFvǣRUǙ2q#3pD;(+#-)J5lyf~c^cڑxzg#q\Ëx@^0ъ?}j'ƏmSkcv7zV^Wh<[0nR h~CGwrg~ʶ֋h<ڕD<۔?Q=1=^na;F+7`tn7bwU/SK? += +רa_FWi,}Z>Gis,uWv%*?:/x>F66c{O+k'-+:5ngSh;P5iαmK7w+]?'+?K+{kNNϾiI ?➎ GBr!{~lx"R +oWx}lnjhʤ`e;{Eq>g7! \8C8.y(R\Y=\&4kAi;E4,l ؓ +~!S8n؀gA}mb&BАoh_,k},ۅ6kG#~DFPUم۠~4^,nB"ãtt)6-hHd 3p8lmSQb;˾h_XQNL|\ D FYihQDބ(4r +h%Q`C1. X/fw, ԋFDUi@`e|4vc9(l iۊ1®`ǘiMEْ+SEzpH +g"\!+D%Tgބ4 19JG:4;LϘ9G ` + u)t' qmf;* m1=aSJQiC:縺/BJb6]y)1Fx?g(0\{n(i.Gv+?C]u&5N .s0WJ%0Pyj QWlTbM&]&1ZRaePoAtUD}Zr]RCojJ ##bԪ4bm{eaZs@Cvl607(*ag +8aFk.B|ISՈ ᘬ"VUs̲WQ>^=p{ 4=-tTV`㸊 }7S-Тl.gi 1C4*9Ā3CŨrD%\ۄ# S[uuhiVl1$6Jq.@\e`-bipeSLB6_Y}'X\9j fMQ6u$Bc.,U~T.]QK[}l'sliM[v9CķU0רia"QSL]oN% +6͓ W cb%b\B4*ֆp䐷=:Zgb긠ʒm +x 2)I#><><><><><><><><>]/OFF[]/Order[]/RBGroups[]>>/OCGs[13341 0 R 13342 0 R 13343 0 R]>>/OpenAction 13339 0 R/Outlines 13391 0 R/PageLabels 13056 0 R/PageLayout/SinglePage/PageMode/UseOutlines/Pages 13063 0 R/Type/Catalog>> endobj 13339 0 obj <> endobj 13340 0 obj <>/Font<>>>/Fields[]>> endobj 13341 0 obj <>/PageElement<>/Print<>/View<>>>>> endobj 13342 0 obj <>/PageElement<>/Print<>/View<>>>>> endobj 13343 0 obj <>/PageElement<>/Print<>/View<>>>>> endobj 13344 0 obj <>/Font<>/ProcSet[/PDF/Text/ImageC]/Properties<>/XObject<>>>/Rotate 0/Type/Page>> endobj 13345 0 obj <> endobj 13346 0 obj <> endobj 13347 0 obj <> endobj 13348 0 obj <> endobj 13349 0 obj <>stream +HWnE}öKbĻHP$\p >Tn@Tt]N:= >4|oIlEܺIf'Q-nvjzKr$/\kt^Mŗ@>|J)>21K3~E +ϧG;fYwsڽPwmnw/".I|,13 O"]؞}| +s_d"(Q 8bpTW1ř(Vsqݏ0Ҭ- ]~qK,Bdk7K5v=c-۫}哻dumWVf7?w/; ե67SקH*2ǟTYrO=v& Z- <bt>y_|oĐcB־rQ"/ŔP Mw}~oT2tƶo}O6:_{}L{ɇӓ}Zf:׊8q: !yMF/peȋ.~zr?IR{R>\%*<\?. :LI.I2,,KK߇dJ,Ezjp <7? u#yq+37vt[K'$>aj,/RٴbMͪ mUDfe31#"ςh6 zCH Աdfߩv$rbV9ή3)Rtz)1;<4nuf`HSPsy3430S°+ۗK! endstream endobj 13350 0 obj <> endobj 13351 0 obj <> endobj 13352 0 obj <> endobj 13353 0 obj <> endobj 13354 0 obj [1.0 1.0 1.0 1.0] endobj 13355 0 obj <> endobj 13356 0 obj <> endobj 13357 0 obj <>stream +AdobedC + + + + + + + + + +r  +  !1A"#Qaq2b$Cr +%&'()*3456789:BDEFGHIJRSTUVWXYZcdefghijstuvwxyz?*?П?zWU>ܫFJzޕM_*o<* ;RnUhCL$O7/?> 7"|ʋ'Vw>utJ<*R~;*Ϋ#E?exԜPџT\7bzP6j*jZMm +⢥USԦ3Xm +^>ʧeAeÔ4y>TT Ӂ]WD{i=H**y?}Nƕۡ9)+u ҟRp8J!jqńI5l>jL uwSw`gn k]ݖN'ovTٯ7ۻ(XW2a!:`TvՇ"ݪ] Ő/e'n'W܅'ǡYᷛT}}7V'ݫ}o>uy=1ӽ(/4Vy80Co16fCL36vE;L2o u{܆xdӴbcbrgl7U;DK 'd6;v^Dpl{Uha7m7 cm +SOhӟ"k\Q eE3&`L׀r&SrK,ݭQE9UϔԩW.\z4;'ˮL~0Ϡ.C;Va}._'GjzSt7VC~MU,BywwV8z{X"}i[X^Mt'5y6:joA֡F܄_`>0|7<gZTu ɩ^ІkiUV֛5ɦ'Mi/aSޞMR'M]N)|:֚8: 'TT8ѫ`7N;FNʇx^G[mR<5y7[UDx :ܦ-wanv|*b|ԟ)Zn}Z8욍muȊeM95Ӂ^uQtLG\s;)^wJS>9,SZo"qiV 7z{_`oεJW'?þMOxOtmD6PMrۛݤrR1Ȯ܄i;h`ȦinKHk&Xڌi83N6'C6i>C&مSra&}HJ=cAi&{>lUY`-R{Ccrz OU+Oqk~:q …ԉgvN|%*TϻN T1:N<**vc/㍥Rx{cE<ޤ=b,uNe85εXOYlKRzU<#{`g/=xa[SDAZzUa9ev(|֕O՟}رWZҦbqR)MRu%w&_:g3sl;:QiRF; +K-2̯#UiOa;? y9ħ'⋦XwiD?pߓMOaxȆJ{A.lj+ТGnj} Q%D݋*Z!D_we4f76[3Oi)k~5k/OICFgI>ۧ(}~~tOia7Ѧ| KQO+B$ws|iz.ث~!;r٪Nŝ4E_ 6vU5R(o|riWH__9 hYp!Z*TgplI˚|>NUU_u8O#qt6_1w8xm)ֵ;y6KT4rֵvk~`YY-y'Ua rk4s^5'#֟?i*]srNWN!TU|8/yi|תz%[2Nt:nGl`̃q2v +x Ga܎O ҔܻWOhv樦wɶJ{9uє$x&(DO~TF6ŏ5B"h7+.j;c 4Ak4MCwI”>\LK]O."zO8xD2 [OI|3zOŰ4"{Sڧk"WU eW35uUTqRΔ4jL{ 5_ +x VnϰlU(z ߗVSl7Y4G7S5\Hq &wWdi8>#ǏX [wWa:y;QVF%|UO'HԩgYt5ykFu&2GZҞcvJԽFT:UK)p /^ajEn#yUӺy͂rʰmX\mx5'#ן)j["jqܮ8 NEtGJx-0;CiZv +'^Z;\9Łr4Kr;y<*!6w.yXw 6ҪƕۑS#oL; -2ms{+YoOf+rhI 7"*x͏ +3Du}nV|:)&R7>}i0)}@^=cVUԧ=*5(^I|kTCNs4V>rw6ffXo18b>&[q;+q*DmS'u*NzyӚy{c1@7ZWBy>OtؘG-i|8Ge3˼šUM^O*w#r )Nw~ȺJ%DGoa eM8o,neH9Ɂjz+p-RX_1&HJxn(75-OCG>* ¤嚕LiM%no&q{4,ѽ^ę\ӴU٢ρ&z)E6W:?0]pt.b?*T}|wlղmV)xiSLKfԙ:{O_g>8%zYyKGC \^LȪW!G@fO:B:ceÖu[G\b (T6ⷍSJPݳBԟDQf+STqVt2s|-ULQ(*LmzEGr"5#rw#y]J7Gr$e(e9قrh[9bS40mSLSIY.D3d$Y|*nVeS*TM"q6 ՝G +Ę ^un7ʆ^UgmCRc쩡+Ҫy+Cu*M]X>N]Et.N;~JLϲu2(hP֮<2K]3Ǒ%]ߑZح)Gq_fr"yQ0LWWV*ގ'xXXHD45R)ҟ4KkNT'/Xr'کY{*EGS]Q^KdeUz'rjѥ6zg-r5 n*ۑ;gS.#l҉LMڥ @O[Hw4V9J qR ^c,բ>GfVQimS~G&raG%֞y;6+qQ<;fi"yQL9WV=-:R4%Hӟkl%r9ʰ[RN ]('r*~ZGrO&u+*wrǭo'NXgo}݃svfD{}sܭJJDݚK|e5T64>>)e7IE6*egQ\QV.Tl|ԼuvCq m+]՟Uu3~.rv^Z3'r-*z#y#KZR܏bdQ% +Pr=]Yhݝ>LGSrk)HH|٩mQB@TT,Jɰ75/SWVQN64%S[,)z{>3vd5T)#Ǚ۔KJ<kS¤<0vw+M:Ss﫩Y Uv>`֟5nEدUJDOGWT3.8t{r=a9MSʫ[r=H=܏Ze6Yg#lE)L"G#n[ dnN&߉|+m'm %ȕҨ-SR*N jmT'ss,uWGs(TkeGs):Tj8wSz4%9ȬW+ez9Cu4=z(k)Gp>Fbm-6p7JQ;Z&1>]JWV ;We/7Tm>sL̞uTR<{9\R}gYufjz8DD:/\50}X8EeV] ӟ{+:Hj9>zv;-0V[M30z$2禭xr=ya +GW.QBm]a +Xj?stA,%B! +>5ө7Tڬ]+ė=/QRq:2pr>ӝMHv:ݜx?rg8~vH_|)S9$:]u2[oI tu)ԟD7kVNq^vZf fNE}֦{# R&܏ldN[tZV []9$aR6H9dFM {mpP9J*yͲ#U)Sbn:#60=/4Q#[#?gZhW9M: +w]yxv^^%nX6HX՟جާ1—:])yߕA_uZdF^t0DjG-VɼK-D^e\}-P <ՀIhkRA_Wj;MIN 2\kΌKԙG-#Ĺ뗕[ˢ8<K:בҘV\"$vz'!z|@֟9a)vm4,L hXۑ9,#K-Մl1ttY,J'q +]:MΕҧ7=/7RD)8>sTvz5Lrͦum:Xz)Y˂zVqGkaEa4 +G⫧v5ѸП?iMKqHηՙy'UYUf9I'h{{#0*7C*GG ,{×j2)%Dku*M]X4iiE8&u%N&U<mВA'NntiעDG¬;_V!T+ƭJ,џ>FUǁpҮJDޙMy֦_dc9|Z)atDG#ٙ9Zcdz'hTBB${%-қD4ӻB*Jnmw(TTu:yL,:Ӫʬ<_∙xk?07FG y5p@Oy쩧*v:vSҟ7;ȵJ*ngeƯ:0z_$J3NG#>O8zr=ǐ)e"95CLbWm-7Ji95RtՃMkkU+ *q\Ov#״+xiiά4Klה6Rx:pM8Smm*{FugZ+TD6ӟFak]vN;ҼWAn0L{ .G2c mu!i㥦BuQ#3J"n}|ޞ:ЇZf KBiΜ$WzQOyD`yyϼIy740D㊔LbkD[nv5yԟYW+HM, tQ)3o 4~O)*{ pm-­#יS)ijH; +]4 +r#ziD5RR8[c:TSbnU:#6p/2W?6 B5>G ul}ƶי1Ԏ^ڸO:g&v(<[h~= gNx6.bNwzPqW\ן ]Fv6hXY/UǙTePߓO=ېx[m!|Ѷ(wV#mR4r{;h"6J +8KHf2V&O!qQXOJRQ3NsazxrWjhu֗W`П +ҊneҵҢL꼉kSfT=]?:Lt=]OҍDiܶ} ۛ c>uI_dqS=3Z*l =4xg; +' (U:M֦:U<}'3J{OyEy z{}RGqEYqJqҟ}My;8ɻ[vEm'|pQCX{)tD¶= ӴhTZBzCX\!йt%me4oÈg=ݐX=[we40Vpa:R(o$yqIf[jк(sJziDSQmR♍^x:]=n3!eNPԟounRwYݡ#mWd5ʎ."iRqx6mU:1'u2i<1'}Q8ItʔO>0'(5@4v,h<jӻG>Qw*+o{yC~n]KmOL_f{wIͫT?ןcS9kv=7H;wok'=^7UXQoiCZy{M>d>488,a*fNGEfŃS.*xx>qYwyJ1KmpkU:^T|ПUvP?OvV_Y58߰zg$lgnܾMWWYSޙ v%,C9ad{rCJұЊGP8$e*j:[4lr˞R_䧂Upj5cTnPfeZq#|XesRl+BG´,aK<=^ֈ}Snhҟsh>sɍN z!Ry4륅ILOe| evE7PlJ,Syidyۼ🔵:}v<8ufq8"O}&ӟxÍ͕˭z<"$=cR{$>d=-C4y웱!7mT]WfRsO2g}Y{nJx_V hW +ϛ/]xDR\U:zoK/ ԟ~Lw^V2kf\y?ڱC~MvXOx=xizCQ=ȇa)N{׀nzͪ&ʧ[fRu'4c<9+eZ7>}?۞KUq8.L:!9/@՟az{j#h;*ZZ )ҳ|XNϷΧiɞEj4Gr65^(\2ie<۝-KOy)#.ڿ;q5OCϨ) PEĞR{7hTW\y56}J#7Ua^*џa=|d<5QO`y=֝3 &%7ki2VStECZxǼhoKM0u:sIz'xU O@;.ޒy5Uu:K߮y!/ҟajZ<ʗm9~~u=+Vu}L|`frW"R+hk@Q8Du]>͹4OJ7ۿ.~/>O#PyΖUUWnl@ӟ|KO̬q=qGXߓU:6!gWYfxlzGdwU-"T^ DFj^Tmu"hλD2.򕴢Qhw>~Z;g<Tw%rHԟwõlKUyi ;{ɪ4uzY%j߄7웮m< z*^'Xfԣn/Y<ŝe)kgUvyj^Tf>A.T՟s+Sܲiu|VdMK~MW.ɧ{$-3==ei\e =2ԡ4yom塗w")(K/yC)S7ͻ*uԥx ZޮxTթҟ𭣣z{ʛi}^|:Ǿ{t1֝HK3({aKbV)=]WfrhE5@ JUP܍\t&n_)C.9ĉKo +ĉ]ORQ u}Ɩq8UnOq֟~VNQz<4<,&ǰu,r'҆v:=U'JyuB")(Pf>6j_#[J%-hoUdן UKFi:aPND>"TT=>4"9GMm2v=?w8k2rQƒW6ѭ+=SI߶\ȽѶwX\JS_ <3M|dy%q׺Ы'WfUUN- +omП ]F,N7H=![yWcN){ R;C UߨMRwf#S+6gO~R4vUN)Uj]׿Q]]Qy mP}oZZi+I<ĨODhŝ#2y5q:Ҋt~*+UŝSҟ\w'me<ڭP+tO3׎<1|թV9W4ZvN~cys}7;Zt')7k&gݚvꢛ LռGW4˝mO+,z*'N T%R^K]uζY:USӟM {+NQN>[yƺ+cct~z*1-ZR—<+=-S^|Qu[khUbfU8u5pgOzw3ڙ-VZzO_TE +d]6uTYP*DO1V΍:0oe&ۋiۤ%Kx<3ǤqyC3qJmTEoW+Ud׮1՟7+ԭJoe")(2WOڞOJJH{!IC(nWbZ\i!8jG'u9=TRuU֓Kky(VN)oDiORNu6_mrӮ~g3YW48r%y+.R8]iu¢̃ZDs=XgkRmu ~Tuaºi[hS}wHiQB!8MP'ROu'(<}_ug3Fi~:d,Uy+Tm-u!ן?i]+=r۪nVt{[]PrS.׍Ӝ{EcEcrzcܱm!ܘj隥eNOe{R"jzS4`҉v4vP,RL-Xeɪ4hoI3Py__3řՌgMsR3͙+Vw:tMП_pJL<ŕ2t=ukH{0_{+'1:]yV(Tu`KڎPnԊs4Ϲ/j7EJu<(U!}RNW4bGO<>+y5.U" ۭ)E*w,\U +ti +Yeuy/= +y53^P׶g66Wv+g1 W\uLŵkrUmJRʟҟ^VCakަ]]S/7֎XVa15g 2ienLc\if9X١R;2)v&òMXSN|-%( *Iuv`bYmμi9яhjǙ̴Nԩ<`"Vz#'qڰ]~6ARPҮws=+[eN7[c޸F芧ͮe.Rj7&EI>4A^6nY8͜sK-;.|]4R9y%S<{_y޿N'1 kL{{[VMԳ~ԟ[;I%×0v[vJPb+N3׈g24#'3)l1\*m Qי0KӿJjjOZR" M[;5QOfV2]}.gndRoEqǙ Ӥx:_qخx<Řݯ;3SUGyŮ^J՟s]w[ET9a7ӽWgqs=gYSu'w3ڙ sKp{'i53Shj(vEyS+*ovwR5ԕ$|S 5U~U6+* ,{a8r[w/3ǙHtgft=Jo~ijuοtv,U+fNxZ}֟j yo*qMl;D +z+'jkH{!QhVQ\hniS],˓ÙmZ91%Нi9nu*NSUIJJ4Sm7Щ0p@Пadns<)E'uGTҮgr3~\gp&3 Scn+iMVCfSU(jrS}ON㰳 Kt_-7WZ!ڛ=Oٽ3Kg7旑Ix;sa^Q٥gl*9יgFcKS֙I/KzR2muֵҟT{T˔!#grgr2bNIT+(g2K7Eu#ngr3i}\ިw t\xs_4=E+d춪\eUCu>]ikJ'~oY)Cq4}}}g3baDg37Қ^Dv~g37ʞDviYyC63&v\<΃ƸܭRE^rDSduګ}ӟ>[EMԐ$or+kD)O|5Ȉz$OC.mKg 5t9jK}w T5+䧭Mt̚Xgw(imVhaN?}ߔ3E]hƸջ=5'tNjf i<)VqR=3ٜJMkuoRZz}@O>..h-[EUX_ؑhu6鯯p:+3f(sg:]OL몾KU<.lnC"9|Q-OJmX]hJs;fVh'30;m)čJ.7%Ci^բۙO>58"m JJ4ʆV %ijMzNlSW^"ys5b%TgK;)!<3f{lmig_;ju]<8>lVn/K3;r]]}\yq~b +RɰmK*hedҟUe Mڭo +r+qE(s#WBw^fzUrng2:j^LeF{tRw3]tKjws=J;*|-Zri9pަ9M}RES&gZq5-ժrQ5.E)cIiSB*M~+օ8!ME]~[,m+;/4ץyz,K'u^g3K;+q]UzRy03IEuÓ3Y~>=/ڞjU6+E*Y]R|+j?ӟEjM748+|N힪L譊Ls=ytiOg>)E~8s=۩Gm 30Fl44'K9գOi>ͮ|R$UݷWpfMh2}u%wLՃRuU֓q䎮Ɲ]JɷۯZ=|▙mp\Q 3M}Gx6Zf](ڦ{r#ݹw3UNLSAGg}{7]4K1vÙxc4u)|sۋ4 וSz_ Jo3lO|RSqprCHfT[/۞^z+~YrfN~U_I,Zӥ<Δ٢w:_ZpK5q6]Sֵ?֟UNًUM*,}VIֈ9MËbz'I BtBs;/sֶj^g|ה Is;/<z9~xs;gn%EXNgp`ihDw}MtÚ|Nuq NO]79mًvT,WnS[ujR>+~R6S>u,r:jiirM)g&E4V@hc^^ůe\d4jDT:CM"y;ݶIdgGf' +&8:1|*^':<:Ogg3fbU'-qk{[msןT;U )Ui7˫8IփapS\AG4]9tKxs;gmFs;/Uw򃧨wF Ϻ\Ъs;_S.+"{'fai)^ce6x |d߬8&v_Pַy7_ƢUqTSSWy! +l_9kM;דT$4V)XzMۊmuB!ޘU!|)%_oO3$%hgGׯKΎǹ[y1׵K3<ΧřTμתq+VK5L-[ߑПFM{Jӊ\eR*9Ǯk; fUOhv ηZ ѣۙJl_P ֔Ky˔"ωظs9Bt9Ś츔>'-3"+EE9ߎr:|dXؑ㬒kY:ȆŪT}hмUOE {>=o?I>u)NhɺgtLjH46HlchOW +cdq-~wd4Wo87]86%fJY7:m>RQt8DgL(jZ#'8>s_o gNC:-]ω؃ԫq 86e㊫h^c+t%OƟpoRfӶ>QWۙWv>'bamĥztY99N.mȗg9=՚ *͗3Zƽ,Ѫױ5!gWd5'Q},7ul*K=U4O[n| gcmM>H$x^vtjJ}iis]5Mσ)){5NcIhŬzAjƌ=t6n=fDzld5D6 4[{N>'qf]p:Tsb\nhDzu+nQI&J-Ǚx.V}A_nEngCS!|O{4e'h-YOm6ny5L)74CvK1/lR'zxyK&ڭ{ۛZѷ3(ڤ|m5-I- I66$D%I>NyJ +R{hm^Ro#u]ZǽRW#bj_^RW1hdsժS_>PUU_9h8q+:ޭj^}.[j^. ٯh[qKDUn,h +x_93"kY_{SF4&wGh›ߛRq{g91-1o6,z{&cGR_keϗS웃D?ֵ'ݿ(Wtztu=_jy@}~P;?>ɣ?߶}>Yڛ]=]Y&lVeY6k~u=Tʓܦo'jgدvTGU}bcKJt5x%\U|MۍqW+6^(uI?~: #sSUOũW֟~KO 6}[5,_SAwhYJkؽ䎿ٱ[k_kG]}KŔ5kqU<楜u89󚆳Qߞ>њ/)Ϸ{Su_^.{>s5.'¬{Nh>3_s=&}Qz+Fa+M+6F7rMRεT4NW_Uzvgo72|jW8?ZןSWO<})~~Oƥ='ҜJp'ZuToJLT)_*J{S:R*P}W8C]h_RΫ{sZ|U긬I_yП ^ endstream endobj 13358 0 obj <>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI]/XObject<>>>/Subtype/Form>>stream +H*w6RH/*21637T0B\DDB!9K?H%+ . endstream endobj 13359 0 obj <> endobj 13360 0 obj <> endobj 13361 0 obj <> endobj 13362 0 obj <>stream +HwXuw}^?QBRDxHIM=$.=a4r:HA" 'V>~PEAY)JYkDД?w,8Ņ=#/A>D.?@ " :"a[Hod2AF#㑉d6,ArH!R"e~ +9G4!7{Hy(DTC@D#>h$: Cǡh: MCY_/B+-CUwiz@[)p' >>&a ,>rUX1ۍcq;]Ʈbw6 ֎xw{}(<)x:B|^r|?~?g+ W79,aљA%#ÈXb,HL%҈b"@{Jh"nw#H@0B ^"p0| @Xl_2P[/P )pOpwA+xIIv$#{OD2 dEVM>"_B RP& `'Qp8 GaM7W[#a]&1 d&Yάd +690%HNB\/pIt.r +\)Wjeg:w{=ߑ~ ')l>yȗ +zo%+(/t ha0J/L +[rQiRZߕvRS=`5VW'jDSWS׫[^zT=VϩW&z_}pdBZ-BEim%i)l-C֖iyHۨj +RzAkԚM{I5pOcz?sB}Gk:^ofEoӟ p0#i3ÌXch$39F1(1!8n|o5.׌=wㅉ)fo3do6I43͜o.4B<`3ϚM-fEZ1G +ZaZUVuźcZOv؜ڎf`G vfgڋ*{]bUv]o7؍vbO鈎No'vI4'͙,t:;: +ҩqzityvIw5upscݱntY2wt+*{=^r hOL qo7˛-Vz^wһ]Z>k~"?___6Ef! #`rdK`m)z x!)䆺B&BC_v*BաB =uu$7#ј{s +Q\']p,Ej~eO1WݜksR&̗/`qyϋ⯋]??:yA]6c~=WqPNwT"|nqAP^.Y02YXuW +WJqr`}-k,ӟ0* o86Ou5b;G/2ee&kZW;1#~p?p Nx_%׽VuU?2MzTSI +;M;sN{e +0J`3TV2U{]SE0w椹 oN M(~w$uuzWߵ =_TU QG[f̚V.5c( %aG2=0߽`$C0iΤk!݌?u ݑ wGMzU]vVqƻu]:!cuQ!z=uaNZu"ÞgzzÑWYzA_WqZ*c67QMu- zVxa}8R!ԎLIQ?ކ2?G~Z^8v[2~N~\g F +8.XKx$]R\iZs +.hX΢3XqJf*9ek{ 0pUX-S3UUavև˅e7%-amQ^Bs~]}wI; sj[s=|񩱶m,siֺ]nK;c:yq}ؒiy݂v)v_e?sɟ/ñd&6ZqYSWYbKl^//3Kھ.l_gھdUs8DA> gq]6sϗ}nǙ1ŢS$g(-8hZYz]:qeɽVt[֤ߊ"벆˚t^Qw>>IOZxʴ!<BމVy"CH!)Rv#-EȼX"$G q@|pIb%P +@.LX` ?CXTiaP hC>gPI)7[k*)1DADޑ*aJCJpk Bۍ!=#EBJ"B5Gj6jL"0A嶺Rlr0+zf +\}S9Opɥ~`jvh\6H2߶ biaPDjߟWFxX10GԜViA}DJ JPk ۤx&=x@~x罙gs,l/b8-wX^9pCIeNsi`_ۚ{2gi=sds&w̑&^[]9d?syV};W8+q)&ή\V^% grpYKǢn^/:mi.˨Xs*\cжUy5hNGʃXADbLBk"@$0)0J11 ȘC|D,}PAGt\| x> Cg= "x*XQPJ,C&38d/ _X²4#SPzvykjVV`-% f- 3D氘5d"tp(؄c(t`F9({!"`f A)Cp A"4$ &DdL A0#D.LL==Ak)P2$a2CrX(,aY8r<,z9r,Q\M! a$.i˸2nX.W2S1~lө= ^NDƃƇ Bb Cl x7|š|/NjHxa / +L1#dd̚ Ȭ0HAf Ȭ 2+B=F1d$c$#XJZ7c-$*9>(yz01#B&R Ą&ym[nE{z,Ǯa]ʰgH!ْ1Rd!R #A!S5A1&HJ+ e l,"o*%7˙`7:I]AQ^g +*"*(*&&(@EVeŅŽ D.*!( +j6fbѴh-V[ɌJۿ}!.2.! 4TkZe .$]&LPv F2Adm "|"Kaa2ʎeKBٲpdi6ضo 0c 6-pim ;d _fYǔ:X9NɌ# +CaZYj6sT SCR6(aDk(Tg,HGu쏔t&kep>iAR nVG;^SY'mjW@ۥ u_`^5VjZcXr*WlmʗʗʗZeZRor Za\ؑ63\S5EԹԚڈC59CںƗ6+[UcTlF忬W:1rUZJEQtʻXk5JC{) J'˂ˊ8IZ-1G$F>E+ Ub֮3Jr`ވ)8Є3]a] ؅#} 7DFvC= Eb)?C(D)cpC$ps1 c8p܈!q81n67kqގs;.h\҇ \)\?g|k7'bp+nq=w5w[?} L` <6qa&0_0i1TͤLdz</^ +oLY̔4)[4w%1Mʹg} LW0}//G|x,7g"ރuC` +f413-,@b@{H;x|>9uYg??ccLf1:s];%O¼hg~2,#0}~E*О,fQ*:'8ICꉴ'*B=O,^⏐{!OE>XRRG^%,,k51=`XKY? o7ypGp#"DFBsD][>L _6{FbH\qwYݬde+ +ΪJcU?p޾J= q$\ SH#oIOR*IU$ kBY5bֶΟu$H."&#X?5ї lO?)ڑIM҂H#ݞ4һI"c.Ed"oy[{|?A*U3'SDW;j=[.'qBG3H#ŭ?eK[6ѽ@ ^0pJbn~Oiޣl*ecdl;ƶa)均lOd{7oSnG,ʓ)o;QĎoPSBE?TSYD%*s +;y>j])ұ]a0iToꏩq&2j>;jeQ[Gm?usDU^;aO{~^ޕjo/}W1 4SqrH¡F0h|L4sԍ[928v.2N|bSEΒ/](19o) +UVgTNV* Ta +UTup աhQQ:ёxy*.UJUrK?z*UiJh'otAeU&uNDDN"lѩ):WtN3_wSHVy/HU᪊DUSE*l֪*TyQ6ky{ߧ0JuXuK]l eH.EuUQ[]bUzjjQmj߫.@uwU]FWuAWu;]3ѵ\]VC_5VCSTן6:M<ݼ[=Ftݢ{t/WAM#\5\7 WM0Z둧ck=^O~wROճ5P-Q?OkyY/^z5HԲMuvUzLoWgлP GhjUi]O5(ӶiƇp}0ށq~5/a4h1E:ޤS0NنEtAj&ѵ#ֆncѽv0`I=y^w8}zg)}׊_bjw_8߉13l%f `Nc`0/0ȎA_0*< Wc CKp1<ėOj1dFc)>5ӝlHgFr8reFdnbLA=8b|Gob| 1aV0 ꃕ-VX%XNLtdv&Ħ+6æ nخ6[vs.{#? ,paq쀣_3'V1LNgN&é7N!8]gS628G痸%p q݃Sa-Sbj#nnp½+xX/1m1☶iޛLÌXfg8f3Y}Ŭ=̺(<܃ fe"f'1^xū9&`N,sso3^]r|L .|2ρyE{|O0~fd$4?[NnJ`# -X 9 A $8j a.8V8B;Jh +%)KXZb$aveXfò\5Y^͊%8J2Ŭc VmcU-a/SFx p&bD$6݈t"҇D&o"y 1gF/QD"z/Xkx9.uN1^DKĔsq. Fb>z7_f#|*o% $xu$l'$Hfwx7$u!iI$EI7IzI $'[$7 za&PIJRI"%ݤ$:0RI=KZGfCZiѤ*IM҇A*ҿ%[d#Ô 2QOK2@3!dYD#r#+, +jf%`{6Y)M@#QdW3/rɩ'w'6Odv6yF乓NV;G^yli˖>#65vE^q{q4IfOPAP̊z +` Y -O\RêU*E@td4,cq Z@1H\WURsJ9l{~{/Cv@>)2i#,:T2!7Ck)p©*CMəreq qڊ ux-8g6aNL}MĿUz$W~i=~ihVY͞2slmNE&TTd2GL6_Dcbw1m2W1 }1 Nb1 +7J[EUeǧy 4 i0$~|Ż 3/LdJY,ppx._HXd(xߓbG%$-(n__~D(Nj磒.1Ŏp% 0]sԇa,UsaJ*>\! P>|(@UH,c,UA^ȝdQDT3#Sfx(՛AW61ǐAek08ʟ3&[4(p(g8OEˋR) NҳOOk,BESS$lv7c?n9ı5235[U{RÁt7?ˢ^T?>G7$Pd!k<EY-4ʼn21(#4{=MuWt2#YXf7.swQ=ةQc W簾b߮~af?'2\I\LB=kliCB^U (fB|/SjŮ'GLw ď3:Mb0˗nV^}襊h9Z~k+#fM[3۞%|a$taDp/&ɋ4x"߁]|tVhij;-pRV:2JaUV#缢WN?Q ZzQ`;5mO.gh'ZZ^l\ +)?-XlX?dLhM]~ݺ\@ .CyGԑ&qʽ[ƛkҕU|?'7k_ jnmFzݜB.>BϺBaS%7-L:p [NlI O۞wg'sT+.a ?^Wlw ls[ODy + ď*R[RT/$ +~K(Lc ECR4.?:,utE2LͶDn w0Gp`٬Z3Ob)CCżh[ B1^AQ]g|QrwYp/"hDB@1(P +JDj"Im5QBŬ/4*hb+P5Cu ~w:OZ`gpϨGIn~tڕJxO`#53g$4aF4%k㻲xw=<Ԫ"_iaZȦ:aᲰF4yFhzʫ?PhEqSsN1BQzFZQMxw2q=c\ Βvt6JO5@Ųcq."IV=DtS {skZi:@"{DR)T`%5;0?X]>y0ˣu2Wc05qћ#ILldcmҒ_uw}u[t2]A}t4tx$hPZGKSU)1UFHBcEm?#<86йMj ^3[yאP2!G0,3||ȓ/mxz+OZmȁHG: *ArlU0 /d-[03ɳ\@A0 }xрR"TV1 +^"k}sm4xpYo}.k5DPQJA: H!^pGܯ`@e z@;g{ /4YgF un8NƏrb{kÆ'Rh=(ASE_oî_zgjV8IAjqIu`gn paC=MHba+{ Qvb=L ߃jၫ0 +p LSٸnF,._z%'0d~] Oʏ_\[]p|YJAVP:??Ĉ BVӂ3wW$H>w.Og?OFM!\I5Vv^p=PKg J0x_|߈o%0ډ` rqx6H*O wB+vZCȇ'gR8AY.QLr,c8W'Ke)1zQNAh@X`DV4VdIК99J*}f:4(ЋlS) ?>Oͅ7y46mw&[U + @է7Պ_F禫v(O_aeo׬`rgFysi-WB gFl3 kJDWՠf5=m p ޥ%jr:OfS/t,) IW +KI^9& 8L֗MR^!ngQ>b'JbAfm {uC ҇ VВw^.Q+fhEs3>GqrEqm7FCC͖Ɂ1^fv]oZ4UZlVmXj!-'O'o q(jG77Y<3$> 4TWZ.sM0^3:`YcYUkDOMn㮭tY5Iy] 7[#'REgv€۠m%M\4vNtMO^6:|V A#3iL]/n4jࢡ:ؼYqdݽ%]F۔VT[7{*js?\7ퟮI1!ޞm1<LJpy|?BpN܅ ;Hq0`=|7v;2pF/ Emجi^+/7Қ;w.N4/x,ncZB Qr^viOh.t߁C"㖬B{dN]W^tp?!PtrT%66)1>pboc! S Un,Qxrf?CnM?nܾyߌ CL:y6ḭ>V*df`k^:k~eO%m.]=IJ&+kG/#. M]_H5c@u3ɴАEo,jI?xPGp!AΈz&rqL.u֞"wxG"$=0/$s {Pϻ++p>:RŵߦjX)d>nx%,%PO +|$sZJy_llKѱvߴTTgWI r" 0WV`Չb$vp.l ]@Ajs^by +&sRL0C"RB&{O3B!B !{JH~ПqzdT$'`偁2g°~Bh_PC*;L33Q1z(40>"ft DR~3,h94RSr9ĝ,h, vRR!,,#~*mW q}M@20P4 D|vx˓&3}*U49*E%+B[/hj8+X\>hfelgڡ 2؁K;ri#9 +h1 +_KT젒"k\ .*o`-҄^ijo6鐔>I]uѣ{SzXH!S:Ίw"1.Ϲ@ўZ%O}d~PTDZ0 w> >Y0i +mP,@]j+'EFͭ3f Or&1忥3V$$:db(a*E?`>]~2YCo# ZJIr)X J\C:C%T{&k}[%Wܑp{ +D n N1S"0Ћ,AzZ$t=@a2e1ns7D7{) ܐx /!lEZJi4!g~aJe*^fİ{ d C4mH63RsXC6`{;:z{:,-,-;z&aFn簣>4ɯ70's41c4|@{HDҡ}!ZSt+c!OwRKuX7T 20}2^&b ް=Es899z82-Җje>d'$Ϫ>asQk:xB<֤Q"-c`/FC}F +MG6U5LLܹMX@bʢŊ*[ +(Q6}>ת]7 QPpA* eEM =i睤ӎN;d9w{g]xgAi6NTpfDM#$i{bC;q*xFY3Yi9X^W䵴f>d|z:ٳt&3q;NG31+WF<tU( z[$v5/_aq c3x5ʽ}rrɇAciCQ#8Wv4 fn뢫VUmPW,lSi^}-\3^O7jjV + Z nbkʘܒ82&Ni~> _k;֞tVu̎%N|y,PED߱Xvf"ZZ^|[{5[;Ry|JK3 +:"59a.&6Au0Jį>~巘\i)0HRnQL\q+1X\0EZ{gI4HE"-)b!šw hLw.\͹5pM\t΍.=u=JRInX&l~*( Yj733%y*uVK 4 _d=BF)"{.LӃA5=|BOȇ$6z셝̈́&.,R-jQ}Jz`$91' l!FCoY&}:i A9;UYN ڎ)v'g?O`7I&q R)6O^*GWyK6s"[̀@?΅&߆8T2t ,e/F& qW'|>Z]@&[!Щw,.r"B}8y~ 㰸pe 2dzaQu֭]xѹxь#g2$[$q!ʕY$fzR?XF6`kT^!Dw#Clv V$>[Kc< +t_!.g|7 ǖSOheɎk5Oсuz% ܂牦cTb.:"$>`,u-NVEPQ!UDbE9T+d_.&}.\$jThY\m*ى` Xc 3د1(obVu~6?/ ]Xd +M`=f5 G17p5@z^P_KiܥSE˩τw'@ +iԥ4xK^ 1!ACSdH<4$O`-|=p&аR!&3r"DME`A >>ŕ` +9֠ 1q8iI250mK`z#|ϾـNڸQ']М&r49A\g8A5pOHE;! ylb)&^qّ`wMAaGW_PDF*%,:^$jF?A/#/v\*7pVУGCCd2֖>၁ၬ_֖q8of(1څ \?F~60fl{lf6EŲ`e-[7=px]=pbyȡV܈+ di%4o|+> X(L +O]*b +vKgwtideހ^-@MY*kJ\*0YZ[ ++ +"%dfκV3ǢVD/ .*" 4* +*KsD3\$*.e%뻌B_]'n٫HHiIioaׁeϟ?(kU_ZY@A18 q&";Ng bػ4w47tqgTݪjɓ"dUETCݴ+KyYRjJMg۲QԶ+C+x)@#J;!I +? a|-0pag;QJ1M[_;b\Tn꾔,b7,lJ`Ԉ5kܤ'!R"iG+%kz]j'ť)Z;zn#srF +#~A|NAPb";c`LnEgkv-{=hOX{j$xs2-}4?:eϧ]Uyv]G3s_ۈ2qUK0 a0!_;:;"4 |eX\^#rY=QY.5s&HoPѓH02<6/a%ץ&}E Ro?*-ĩRkQ..4"@E)‰q$CȐ7 |%$A0|,N5ʁoxTퟬ3vMKX[2{yk87 Mb +>ӸQzګ -Vn?~qoqiߚ~u僽f$ RRM6 +5bJ)2U·Q>ʂx ]4J) [(>nv=Sܙ'D>9hhidj߾3%eEIB! Y?2[ o9xI͞(>7CCd;:QDiO 9&sjpcN/MӔ Iyg>tHiA0`q.9Ǡ]\UG:So5Q6PUwJYfz_0*#fY?b*Q*8'Re62X +rc;q;-'UskT_K&mznQŒ,f-u*nrT Eƒ D"@/fphi/pjِ/n_q|2C2uzQ,gKy.<q!n֍' iԯI]\/ÏJ}:OZ\wluc [i21pDiv d+c`R75yU +,|>NC"-Uf~UZ>.=2I&^8t=I ~nQ i5mmrI^y汩]8%i$Xh-&Lce^_ >OКfjaf}0Z4y@/4;#iFlLĜڎ{lgmt%`K~ᑔ҆)C%^s\I4J/]Ǧ'̜}p4 9Y\'qZI%wJ10gT;~z'f 4]G, + +F}N +YD%[ Rv5`AaZvNAW PSg½ag옻2rh讬vTԂm,`E@y[ oXljkuZs'$Fkv2L9Nt$iZ1=|H`gȹФ8[ɏypwvб[U(JQH*%P1j">G#Krˌ$^``ss7ǤC[nzis?ӰʨAHc6S̘G"y\mp28{(S`ÌS¢7o齝3Y}Rlwҍ:E7J6[&I|tqAت7ڪGTz2QfQ^4#Unffl\z,&v&Rkhv8(om/5vڜ%XgS;weemOp&hodҺGK 7lZ۠T!`W~h3ԑs43T o8E'6S|GWM9\A}y4wW٧ ڸv.WwٓcP`./(-+/9_>gj'NO+w~X聅î6CIC^vEܞePډLEs2fR{ʎTEl0$*:s [ɠV +L=l|&y>åÕ) ;v<&W}CO1O=ں!Ʃ6Aj nf!נm>|8oGu8CMȥPBKa&XKC*KVװЪVZ^L +-HiNC%R%,qM502[!SaU|h9s'L}j;ZsʒWVrGxMHyAqCeM#6k}х +|غç ӆe H~L6ֻGTg9kWΓ!NS}jר+в2\ +8"8si4?󇐩23ۋckG 4?G6V74U4r)ڃ m:T ǀL7>a9B:Yor/R}OXpG?\NX= ]hv8QXs!a$Bqxb- " p&p>nLv4rwh2̛EL ATkJBƹ҃L7 +x6V'Xrf0hϨff?y$j.MT A쳍`:%D%f>׻zK(<އ2K +͂/"xű[ߓߦy=q#^=פ]'3!@ ?4㟡GӤ7i \҉f0zL `lߊyA>2a$C_oZȴPt 4} MCJt}P(AS]J PLj>.1?$T5G,AU\yspNl ]3DS,[-2g Er+:9QAqWVǜkiLݬbzcH(6D0M+W +XAD ׌]&Uf^CW_˅oяv%UALxЙ޽MY$-6NnO웂ՀRM5-/&V|hS(8]TtL#)E4En.G4Sbn +|HʼnzM6 +.?|m`FQmM:l3G-nlG"mt=m ,H8]7nZ ymH଩7tB3hi`.qMI; +gĻj~bK¿9IE%!=Si4b:R SefX.O&x3*p]#H_s15s@8y:> LF+ȍ o D 0JO/^QQi4:vɸ F&v#&**xLX D=(( +AvUH|l=%IeV;YrnIl뭋W0 j5er{ML jWJ@0ז5m6A]z%sϾ a!!˯V2Q~iڏ1Gy8*qe. +WP=hMg+;D0;cY4„ݪ[p~be99Ѯ0Tt W.ceWbϭ 1 ] ,T*fz1 VxS gz-F#z|h + +NK" ,g[KI9х`ey@ܽpެ;}/B;n\:3F`MG̜ox@}p꽺 Gc,/FM>ȊN 6YEFpKȊD֚V|y dI"'q8HGWPs?Tnl 62O݉cG5=00,488=,OcMI}Oj8'es?sf|S 7X[|h&*D3@?-aVVO0K^!޿A$;4@v\Ԭ\ n(6XCzF -uCu߃)C[/QSg3~LavWqϓ]܉\MK<(H)T]8܋ GcL5PhЃZZҢ \7_55䔀=/VC[l`j EzjY*Wd6Ί3hxZdL@Lo!I1! Oc|TEL@lo+ 7.!^6`&x҉++/e\kOUNWszEx84-]D&z^uʃqe#R?Bl /Q˷fE(d+>_h_u㚡= PʆuYvZ>8dn3V:p;D`ld}[4UlЯځJGj<:j"W[RYzXJXru3@nK|wL}Y![4`= <[P~< &h/%塨.(I.%=)Gu9JSݿD͚o9N,~QPb+}ȑLqBAwK_#B- @EȉM2 b=84Wdam'L%x6@PUN5 KLĠ7ZϤf#Y) ļT{I9n^MͿ +_?DB Te,j$YԋdQ/"JgxWǰw`X+EULׂ\i/W'Y͉\x=i(@w*|9)>b4u;܄pQa=ɢZf`kQ98%m ~z+t8!_B!Oǝdwkjrç#^MoP=ך#Fsց/nlهm\v~E8vCV\ґ]LG!}Xh-MmDQdT;p +.i#2@![}zG(G`v>m[فe:4pYΝI.XQ+TܢAr6-$hbK/ +"qrD6= ཱུĩ)Jz`(lKaw-;6;~>WiTWTh+`$.A`(b@PDhF K@F4 + - `Bj`p _;g^/`32Gꪾ}wy;X\'n۽^JCZ`eA5,*5~ƸĸW9w?fIwOe9P",-;Tz<8 S$o%jn̶-m͈m^Q.9U?ܢu]eoSU]}(;3?Z|'fӡ5q2u䕃B`.h7u o +"RҎ$36}eoz>+-W;.gyUߨ(T1=P}@"a Fs~.8/IxB +I9#c 01s:Pa V%EX vA RHK ]tySx$`vĶ *֯,W0j2h{r~ѱUt35tt<1 }Pc$~{"$x9&,*ȕLJdbL]Xqm3/dd e<'ՋIH\bP!D +3ȇ]X@MhᔳV// FFj^r$1aݺ Hgѻ^=d͘B&GAt;=AcT`-f ;gkԅ利taXuv# 0 Ȟ@zjg=l&-z +A!}&aaCnɰ蘢wM` K.A&s9 l{Bn *: 9 ]3GNsEh#& rF_"k'2&ȁDaixR-7J"=T]A7UPj_-osN$Ţ1+ܞ~!tt\ EGU=b)Ȃ8K6[޹V,"8Y5-_Nۙ);j=DBGh:mD~0}D(5ƥcuF4ѕ%`ҷ%KÄȎ +~7ts*;ٳ\`>t\4C.oa~/u7|uNZV]r7uqcSv VPSW^]wշJ\;pʁ@q! GS x/;`/'ў-.˨Lg"/ ' X#cd0)OݸSvbIw[/ Yx)ҋ?^@ 81/TEBy`CEtމy?8pGhZ()??ᦄh7Gn.7l^jg/$mlX0H¦M"?"iYM*x`hvs)=XCB; f;o@Y$c 8MXNۄ򅀝/]xI|8Z.|+#sF",Hdo֫* + {:ʼ<g<0IJE"&.1H\@E )"B5Gkds5USE *?Ϧ1xj{NΜys~ M"vt|x9͙qQ̦Qzċi)iҚگOЇ/O͑`tik"d|9HszH׻-Hשyucv:9Zɍ6dTkOw"Eq8/{+DEIesI7c=/$^YdQ$tՓNp7ٴs~}scѴno*?$&4p7$۾sAX`Kp\ujSTٶnYVl8m*Ձ%Tc#QXa.;޳)S +gT(Б#A 3'?䰤K{`}rAUbKD$F t7 n 8 3V8Fj @ў>%Xl4=Wj/7?Uksã$UUT][!>:uv41MZ4S?s3szbcRY-j`f?C'^ ;!4*2/Dt3egga3C $5XXf@ +5) 9 wE <^p᠜Dq~qP3S$YHwBN1Z֬f KE +OЛpM"c +_,j*OR,BBp6EͲMxL$5XE*lfV$™#LHpFgA$.@g"A48pC.werN` %(i ap;%:4m ImS9;#8p,qh1ٱ-wtfmB g>tm| +v`]N|P!kޞ|SӦҚ:.!f{Kp:u5)+gϑXX U +ah_%k3:НcmjhYӀY8w$aRi`yM0x0L7q3Mע~{|>_Ja]n;q"a`X=쳜N8g +?!a =$jYlK5D`95$b +X 8{*;p-aJ8Z;:}H"͌rF+c:SsOZCM8^*>\ʗ>{DsR+2ܣO9eFJ6~sOm9ȣF۵*ǀ%/g%:ljyO6u&0ZJ0.}xؤϼֿ ME`HKR6檭,yv8Gn68oX‡G9'I= -+B˦>ZvAR^  :YL$h.EtkFiO%8Ih#U^K<9GT&$YJ:'p^re{pD' >GR*|eD(;!K=]+`LD]KWGHtH:4iTM5ifU}"t5ߠ~JյeS1븧?1A aN [Ŀ@eѲ<s%hrZ +#{Q"x?sגƵոfMZDxoqOH AZ=(~^b)׭WM~(_9>y=h.ҥw)z`(ѱd<@r/ɧcK/^C Uh@ œ>(bBYn õD{#N%~wNg?YY/Kȕhդ$&mKtXN4b,/: 8|GK+ډ:بsN$)'ikjNZ_Qe7{N,qgȋ'͛TDOv2" lW:PمKh?J_mF¾ׇb#Ulo-~eUG*฿4t2a-iփ⧤C' +԰\<3M{Cfv=mp cLaI"9,k<;7ee$@5[Akz F]A!]RUQRrlX:tJ,\R:hdi=IlSlni0UUdggBsW}Lc[ 7Er>?6f^[r;jXsyP0^%LtV\j!<0jg +wʃH8Cw C-mibM43h@WBauW%,c@( +("jZ*DKkEK^o}SyY]]2ā S!߲#^jg;0^Ѷ,Ձ* p4h*eTIeMDioVpaIH]~t Fvdjb(|Ҁ2~!2XȚ`WSu.;8aKJY^eb-Z`2lganN^‘j hRqKzz2-MyT[nMqܣ'Rs@ࣹA:j)NHgqWjVI^/}PǶPN"}9x6/I>$ n@G1[y?m_.D5UJiM72o`TkR6yMҝhL[d1=&:LR!K xbVB ZtNYѵkeW>^_ϕv00ɟ6}>0fwm,Z:+E=Pև^[#f2lO+wNNnfPiĺcVuAs(d|溭yey%.BB z"? _/., + + ۲~,6X<)$;J#RYσڈg{׬կ+Bf:e|!g{v)f[jehfK4 o&a\s,F>]uP<Y*"SU?l&EqDEdz"U"U"3Pu "]zLA(&;2XI _?B8CPBRjAGT֪CE:kI%Wq~}߶DQCep *՟<wx86L%0 fw7)_ Mw  +_$xsO7 +Π:ὶ2s/ 9D&!$I |<'GYO d/kq+{N,=Wƥ&!7x <[&x7,` irr42^ B)a*vWz86 yB6ARth,KXbɦ>U}iWP,`?5]uprQ4UN$Wq Үw? lTy}1D$:\ eBIV=sq>K&AMWjS\d:KD! LFʱ*rѫ_{벚$ +Dؓst +h(;Rpa` KWG|RᰉlbE+o*xyOvO]y4G)0ޞ!, 4x$4m=q244*",TD$U[V-& .b ])M-)ZYȎ) &uϵ kIu_s$yROm_n>4 UcZbJh;8IrkJ50\/ +vN}4\Ma I$xE֗JOXf<7l?Sob"[&˽$'E5ؚO.f~ŵ:qj 8h8zB7V%n@ϰо/?\`(c&\a9K0GSn4ۅq-EMݦZSw͔Jh/_iJs=SoN% wL Ǜ?@ۍU@U4n t*1Zht6Pm7 \[ AHIvhi a FEP+ H<1h#HDXW qkF\U5QQP7(K!O ?ÐX'&^@ףUMQja82k-uX&a tj;=tm;eXչhqsQoY;wp]Pmz^$j̥8-f}Պ@LYdfyu~`t<[&^#lk՚dNM4f9UZJdaQfl?Zmq|.6| ԄbtO}YVy~Ȍ6! J6C dq@>?0Yѷ +s:f>&'v/2}|b au`$C䫮ϩHO nm]0QF'<)E.9m1GN53pF" 6u(isKK\'A̽'b@rK@34"3M f!Wa c=<a ?GWps'E J><88x5|T0sO;tG=mnv~|Q*tcWG 2 +_4 g\[gEY+j;Lj_OsgNsJ~ߏrz4E+\8N_,*a/o-T ~+Zh_T|,Lx/W3[oqo-Ւ}Vͣؑru]7qD;=kZR~6cp =un¬ǷЙ'#>5㑲P]Iᒳ!A_Z9ğ8mVԩ7Y7hMN,<߰N'}[wɲyX0@[/++a?8a<6v|%ڙ qO7U]z@8'f 7G-U\z8CGJN&_6o}lZN|}:ZgX_CLCBqzPoec_s6;>>_^eK]7e!xwը!)Em'9%8-wk$H꫻ +&MȒKT+۫ԍM6z0&WŜCΧ\ʉt c!f <Յ2h)$t5hq +xD30 DllEɱ8] v7Tf1>+/sDd88zy1`mpn#Y3Up]ɆX6g bِtxHb9ɕ}ˠ_ ^㝘!b᧡Vz|$kݿw61K[4p>00VH|ԡB 䀿;ī?Bq=jG9r.t ]d0{`"G`uvz!! ZN (;|VU +78ʶ疔rCTWTaP:OfqqG5Gb$9š+0:E1k";Y +f d7m/IN[IN0EN'֧09黸 7`Ng8>ao sԼB!L '}1Z&S]/&" ~ 7;N}LْOJżm' e\h[0qś 2UpuDM~%)gI/C]p`d})DGć$q mtܡ!7Q_xF0Vx#qlQlĜl}l,2H8Wъb 0%99X" VDBTSngvXSpRQ\ZO1XcdqcALuV] Y{l!OY_PNMqzq1 V:#S:/:Sdwm'įT%1|.vHh/7tg\qn܉Gˈ½GRsR70eDں*WzZ2 M -¹ߋM,_ú5u:UrFüJ7(搌('7ᓘg,O m0R==wY0ᆃ4$Fh6bdӘgsuOzzn=y4xh- %`jD3ШkZs#/:\:dQ:&7ׂX\Fb>Y2\Vin hb7R h-!\f#!rxi+8hd֨, {a6VskEZ(Wŷ:::uԑPibXEm: )1JC`Uaf  `k$k%o|~r7ȢM=8$caYY9 jJK.@ONOoN$ +}\ Em^{8x߱ 5ZF|%w!ÈBP-S>w /p(}/=0gb-S?q _w9L;/ O?Yig^X0#h _y-Tp+#&O`"'zJjǂ+9CI@' sSNKT޵p䡤Zsn%W5%%Wޝ8 (xGBCO𔑎uPV%0F>. eZ?I"w! ]+0͓bb 9{D 胁T <=8enyrƙhu(׀}༄CX =[&hǤhىMOՒ4`(#uf{ ^Оމq^ߖhi2-d7|9јO} JZq[Ew7t,ԖiS1MmɘfcV o6sMw/PX.8<^todn5`_~ofZ2?RI%1!6Rڶ}s$:l8@u*ETӚǰh6euiY[~S6 +7#HR~yH +H/Q$ ,3cJVVa(_Cc + +zcygb,fYBf[Z&פ2p5TX(04ġtGljC?I~f忻UD*ʱ̥܀InE+e 02LdawZZa*MFyoݽG#l^b#ZX-եLmg O)N'$>%4A}(PLuRv<"UJ4,ݢ cQ_Ϯ66TZ~haLzE:Xgf#hQkIF +6?ktdXF[qɃş5k irlI4Bh/QCKF52g9)beAAhg!ft ep{=6^01ͷ/])ks5A),=}9bX-{CĘ(#@(Gfa:,k$._dG,` \y.:p݄C20'J"dyu -͢F,"q6ina ۃ*α"2mf[7-3в/̲J2T`APY*UFIe*`OU=)Q0z޾"QA8'K&8&UMFZDiZndbFx9tlQGpNg|*B82núfWS`0lv-a5f5TXTdL9!$HQde1H0wIA9L7e同2j(Rͅ0w#/pHAÙ"?ߙ1Lus:ZڭbG?#$YUPV!=J>8cq8H~GWX (\Fs5P #Bg68H{QT|Ej7(&h@FAy'`^md+ 5n#`&W}mN]ѓ|gЙ1T;5xMI{1Li[9S\JG"+BO7nZ`.{Aq(H螡dVV)SAs'L4)L %I6$|ϣc˜q~Zj{Uf\u]q6r=ɏ2" olH(M@l ֣@ձ]+*0VD˜-EEu[Q l̔{vuf7FsvUn;3ϴjѠ#,ҥFXbd2-)Sn/Ss\6AX \ݤN̔ӮbK7jA!d; +B Y^5U`.U-Lp%kG4&ӟ+^IݜèhtVF +W>ZAPɋL8R!M fz#,il3@YI4\wpy] XX㽔pUaM4p]{n8r^ 4YyG3/] YyDqʘ3$GC~YzWkTSW6`nA^g\PiueY:Z(K(TPDA2Dej<꣭ +jEB^FBF-'P7<=Aao`ZO`ki"uN]! ;)>GÊ9}w%tcf88f"|>cV 0^T~|q &pE SUL/B(Un%(gX"n%#5aZmygNf\R]&꾺P~"UKXH/D6^&i(kx6l>`>{Hs uE X9*L#x,Fz^jFWF]RVFjvUŮf5*v5[WR pK4+tn< +ߩFFH惒\;J8pt^l/oz= +6`NR]L|/VbLԽƊ[j;'y؝n׬] LG0<^-`'0z] ȽG3{0ZFZLRwޱGHȝ#oIhGkB U\:JBg-8?m-521 ; 64AT#- cDrt"7 +S1x?[!:X^{6>Y ZE_I"X|5ϑpW'KWr33/+W +#3Z EShS43(Z+_P՝|>Gx-g +Z/J\ߎr8. 8 ,N' NAuBNruBBhi4SޖiG df'w=$X0* 6j$t#h#\ D0Yrp31>zͦHHe}y*g.Eo`.{ͥhP7u"ư6+rq|+.n!yi߿J%+ O4 5&ߠ3^`?Vk}'%f\h0`9 , +٤g[hy{linc\WOA.z'U.#Q駲22u,Z,K hryzfCݹ5֙Mfρ]`CRc'j.?uO,tCʾ-ʱV9 ` SLjTƫcUӨ̍Ncb8ϸpQz1եQJ>s80j7SچFilu)UFMr}!O<'dصʡORh|<%z>V0j"9 CDI|;mNLp܉܄kB +oJMi(b- hV4%N{A5 ɄE|[azc!Ćo1Θ{xh(~$Qة&cd]C(ҮT:YK퍍GӃ(;PJ7l10,1Mj bMEI|a**fq1D7iICe=U"EEDM}" +>)FYﬧwfva>NNسg~2\BUQ?t3䱴gW[7 }zfgGyr3 h&Qt+^| +%rOp|˃p:Fd%JF*^[?PPz'9u쌚6!2 4w"&i[dPH9dTR:p|`Èk4)ATiYjz}-Ef +rAN:l(6q +!CwsP4W>!֣\AJ#]& EgZ+ BE{cONڦN|h9MGޛͶK);ḞEm/P>Dmf7}~ťϛ>GV!jyf"1fP'`A+"I5N;v~];Wf'o.6-<>1O59ԊxERL gt 4Olz7g&u.RgԻ9!:Jbt {]Q=s|ӵD +~)Ho1?FllHbVwj*-vSZʭʥ-n~VNijRpJ++8@vxt 11JvyF'(%4Zrkup(qrH߼Tnw%.i-wt5=_E?ZB835(`FᨑT^̤NqȸgpcP d?Jݹ# s~^R6s0P_-|mLXF] o}p>z Rd>±u+|wwgsi4  ;$ +kiuViC5*o;"~X I }5A9wp"ݰLn׳6س=ŅqFM9#5Z=(W-J.&^Q9m߹Po5qm>jͽj'F;+L y]-P&x{6;oߌܪT>1m:2%x!8썹zr;4Il}&S/ǥGlFlâ.ili,5j*IL#;qVu谑[Gw,dP{Ǎx7'@h~1A`$@%XiIb:e fˉ;kVN>]@@0H)ъ*➑bBJA rR3Ȕjv#"}|2$2I;CL!H+8I0 'h*n.}Z$:m@~Y)20]ܶVҐ{FEK;IwڑvD ֱٗzZf ֞6qNzS,YJ6'FT6j(;J +ʥ + +E3ݱl]cٌug#v+#vɈ#F=bw@LA(݊SGKn@_/i?P!!~5E_N^n2.ujјFsFQx60Ys5.jݬN()=u~e9%'2bKrF99'X%K O"nV#Z}A'X6*mO'X@xykIbcn@[XX~x +}i7H-lgPv_aVXB,*Onch< GbNeAk Fi2#%[)I zo6#! 0x3ΥT|Rh41h?֟[%¨|Oc'Er B=jhIUr< 0U>M2>迖>J^8%T2 "&Oy2s #|+׮7hR[\ȏƃbF"FbPL[(QD!;l +F6~MK݄D]!MAJ2L  )Ɖ#+ˬ330sXÕ:"r p2@8]8 #Qt']4x ?G^sjڊ6E +"c۱B/:1\iU>\|{ +C&K}:Kd6z\rDR4zWxEvE$[,` Jsc}۽QkCwD+fȤO\exo!f1}j&F 5fl="c"x7IwjO4x}hǢ͛ȸCm)j5Xd@FetG{5ufa"F)K5^y.gJp2U`E%,QqPX8["8TE\D ԭ, pnBg܄ py9qŠ$hl`SĨJ,DbLx4@*[F\ |zs>y+sMOBU7T=X48[[uU7K +=.sIwBl"nW}eVsw%>36<>fzC7(fUdtYtDɊ|n O]%[9#'>;vZ,/@VӔ^s71SdMyns:*EYeu6#w-0`TDj IcXZĺZP_O=wޕ"Dr:%yԕf 6.Dvo|= 8Mwk/Ou^g/*@1Tzc +- 8}ϒs2} ;EȱSǏN>T(B +]li]nصM« + ڲ[iJ&2bXg?x Q( +U#>G +۞}h-!du6^/]ná Ca=[%G(XBTpg~Dl +Oܺ Zc֯ݳ7!+bA{S'[P ]~3(4C0[gos,дQVzUG2nȟfᱏ/" +qQ掔so#E}LTAvVy +EB_F/"q8BD5pM0B1B(QH$EH HJHѓ06w8pix{ɸw4N_nRQj"Hu Y5=JڧGU0 (ۀ4%Hlh +&]%=4QV:;y͝iCD2V)cQ#:?B~,3|Q>Ho^wt+aݩ]M:xx2)W7-+N0ipT ]z\2pS*!g]dLB\wsYhNoa %D{eG:^Hw12nKy4LN  +ҫ5z!JrӚp +k Mt>Ÿ[gqyh6.Ϛq{tkLu + m!93㨻W#0^00֒,noH̜ilԌET1 7*2qCYm^aMYպDJ9%>&&` 2CZ:[ +h=?bߧ0Aʹ{ @V|㯢~ ]6S0NZo,M$zh</\$K`Pp=";m|PљIť]L^u.-~||0HD0E)|ds⹗JW˥Wջ[~u,¦s/$?)r¿5mGCbO ydK2V-0Pw*&"&,N.[^[S,S~/r`r4v`39c@5/!XFz-3aT~ "UЃ{|$Wp^SՆ˚*Gm1 -LX0ir@V. ǁ#m p.x԰Sw*oPTHJJM]tib$EN$ix7 +MX>7`0bQa,>݀ˀ3#Æ 6H;1c2"T@䠛Y'ӁD1.<BTl`|E; ~Lg-KgY:zB%;/\~ K>Aw+e_ P)-N$\v:[ɸ퍨EQg,=莢Y*B1L C}Mֳ]"M m2cO{|WEXޒF0?["n fַq,UF=vuߙA{w'N m0BAgEVM 7|Fd$LOV[ p՟N531.z`PA ։I6DA^ow(ŭqo3f@:`D=]9Qc>I +ɍ* A'58-<00;B4U5S5/'j"|].Ϙ޼m˺?,{kmET)7e!\ ̓!l #RoDIۖPH >"q!dȳ-W3"&ZLcLDjxg-Yl;CEvj յUŬ/7 ^n9.]IJQK=0H~4 +#ٴߨIQTt#dQM^]ZRz ޹LI67Yn*+K;(j@y Q -[,VRI?vP,⚲^Xe[CsJ +e3ĖTQ1bqǹM񉻎d ֗՚WBnl9];4n=a2;"ʉ9R$+'q +5-K[YUtɫ !$b= N|?W.n*"W'eTmN:L\jm9?] -lMGŲJD"ԉX8s&aV ϖɺWڳk-5@^hvە9U b!7Sڗ(ۗ҉)JFWͯ#$+nwYCIiP5TqjG!i~ +}Y +)S2#&Tg M(o.kP6#5e߅ ӢSL𻣚wb^\wBU i +أPGأ4Yഗf"9Y~\1Sʁ醜Rrp)G4B ANۼy9?2e]6Sfg -۞|OM(_L%fL4Km}miZhp-O[*УVU1 1.M\N:/j_u#ύpzp +_akoTs>׋\#3۬/v$fvzDfV"ueetUПgiL\fvlWUg5㖌7|WܘU7|]h_-\' h78{Cz2F}>cTXfgǏ_ݕgp?yzf]՝&J +=R䧠36;E!$ѱrm?׫&fLg|pN$%}6:0!n0:m'ChE+g漢؂QB3J J樏,D23h.tᓒw]dv)BQYk,v7:hjL3eE9̈crQNe@7Qc f%9]CC9ůDE0%8GΓ(JjMVkA'[`&3&s#f[7+ԑ D;Px3c%[ +uThOHA>co92^5)|fϱ1B>5 Y:lQǷw ͎˘q)K8۰Ԇ&)Ce{3e^m /-4>'^ڣ,x|!Zęu>qմ5AЊWE#ctUCD1/jXpHMRqgϸgoAcsy}߯i;.7bu4vyzBԝ,Y,FNj`;\~W#)%=)^h^M?Ew+yR1Wc|W$~|[O4$if@M +SۡDK0s\¢qCN|&"~v /ɰkLӅq7wMaى 5^'٭xG6`Vq&*E=t p7=:(Wo+Y+fP줣O4v$ OA~;I.21XJY,Ћ\8>,t084þgߙCAWw$<,B&N`*2E)}"ۤ|UALv[?v۶N{;2%#~*x]8퓵P +*i/Z=۸YhZde-2?Zdl|BItp'H0n0ptPKOaftTP[ ~<m=Q:-o;E'eE 3$# +MFΏA-H!0 8Ci^DK' tgx8.a^ND取ހW_f`Pۑ؊Uퟕ835gs584I:5kv׫J&B{ :FM Mz,HD07,!M#f~lYޡ\q R-~B'NsyyGsKߕ1]=: +:]n:j'dw0:~SZ+TXijpU+5*n-do  y[[2g)"; 7K m᩺)G7j3[>tcÇMɫAM 5TB>f_9q0$K4(8˂~:$4Im{fD6KDjP)6P=)QQSBEGkQq 2j-:hKg_*rtaAQo<= +&ljL{[&nL*YVH'dcj}ct1>Bc`@N Vk4ְJvDG?Ur1sg,xGTrv()7ްQ~pA Box\evB]h~ r9旚wm?m_m8p>ޕ0]s;鄟Ip+1N ϗ)4kLT\FZ 9#1xI܄ ߄+Lą"#4k!& FHZ˖қ.n=}o4FзU?/)~6Ar &OO:)lϾyb@ r&_F[2jyfS6é-r΀Ԝh˄-\&T5~.ǩMK.oo͈] {8C >6?0鉞>\u{!{{-sl-,8хT0J6z 2 =q v Ovye䡷!y +n^>Q + MdMW)Ȑ k薸q+JPN>ExPHVL Jpf&&T0RFt&Q&Z[C#L"[`9.K$D`98#`Pq'Z[I.jwHVT*Gpo[zD^8wƍ~~ox{+/kFtG~|лj0CNnWik9Ë8p1 =*T*aI<(ׅ+Ƣ~:/ //@_ (KSWy.!1*5V ;{~gH@-: ` Cl1SyO̸'{C%?勠H6e2iQ02%.Bii?\d Ҵ؉[Mir?ME-ت7w0%|\'2m{\5ԌktZcW:y]:L-KgrxdAGzJ ''xi&;gxڔR^JoIBHL#uI=9Ό4Hi(4,t뚩vBg=`WQ\O@#h +9\ր +,*+(jbeThD "*|>{ G[[GTO}Ug@LTsGW;DWgV `4 TIOʔ6Rvk;f13iNwD&#֒3RǏVj05O~G=^wz{ 8H=vsYBR)=haz8ɱq^z##JN8* +0՟o^MP&Kg+qςpAEQѠ0}{_L٤oaitCb5 $ A @ $1u&h>O,G%[n5 /< -WW\I&Xs.,tm"3IfFATOzܲˌ/ +o\ݦ.trAV"rn +а(cy _TS": ^kOd1X%jObVP8͒šX҈ӷ2 \a.&G]E;rh&.蝠gO&t)Z瘰p u<'?4ydho$X:QкQKS8Ht̫ +0MmlNF;\K˫0A'. +r*:7$dutxQ/. ~>$}W~-v;Y`m^S&|΢Q UrUWߝYS݇Gw=ׂ,|_ iKȖaaͰh ~QW1JMx#Q +q&8x4D]6Sd,&9?l:xG{ɍ GVY]a,|%P1]1CPc<(,@C=D)d0~^~xZ[ N}3X]WIg)v9埥U=ߐ13/ܚo{JxNhʏ`]Rn O + Ye"e/VsLeUpJ +]9^O2YXC #2/}Jې)f^.h!\KH9ьMi'o=?8C}B}2Y̡ _"h5qVz˖oqlxPY*WxB+??*HQc PDc!4=F'vfS(^WN-MdfQMuXǙJ3 ˏ 4?1B, E./-A&25`h)_1M$S-x!"94z /IK + "RٿDM0BU+s~̡݇}#^lߵyg\H"sf-KmF1 2Q6@,IJ"Cr;E:('yFlJ!#w'oFIw#+ ,w 0V|;uB=nwt̾QWxLm!7:AeIMmiI LI@+8MovYG*oˀ2ѭ/#xFzv˜f8cΟX 3ؘ{P$8UQѱc skV9z[ NK<\p;61<""=Ap:sx C;yQ\ȬZ>E ;pVј\w1ע9!۩Bz`S3BZF.)ⵓ)m hPkj/u5w_s7`\ {͎I)H1mR ,*ISZ뀯Y^嘃y _c='潥ug*7p6C.WVb +8<(pH } )7$vE>βȨ /W4-r.|[TqCˌ%{Lό_T{J2dx'Ё = l( ̋.֨8rv+A) xd-@6~txPH5ouQ`E#_q *ߨ]BΖww|B]4[[S gMO[ktY'cB@}Vys4!:[8qL RRQy-HN};ӌLN ˎ_j Ÿ}t}w}7<{&y+X oCjig-&`I#΃m 鍔 ~%RxhVay Q|G- +`_ooi߭P yq"?gp +ox`<*#6{LrzN-&! +\Qd# N3C"H+z (F"PGFP8EN$jiէuEo\h5]f)Ch`vѮV'G8dSVn +qicJlg ;\%?7CvXL(Ef4_ ݷ Mu~هKδm%d37  e +YښF ݁/0>]IGEp~KM/69^.ч9{22U&V7,;8+7 +"f<I}, P/@F R$Z2 [X.[ '⑜fcDiqKԘ!8kk&`݌JH$˓ˎ8 NˏdރVAIȰ1gl|mGévD(`F !'+ +ҙ>`bu܂աu^>,8_ 0h@_}N!_F\Tt鸃ԽA-*G4>u;'%U],m?2oj[uLv;o# 4o>`=HAsoq cAT۪,I),Va̯qg;~ށ;908Ӝs@\ wŠ ʻHw($t9 dO + 38G \d+?^ʼn@p +zyϙңZ7Wmwd6~wfne"$bFf0-1|{/Q +z#FrmmܹTkB9&T՟VkWh ~L..C&2ekh df́nzꚫZ]Wqksh@WR}d r )YE-b6'ٻ6hY#G$ťG? Ԥ +w׳+*+oa ԵK)̋\gI\$cĆon`֐ +KD,q)U+@1>bBnCu@IwA)>}gb!TXҧϑ&6]@+'x4(K)۩ X85KD3,9ww`Z0ghuJ;+)0`Άӭm_WM{blOamξTP_kroZ\J ?.4Z#꣚Ȯxb&1QG9~mU8 E +[\WQ,B,~‚** 4Vԥ +,PQRC_Pc۞͙{wc(ʮWS0#hN?9~GPʰC:FaSPlY;)oF^G*uRžxٲWɰ_(XJ5c!˄dB +u f|:>v;ZBpiž?ނawh;2ׅPsE6_: rt*;י0a +;"sx Bҋd*f\G[8$ N'I1 iSlL(V.2@Mz*a+ֱێ %-_hdZLxzau) q9 "M-̙߄W*>r@2mO.b69̓]u4&JwT~DLo]^A +*1l3ijsiIz!F{VQ\H] +S}y7DTF11GceQj>C +.6! yWk_bVD ."V1ll)$V6{BpQaqғs.?3oSj؊V3*"`4[mE̝c][\jrN| +\ڎ}d3'L&Kgmf7O;3x +Wr +<\Iߚm7FX={[ ^ +El7lq,EVl-C B0/y< Qrd +%λ]F2,DEqyXr6Tђ9O($^5Y f*H6P5X’FhmJgo[:a\FBq~[+mR,@0\9xY$ZM@VkWƭXƕXE +@0R2,.wwuR0 ɹJT /4 $4l?=KFKIe% Ȋ搪͏$yw~*YBX\:Xy(%5TsA)d9!ZG-ukva/[C?Ai32dOJ\v1oc(ɮ3&vudLad,gS&>Z/wι; `]`u{2uKztx(b!Bu϶C7Yٖ`ټZ = g +)TS!p~pV8M&4v% qc__Ev';ȕ꨹G䞲EFcѦ̌O$򃚖&(Xj3Χ?8\C&~֜k|1:ZmH ^0]r` o (dVSLcQ^/Sr{"6-)f^p.)E#\mNB?x +PhÔ^uV!@ \藢{9>VdžwHGRID -oDHY#<7l 'JĽA={ýgdD="QB@<%u "ñzVcJe4u;e:J++[Rt8 cC{5L5+A(>X3Bqj∥JS|+hip OSKG |H6) %17D^^&n4 IaAT<><s*7L{`"dD +DH"{@$ };֥Lj "!aC2UVMA!~|b1Tih0} C5W>{.cAj4=ЈB? j\fJ#2##+G?SKa6?a{.h)&|xLUN@6MrjR{Ҡ(WȃL-v5: L5^u$q83!q#<dCM?SAchU}rBL!&x*!^f.{;?=")Աz*vU_]]_o6f\O9J_ ׭Iz{[t| 3sȫ ^&+zqW.Wռ^C_՞,SKi7q YUM2}A&t%yL/.)hd8WS endstream endobj 13363 0 obj <> endobj 13364 0 obj <>stream +HdnFཞdH#A^ dvԒ@ }ymc1E2^:=ޭNxϗ4]ߧ=/Jmx_~k_z>>>\ݮ[?|Oݧp>W뿦8//ݧs~|_˽t}wqyxu;i|2k۶1i|tfw:Wf㞞&Ͻ~JZd#ىEED"GY"r+W¯_ ~%J+W¯_ ~%Jo69+fe"kfl eȎ!{f3rdȉ9!g,2k5~M_ӯk5~M_ӯk5~M_k5m_ï ~o7 ~o7 ~oo7 ~o[-~ o[-~ o[-~ o[-~ w;~;rN̡c3f96sh̡c3f96sh̡c3f96sḥg3f +߫{D endstream endobj 13365 0 obj <>stream +HDPL[U~uPJ :Qal LDƐ +cG)XE:,9ɘ Ql L@ƍb@z\4_=9-QV(y6j8]oo5Vz6)Dh&8}I}G{wG,!yGnsSkV?mɴvgٖV_˒fÒhTx\\fGƋŇ7,5Z# \2Y9n;ǥF)/Kã~-Tb`fԦ ~8`/|v?▫cG\ݟJeZ9æ˵z_[ǽ[:?hM:.3э[Ţ$[س=gFNᖈSR!OhXՃM =,}0K&^ w/}e{3aj +xƅA+e#)&tc&ڱ ,y + BBVj<-QY\n+j(YJ$`HB(~/M'6*A="(|ňУb0R;ԐpBhH`O pC&ء1sO-KC +xnS@jMoOC 㛖6Ċ`s `HAb R+jeǚgf6/^R\½s7Jh1c `3X#JLL \M 3 ɨԐgOÉwFߤRPzaZjnyRmYr}h4Uyw~o$A!'>IE)QZ)gH8HYk Q2=:t(]Z,fU0fCYھ `H4g=o碂p*`5] endstream endobj 13366 0 obj <> endobj 13367 0 obj <>stream +H\Mj0:,ED;a(/CƉ,|H! +=d۝:ȏ8ۈ|WžLzLC$:?Bk\R\ab n|W|d' *h8ކ Afٮwiݑߗalq 8+ +]j@i5קɲhnCUEE>3C*-\>UT5sT쩎ş +GᙋHkYp +T_/ endstream endobj 13368 0 obj <>stream +Hy\w~}_?˱PbYjЄQOaxh= գ<k ^LCg͕Yg93G6X"(I˜1wDڼ^"Ҧ_<0m3 s/6z 7E/|}=_DDG\$ yG qHd,2DE2dR"eNdR|D#A=y(DTC_C_G#H4 +E1h2NA39hw3-Cw*;4z^Co')p' &`4,>Zl5;UcDZz,vZX;N"n x>O3l|9^kx) /#x-~ß8DbCh"LdD9(#vD-#D 3%@ 4`@xt@$ P0|2@X>`-;A9oQP )pOpwCdIHF/x2"ydEVM>&_B RP& `'Fh8#0&8 N0΅90.Ka E0lNQOT'*bT5J͢RyTTB=!-&݁x:DϤseJ.w{J}nҷt;03L4$1L#f))f61[r0S3figb_cdwv;gjv3fOf/C)Gr +zp}\7M2n1[Ǖqa;]~swG3!/:|/?GI| +\~ %W| _ |#̷'!"B'_( Fcd!]#> BV( AZ8)(\~ wG3(1Rq(1ILęb+.BD$nw*xJ<#^7_VM|%/iRH"EHoI0i4V/Mҥ9 +ɍM\!A02PQRl%WYRlQ*('JҢESj:QMWEjBNݬnW# zN6ck&kҺhZ QZi3,-W[kZA+viZViZ֨5k-Z֦I5pWcx}ֺ?z + *NVJ󱒩J.(7'~fxsRXh2]L eE94&#ID} gq]6sϗ}nǙ1ŢS$g(-8hZYz]:qeɽVt[֤ߊ"벆˚t^Qw>>IOZxʴ!<BމVy"CH!)Rv#-EȼX"$G q@|pIb%P +@.LX` ?CXTiaP hC>gPI)7[k*)1DADޑ*aJCJpk Bۍ!=#EBJ"B5Gj6jL"0A嶺Rlr0+zf +\}S9Opɥ~`jvh\6H2߶ biaPDjߟWFxX10GԜViA}DJ JPk ۤx.=x@~x罙gs,l/b8-wX^9pCIeNsi`_ۚ{2gi=sds&w̑&^[]9d?syV};W8+q)&ή\V^% grpYKǢn^/:mi.˨Xs*\cжUy5hNGʃXADbLBk"@$0)0J11 ȘC|D,}PAGt\| x> Cg= "x*XQPJ,C&38d/ _X²4#SPzvykjVV`-% f- 3D氘5d"tp(؄c(t`F9({!"`f A)Cp A"4$ &DdL A0#D.LL==Ak)P2$a2CrX(,aY8r<,z9r,Q\M! a$.i˸2nX.W2S1~lө= ^NDƃƇ Bb Cl x7|š|/NjHxa / +L1#dd̚ Ȭ0HAf Ȭ 2+B=F1d$c$#XJZ7c-$*9>(yz01#B&R Ą&ym[nE{z,Ǯa]ʰgH!ْ1Rd!R #A!S5A1&HJ+ e l,"o*%7˙`7:II]M.(3pPMEEE`>AQQq߆as`pE(("(DdS@''MϱIEh4'+Ѷش3󅙑}s=ƙtMVQLa' [ hv5Efx %X=Y*'* * J + * * j j |BSY0aǍC-p#6cLYZ`;Aq4X2[/X2cU~~K2t`DƇ jTf.['pD (?Ljyؔ+W gxopInfo&$38 +3!Mpg/itE%r'(| p +?O+3̱2sl؈r QF؂eȗȗȗ%ZVdi+S6P~cwTZ.[{ɗ%WgvSkP k*h+5jQ_RZyzvbٌ^ +sP)36/X]V?W8M~qVR?T,䫤rӗKcj1J'5,hiZC@TʀQX'iNaK7VX MބZxn1*Q_3D "Gr C$z +֡XWa}njNcF2&1i@l27q؆c7o. ;v}@g1:a?a%8t!Lʄ(&$3! p LD%85t8\M\7:ᚈk3Wqsm9n I.Lc&eۙKL0%w{qb4.fL.x,#<.s +xyiL{xW=^]x}3HHe }2:1Å13~df>ħ̊`V7>R|;~*oMf3{!9%021:s%ȃLv''&"a9B+n&y0/y K!܊̏f `5/$,t`a8 GT5Q?Ac,bq1bsXObW9KRWn`;,j},B 9$0 +Ŭ+X{V%=I%,I|VgH"INR IH!y#Hbf|EJ2)Iu&u'X4 iŤ] ʺn۳a!h +6g,6eMlNg-lbWͶZ=c#W#<҇Pe6F +U32ɘOf2qL;2sɼB+Yed&;Nr GE%v (=F]EY%)t m-kƢK@wX +Rw)rȏ" ECPBq9Ń`QH7PtJSz+M/({Jy2Zߣ|={6}fo9XDE'oSqJ*? UT)j!F/}9f߯u?'TR=4\|hUOZF4<4ۘaQHڻѡ^t/12ΉtKt +~7~9 toJzca.z3 W=%>+SG_o}׃~QB0GXldA%\Ðpc~1ԉ bw`x _c&Fd2.<țۯ})vcʰ{ǨFm {wwbCÌ~+q؄C9c:3fcXc1*8q%Xøn[ĸ[2>pr q`)PL4089 |_b?.,p u3?ILڍ nθvw3܇➆ &/er)Қ))Lej3m-v2݌󙾙x#L<*'3ؘ 34YBG%Yoȶ ;l#>FeO;EկQtlViTWj@҉]SSe9q $.,*(=#H$ chF ( "qnvԈB3nsɼ9sǻRdVTUQFucTes1<&cӇ!e}O9e+JZWGM>|UC}IQڤ Q?'X|=Fq/2xKZW2r4lL ((ȶ5lY W5+>wBĄظM=wKnvg`fɷ%Cl':!FCi_~b!&c{g@Ev:q Imw@0B}vru6^U5Hpb!WJ6tٵ՚4O]S}f!+-_ʘJEl ` ' ڥPHr Q',Γf&ۊ6ztm^YA}kCӢBg>>6o+7Zu[.= (4<)$k͑ eÑ4v( tO=IqϒU,C?NO"}pi(7+f[tYSnn \ź0~ܥ>i(\@q)|*f?w?O`(c0騀OC)QbnKHk@n.!fOa MAsx!#1T1(>ð}>iB.>i)pK^JӉVh=g1Z{_ m}5$&R'UTV6׬]f>ǗR .CÊE<ӃPEՎ5@@ӗoDT3PPEr's9=rTu#720ظlkHM3䴦P=̆g8 qb/ +'ScxҋG%bo)'3'rGQC$#VwvQwӒ0‰̧<(}y G/C7̖LdL-ay<50_:iu&'N^+.)[(Ae)4Ƒ+[ʣG41I#"+ٗZ7nXU;d֭l١([0C.&U 5t+i{\A!5`匞Cd:ݑ +h%3Mz$}15L=z#ZB}~[ǽ6\ +0y &<(B]/l4ސɺ q1Jr`"4<`:| ֛igɼiSeBF/(gT/uFEu]aញFoÌwV\DDy("jDYO+D m| R> 4تYc(83RF\*3Zf՟w;FrXꍭ V3o>Pq՛朏ͬ/Jy訅2J*vF Ɋ'vn*Cg}tUݾ$Ϭ}ԙ-As VSr|h4 !)N0̲<_MPw2 ;`~2dT/w4 ^B - 찵mE`+:6e%M^hNlL)ѹ{\з2_"`2lJ\b5଱yFM6pyIi|3ɔ^'-v(ϡe-[\c9jpQs^t-w̵hO2 P>Dn _tr1$K;x}0\)dЩ )*>A6a C`f&rqxKupZʤ8:y!* $|LgzaZl~LH{u B ˝X( (Q\o _/|f[S!2 DL'j^SFԦO ,"`3lNE-Fp_:H|= 5$c: "A M1i>/hr_wv\Vl59C :LɄ*3atnQEajza 3*&\= ~FQ WB7"6ba Fh ,IV>QC)1)1(tL~xͧk*31hDM3P.Nw&>X/?Xߺbǝ,O5Fb$; bIeSA/DR1rrsȍʵ}=π' mx h叡IΚǯ .95Re@@T;a=6vӞ顡 fbnwN=TCIh:nc3"cfg_7=~ǃyO[ sgRTǴ@u[ϩ;҂Cz/.,)2Ҩkot{s7n2ȕ+vjV2h# 8uO@Gg~ԭ}u]U+;N+ +?Xcj? H@g 9<*Dr:Yfq &B8?y|Ľ%\b{hќ 95ǚ*JҸ́8ĮT}=zhaq8=@:4: ( wtkItzrn)ޘo6,g|,cGfo<@dtuR=ȖAK@bToIF'uA(Fx [H#67GQD5yQP_WÀ y#?{Ӓ\"9tI"A "JSO{a;ٽT+qyMJ[zPFJUb(l_erK=߇AȓfHf4UEηgq3 = jly#..,P*ubxW<&dV<0\m\͇FUM}zY1TȀ&fy% 4Ecw#2R^cY#us8,bᎩ\e- +N]B06e C2GL;;B:x'">Bn=Ka6|*?CGKSSvn?Δ4)a\+E:mfE,kTGxlvƪ$oaDlVގ3R.apegE,_Cz"XDf+lҳ}3TWdԔSbSl瓽(׼HL|W/ +T/J$.+<2~g!(3SJ=YĪ jɏytk(Qu>CVRnPU["pT;x?%B/T^^=SQ͍Tt\G,8?bհM<ܢaЏV(TJ.E tZ_6!+ߦ >-omn>ǽ3dPq|?1 |vQsÇg8:ΘњQWT](Q(|}qr ҊyلVh['?4(+ xL<_W +:BPMLX4eE6a8&; ct@b7a=Ϲݖ2_so}NMUDAvȤrͻRm 鉰WƇcZGK _{;+[UWC7**қ"Ӷ|O?yEPp Ygң1ͼ6Ca RZ[J ?M +lzJ s&Bseg7 {(\CѲ`BaՙK|mH#^5?c b(egoqU*:UsYLP¾diYQ5j-؍@l'8oapqɃ^!%p=*R 38CoyOhp=赮̎/ +[ G;G\ʹ^)|u=wR#2x]ܰ mbŎ20/w2T=@ ߦ 8>dq;aW-'fdN.X%eO1ϻvv[?G] ^^RU +$P>{XiU#HiV-Ns mE׹wF,曂܂RX!~ggV7lTWJnѫPxb>_[/c^u}?x (maǘMf J;ҳO_54~Er(Mtxf`ىٙ^.%R.T0HP Pt9f^rKi5!~=l4"ߺ`+ g.,N:22PT*mq8AЅ'DHWO*m롏T@; +Ӭӹkruw8?}K)ܯVJ6nKʌafF3 CJeT[#R}eH_԰6BB0ya,2-E?ݨˤzbu@ p@$ptޟ`Unn;aDw[*tCT&Oȯ0!N8$)Eo^%}!δMōh(IO6D0zHǧ A&#6ܔb-Od'[#L^2w^kd}$mQ׽}tK6ɹ<3.(r3'Qa/|hz~-*<@!9T:NC$ +^$g;gM,42xZzrrzzJxPPXxz2RS򨜲 cE) VGLRBQ .Y'ܞÃW7Ř \,籶Ԍ2 ې//Xvv'B4 0h(ݴRT_'W؝vrIZFʯOU +'-obKnnHLQ#}N[:(lg v=L STa:Xߊ_\Bʄn_=zd4ݾ. 6~{GoTۙIu"gq`z`@ Sv;> + ICIaRoR=ӤzLjאT=0ě`X>G7 DZ1do7^u99 g7B.rWҧQ(L@ QIvn0d hr3Ӄ1fK۴K5-kzcby}PD^nI9cI@*f ^VrG {L*i#8$>_2A4O7t.5޿ V+TT xu4udpDST;C6W:5t֕Kڝu8> {|,~PQ9Թs!abGZJҩ/EmP:_9cH^t me߈/B–jGL`lKRCf L\7gl9Xq&R _ +^q'@CH)Ϳw)/X/,$IV +]kU +kڳ/DeJ2WD;zꡞo2lVhAA;Y@Tz8''և/z̹YaG9=DrA0Eh,dӕo\6^X=3)!o`BH kmH{q-ƽF_?0턎:P RWgPR_Z͆~Lp=Ni(XŨ+Jgd3r /͆Iw;:E)RZ HT-Q٘0G,BPE~Fd9gz.:+Mq!{VXE?j}I۠{ g\Rp^'8=9^QQ\Y&L:J=v5f51F"((" (n0@DfED$nqAFjpվn3Cq?8{ݑh$ 1u--j;^޴֌u@V++]?q125:>`eK LUq9sҭwNUc V,^[`.oS?eX[cw<Da1>=cbلJP6(7dr-NV.%lmj5T0!U8 CJ]z&0Qg&a3'm$`,Qc&ZcQ>_86IRSM)NgT. 8cM5z`:R\ +PMS>`#Ў:ٟz=:tkNAM['(}.7 H45 LIX%F868 +BĆ2ۧq:|x3!E')uS[EnLgAbNB*hDFZDig+LB_#6<#a11N~kü+u6k1~t*,!f7g;0=&?w5AƄl,ARKZo[@ 8bv>:Ob1\kKۻ'AKh+!0uE!(" !Udӫ!rQU*)yl92sy + t5;c .;&@]Sr6?8G! lyVVOz `k<M,KV2OJ?t*=-yz ^9>5%''o ӓdRibq=0(10]8tQEncy# +O9gR${֒mm& +Υz92~6$s-غun~3Ù9ߒoy XITű}*\R}jjBir;EeFD<];B)܅c ]_ӟ69,$jwSOe$NDzV\ s +'oU Pf?C-9uu]݄24)^bݾ!K+_j8C-5eFB5%Xj0 +1@Tvq{4*v o~]Zӓinut Tww_ouY0y |1~ݽJ ٍtKua,RT@"gE' C0f$%sx P_z7D]5֦T}{j]*p;csT~_xt(HgHf򈰭A9YLQOtG@bjv& +!}P:ؒݏ$U$ n~;O^LN,v~MF0;)%+LbiBxd>LC=~}X{ };h@1u`N% dO ~SČ5 R%vvk=ja4&7d͠dBfSq +MG_-U-u/I>f #0BF7͕/P QmOx`M nП!WdsTn`j!^f-@ӇcNWXo狌<F%ea.v&WvuŻToWWg=LXAq}ghkS |OBYÍ5d5H>=#mQU8jk5ڌRx/dPzA2YJŋyT6Z0kGD5'DM/q쁻7iS' Z"հ@5~8Bpz*.ƾߪ l{mJ?8T[56 D*UU%RZ"uħBO1ʐ+w 7*xTG&װH?If HٶR[pגe }ΰ!)'-s*o$&&ۀ#.+ZhC0%쟡 J" *&x4 ZJ}M2Z4.< Id:K` Ñmp\>y\?./uufc(YDEDb%Q,7<QwKbAXЀ@7(Q*K.YN+(!sv~7~~X!C Z'>¾oAmOh)N'ɘ`()g#Hm#l6?\̒L>$+QH:PB3!xꢾa{߽PFģ0kOZ)Z'z[ہ!v ;vNjG .$: f =hAh>"?q Z8wޟ-K V3څ>S]g1#%;00 +qOS'D3VZ\ ޔ؏do/HpB#:$:=(̐&*C +R% < +XpPshD#Pp0jƿ,c'̣Zm&':Ei}Y1S `".M_\ش, /;`kOZ$Ec*4 >>͇ۖ;d ܦR}SkԯB2dr1 Q(DB)=_M Ssbl*.8G?Ɏ'aY!AWǿ:yZs}ŵft؞}=O:uh6c%R-bRML*!LIC!ϨCl&!1FǰM3@kCn!3B1O[I*c$Z%kwI,G vl0,pNMN ݱ}߮hdoXu0Ksڹ@k3gMit"0A5cN 1֢Gh <"!5'U؏rB^:c9$c$?0R1;Mԭà \oAgR-y1E CF%8QV 7>;$}''䑘IE|M}FY+#-#:X O FeQe k] olcIu +L+!" uM`]9XְU/~6,șN$ϪtuyZzDlE_"${N(dTZwS&o)+H'UZ,eqGn+/[^jljS4][D:IL4F```xP9H?_K07q= l0 6DpPg>`IQqKtn0+"\|wwR4w[ Ӆ֘H_t2X[<:0&)=NX{2xއb#oS#n>k$BS3^)uW#'K,P]CoV,3@[JTCW J*BW JL=P]ۯnN[X(0vT_h +/;5܄}RC,>{re\ObbJExhZD VO~A*^YyG{:G>¡ˊ0&R&r ,\Ȗ .bCԉ0C~5*܋)F~#d ;@ d0@NdK$*K7+4Qtء; m!cpUXW-B?Uq7E:!\y bJVQ1P͡s)zqY1đ[|7CP:/X>N_uQ|]+$YbPO#"Cd툰3a礆v( +p4ph$ (&$NC ȘD7"٣h ZcZ ug S_qQ::K)#>RFB + BQ"a"#ax *XGE#(L|Ե/s"H+m6YJxuǗ3xj|u +\4٧CQ=8 0ɚ!.9݋i [ |\ɪȷ JG%gd|zaYa,IW_e|G]B,zv- /7 A';qyT0iZKPGg + OQ~/Pcq5sÍGp1Ec){8O+Grcthx΋?[#,[{멌]/T~ѮyGB= DqiDvN5oHZ1gwPmE/ -=.v:U(!Xwf*_W`Zj0̦?$#b)Z}@ ]eZ^AtiwƟ8Z=y ,pӟO+◕e*^#<8w\ UV=z/[ ..|FE%Q ʥ-#r7 +3 Y$<,1+H ;}:aBw1_2l7)93s̡k ݛR>˖x)x 7#$ G$V $|g&p$%G"._6'_Gp x0|*x$oc` lA=L + M"@vD7,2MOMRw5s`H* mT2N֯X%]Cū Y6$Ƞj_kW%"klHY>}*ju}ȮHfbkvDoRz-j5j/TY&b&8sn1h 6ԢI<%8&0 $r 9H1 bȅh(N>8u/ 'Mu3Q *`ϑbAnְS4us$=dŠN3 +..#Ǧfaw=®$ GRP<"?&BmgċޞL}.+ %snѩ2)Fo}g-0KuLm]LW-_zU0s2qCyEOs^)T"%$B"^J$DADRD&)`$E DQAaY|bEʯgH*Hn=_w[$(p G +у  'nOܨ;#oP w;}x|O<=5GE ǰݺR i @L +wS|sd/C6"'S +׭I}o!&B~K,Bw'hi>.NP\ "[y.;͚\Z2IZפ|Jt +O7+<+Xx2ty7kPv?G3;Ay@]ٚ&:P#y7=xYB.ze^KG5ZS}xfHWS[zkas\C4pL +k‚'.;1oGV2r#c"֭,x]GVY;7nP^VTܨ!C~' + =JnoMQB'% D<+, + ɋ:!kᣘrUk^k^FpttA03Lf8ggEw˭ГY:.OY|t`|KH̵MEe2FMByޚeQыe5]H>bΊ֋d/yz#%)X‹.Ze,Gf8VXH&Zܧv eN: ĮGDWԠE N; Fjcy`2c"CBVbL ]]GlaS+H[Cd3vH W8K9]魃 :УpMn#f< +W͝(|. Nx"uhY.QeM4pǨ>C{;^ xBZ3ji6oK۔:<ިF^#`oy *ΐv5fU/Z!M6bg:U:߿H'Т (jjzG*>]]{i;W-wrxZ(avb'4_ 57*&*$j{=N"S ғ<4ǡ62jcbSv@+y.f)WSЫYG/F^j+6p>W{ƶ w0'ɐ f1^V)T I,B\;yW9# @4ќ8M|/l L #a~vV'#@s5;gT:./pczSʨsa?1;k6Ǽ/UԹE^tQr >r}*VA (֧HjXT(T'*S-∂+( +  * +o/V&~9{iRڇZI?P>qA2k~Þފ"q{e#c%oTcr)1iR6B:eO/DF&r8AJ0>*Z^#+ʫo{c?{=qO15UÐ9HYg GYK QaaKBƳ;{sjвŻ?|,?&F1j}2-)I;U`W_GOF5qʹ?{L%L63N )lxܖ|9s穆2IITzƮm=琧1UD=ANxbF] 4X5h6 +a1#MB@'%]r,hNZsʒYthzFX&–M0omj:B0zy7$*LNJ!u*d_# ]0]?'_Nvd]$8(=m&s'BLn @kg6h,1ᒪyԚpK[^+n`BCtD7w8RIluREtYxQ)tO5IiJSF i_ 7B_ǧ`VP7ǢaLW5|Y]y;I3=p"8%T,8т-."a#n8bo0~2FZRӧAW繇8e53P`Ua,B;0@N4SQG4Tqi;pNIOkc7gh 0:)pm`.ueE1d'\?c(?S? YGhvVv-UݷJJ ϣHwrH]$֫G1VaSm&/FIIG [AY7~r7Z؎KSO4_2' v5w_@a ¹~K %8{\P?/5r0abod]ïDL;|´7ygiͷ1c^ǿnzuzWJW,H]SNt9)3mR1!A+pQxL{!d*h];BR + 0qpO#yբ.)+Hݒۥ_ŧı-momEG.4΂@|/zo +/E# `&~# ,E=HH4m—W+X 4&7<S@t~n5aQ bF_v$_9cj&6_&ոE 26)]7+o=`;v a!bJi^XK r,oPNSXP3%9|7&~b _'ѱZU(W95{lnx}k2m 0pAb zc-A< SDCc]'n!OThsU41aoDdEUv4AN%wF@YpLtThyhFMv%3D4Tb{X6 Goٺl茯1[.*vED$rtAt ]r ӑS﹧k~v`i)#|Kl,A}!+͞E찊mf V0s +'J-k+AfN&-FM ,_sӲڨhA՞IdBRvJ56'~U9aIwWǔf5itV7 8gZCɤ*(ꎬ@zˢJNh,s\E7YTbxP&go0hj՘j9FBŽ8ƦyH9L oOtMUdk8z""YTg:^_A;/G$FSrɢײ%q:V>0ϕ n!]6 | 1qWsqCO\n}~[q0(R 4c3zw8W1a5 (E`K4`{:~OԞ(TT^KRdQQ< +Be/-aaL%32pM*S|&.J;V!#&*ؔDŽo +Ulwi0Yi۞ݪml$,C*e(P>H փ$dF%q >gh9Qj"L/BCh̽ %}1$@GG8_VyRgs*zOdȨIFPߒakz +A/3%?>,A,HD?afbKDoi#6I"_(_? a0]?_(G|s}G S%L])>gQXuNjvheRWz'|e}qW}o3jQAKa@_Zlj/*0@*xn݅@ y|:UC;҉̑$5v/Nqn2d;Lq$XuOوTYR}"&.U+ػ!HA $*pĦΘ]$rnKL&U()pXL'V#?Nˋ6cíAj9jL;j+ol{F"x Ez$ $B.`^7 F=>k%A0V%e>'M6VK'8BxR-,ME49cyR|Ơd^7r !gХt8ԍ8GIQ +q|;+jD۲՘NE@92F~$Q.3odCU6j#豲0m9gp;/{ Na/!ߴW PTwWcYENYt Rk@cu D\CZBSRtp0cEcT +VXpAX]PKc[]X(T20s90~TjIg$).,0q/\th*w9 -@^m4A9d/neV"L{4m|,~O>?>>^$y&KS5'ʳ &z.:^H&5qFOayM_@\w}:(z+c1u`3^E13ifBqor#uD _--c] +UpBb+ay]醨Ė҈^@O'\og pAFQPuVp}z!x2u8Ekib:-> L:Pv3uyjP´6yuՎER#xy_z\}3E _/ }H׹҂/Sي0lcٺȂ*t+uߧX"lzBfYěO>XcXxq0  +ET~M(\K(8h9 \WCmSa:pjqyxu豏ZoC3W`H/Dtxa|G_N0Xt ? e\F*,Y' `: N#/0S?%CL8Ae1P f +5b/)e(\t$:kSB Pc P8!7Ǝu0-oW6CSw/qb55VF{Û7EnݹTDضc9><3=c2'ʿrMRv$8̱mS~_ŚܴdI/ps=^2Sm{&'%$ +1 @^˕PUKa]6l8WsK h ~Ū.drQezNT4_Be90.r[."EY]Q~U#*V_]O,?qpSz!C;B怮:_$u δ-͟U~5DŌ1K#Z^Mslw/[.6CW  3[-/}H^T?N2~ ,ڄ4X?-e.jOE۳y$J_ڨjd1J)/I&!H1 8mJZPr* >~6~}3PhzK5\땟K/;SGg*4(ńMeC̤6'ksnRW3iEe%*hOIF# CqU*}:Jt"^ 45Tf Щ0vr1qlUӹ> w af6T*:8w"wtwCp(B-C72jy!%Pنc~Ӿ̢t(c)f (Zu*>򄜮Ԁ越ܷd3gzѯ4/b+뤾c}|2*ZWhoȞfXkjf: 86y$c6sS})Ly'wz7~ԗֹ!xCGR"CvEG@ O+RJ n $I}8<Fΰ3}'xäMu3J Fpks7{uc|[~~?T^r*_ySDay1lf;|r/CYqK(ᗳVhm_wFd$͛ !ƅ bn9bhqr'[g#7! فd:pzH"Fl~y#GC4Gso7Xz-!!G3%=/9t[9>0] ꃳf*C&UTs+R]ۤQ9EEy'bElc=zqq412WJJ 0G&EM`Ou)Kd2qUhWb|NYtRBGg^iQRӨn8a>ҷτ%ri@AjX`(+T@#G+WStf"Lfig%"R&Mu^\lFU6-x?xH,3DždL%XC^!Q)Xב'x2 u4ຩ̧ CrK@< ifB;2W!8~GAYң&9SPYVw8)J݄_\oS͸ ,!IJIAn2274t{ThX~T HO͇SiS/P)WHjug$`Q7 'pY~ά%wF3.p#X"m?'EF˸ '>T9$LwCF7rVDn>͍AxL|A"?>HO'#M=AD7dB;|!4C*cItL@h_qmyk|?O~ +1w B +7 "~"jٗF4&d:H"QgY=7``3f'"  +!֦:DOwm^~9I + +-[D1tΉL8Pv;0[tMFR_, ھekvr{nk`Β#Y })8>PT*͝E$9TNwoRl.^.I _i->j!F]J|fyXc+j2DIgWfLLr}KxvHwɵBҶ#;jx{-ej SuDy&/{ώlT50c SU+\Ƴv-P6;B&m=:~bQڝ:Ff=.87(Sфń=Tsk! +;9w?[2&M9)#n od>ےyƋ<78 R =a+OhgjlI./"1甤Q:[j*,.퀘 rV!z(P.H -Z^Zh[cr˲se'vYЍ ? Í0rpwup;,9QX8p$R!v. + \ +Vx0B,\vI]w)Rz³=XiRTqE#`aіՆ )Uq0Z ")X̻':{-k|йe7׺M|2HA6czG5ugaӐL#|L!˜PuTtĊYDԶ֭UTV RFp"HA+=4j+-" X Tܗ//vT?~wAy΀>8U|ӿ]Ra(3>aj<ŶBd{8WeByY~a8GK岵g[~m_cQ&BWθlq t[Өli{\ﱬĝ T +9/!L5Iv=͛^}:,撘 H#llڦpvAP6}ybKUQ7oOVVE%d>آ &cG 3*[4 fc2wr?|>`%;pA$KƌhaM2N`}QIAGx(c+T^ΝJ~IkDÿCsޞ9D;v$?C/gjz#S2.l]b%~Oq-*|K5Ph +ߩDb諧NI&3Aph= @^rp Iqa|_$-Ց/ n"򅆘eU`'H +Tgܤ40H*1-Ug=AgKꥏ`-:LA uɏ?jȖghkI4(xypA6wR^qbcgOz~9u6rV ]Ϛ`4w^Ft窡t#:1SJIn8g[rl^uEY)釥_c/7۞@3hdKb1:7+35o *+.$<+zGŲ0]]˧сӆ MJڔ>&~t+u22UȌ[$90"|.̴^tƋ=~BECVi!Ҩ/<+O#)RH)OĜ0 U×Zh,SH˗|VċdJ7 vc|T-r7DBP +C+#DTÀ tRVefd-elK.ȓu 10)b7 eсy@ݬ*j5ѾVdXEB#!ԊZ `0pMTRwed?[`KbYދC}b +S=&1nsD KgQQ!x'"p*dEWe5k#eg) A3 ֯A j-(E/"բD^+#׈E\M^lZu_^a*c5BhI*6a-AJCVl 1Q %v>¿Mmԁ:A#uPbONHmP@I7AޡC`N+L]}sipx>V`1ݏfRLv3$҈7pU%5-T 0N£&t Yf*HګC|FEu]apcXqiEMUXM YF ("Œh#cVb|[+uBEE]FA>@<dxV} ?řۏ66% YXZGU&-c ovH8b ^0x%>oӟ٩-uōmt&/5v`?$zSOmKfEZM}D<Ω٫˫~6λ$jK<)]r&GْT8bvu*b*tG=}+3@caRe݄#M64g;4p0#iZ0:ƛe ,֚*hBSOZ79!`SܝJcݘSeE1(ad?vC`|qB| a\~:Gk'7g}ydNPAG#!V@DLgP-TydLF1LK |`~AȟL\6w^faRS:̂DjL(yeN!{S[֩ܬry%_*Ǵ󏅆R6Z1}S%\ZʹOa&^6(X +Zd_eչy}:9,[ 3WaW,#0eFHt(\s;!UoQwA@9F.lai)C)0W`&:Uc#D6]#R@o| Ö f8W|U+~Ml)X =iW>I࣬yYk>Of"j{eFlWwE:0f nrBҾ8kp ':*agi wh\8&J2,}O9zdh\@`hpв#xs*Vijv0uÄ؏F~d@_b{azaҁУzP4B39\I/iT\1Kh#![`nm{K̸;p#k!T;wtZޢyNg& [Hk5?I-f3A4Nx^b&S8nII@wqDkS+Bgr!1o_DP3I6Q`_ҙTN#d/< +K)ƿtKi^QLk$ea<}}Doo,}[Ss+"L<%wUqWVU]}%@=( tQ@&}j!aCX:Q(b35 btAJ 3[[/B*(ydڤ6u/LG +$kU]Ys$UIY>gJoU}^O"Iur +AY;ɣatN'DI܆Ӿ̢J)@oGMϰ@j`iE%j +oN~;;rql6m?uΝ_$) w䅗%[Yuvgb<{B;M-uw:9q"56CYdΉQ5tQۜ|ܘ?BؕO✧Ub}Wao3 nʫs5+FI*2&Zk;B +c[|Irзm}^/`Mΐ*Ɍ{{S=ѻcvr$/ +Zzٱ>m2719٭Ѭ۸鋍>f]劋"ypo)ȴ/jP31{z]$b7Wn*q +^pH9"H똺w[k69 @De;}s>/rk85F~TtKuUYnյR#Cql)gۂ6n }PЧ{5C^`!YLnU/HA*sHصT+3+X Z̛TGi9zh\Ԋ& X/1>( qw {Oզ`%/t\n{\8m,G#15ޡ2ñE卌s8Ƴ3=g%=xh DzR-x9#746^V6gt.'PJ\bFeAH[n/@+]K;rj>]~A޼Y^LFVd(G4d284} +,~g<5 cEV7 U{]ip h`Hםws-`\(on?g7˰_غŭ2pzz&@dk*GUM,dM/'Kx%ƤPDH"ٕʻR\@- O8¿=z${m[?`[>KoK5XJZ5$z:5QKY%E{tD\4=LS.?GA{AZZTa/`K3V=`UWo:>>fwl#kjm \nQ^-zͳ H+%UO{y l,8^olKC*3$ijsoW>jCӤl%Mh`ތ-kpºO{z*Q+:F~ݧ/u6F!iUN n耝JA{ԝc8h wZ)YW]O:QtIq'y:hSaz`ĀXY?FN9#gNTg"93fv z b1sl;Գ>GIfhG٨?`qz+ $MzzeD +R{~+TW0B,Ppߦ2Rzs XAC*xX5!"E(wDy]|Xğ:6  0[DYMWՏԜ9k>3yE\\4/Giss0AO"$cƣ$ ?[54k4(Ei4X kqC[a91V%F4=4oN+x)',0%\ ^țVZM_Z]ߊa>,YՖ[xؤZؤ֚ ݻ&Y+jwdEM:Ն2P dv%EF&DղvGE'H.";8 Mьl_G㐀c55{ o*ZۂZN˷e0C0aۮ2%MuBUQSBų >0~Tv+:lC]W.yCŇ(ơp&pv@.[ZMk E\U& +h|ĪL*UiQ#Qcŀo4 玫]߷wk0∋ĜE.++ +rW'{֫<(gݴ=!I#TOߠa}+>R];^?8 ga2W]- nt'?‚_JZUmSJswZʋt;Xq&urڤ) blUśWu@˨Sm-C@K%)I:k#NJ{m31eKF7Unh81Oq [{T6rj㝨XBNTB/>U,Pl{ KjcL(\Ͱa(+RACo3:t;ܵ /J1]R4SPf }ԈiL|o\tq!J Ww[ S~,|ItXLx:3L,J _ R|;JLax2]'rrkBUnf`&B#?L1IX[lчE4 p='^JlCE`̆*w45,#cZ¸3зCfoA3¨QC!_S +މꘖxb0<#QiדO86?)2W%.>R!;}a2oB>khÌroDhߧLf2Ffi&.)AJD:\q0*:%4sQKPeQvە|^k_s"EMV 5r$5\x'Ya'=6_. +~ j# T9!˚Q[Y%j+j C޸?}VM:r+bLu ͼx&_[CwmBC qQZ[yS/`7]UP;u.^{Sg, ^/ Ic)Gxh6\U0эV +8ɽh/7\1P6; '-Vd}Fg BZBHzfAx spy ȕes/=`i$DbZ>H[\'F6. JJ'Bw)=U"!ˍXc8{ޟ^C8d`u +oPɻOR٧Vou; aLS2&Kk[1Mv)]iM;nUEwT@nL" )/QG&_Pki|I`SI.!?Du8S䛘0JӠ&UlH$~lu)[#$HiD0b 84꽩G44^׵kaj')8H7et;JDT5L%M +8%ACs#fG7;;Ȅo)fcyUx]h^ 8*$[Wfy%3Eq;43f.u1D@xzLD&K [} Tfhś3SJvI^^ʼ~mIf@@ҹYK2W%)RR֭ZnSMtaTOуg G @A+4@F*K?`] Kx?SjNS50B(\LŊ: 3 ga[o?i{4> ,׬C\itfRtcLCFm,h1as#fqRKTܚϥZPh + Ax`p m dLΜ|(Ug9we'I' 豆th 52O xB +ʆvaK\m+6ӳsXҟ%Sinx{ŴX1͝]I8*ܻvqo3ͰjtX#L"i,dtޛJcA++ev^ +U|mnDJI ${!́,3L +0a7<, Hyc*dcr +/K2eKќG߆"zZn|wǏ]be=amwX%G4ĩ`&-"k!OLft])ǂ ;N$LzOMRګ43 ިs&ZMj.2mq@.GQnU2.B]*[DeՖ-T=x"T+"u@-lI0T16֍afIso>ϻ||D93,Ձz +Ts>'izے^t;yA rLI9֚o3Ph.tc9+s e6̽`4,ci,;@UzH寺MeʽF`Q@Qx웽q'S/w-[@X9N@JXP]'oVShhsf MJC`M:vaD v}=ex6f\h5,ݨri݃iٴXkQZs#f'{YAj-Au%Zn0EUl|LJתɳ :?3gx:++Wcw;R0vԍ$IDA2t$7 jKO(Xa}2[fH_8EF\un{AsYqU.Msa ~I0c+mymY&gf[t<8I%csϥ.:"E].Ƭ KG^RV]ۚ\V~GQ+jr]7foCJ[8WPQ/.,pp>]Lv?]DVőxP9#3_ +3 0;P?"8Ͷ +iS; c5ӆ(i܍ @MYVV&wԉQr8œ\1Ul2wžM:##2=8$2B +if:y9=$C.5,iKb s $!"iQwIelRI6d!$+H_汦lO$x`o)dj+BA +إodK+cP8`I>m`)5x<knrd Iټ[.r.S +ߢU-%Jf7Zh\({)?!qƕy0PP5UCF5Z)hWnPkLhC# {a򚩞n#'$AyӉO6̽< uü+o 2? XĂ(qӧ-! ,ab"v8krQLn*Mc鎷fA c"[GpAh>at5 +DO@gl%06H y)0b[fgѫ~Gu8td|y YN%{nAB:L4A!ٴ~3ń{4 ~!0)cͳ;ўf;2Oqe_fp4Tv>GLvyꠖa4a9h,r +Pd{aM'~~aɑ#9=ךcߗe S.3ST.Ο.L,7vr0)fmv8q%?"pE(\ '%j`\(M%T<_2~n]SEum`<Ī/<-=Dڽ>Oj74CHAN]$z5LYT0cu1MuY=wwAi3;w?R˙Rd97{Bj$)`|HQ\M~zoqHYAYK|3JȦh +#˛Vߊ3f=slC0pxDK{87 {ƔXfʂŋ J¢wPή=Mb1Gǡ͎] qGشd#C!#XGBb VCN + 9a:uq4r< ~ދ}5B3C6m=B-Gp0tM]`ߨ18tt[{,L2e cq p^,Fb=Xf?JuQ FV(I^B Vlj~sN\`s9P; *8AMQ [[/isw!(xD0i yJ`9sʃ-8Gw#|=^T^t"aӏ3Xk 66BH#ˠ_T]aPwGU&F&Jyy.pCS]{\¡rP@k'B oȵj哰%#Z]4 +eފq(!+aL|pݮ9 +µ[TЎ7`! /;`\@zG׮Ȟ|F`#ce$e65 $}>U$K:d3I?$f7xlѼOULF=P^cY(Y/ Ռ<11Lt%喨lm,E~8[sJSμ0?q0[#Acm ݹbչ&"g;?X:$7C LfJbfֳ8_FNajNV2_ WIG>aaNeN*g3i( _30PTʱ/X]$_s,R'<ҖPG*2`6`+Dng0 ;Z@#YRfIkN7?@[se~ Pzz3iӫαP(+ԁӱ㡆AvuvU9kAWc,n̠Ӕ}?1 }{F %lC#̳aC!0 O3,Ea3،:+7z[R qk:!KPCx%O V'M\ B0WuFqVt;֏O@ T@ goYǷ$DVhrI^UhbwpX=OS!m՗:cB۫O?ո 0`&B5Q:aϡ'kk^goER".sSD&k*P]qT [J`);:BU}C;@ bH&:"P&Hjh7f< 7\xӞlPyA2e d- m,Xb <>>3>.AP u[- BA(yIP@ k0L-M( nр8*$>qjfr`d1*Kc%#H4^PFAAqVAəZLd`#/֫5+ zIĕ F[o Ԣ ,ZLUhhPEUw `bhBeN\s>ծY{;0|zOpN^@qt (VaIZ]0Grޭ>,Aw +S)JQg$N`t\`ApAe=a҂nvXjrrB[RS]7CWtB^Vt~~WSS-䇐Xw]Cn|RypgӬ!+Iך!(.KFl1ݣҿV_YyOMj~T>7)0pD_Rї#N N:g:/Fڀo~Y~ xlA:0FQ‘0AU7q;A&xN-۾BJm(hcgi&®CY$2rܗs;˿\M*\'] G_><^{ +L;UWL=HJ`n(rdrq)$N,6 $n~3XHA: A.hjPqpqH4tɐ(7X4;[\lY!z lh +vxe]*>c7nk؍ֱѦWk {Ÿs,;*U&, :Op9 +Ov0a=\x?11=k6n2jt 2tB8=h`sgջNW^Ԑ!p"߱ͪZƔ[F!:)>Z:;6dސPX 7`#Obʶ +:RPK3bIJjɅs-31eL ;~F<9K>a?~#`V0T4R}U$-,aТ H!GJj&:XxQ&P7 κcDwFzm + +a3 t vbJ2Ui+*gMB,ZW|?=(˽WSUݵ"D& +l@"*hEbyDPAi3DEE1Bȹm.OkNf:ogw~9|loq|fN'x ,JYܡX#0H$>d +~w߹$^ऻB)lK';`M{5%rJ܃ ߮jJ[>R#.e1s=d AQRPݔHﳃ2˭Ze_8fj> +#H7ln9p. lfnH\VUjf@pn/ta!R33KuU]EƊtZ{џϿ΋ϑTeŵk]RDQKX79Kf-pl90أ : aTҘ^U%Z@$rXIElLT7c Ȩ#h#n,ed`i"Re"B(y #4 ;xw-2u&4`݆Q l ݑ99b {:BL#!Eֿ@rӍ3]Up18A0&c"HJc"E8\ )@5k$8 HGJnN&x [a%rȢE udF"&~O\xd Am:S/6QDڱ.{8+m23ȉNȉq"ooINX w5+<;3YJ0Oxa@r%[++ܿ_}eqfh*qY3[:CbJHC|5),X*oJrsnG +#;҉q;ŎMh97l +H]q4\}=`Ŀ&IjU[V2BD4:J:Q-\u0ӿsj +DZ|Zgc5CXVH:Z /2pٚ첒_395%,aDS*Yu-7liТ<\Un @)'XhF|]csuuw"!fi1;U_psU)RmtwܼY{'лp \Z +fV"Qqa Hn_/ˤ}Q);RDU,GiLK1_ACS5ADZ׮asUPkېfcK=V£G\@{MNZ9!"|ۣxIJķ%`D88J CG-G+njH0c1fh +1@l`ApsFj/b.kLoIqɄ\M2΍/ʆT_ݚ]TKQ&ZJ +_.s*_4%%`Mzx;oZ*;\S44ɻwj
  • +X|H+v( 5ՔTq; "=+ex'ksnHQ #'EP^ʯ\) ['m8b~nDi8=16袹$(4ڰa7k#WN-Lz!2P2sߞbxoۂ'egkU +F Q#< ꀹ&J,"0 +A3joY';ByFg2gz4}>F ^#]Ww+G$PHlK\ Vtd K# fdoỤ04x)1&sVTO{pAnT\"[4jmٙ+)`bEΌ\< hOG{Ͻ/w9J&ׁ3Gpvݢز#GPg_a*4;0,|zNj}]<<ѐqB=)h1y,|Zi%$zi*b23ϭ + ȍ؄6/7RR|^Q^蛌L07C]BlbH Vڌ O,zCY9Vk=w'9Y oI&J憏L|ڍ۔~[eǵQԂcFjt Ȱ҆UzHE8 +99d٦ꙏnьG i4nXZWfݿJ"}M#?kCzK}婹b9~ jS,n)͏謭2W:~oFLOP@lDmֹEqzOp^Q:DWcrBꙕf]S20~ԋag0W֪yi -Ka%V2y/6e68K䄋8euDJt$OI?\Jq#/̓'Y`:M>v8 Rj.vs/h8"x~٧59%%j;ҍ@Ui!n/R Z!A6>]bb +3nTqrr_WrvUo9rUo.~ o]pU/VαŢ'BsBkBFl^f0LX˷]운MSj8rp_0/ - +)M LU>|+ q7dz)8f^4dYݟcv-a/W|~KMb8ۙ_>d>isstZ<+~dcaɿIߋ' +BĐ(Bx}^Id!cv] >5a }b=F^ M6DΧ ?Bܟ\ÌcXl:f Ǖ !'{"=/7$# T%5-?R<ÂT-`OD璉!@̂>nW&7wx@eK=` +ފj?lV05{7_O_[j:kJ7o;"Y%˃vʇ$.\ -`,X` +jm^; SSI-,3+꙼ԑ+-i]TAlM}SHv|]$zדjVpĝ6H +ow:ض^)=",$4}Q[UҪjoq;hO_R$|JEhDsb9= +h b"1DTbǢ6ބ>q~t96R64u&Ɓe*빽&<PwjU h#h ]Г洪"30";N=Ο| )n9sJv|mA$U{rG;l=A?`\Ŷ܀ zݙ"zu0yeAe8YprkW.-3dHMIUbɌNKD~x4My?w _yNe|/Te|H +B2i%Mp%)sFogC/};Q +X}#!ktQ(*D+P{]YN☢є\_:Gy:o`AEʚDI\ҌBϊ0EC*En($aFwhvܭY n8F48 f ?b4Jɺn&` ba+$:PEvdƫ3 'Mzn.UR*[/,Xgy&"B*DDA%5y*|(`KGq*۞t:HgM|9'?9v!rA-(lYZ BQ9R>ؚ.`C51C6QzqWACU̔<<1l~ M'2G 4ud[>$a +1 [x+ <tYߊ4 QeM9&5Q%K'?y^yڷ 3ke;gcST3R:2;;)/pߓUV(N$*DgEK=wS~+b'DB7e5o  V ~]l:Ȋu"c + +9o ;N>M4/i?a&A5KCEnJ)pF=+Y\ u|"}Ũ W'f8M^@N ^?80巁D&7EhX,@=!`U:b?^ʩwp&e4~]bR ~1LB&I݂)سB/(<;:⯓+:5<7=˝cYP<ϱf3xZ{,b(ji>2l&x3^Cj43x:axȠ'g,:.ՙP#| 0K}2%Ww9KPК8d~bt6o'߿C:f{ IqS,GY޲ wa-ض #l8Vl +llL_f„ $V搫Z[ݡ= ? _j9ҼU6AmGsMԥ3|:r{ Ύlo}x}…¶} 2SoboL8h rn ,5FH-\6Jr":ׂԘVr]Baqv3n +(7 +.LC1WW +Vϫ+LNxUSu7U6yynx7g00D]Es=nF4!<'US 9{.^)܂8擬HPDK"Nr"LBo\Gs'[r#/HmưgZQsNJK3N痘;kvs +:Ny*M9}@w*&2:>6RپQq@3C]$'=@|2C4*$.^؏TO<S.Q'R# + uyw{ KrEEj?@uh1eڃ*ܮf[\#ˢqjAXt]|lÅ],ǚJC..#jJ5R>2|d* {s{{ҳqIb(hФvׇGꎯ5b_YT9 aP_~daXz}Furn &}qNy.Wy*0?f,Lq|'0%Z'rlVYv0-EBӱw:ӨIIM=`쌋o hdwD"ƉN‰lq&JnN[Wmm茶W4Z+fW_z7ya'ga{ #>FHK'LDwJ#6bbo@\6Ѥ0= (/|O#IDFB2Q1"3xO~BaD(ʈTˆMfD# +`IDUth@ht`S.pr=@?,|'N2G #Qs$cM:1pxځ܁hX[J0> +Ar)Vf~U{Hg-0Ş U\2IS_r)dUOExc0lB=ExAuE iVeMtjuR*]l!X4mb-1JQXdmUuƵlmTJRkfkPU/r(?v.7WrJ?RZzcp:l kpT<̥CwJ rWڗm +,)<,9Qj(jOVqL7/U.V|=F]33W +9㗈sb&4:`q|Quf 16]]<OPyJHXY)exd}[(JRFs@3b[cw!!J!(j+젊CGp͕r4W"P&s@uPy#FJwwtuɅ1fR`$AȠ#n1|#EO0r]T 7p=y䋦B, K3F ar +=@i#jHLt8VN]ť,fgըj4"HP_NrGِ::Ƣ:~,N'dp4ؼh ,&!v ^nJ;ţ05hj܊;2?#j^}9,Y~ճg +MF UF{sɞ_`uܣ:p +})Up9R&x0堵Ag=ei$\Ƹg鞒v,oB_xg1:J.E:պ 衺j6?Mt˷^WOp endstream endobj 13369 0 obj <> endobj 13370 0 obj <>stream +HdnFཞdH#A^ dvԒ@ }ymc1E2^:=ޭNxϗ4]ߧ=/Jmx_~k_z>>>\ݮ[?|Oݧp>W뿦8//ݧs~|_˽t}wqyxu;i|2k۶1i|tfw:Wf㞞&Ͻ~JZd#ىEED"GY"r+W¯_ ~%J+W¯_ ~%Jo69+fe"kfl eȎ!{f3rdȉ9!g,2k5~M_ӯk5~M_ӯk5~M_k5m_ï ~o7 ~o7 ~oo7 ~o[-~ o[-~ o[-~ o[-~ w;~;rN̡c3f96sh̡c3f96sh̡c3f96sḥg3f +߫{D endstream endobj 13371 0 obj <>stream + + + + + application/postscript + + + Print + + + + + Li, Alex + + + 2016-05-02T11:13:36-04:00 + 2016-05-02T11:13:36-04:00 + 2016-05-02T11:13:35-04:00 + Adobe Illustrator CC (Macintosh) + xmp.iid:48acdacf-5b1b-43be-a27e-fee3b5c20092 + xmp.did:48acdacf-5b1b-43be-a27e-fee3b5c20092 + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + + xmp.iid:8ae610ba-5842-4dc3-b734-ded98ac8dd17 + xmp.did:8ae610ba-5842-4dc3-b734-ded98ac8dd17 + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + + + + + saved + xmp.iid:aa7e3f11-1033-4ffd-b579-d112afde784b + 2015-08-24T15:23:31+01:00 + Adobe Illustrator CC 2015 (Macintosh) + / + + + converted + from application/postscript to application/vnd.adobe.illustrator + + + saved + xmp.iid:0dba57c6-5449-4ca3-8ef6-d6ad5b6da0ec + 2015-09-22T07:57:44+01:00 + Adobe Illustrator CC 2015 (Macintosh) + / + + + converted + from application/postscript to application/vnd.adobe.illustrator + + + saved + xmp.iid:8ae610ba-5842-4dc3-b734-ded98ac8dd17 + 2016-04-25T14:11:19-04:00 + Adobe Illustrator CC (Macintosh) + / + + + converted + from application/postscript to application/vnd.adobe.illustrator + + + converted + from application/postscript to application/vnd.adobe.illustrator + + + saved + xmp.iid:48acdacf-5b1b-43be-a27e-fee3b5c20092 + 2016-05-02T11:13:36-04:00 + Adobe Illustrator CC (Macintosh) + / + + + + Print + False + False + 1 + + 12.376902 + 3.726714 + Picas + + + + Cyan + Magenta + Yellow + Black + + + + + + Default Swatch Group + 0 + + + + White + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 0.000000 + + + Black + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 100.000000 + + + + + + Grays + 1 + + + + C=0 M=0 Y=0 K=100 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 100.000000 + + + + + + + Adobe PDF library 10.01 + + + + endstream endobj 13372 0 obj <> endobj 13373 0 obj <>stream + + + + + application/postscript + + + Print + + + + + Together Design + + + 2016-04-05T14:35:22+01:00 + 2016-04-05T14:35:22+01:00 + 2016-04-05T14:35:22+01:00 + Adobe Illustrator CC 2015 (Macintosh) + xmp.iid:a811c05c-74b8-41cf-b996-ae8bda5e53c3 + xmp.did:a811c05c-74b8-41cf-b996-ae8bda5e53c3 + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + + uuid:1429a63f-381b-4bbe-b610-dcd92ca51b5b + xmp.did:d92220c8-81e6-9646-85ef-ad1bfcf188fa + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + + + + + saved + xmp.iid:a811c05c-74b8-41cf-b996-ae8bda5e53c3 + 2016-04-05T14:35:22+01:00 + Adobe Illustrator CC 2015 (Macintosh) + / + + + + Print + False + False + 1 + + 150.000000 + 150.000000 + Millimeters + + + + Cyan + Magenta + Yellow + Black + + + + + + Default Swatch Group + 0 + + + + White + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 0.000000 + + + Black + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 100.000000 + + + + + + + Adobe PDF library 10.01 + + + + endstream endobj 13374 0 obj <> endobj 13375 0 obj <>stream + + + + + (Adobe Acrobat 11.0.7) + 2020-04-11T20:55Z + + + 303805 + + + + + 978-0-13-573258-8_StandardCanadian.pdf + + + + + + endstream endobj 13376 0 obj <> endobj 13377 0 obj <>stream + + + + + https://www.alamy.com/image-details.asp?aref=T6R86M + True + + + Your use of the Image is governed by Alamy’s terms and conditions which can be accessed here: https://www.alamy.com/terms/default.asp Rights Managed Image information is liable to change; it is your responsibility to check before you use an image. Please check on https://www.alamy.com/image-details.asp?aref=T6R86M The image has the following Release Information at 08 November 2019; Model Release : No Property Release : No + + + image/epsf + + + Zoonar GmbH / Alamy Stock Photo + + + + + T6R86M Ulm, astronomical clock at the City Hall. Image shot 10/2018. Exact date unknown. + + + + + T6R86M + + + + + Credit: Zoonar GmbH / Alamy Stock Photo + + + + + city + hall + clock + at + the + ulm + astronomical + ages + original + donau + alt + city + council + building + tour + astronomical + clock + ulm/donau + city + hall + clock + originally + ulm + an + der + donau + at + old + ulm + donau + middle + historical + history + astronomic + centre + south + town + hall + astronomical + clock + city + holidays + city + hall + hall + ulm + top + ulm + a + d + donau + germany + middle + ages + sightse + story + the + south + germany + + + T6R86M + Alamy Stock Photo + https://www.alamy.com + View your order summary at: https://www.alamy.com/Order-summary.asp?OrderID={E756F3D5-0DF7-456C-91F1-6B3CDD789DFE} Your Ref: DY37499353 Downloaded: 08 November 2019 Image ID: T6R86M + Ulm, astronomical clock at the City Hall. Image shot 10/2018. Exact date unknown. + 61CA071169DEE44E9DF350878C1DBCCE + 4 + adobe:docid:photoshop:8a09bc82-e821-7047-a2d5-59b18fbe1f71 + xmp.iid:fc7b617a-f922-4d3e-af3b-be57daa211b0 + B1D58CA057DB32215C2FE3ECB4D4CE72 + + + + saved + xmp.iid:1e25dc92-0430-4054-9688-cf21b7477ec7 + 2019-11-13T10:19:10-05:00 + Adobe Photoshop CC 2019 (Macintosh) + / + + + converted + from image/jpeg to application/vnd.adobe.photoshop + + + derived + converted from image/jpeg to application/vnd.adobe.photoshop + + + saved + xmp.iid:dde89b01-c20d-4d5a-82aa-43f77db8d753 + 2019-11-13T10:19:10-05:00 + Adobe Photoshop CC 2019 (Macintosh) + / + + + saved + xmp.iid:f669f734-28d4-4706-a4a3-5881addf764a + 2019-11-13T10:34:32-05:00 + Adobe Photoshop CC 2019 (Macintosh) + / + + + converted + from application/vnd.adobe.photoshop to image/epsf + + + derived + converted from application/vnd.adobe.photoshop to image/epsf + + + saved + xmp.iid:fc7b617a-f922-4d3e-af3b-be57daa211b0 + 2019-11-13T10:34:32-05:00 + Adobe Photoshop CC 2019 (Macintosh) + / + + + + + xmp.iid:f669f734-28d4-4706-a4a3-5881addf764a + adobe:docid:photoshop:e5c4f31c-2398-1443-a436-3a8a07e12ffb + B1D58CA057DB32215C2FE3ECB4D4CE72 + + 2019-11-11T08:58:49-05:00 + 2019-11-13T10:34:32-05:00 + 2019-11-13T10:34:32-05:00 + Adobe Photoshop CC 2019 (Macintosh) + + Alamy Ltd, 127 Milton Park + Abingdon + Oxfordshire + OX14 4SA + United Kingdom + UK and International: +44 (0) 1235 844600 US toll free: +1 866 671 7305 CAN toll free: +1 866 331 4914 + sales@alamy.com + www.alamy.com + + + + + endstream endobj 13378 0 obj <> endobj 13379 0 obj <>stream + + + + + application/postscript + + + Print + + + + + Leung, Anthony (Canada) + + + 2017-09-05T11:24:22-04:00 + 2017-09-05T11:24:22-04:00 + 2017-09-05T11:24:22-04:00 + Adobe Illustrator CC 2017 (Macintosh) + xmp.iid:619f6959-b55a-46d6-b201-582d28a1a1d4 + xmp.did:619f6959-b55a-46d6-b201-582d28a1a1d4 + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + + xmp.iid:61998c4d-4eca-4346-9584-d9662670ebbb + xmp.did:61998c4d-4eca-4346-9584-d9662670ebbb + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + + + + + saved + xmp.iid:aa7e3f11-1033-4ffd-b579-d112afde784b + 2015-08-24T15:23:31+01:00 + Adobe Illustrator CC 2015 (Macintosh) + / + + + converted + from application/postscript to application/vnd.adobe.illustrator + + + saved + xmp.iid:0dba57c6-5449-4ca3-8ef6-d6ad5b6da0ec + 2015-09-22T07:57:44+01:00 + Adobe Illustrator CC 2015 (Macintosh) + / + + + converted + from application/postscript to application/vnd.adobe.illustrator + + + saved + xmp.iid:8ae610ba-5842-4dc3-b734-ded98ac8dd17 + 2016-04-25T14:11:19-04:00 + Adobe Illustrator CC (Macintosh) + / + + + converted + from application/postscript to application/vnd.adobe.illustrator + + + converted + from application/postscript to application/vnd.adobe.illustrator + + + saved + xmp.iid:48acdacf-5b1b-43be-a27e-fee3b5c20092 + 2016-05-02T11:13:36-04:00 + Adobe Illustrator CC (Macintosh) + / + + + converted + from application/postscript to application/vnd.adobe.illustrator + + + saved + xmp.iid:61998c4d-4eca-4346-9584-d9662670ebbb + 2016-05-16T09:45:06-04:00 + Adobe Illustrator CC (Macintosh) + / + + + converted + from application/postscript to application/vnd.adobe.illustrator + + + saved + xmp.iid:619f6959-b55a-46d6-b201-582d28a1a1d4 + 2017-09-05T11:24:22-04:00 + Adobe Illustrator CC 2017 (Macintosh) + / + + + + Print + False + False + 1 + + 0.925855 + 0.970551 + Inches + + + + Cyan + Magenta + Yellow + Black + + + + + + Default Swatch Group + 0 + + + + White + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 0.000000 + + + Black + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 100.000000 + + + + + + Grays + 1 + + + + C=0 M=0 Y=0 K=100 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 100.000000 + + + + + + + Adobe PDF library 10.01 + + + + endstream endobj 13380 0 obj <> endobj 13381 0 obj <> endobj 13382 0 obj <> endobj 13383 0 obj <>>>/Subtype/Form>>stream +HLLA1 +>PZJ^bM``"t.03x[LL*ȁ'W;]% +Um ڃk,+-ngY-3lys@Ek9I9]Ā;\ & endstream endobj 13384 0 obj <> endobj 13385 0 obj <> endobj 13386 0 obj <>>>/Subtype/Form>>stream +H2P*2PACl.}`b.K=#S K=sc#]Qʕ`@ P endstream endobj 13387 0 obj <>stream + + + + + + + + + + + + + endstream endobj 13388 0 obj <>stream +Adobed  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +  + + +  +    + + + + + + + + + + + + + + + + + + +  + + +  +    + + + + + + + + + + + + + + + + + + +  + + +  +   m  +  +  1!AQ"a2 Bq +#$%&'()*3456789:CDEFGHIJRSTUVWXYZbcdefghijrstuvwxyz !1AQ +"#$%&'()*23456789:BCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz?s<UTQ +݈݇U[=^ūuu6Tq>K_@6{X-,/e8=Y vaYb _@s<13eiU:CrCiם-O/|b2dapG@_6_G'F5{>,KPeò4dkˇf5|}%,_`s<0gho Íyp + +=VC,_`Kpd(2fcY l+8=ŐKs<>Wq36Mv;G?VvBšg05}|}|}%_B>hCC; 1}%,Ad8=Y l+8=ŐKs<*vc8rMW[.UP||>`Wf2R eJX-aY1d2ᰬK)bs<1fÚ3,f^Ĝj2I[n |q|> +=VC%,FHb }-aY ɆƳ1e_>>s<*vkTQ[sG]![ea} > }+!,KPd(2f) +ecYd=As<VC#2RŜ)b vFT>Wћ gX| s<!mnuDSzV,F>A,}b=YteZX3%,_`LnFtٍd2ٍgђ/}|}s<)ęĦHׯKOZ J3Dj>=ѽ}s1/e(2RŔFtٍ}pp{,Ks<('1=(_қE ["D=K2)b Y82Sf5ˆƳ7b{s<5<,z•D>>hYG_ Ɇ|f=A KPe82Ŕ0Ƴ7b{s<5Wsf.qq}@_@=Ʋ|,YA K3P +ecY,_>>s<5iTtǙ˜cf:>xl+AY Ŕ))b vaRAdcY,_>>s<5O1Wslpv|`J,N>{tc_Gd`AՍgX5,0d2ᱬ2Rs<)6 ~+WGVrk@>X|G }+!/eH2R Y82Ŕ0p{!s<*詫zJӦ+VՀ_6_G__7fu|}5}|}|}dd=,_`Kpd(2f) +ecY,_>>s<"|b0'7ӻTZx(t1} K{1}p¤%6a_F\;1KC/_@s<>Lp@orؓO$x)[ l؀&4\>G6{Hb gX#gV,L65C/_@s<+vS[gG.=1T>tNkCd=Ŕi` eZ,³%aYA gbt}|}s<<-3i%ƽN[i&nS1|G@=ᰯd20}%,RA/f82aL65(=As< b)W~QL>X|Gxl+AYt}-,,EԐeb2a YAs<)=\:c軧%QÇ7YB>\|GD>xl+AY Ŕ)` }5,0\65C/_@݉+S,~KWUրL8ʼnKfiլoWkÀEN"t}WbZX3%,YA0ˆ²0p{!%5M:s< #?Gja[M<0N=3MQI.ϖn)6̫%:yWPOEN|q,3,_Ga `Kpd(2ҍib lk8=ŐK9.S5VN&c6e\7qt(k\sq0c4shlIxjTۖ +ٍՀ}.>& +=YteZX2%,YA0MVC.pŔ| 9^GeÎ&};tLu.(ә +5X]9X\D}S#}|} Wq{a_G +{i` }-GRA gJhц쇷9am.FW(,^ߒ5UcP3;|t3MrҔA,\-KKίt0ž&K6}z|f2Ră-0$)b,"d e3Y9$6nKض~r3qWY<ώn3H>UDWS}vF_tI&=|aͪI5 :3hàFħT*㸡F]dbtW٤3Q0龲T j0(ôC mg$9V}tÎ&ς&&5k[A9ag{ݚ\xn펎|Snd96K599 +Þ-𣭏M{C=9&W19\H8eٖ9p˅QiZmߔz@9=M~;] u9#>> 37> Nrk5q᭮\PKD9Ù:Śfwu]lwe] 9$Geڍ 1i5jvٸq}9#>텍rtkufճѻ&N9e3Jzʚuγ]ʒ931Lg7 lcn9 %iշ%X9|{/<ӒZilt.@9ϙ]*XO^t:yl +k9N> c ՛F퐿k09.OcS=8G3`ٚ93hëLO,4jl + 3҆9yf,9bQܾmti@9|>ؓVwWմ9ax^6z='9|ax=ݬi1p9`=ݭg5 +p9|#L=^-f=9`رVwWմѦ9#>!|@Dzプ5z`(9qiaS(j23iG@9<:9e}h}7٪} (hڊH0bsC=O^Y5au +=V:&GhVURςuqިVg=v\18uOn/z,G=STq wibjdž2%G6<Όm\HDqԣ-R&鳙gp룸e(EVb}9|џfQ3GMTs|x/1Sk_7ci`Spς*z{:Ǣ@%Ӣ/t|uAWqC}91-1cz}g@ޒiڎH!cCU[N=T["cm l{) 0ꑀ1SV=QgLY>z|}`K=>3|5M6bfO1ʌg"o)&C-]=ǧ9|?>>v:b#Fs &741 qv>/4ґ մGKI6GN})bc1|eZ&ae\,%rX$a +$f7E}&eC YV5te7.f9e1h&{$iӕtzkul&bz)XyVl}|X=Qg=EMT>WzY Y xS ,e.-U## 9|mU]u4^>QzGC;=>3|Lb{b{_GTha-ǧ9`\/OO{Ywɳћb%N>W\aƳ:A& +ފu=5tzkm+1qǫZ^$<| a}@0,_`=C82R!0Ǩ` _`Ʋ$bL1ٖN_G1ӭS>r|UvxkxmΧ¾jYYW >!Vb}T@JlŐz/=P{b{_GE+ؾ{Xz|9ØV7qasbHѩvM>aYE6s?wr/cG,\ +F HA/}P{bP2%,A꛾2ib2CP{cYAzl_@٣- +: f<§15::f>u||_GAz bO/Mزd=Qw/>>z|d9^وoAv mɝVm C Xitz(+*kf|ʣ(>|GФ KOb=Dh e_h YA Md,ƲKK::C>[8bwS0Әg +>>N:>Lh>4>Pz|d>_dYO+=>22d=Qw/>>z|d9ߙ )]:yu9vOkfx4MN.H X# b /}P{bQ:>2)bT _`KP}$1e65G_G_>> uC

    IםZ3 s QV|d>Cn>\|GTYO|}/FH` _zՋ(21d=f/zl_@|}9cx!2 `| >>l>>}1Ld(=SwC1}$Y8=Pz|}i|}| "mNN4wdi!SRcUVN&6<>h>C_BcA} Dj; +=e=RO)bc/Mز=Qwl_@`z|d96C/جjiGNJ6H}f)d.S =;<:rk@}| K>(2Qv (2RŔ!ꛀ YA e] ={m<8jjp +ZY+\|>} +BlA>2@%,YAL|G,ŐMC!ꋾW=}`}9̮ۙ8ܡK_.=1j*6ҜYQ;5,6zt-A,,H=C8=z)`T&3ƲKK jNݓir/ 9#>:C06L^2T VW fbCbz*O*W>)&ulTc@|>3kA/}P{ (2|}3C$Y8=Swђ e.Hdxq"τQWT: >"t} D>}؃#d>c/z|f=P_꛱d21d=V_GE+ؾ>9~s^ڞexAx؀ yzrMSh}o kYldžlx7 N/ё!,Mp g` _`ƲCK?%G +o NJ.(qUS2p5s |>pO|}=CA뉋!OnŐŐMGC|{b>@9|쌯ap#wUˊX)POsw5,vS~Ai\"5} a}CMD>&u}`Kq/ǧ#FY,Mp Ɛi= lk8=>>>>t}|}qqij[g;^\Pa kˊ)GЈ|,ΠD>NX`K=>>g>2T1|G(=d=f/zl_@|}9Vv3"m\16G ƬA֚>2%,YA.=CPdYt1|e65GG_>> +}p)_ia*{ J揯\}| FC! }%,`3||_GP{b{Ϗ!5ozb=>29`>`[ˊzXp-pQ\:=sGTߐW+n>>:|}{X_A> en{/d1end/{cYA}{݃;4.U|0Q*}5}|}|}}4}|}|} \!`K>d(=>3h|GCNŐŐMGC|{b>@9nv3Y=_W>{d>C_@JXA KPz _`Kp} _`ƲCK0iI {79\=FxfvYq]6lB>>l>>}|}5}|4 FC>>B2FCzd21d=gz|f=Qw/zb=>29S5N g#'{W\Wv xf;XqO>aN:> }Ծ21A K(2E7|Hbxlk(=>>>>t}|}f;r֎=5]lBqT'pq}@ˏ>łίŔK2RŔT>W{YlYtً2}=1|9`lʸܑsG hS^{ocyr(j舝Xˏ>X|GG͂BHA$=Dd(=SwC1}$Y(=C YA ec2MS>exf]ū1\7Mwl|>HA>|e_ }%,_`z7bdb{_GE+ؾ9>C'9H-Ƌ=AUsAc;Tˤ+lj` L>>\|G {||_ђ/z|f=R>>t݋! 1}}/`}9S5N6yng[]<8 (1y]nM9Gv_ѳk_B>毯HAb|ebTƯJX2=Pe8>qd/{cYA}{MS>[(qo-FG@0>Dj><|>>z>Q> YAK=>22=Qwl_@|}9qZ-%Q򥫟J/hT]9LZJ}t}H|}|},>D>>hn>@Ka؃ KPzbHPz,_`ɆƳKK]< +"+8wW˓aR>jXgQЉ|)=Sf H_ }$1}1z(21d=f/z؀zb=>29nٝWeꯩ±/i)!lU4NVtzjU]uT.揯1}|};(}ƃ@ 1  APe(=RGb f,MO//_@v#y#tu 2 RzϔYzGCYG +P{b{_G`E+(=}`}NK'Vz ue2˂nxavylX84SӺ!~VNH=9詎5rڰ\d{bQ>2%,YA=Pe(> YA esUU Wf9^fum@_ &uٗ>OC/OC d=C}{C#@6|}3#}L_@FK#FF =Y~,or<1f*9zi\"t}4}|}|}5}|} }>2}i`T>-,=ă&O//_@w4"Yz3umkɰ>pG@>z|d>|Ј})C!z|d=v,,lzT]Os<*9zt-+N\'A>G K>3ؾP2%,A=Ŕ0 ŔƲKKG<&)Pջ: __(@A&u}G@_6_@>K_@|zz|} %6bz|d=P_(=d=f/zl_@|}s<*yJ֏MSXW.+|.毯HA/zWPz (2R|}1eZX _G|e65G_G_>>W5bsg[I6],|"5} 5Fw>z|d>2>>})cN_G@}|}C#@6b= ._`}L_@s<+yzk:<ªcE0@'A`|G| +G=PpeJX27|d=2RŔ! eXOKN<&wh5ͮ 5`|b5@}|1>|T K=>3|Mزd=Qw/>>z|ds< 8X<^F@}%򏯏1|"Gђ$a=@ e_h YA,Ŕ YA e4YO9U _S X| E|LYH=RO)bc/ Y Ytً2}`=>2s<#L.{Tt3QMl|,1|>,H=C8=zWPd(=RGb f,MO//_@W4U4sΩyjڰL>>\|GT||!`K=>> ec}|} tً2}`=>2s<>WO&9I^QSi.],>:>G_ )b7PzbTd(=PA$Y8=Swђ e +ƈ/28|a7>>l}|}PC/Dj>|&,|zY Ytًe/zb=>2s<(:Ǚ+P՛QcE >.p +B }Y A'WPd(=SwC1}$Y(=SwђO//_@&ܝsH^Q"t}B:>"57 zzB2ROǪ%1d21d=f/zl_@`z|ds< m<Šݓ_WC'Q}>NpbπL>A KPzpŔ"YA/>2O//_@ڝs]Pa}@w>D=QglY@CԾ>=>3|d`{_GC`=>2s<<53Lf\œ*晼66Y} +B Fkc{(=z|eJX/{,bP ŔPz|}i|}| (6q6}k9tgQ>N}|} @/ }G뉋1=>3| Y Y _GѐE+ؾs<*vSTbG\ˤLW-+G`|G_ |dc{(=_A,Mp e؍_FHbxlk(=>>>t}|}[_Ӊk9t>vQ2%򆁰>K}|} Rzϔb }/>Cb=>2C#@6b= ._`}=>>Os<0šyl nrNJl5꩚'Im||>>{|>> Mp f,MFHb65G_G_>> +f*wfK#5}|}|}4}|}|}]}B>j>>WzB'Gђ>2T>W{YlYtًe//s<*vG"u,SnQ\:>GиΣq__(2RpeJX2]z,bt1|e&5nSb{/s(jFa5}7_@>h<! |}K>,C/Ŕbtً2}=1|s<C_@ˏ:>ΣS:zO|}/>/z|f>G.ŐŐMC!ꋾW=}`}s<!|b;4Y.|5PRo@_ >L>C_@JXAzt,JX/{,bT!(=ᱬ>=ATCS=-jj`_XO>j>,}4|_A`K=>>dT>P}|C@6b= ._`}=>>Os<*2KPzpŔ(Pz YA e8XQ<ί9BN}>(=RQ_1f=>2||_GC@6b= ._`}=>>Os<>Lp6s=/iqrUM>X!YaD>}@da=@ en{/d1gn2C=ᱬ>=AF\/WKY&ڣԛB53@>X| >>l>>F\}5}|}|} +BTƏ32/>JX1|d20d=f/z}K=>2s<>WDbF$b&ٓc}383ÄCe1 K=D2tbP2%,A꛾2i`T(=1>>t}|}q(rqSa_0Nƃ` +BTί}=RO)bc1|GŐŐMC!ꋾW=}aO s<>WDbF$cS-V_ZO'"U, + K>(=A E+!'F/%aYꛀ YA ek`z{ ;k&FL|q,ίG@>AϏ毯ؾO@cGz|}uGbC >>OF lzT]=1|s<+vĊ,;,᫷%UK~X*h'rs} +B }>2z)`T>&37FHb65GG_>> +hwS_QkFuLV.*|q侾Q,`!p E(=e>|d=SgC|_GX#@6b= ._`}=>>Os<#nv7)Iwya2ns)e`J,H>ƣ> }C! KPzt>pŔ0 ŔPz|}=}6_85G Xg86|>>>l>>n>>/G@=Ř`K=>> f 2|t}سd=Qw/zb=>2s<>LEW;FXVu|xLLTh2s*\n<7W@{=D e_h YA0Md,Ʋ%8ZݖF_G68^(g R!1Σn&4} }|} }u|e@Tj>2Sf,/z}GC#@6b=@_>@s<<ׇN,i1Yx EuWF^aecou[&NcD=PpA,Mp YgJ( e獅ɜe*ھhU֝1Xfѐ\'A&u@cA +=ed=R=>>FMT>P}|nŐŐMC!ꋾW=}`}s<1cdS+373UfcM5 :B..öܓMiQ]+|L.%J`; }%,H>(=}(g χīN3/(i&6Z8ܭg1d|d1f#348]f'v_@}|1>j>Gz|d=QglYA#A@JXC|_GC#@6b= ._`}=>>Os<1ՃEwA⭝Wp>;c:[/Wpwމ_:ܸ_z%|P}Ӂ_:%}p{g0_x N^;Duk-4|}@Sm̧9ŪYo6RkҾL>> E(=>2b>d(=ŐAA{ŘMP>p{b>s<0ћšz̰ˆh>C_@}|a}G_6_B=Qg=>2_T>O!T>7bdb{_G`E+(=}aO s<)SWËU~湥e=\v J揯M:_|a)bc}|}F lzT]z||s<1ÚgnrNJl5\)ig.m]Y>:>>l>>N|zϔzG؍_G_`z}|}F lzT]z||s<+Bq#SxΖ{rUm\7+`4}|}|}5}|}|} /}|}.>F/Kd,z/=CC#@6b=@.YAz||s<>Ljkd{ ZlPÆ"t7>G͇__(:= T@JXK=CC#@6b= ._`}L_@s<1g2(g,ˆ,x_/TTi0K+]g 5!d>_ }%,_`z7bdb{_GE+ؾs<"M5K +-L8T3l}} X,Ai|Ё }1>>t݋! 1}C|{b>/ s<+Μ^ :YUpߖ +Tio,3\=SV}|d=1_ gѐCb=>2cYlYtً2i|eF z||s<*:#֞Ji\U \"t>P{b@Q>>2)bOǪ+=CC#@6b= ._`}L_@s<*tGs[UMM>[V_XO>z>(=>>>PdT>W{ز=Qwl_@|}s<+vxwㅝ=M*ULi+`>N侾Q,C/@JXK=ززd=Rl@`=>2s< =SOS傞'tWJ͇,揯3=>2cs|Ј})`C|_G! 1}C k@`z|ds<0g2ytR,2d)>[+2Q X}|/zu|Y@o!#W>2P}GnŐŐMP>ꋾVP{b>@s<>Σ},>2#s(>d>=>> ً1K=v,,lzT]z||s<#6vv7Ɠ(d*3/)x9awIZw20_ >j3QK=RzK={b{Ϗ!P{btѫOs<>Ljsba李[9e/0dqrGWo\ʙaqR1!毯p{ }/MZ>(2ROǪ+=CC#@6b=@.YA(a-!s<"f6g|Gya.:Yi̅ngcc`Z8QZVU\f&7'Ba}>D=CGX|Ё eCb=>2b=f2SL݆͘Z2r ك1s<1c="YLXh1ͩh<481_z |y<]cG΋GX:|;|cXQQc:ϝ +>J>u GXУ.Gv|УE;nxzG4qıUEml|uD%9eJq 6e>LUx⬮W:ϼU 'g`OpC.z>v _:p<};;:pAꜞ=UqMU\Qys}|]Z-&6'4TGeg7u|]]FDwZ5L|N➦SNN>;ǯLe 7yf8>_,"t_oG@!(ŪL$g1ieFZvq}%CFԧ]6\c-:\lg2db}s<#L -GsE憘M1>/4ґԴFI3) p%򏯏Ф 2i||;3>C7R}Pz9\<%s<>UTSEm >+PY:2s\k3K1 э#\a}w}>{|b>2_K>}>O.AZٜ%ph[s<03Y^=FXras1#NWA5jǙ^rپ۾>|a"4 3i||H}|d:/>>P}G|}>A Jl}a+ >!HvٞOs<>MQLk !fz)ҷZs +fiLU4ηL7G͇аD>>/H}c>>C.>T>t}z>ۏ|Ő{XQx̷ؾs<>UTQ3{z=G +yx1ѷ_-i9nc=Z 21$b>X|Gq|>p }|}5}Q>1}>>C}/z/=>2i=d21}F@sKAMXlqmUE~gvsoF8צkm+x3+S21hXM@|>;@ˏ>Rz!򏯏6|}_G|}>C}Xd=C}aN|,F/z|}ЉՎϻOfk;zcǙ2đLh>>>la5}7f4|}4}|} >Gٝ_ٟ! }z>|}G{b{Ϗ>_`}G%g;9\}|Lh8(_._FF/G}G.A 2i|eF hzՈ>;9} D>>Gd>>> 2p}_@}_ }G}GnA,}2#}|d=>1G;9`,>Lh>A"5MGЙ|| 2|cGz|}|}}b@}C7/ }=C},Y@2i|}#z|d;9}&G}>Af>Sw#>2 }|d>d=C}aE(=d>#d>21}_P;9__( 3hb>6|e#PC\# K>}|e}@#d>||z|d;9` >ƃ(||ϏK= G@! }=C}aN|,F/}21}_T;9` a}@Ɂ}@c@ \}>>{|b>2_ _Gѐ||_Gb>!P{(21}F@C||z|d<ή? >} Xw}5}|}|}%򏯏}/|}}a>>C}|d>Ё _}>ز `}|d=Sg@<Ǝ?&u}4}|}|} }|} \ѐE+i|ei|d=1_F/|>>Q>}b _@ѐdb>2O>BsW} G@>j>C_@}򏯏N>>}C =}`>P}G|}>A X l_@C5 ^Gа|G|!}|}4}|}|}FC/}WϏ>2_pă|z>O(=d=}d>F/!;91} G@j>>P1'WP|}|}>CM@z/>>.A,l_@ѐK  ;9p%򏯏E@`5|G__(>Cbt|јMw|ѐ}|d>pؾ 1|GE(=d21}F@1  ;9]A\M_@__7_@}|B}4}|7P|}_o@@!b> _}>زѐK(21C;9毯>A&4w}}0}}!_G}|d>Ё _}>;ز2a _@C;9毯|} a}@__7i|}!e|}>}|d>2i@z_}>|Ő}2#}|d=>1;91:} a}@ѐQwza }>oG@#|KP)>b>>>}|ŐMG} _@C>>=>2;9揯G@__7_@#Q|#C_@__7_B}3L=R>t}z/>G@6|}_d>  ;9` i,} \2 +OH}}|d=R{`>P}G|}>wlY _@ѐdb>2O;9>E\}|a|>` R}Y_}|d>2i/}P}@Cز 21}_O@@;9p a}B,HAd>ӽ}#8>2C72{}Qwzbdb>_`}|d=>1;9`.>/}|}FACq_GwC]# LjЁK>>>}h,F/z|}>O;9`,>\>i>毯2||_@}C}=}G_G}G 2i|eF z|b=>2;9\ɝ__d>g}|l}z>}_ }=P}G|}>wteF/}!|= ͞ˀX}|X>Ld>1C>G T}X _}>7|Ő}Tً(=!|;9} Gd|>`_XO|}ϕ}|d>2il_G`1|G`>]@#d> @= ͞&} \}|/.X}z|b>2_ _G}_Gb>>>}h,F/z؀!;9`,>՟W__(cFcn}>}zC7/ }=C}aC=Ŕ `}|d=C ;9毯}4}|}|},>D>>X|G|FahT>>>>G !Hl_B=pz/=>2hKPdb>F/!|;93}|},>Lh>|}>Q}`]|_@{b>}>}ز Pdb  ;9G@>K_@ ѐE+b5@'GC>5|}}B=R=}FCF=Sg}aD/@6|}_d>F/!;9\:>}|}i| # Hl_G.A>6b>>>}h,F/}21}_O@@6滼>|q"52i||va`AK= G@!._A _z|d>wlY _@ѐK(21C;9p%򏯏Lh>|8>‡#>2>>@# #WCЍ>b>>},Y@2i|}#z|d;9XOC711A`}=}hNb>!=} #G=}_O@@;9揯3D>:>!>V#>zC = _}>|ŐMG}Ώdb>2= ͞ \ˏ>X|t}4|G!.}|||f>>K!ϏG}|d>,@z>!lY _@ѐ/!>>=>2;9p4}|}|} N| } /}|} +B!>>>GؗG_b>2_ }=C}aM >>2i|eF z|b=>2;9},>G_6_@}|@}|2 +>3n|}{|b>2_ }HAd=C}aE(=d21}F@/_O@@;9>>vQLj>/}|}f>G|cFp}Ϗ}GL=}`>Tً>}b _@ѐdb>2O;9q>Σ`10s=>2>}!=R{b>}>}ز `}|d=>1;9>>NDj>>_a>b>2_K>X}aM 2i|}#z|d;9,侾P>p!HAd>>/}K= G@ /}P}@C7|,F/}!;93>Ei|ex!.C}/z|G`>NA 2a _@C;9p5}|}|}!|} Lh>WФ 2||}!Mt}z>:>>C=d=|}_d> @>O;9a}@>L>؍//>>>G|Lh>! }=C}aE(=Ŕ Pdb  ;9侾Q|>>X|G__(FAz|||d>>>>G_b>2 h21}`>P}@C|Ő}\o{b>2O4:ǟ|,` |>(|b=>#(>}|d>2c|K>b>>>}h,F/}!;9侾Q&4q"t}&})= _(=p_`>}C#Ё _}>|KPdb>_A>2;9>A,1XgQјK_ |}|d>pb>6b>>>}h|Ől_@ѐdb>2 ;9Óf!3l>>>}FC %}|d2R}@b>!,Y@2a _@C>>=>2;9p G}5}|}|} GGѐ||_>>};+>@{b>b>>>}h,F/}Ϗdb>2 5 ^f4@ˏ>L>hgWФ 2 +O2a>Cdb>b>>>}p_`db>_`}|d=>1<ή?>\|GG͇Й||>8>_(=q>|}d>{|b>2_ _GѐK=C}aE(=d21}F@>>z|b=>26滼>|A}>QϏ1!a=1_@{b>X}@#d> @z|d;9/}&4XѐPz|G>wzC7a _z|d>wteF/}!;932>Dj>0}>>_GѐM>.A 2a _@C4ן__(F揯侾Q8>P1QA`}X _}>ز Pdb  ;93pو _6_@>_(`HQvg|_ =}@b>>>}h{bdb>_A>2 ;9揯侾P||>!b>2_{b }=C}aM 2`}|d=>1;9揯p4}|}|} @>C_B>\|G|)>(=>2>>>=1_T2ؾ}@b>>>}h|Ő}2#}|d=Sg@;9X|>|>p 2 +PFp}>>!.1AA,@z/>G,Y@>>2a _@C5E7;FM- MTZM<}# jcOqK>FXSgܨVk;zQ6=6N 8錔=!b2ŧDOtatc9D٢c6&҉x91z_l_B>1|G`>]@#d>l|A͙HтI XgQqljfQdŒlﱀ"5} +k97>m }~:h2ҕ>: tIUNⵎJF;9侾Q.}FA|b=>#(>2bu|_T>W,z/>GP{b{Ϗ>_`}|d=>1Ub +1&#+(ƌu2:1Ʌ+e:F#ί@}G>%e66[t +9%ZS$\ES=Zgr 6滼>||>>|q&u>! >}# M{b>b>!@#d> @z|d1|}|fŒu]cF:0g(S&cd5>Σp_XO,Zj'Icf }it5g,\W~J'X;9p,>L><N|Gc>}}|d>2i2c_}>@#d=q>z|b=>2eS6cc< I*}8%ʋ`4ןW>G_ !O`>2c>>CCGK>}b>>>}h|Ő}2#}|d=C OS6xŊ1`1fQu3aGG1>Ndm^wۊUu4zrQl;9p,>L>Σn}>1=>2>}||>!ؾod=P}G|}>wteF/}!| u|_*Wd1Ⲍ(S(c|&|lZM8S,ܱoK=(VY;9}4}|}\c侾Q}>Q}}>}_K>}4b>>.A 2P{|C>>=>2d>> U3aF:ɈNjvQg uc +1'<|>>,n|s_gpksdžev ;9`!揯3:(|b=Ci`>}|d>2bwK>l}G|}>wteF/}!c1K6c옌x10g(S&x|+}& p G@}&StY 1Tk sb>;9>A|>>>l>>n>>}nz|d(|b=>#(>>>=1_F/G}}G|}>wlY _@ѐK(21C[(|})fŒu]NjvQeuhS&cOy}y}ݔ5qa9p;9ƣ>&u} Dh>Afz||(:X}}C7/ }=Qf >>}h|Ő}F/!>>=>2d>> U3aF:ɈNjvQguhɀ,([(y@} X.4rNCg {b= ͞ G XcAG͇> h}|d>}`vg|_cPؾz _z|d>w{(=d>||z|d1|}| +1hɈNjvQdcij8F:0 y#6nc84g8kc;`;9p G>j:>!'{cp}a>>C}|d>Ё||aG`>],Y@2i|eF z|b=>2d>> U3aF9dcŻ(ƌuFF毯|}FC|G}>}_}|dGn= 1|G`>TFH=1d21}F@>>zϏ>O:F#1TͅcF9dc|GGO#(yi>j1ybxNE^= ͞ ;\ 2 +|cp|}؝o@C!ؾ]eG}G.A 2i|}#z|d1|}| +1vLF<[h[(ccF:0l\#>zuK7QDն5 ^GW>#>!>>2}# Ht}|>>P}G|}>A,}>z|b=>2d>> U3aF:ɈNjvQe uٔ|LQ2b1_F/ />j!lY _@ѐK  O,Qb1ݔcF:0,>Q㍓e/}>\|l>!<, +{5yh31f;9`&G} /}|}5}|}|}GB|)>n{|ѐ]b@# Hl_Gѐ _}FC7|,F/}21}_O@@lYWdcŻ(ƌuF`4>C}|d> = 7|G`>>P{b{Ϗ>_A>2O:F#1Tͅ'aF:VQljfql l0>>Σ侾Q,c¦:Pe2>>;9X# d>>>>|wze|}GHt}z>!lY _@ѐdb>2['b +1vLF<[h;0,>QL(,([|1 @:xuDrNQѫm;9揯` 5__(>7a|>&u}FC/}1_ +=d>}G`>ز2a _@C['b +1vLFl>.3\}q鎞dZh \؀;9} B,HAdGb>}|d>2i2>}5lY _@ѐK(21C['b +1vLFQG͈X} {Z꫒4Tּ,]Ų;9n7>"t}GWqy}b=>25}||@(|b=CicG|}C>}|db!ѐM}Gntel>}21}_O@@lYWdxeъY0,1LюY>QGo毯3~Ʒv[A#G0_ F zX _}>ز `}|d=>1 u|_)fŒrɈNjvQdcij8F6L95G b<ᛲ+b4k[!;9p,>\d=1b>|}>ٟ}|dT>l_GѐC}a >wl_@l>} _@C['bl(,xeюq\j>QL(k_c>kWL<{K[-q%e;9侾P/}|} G_6l ;C #zC = }7@#d> @z|d1|}|fŒu]cF*Fl0+eGxd>de7 ᛾8aÌb5ɰ5 ^G)>_(z_G|}>C}=}F@ _z|d>wlY _@ѐK  O,Qb1ݔcF:0g(S&x{'G6lh.F%٥ϊ);9p }|}%򏯏)>}x@}>>}!D=P}G|}>:>@6b>2i|}#M| uGb +1vO+(Œu2:1Ʌq_cL>>j,6&CEusۑcK E;9`!!A`/>2_ _B$}G/>GP{bdb>_A>2O:>LQb1ݔcF:Fldȣ! *γ 8Rˆnl=;9揯p }|}.>NGa}>(>>]UZ>>2i@z/>j>7|Őd=D/!cb>>LQb1Ⲍh[8ccF:0 x`<n>> [3fNvgu0SS.q<:p!Bz;9|>>AgWи"4 3 +.XO2a>= G@qz{F@؝_}aE(=d21}F@o|}#z|d1|}|fŒu]cF:F%1ɅdGWxd:侔}|} 8R> V4r8io-0H"rM;9}4}|}a5}7_@ˏ>L>>јQG}e۾>=1n}|d21}`>P}G|}>wlY _@ѐ/!|(< U3aF:cŻ(Œu2:1Ʌ'{ x115d13S1 ˘[FS|𥉉K=Ks1 +`;93B:>Σp>Af>>O6|e}1_؝=}`>Tً>}زub>2i|}#>O}a +Yʎ`1ݔcF:0g(S&cOy#gVl@}p2XL;ǝ'SuBZEtz +(ҘfM;9;Gˏ:}@cA|&u} Gѐňj>>}i|}|d>ЁC}aM,l_@ѐ{_G_T^ 5em\ +f#),#уo %a`‘,([|&4d}*2}d^>5RFsNސs٪Hn%7%F_Y9jZ9$;9`&5|A}@>\}>2>>G _G4}|}ؾ}G۾>}G.A,}2#}|d=C M@| +*GX޾maOpY|`|c_8'Pz-M>oYp)l>4ןBXɑ}@>h>h>_(>}a>= G@7|d=}F@1|G`>w|Őd>  ;9`%򏯏p i>l2hb>֚(>>d>CX}|}ؾ}@}G|}>wlY _@ѐ{_G_O@@= ͞ }'p}|} R}>Q}}i|}|d>d>},Y@2a _@C;9P%򏯏pf>>O՟`>}= PA}T1|GE(=d21}F@/_O@@;9\__7_@__7_@gQ,>"5  }}@}>!P{(21}F@>>zϏ>O4ןG͂>>l>>G͇d>Sw#>2>>}{|b>2_ }=C}aE(=d21}F@/_O@@;9>} >||G>E}=L`>C =}@b>! K(=f/ Pdb  endstream endobj 13389 0 obj <>stream +Adobed + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +  + + +  +    + + + + + + + + + + + + + + + + + + +  + + +  +    + + + + + + + + + + + + + + + + + + +  + + +  +   )<  +   +  +W!1AQ "aq2#BR$3b +r%4CDSTs&5Ecet'(U)*6789:FGHIJVWXYZdfghijuvwxyz  g!1AQ"aq2#BRbr$34CScs%T5Dd&Ete '6Uu +()*789:FGHIJVWXYZfghijvwxyz?G A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `пG A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `ѿG A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `ҿG A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `ӿG A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `ԿG A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `տG A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `ֿG A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `׿G A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `пG A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `ѿG A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `ҿG A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `ӿG A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `ԿG A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `տG A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `ֿG A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `׿G A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `0A A A `б1PO2{l1:>,##"RocPO2{l:>'-/sj)!N_OC]<;6?OzoG# Y0[Y?c6?rK?K?#tMV?Y0{Y{~uJ}/cMj_}KVG?OC<~u}/cM_}%[?Cͯf_X S}iSOZ?1(~uJ}/`&?##g>?V?`_g:Cm[0a[c6?_2KjoG@VaOD&//9XCOD<OX T??ڥGY0.?s')T< a;cPOwxْ~uJ}/cz7:"YGS?oU(>wN? +6D];_gT<BUD];~uJ}/cNj_?t˳'W}9Wc>ty'+:rox1osَ8P|cz8섕t=YI Y0ǟo2zl:>'/쎃hjC?1C}<:l̟%??ɿ#}5g{v?ъ?qRCEg.~duJ?`'.M#z6wG-Olɿ!0KW) Y0g_̟d?qRɵaTAӲٓݱTcM\=e`a4TIӻٓݱ_gJ̠ }:vgLgT8CK }POv1{l~N,?&EGWF?+c~v}?`'//QVKT'ҍl[(>'5!_WEdaA>Z.c~wI?`'U?YU+< t}6?OoG蚮x5g:{\~v}?`'5Һ&'cT+.l?sRJjܚ nc?;e>oGWU_oaT-?lz/⃺|<t???}Pk16cl;e>'5.M䢭kٯ0ϳS9ro=G~1{lҟOoGΦ87d~'[6OlOG!_coG?o>` t??ɿ#:3l(3wJ}?cN*\?:+??s'7'd?ɝOoA(?~wJ}?cN*\??` S8rog#T!,Olꞌ*s)9'dz⿬([~v}?cN*\?_䢭ɯ?3cvJ}?`'.M 蒰_oaPOd?qR_01{lOoGtIW<aPO1{lO&#kPOg1{l?;e>oG螬85gS?` S8'd=Y[cPOُ?c)T7d{:&`? ?˳)9'dt'ʓ{~0?)8roV[A(c.d?qR${Y0o2{l:>&.M䂰u_1({?:>'U쎑hFuSaB=^.d?;%>UWz!lz?-cv}?cN*\9Da?B<S8ro^Y#?td+??ҟO*G#ތl ?d ?Z|t5qRO#*T~A=?;>&.Mc::{Gw3)T=эQ[쏕T1ElgT7du |x6dW)x7dv]m8~? t?˳SqR:$ Y0s'l~vJ}?cz9쎤=XVO }'>T/f/` l?sROsjF5gw[(>'.MtOVEO?OB]=~v}?cNj_SV<aPO#1{??OoGչ5g↺x=̟ΩOlɽOoGG$g?GC=<+1{l?;%>z&tOWOzy_gS7roWET>t{Ol?KoG"7'p('qgԹ7d~?Go?SPGO,|??/_oa_t焟?sRO_oGʿ gN*_֦POG1{l;>&__T1{lҟO&aUB=6b?;>'/辪x7d>O~bv}?`'.Mʰ`%c?;e>&1хQ[>vc?;e>'5.MâcT-.l??Ã_~s/f?` ŒѵHo#5?dx~uJ}/`&/a;cT5ӹ/_Ol~G5!_螇+J-Y0Of.` l?sRO_Dt nnc?;e>o@:$` ~~c?;e>'ui\aC=<O` d?wQO?g?1(k.dvJ}/cz;t+Z^G |ꇺxOws/P`OoG)Z1!f_X S}uQBq[0#̟ޱR}DdGAmf?cꇺwls'KW(>&I+Rb (/ns?cOuQOoeY~*_aSPN̜RK?Dd9Bu:+0.d?:>'UF dPOo Gly](>'Uե͔/Gҿ =_S:'dxꪵ#T%;|lgNjG#tQV"k>POH/f/` bC8ro#̀o1:wOw'S}uQOp7Еqpcٿꅺzt\;6?lK?!%* _>{6?ҟO?K?#Uy5)cv}?`'.MUV<^{v +{2{??C+oROTcͲMq?яT[ӡ̟ޱJl~?G?!Į7  ~:tOw'W}sRO?{xٗݰ~t/`ԏoG΂'1 [?E]:~t/cz8]םK }N8T|c:7K?Eӿc~uJ}/cM_Ǣ +5g*Txݱ_gtoR? +JN!;0:vGw/+ڦ87dyЭme;0Ǜ_t ;~X }sROY,<ctm[KX?='C2!wocTQӨ.̿ޱΙ_l~G?#4 ys/`_gtsQ<*/u1(^yyL?Dd{'zP,?c?t10S9:ᓥv?؛s/`_gԿ<Bհ1uܣ OX Œ}9'dp+ +7 Cُݱ8P|cz;tGWH Y0ǧ?ϳ'9OEQ#PGO癏?c';'dy +_o@ц/<W݊F*OQ:}1+~#p[C,y<̦=8q_T{*#,۔ 5O?vD'w⦑p9?IgahĀqIG' `cHҩ/ ,`\1 ~&xQIrXN=@t[ m[@ǘL$&H:~oXJ{3,F?cDŽzX-DqMM(F2!tq mmTxɏ6?ԮVDA뤩  ? Nr~F ?2JVCUq(鄷)Z x>q횇[ˆ汄H'|_"?Q/E*%WER + #t5˕T ~V{jm&Ӝ]HG`\| +M8QT&vl.O?Ts&(oMD nhG +@ۇ>٩97yc[*9@=Pp wҁn +=_=Ok[,Քkߏ,sB"2AJIlO| y +HhRlz#!q!M۞%)>j2,r U-=#sѭ/G̩ 8#Cq8f>(rI~?#mx-Tg%$zcA#?#Ћk )kZHUw<<ӷ1*6QSn?+mh52zuΞD\~-޲Ь8Pɪoy<`@6?zcӪ"=ȏ¡Cv;Qhu^-ncI'`ްG/\B#a ydX.O[Z=<}~ +#Gj;&> >dE!׌~ -ێι5̇ǗԈ +#ڝOQri> Ono@uN0sO7HwG&<& QN2"7cH~m z2G볊%]0^?DqI 6~.IWǸl#BHկ>YB ʪ״~//ᥭ7¦l?㛫"?`PwG˵mVvxLai6Sq-):G_ IH5 Rw m荘nOuѰ8aMϓ0 +c*Oóh?jS78jW:sGXXw<#* `v\؈ +-[ :XUtܝbxG<%W[< {z~}1eEȏLv;I6GQ68jHBBp՜$~1JT]=hkĸe#:5P(\ KhhU1UaE=.!>O?T~* ฏDVF~c2HϬIaLkXIXrLZU7a9f)[`XP€㥏?}?:*e\y^oB<6Ed|oꎏ04,HW?Q#pIz!*LJT(C9R9oqk@c\v"@k46"Цp SOPǚMiG c>zDr +)CT0{(}F?}|00}18QGdIo_kWn׸ $I`a:9 v +6WA=qp15|G12tЊd xHvn% +y;}֏|c#]GϻH@M=XaC`oC?gK:슓.l aY(>*ye ]#͏ oWuoM5^ޘ'{y{#\6ׁyW(P@e9٣k#V.Ab]b +?yu< zUeB9gz?rTGdIvi1NuCc*بzW8EJui >k{ ~Rd>oL9I1YPÏn1j(8FOBn@G.X‹xqWsY|;*܍f<Ӈ-ƾЇ0:-o|[JÄǠ s2#U:BU;A~]eGql9Z?M6@P"xGea'TvW}*o|sn?\zICJFtQwqxj5tnv@l8H8wс;>iGȃ)A@ ǧìer)1dly+&$5ƾpE^ԥ87xGHG*F>GLA78^RG1zr9sLe/ (' %@\[ ,Gďɦɽ0+ i1+r#}.}& ~/ndF9z#F/cml~F&>ܾpVĈ28DrXM~{c@1 '[\~UѕΥG#q嫒ǰ¨Rd~?8W=@ i +zc +WG5sOA.k#P°ն'iN>Ts>SJ;Xqq+L0 (H8}Q*l!MI$ cTtIz?90{٥.XP}̝.n!"׷0V'7,E4NmmF2鲝7aƤǒ,FRd|)^G +'i +,?97T6=9e*pɾTLz~J~Y#/<GN~cpG\G}%4NK.4^:_Wu6Kf׾&I@ycXmԷr5Uv%@ FzW# >v(%4I<\Gr>ށ*2-J8[I?#xljc&U7 ԕL{Z1͏-Z}q®ݽYP=c1E\sl~k\(~ xD?<]Zcr?*08Bz4G缺ǡÏGVVʏ3|~.K1ql~>kwӠ(7#7I?L >vy3dO}Fm@c6 +:? c$z5e}ێӇty[a;zV[e>#4+oI=ÙF: {qEZ"O^L\16NI'q0~'dix'(?Q\n~KJQkK5Pߨt~ꍂn9ߺ˕t݂[ c0иP;%WRL/߇pi;[{!]t}#/8;E!6r t˗UG8#K78M @øN~$;clx'704H>xL'*+1B+*YR~.ZTxuvu`v֛{4W-@X7㊒r tvZӅ}~[ + B:qhxBGMsr1k- #XBGxbY:m#_P a1CiSk<۩Yo)7JoMm}.2O㩪\'#M0кXJJE%6颒}?yy F=K`hm)p\!d}U~OeK@;j>Ch=&]&/=Soըz sa $.R _gnG‹Mue|B^P((̥ $qB aHe}>:@LW&Oxh㼁?dʰl]H<Fqt61e(\`+L~LU w8\[i;''rWҚh-o'?K$%%tXUO`ҽcs4evcROpjqfZ~0@OxGf2I~8+OSMR{za e |>T$$ fwu>:QQVXaͶ}'1>0$$IZH>JqBi*CT=K͑|knz@ jY;KMZ0:*4E ؋ܩ#O\}5M{Ga)5 񎧪 l7 )?}#$|KRH?#O>!7J4I/5Cs͵a.``GVD"қY$ `4(<5-B#%|o-Rzt1e~ dh,sek5ѓ*H7c ˎQRxDqtOA1N!9w|VS̴JGŸGQs26ӋV AXȻeqԅ^v\pc7%('!Pt} ت4V<OVH#P#<' qGair-Q[7-Lkߦ*[X{]CE?p S67cbQ\&'jNU +ljoSb'G&̫c?"M!@_'$ 6sbtl t3r\R!B8g1J$0IU뭂 +Iűo8۳`w+#*kH*ZNkv,kG魻8dR8:Y>+zJf +cg7w>VHLjJPHBocXVQ;n9S=Mhin}jRLuiTuOQCxgT>ʣDvkXZ.e7MqSݱŠk:w%_|q| O:uTbڹK]SEx-}Axi0})Tp H3oٌSH>e$'ѣnY5>_ )+r+syH$ض}8ga$1TjTwu +UzFUB((_gBXRx\相 z͍eQ GXoU.A[U;oq,miWڰԺŐ> PmCʕ"mb^(|Żv5Z?t8˦Zz[ΗYo^(62齻{%IPROݤ[GmvI߉;D~Ln˻欛Hx/"? ZЀGs;oڿ6&b}= +ܑlpfoO?Irh,J. Ч~,<- [w';T G9 nr$Zg%c{XU}KI6 sj7(ܨo1W$65@}ƣa?KœJ=r>ٔHO;鎫8 4) +71 Soo~ȏܠ'*# tOӁq8iBā/AoI.eE)8#];Hq Z+ē#ri zIa5ޒQF@q|?ӃLO +1?x}&Z D~O6>P#g{O*z]V;2ǀݏ_ΙyG欘?I?*e:ߘJ `JI6<[xK8!:÷Mtd['G?d~p=g +z\`g'_c Et8ToΧrD'/ I(Qb[ZZBA43=N} _ijY##XfM2DZ_i@{%/ai+d~'3گ28Gʓpxx?~;Y)?tP=jar_g^,Pځ>-a7*8#0~O0{5KR{ґ:ӑ<cmfYЏt{ +, 1̎+] @?<}c5G<[O1H8fX?RǿõSNG?wqBtIWyuXXתST~J6̀\ҫq}O dP_1"JԣD :}$irAx(0E B_[6yL 7>@ tLbYqw>#JuqV>],bK[$vt쇖G pq,_t~mHPݏl=災G@cѮ1PRPY>Ǒ/[|Iq?VGn]~#:QI~tHYP>!GޓxP Z5?dt|O/^={M0> *my_?ק[$) UIzY#ӯ+ )ˊ.cNL )Dk=ZH)'GI}^UY}x`;gs֨PIQ[&gԫɫp#0A\NzDߩ1u]|]1nzQ<&9ݮi]m>w\S37IC_َvk>To @O8WruR %G׽?<^HKyfEr8 2[$wW|z&f?rI g#jxڭ-Gq\EG^?ԋG/qVe [^HW+/?yTG[`vQ8-dH]rxWY*W[Pݦ%LXwZ򋮦tG~T{[k#,:~{u*_؄B%t30Ђ;F۪ ߴr/I;OB;Ƙ\{0ױ +OS63*YA&ܣc l~VcLWogco5m?Pr1pSca^KQkg:kVu7`<+ ,Uy<Ǡz>K`~ƺ[ +z2}H\k~8%U6JGʫP[(uVKN4}?>1;۞R +=CUP#xWV}Ю/,*TG.ҮRGw Ux6mӆ;gA@tc? B"֏9i + ?iq5N .z ug)n9Yt6:j %?qҏVۦbVw/SxIMbnJSZ][9|*6ae[zM⌶鹉iDgJ m=? Ȱ>* +Iwpe@[CܨN_}cpBʿPc1 f? µ$ nR +eb*èl=Q)C*<Ǫeu}֥6 +$G ΟlG<Ş`:.=O>M&|B~y/ӭo'w6J/إD[>cmM>k폼Gxʎ9Gmjv$ pRncHdR&;?:h *}8S4O vn#FZn9s?bs*Aǣބ,{.8 +>wZʭ\O!"uR#Z>ß(#ӹqxLdJQKnFBz/uEAMY )>: +h/(6м>{Dx̌mjSDz-zv:)872 *<|cI]#*{VHT=ӇB!OXU>Okq)A#E0'HZ>a)Nn{o >8 v浈ʫoּtLP[N-l׾px~A?~S} m A8VniTx EWޣ8ڛ7wh}=i? w~jWNeu0[cDx[NjYqM!:[}1*R'<وQ*BuҪ6\xĴl>\[NJ'յ['P;ڎb +UvfY1UNqb!%*1djIewI=iIvSGK +}jy[7Q-~V11=9:u}R*[TYG]n571_gUkGX_lBW\rs- ~EЃoUBEgE1Z+)ҝ%?hGcX~kPn~1?>LUZ `ҝ䟴#:B~¿#UӮFL~&?Z#Pid9 +#}Br]v6>dy~8%87b?CiK> +[IK#G9 [* x50hx{ WGW,J3j1Heb^߆?_+u?&?2|RS',CadT3%DWX#c{*.gdW|=$ez,}M`8xٝ3#%[[3*uh(M5{ۖm.>XT'ڱa$ +z9< kSC)U#k?W4YTfCАrt{9YTYdr Iy?#26@bi2Z%Rmrڌcj]yX~0˟RHnoc!zw^h] xBY{M wIa+E* R#%\Jh~Qmv?ӏhW W)S̏y˕[H(>{_;Hcx.ֵHџL3MJUǔ78M1^;Y?!Pa1OfH{7z9{`6X}ZpT+s̙=mTg9qg9p/53Gs}@b oCjbʛSLтH9]\&=4bmzP#i³N!lT1GIތ9=e)<+Aq1cD5mF@<{JpT;,E(,Zp<.SX'zy-y=A͟J/қXwOe)LWs.l7x䬼 #B_HsV(f܋bHhj<ë9%+\L1z0ɀ=@on|}c cS_UUuFƴaLs Ej+:&Ơ5~y?l~NswUF}JmOOQ2D+=>u~?lc s2螠2 w1:Tl]s򊮣L{'=/#1<?LXDԟ>y5?l{ %-O4Q5QrDӧk t?Տ=tWj+DqIt9?3c _(LC?D{imp۸ ȑ’ecy>N#Jajk򃫁Z9~Ao$]eG{c|tzP#VXjB+8_kn : JJ}7& +'S9?a?) K$Z=kaOXB9aܟ ?0X9GN؉Khȴ,ZGmV?NXB{8b eOR- }X;H#tFֹON8 g~)0읽h#QZZ#*V<頏̹(8piգl+r)K^RfO-y7tqo~68gގw:j72Qc΃{R?] |)X?<)qs?(òi_)5@bzpv>Ӫz=ԟKXxOI#Tޏ9qQkƙSfN<׌'OFҿ/tNR3Ԍ /#j~0'gO)#%V|W PވӽO:yGBN?cTGOdջc֯=@6?g4kWqH J~nI=j`?&.'ד r#ќ!ޯǗKO1<O8|:+Ӫ;Du[qcQW𾤧TeF=c_yN[re y?{$BlԔv=WӖ&J>y-Z1D?9@?#JaB_P X?yL J~1F~J ?4=ȏ%d[J F䢯⪂U #4 Kj}q13+R~Ւ?Q̩6Ȝ)V+>?:<$8}_ù4 5#$#vTXs]OF:?7G)Q4WPN11 ӮsJ.' +$}-}zg*4GljSg>яi?7 tXm7v@~\y?"G܎r͸= 6J mn>x8+O6mts( 6NXJBJt$)bIN8\*RJb [_9K} ӈIS㴿>\ۏnhؚ{4(VgӬзqCHe Cd|'0.B)6ԩ{w))%1P8)1_WQ );wQu]}3JiBIol~W<Σ%~1o?dA1'VT̺#&<Kca5L}f?]ZG<79p\7yY )!W$%9Dwچb;[ʅB䅎ѿ~6 +W9H B RM>\W<~n#5,o#*QyHYI=F<+wRH6{Gtm#JAk㽷JŁ r3e@1> e6zc88 Lc8~B)q|~1 ]H?=r1R@#g_W8(ʗϬǟg]"5қWv~ |8z rfg`~6ہ(s#96J}D!W*H?+)BC(ž|2>Šx-CD|Nm" JL~Rcz4:熛u#maX2ٿSt}ǚBH5$|{{w #FN5kNLxtlcm 8^e?9ǐGO ڣV?6nt}#VZe)I 6/d֦SyJ9K z}CC*HJeW'0TğN2›H)sªm_~%.6B>#4PrֱRl_Oq϶?dG Ƴ R4Ϛz7QY>1Κkm_~" a?0 Ty\9VWZR`HV&A>ڿT#GO +tSmdwTx 0tڷu϶9Ng}{Mf|z@ލHH?͎sV5϶;|czXm7056sFݿO?&sؐg#'EtUJrTƚrec6?x*0\jc-|}B; 4|Ạu+$##ˍ/N[s_GЎU#mNP!,Ug]|}k&^A@zY#OW]SwJ/̓t#!~m{/֯d䫭9O=?cH%#q5ΙaI +㊉$F+u^PXH[i@<7RǥQAP|ۯ-ϼ4VͶ|ӏ32J>(=VkECptf.s}j+cS)\B|ΝSs oՏW}ͻ]G$}N?)aWO)M̅EJS0Ep(-PkE ֝)B'.8z8jh=(\ iye%uA&jbJnvy7-BO2=b"Yz*w.zMLf m6;O@Ez?GBy%BU\Z]ml]; oq?ӎ5H5ȿ?jGg +TW/s֣Tu +n99X7>wos|  +r?X2_W @=b{)B}ȍM,*q"z5!0ʿS J͌pwVKZ[aytUG2=qD=5N刂4V;>c/9z) W){t͔9XEcH/8Szu9{}6"8K_?LsBy\tgUNkyJ֭QI!rBw3 QOd9JIPS#'A'P~wiy + +诣v@r2ϡ\3Ą;=a5TgB~~OE \>`֬?xo5tzE-?dtpB=*~:6Q5 KQij:Ý_uGa2u}BdtfڇE'_*$䀿FjqgqMبvF? ~Һ_EuQ}X)zÛH)4"^h?}=ʚviar[/ޑD#Q'R32V\0l)B}_ y ٶWn֐;8uܓl=QpHwϏeQhCg_rSkŠ" =ٱݩ15ٷy DHw1&c򮈰*rܽJ2wH85F$ܾ"od0g''\*G,mg7ej?kP_cj[hJB~38(ڏc_h=|-}^¡8=Yf<]Ԛi;GV;tg.WcG/Ў y]Ѿ1jr#XV_Ջ01CAQLĕ}>qr ұ(QsB:[ |֢~h#ʲ1Y ?(Um0>_zzddԘ^o RhTk~MNKkb%l&?K@THᖹ/8*F_τGz;6 50?R9֬=ݏ|x%=ggG&Cl jd%Εbxh@?vsl߬z +!}ic)&# Oz ?#Y#Yt~#9ŸZCB6y/Jj_SqMTX!N&`Q*~؄Ц®Rgyu=[2\P+ǩr8?yNtCFm65yտڏqOz[/F<6NӍ}ǙM infXՕ~>~)omcpķ }G?GYZ9Ф5A~m?^>P)"q0 0X=vh]t$g?rVjc{SoE+ JkГY&JL9(ʬ1Jo>|u\~L_Vly7*?~1Zhޮ}G +z_/k+U?c*?h +ԦK+Ҵ~1Fn?Y=+яJ ZT\XsH.)79-ǑI'Ǩ͟DԏUGNsdc14Y$4?_//,Ds/:|K9ђto'"&+1}[=<*ʭ'OgY'{yͷ\?ݏ3hr8{,&<U';a6YzJ9~CGj!]0O(H>݇q2{=Q_la%yuC.cTQ?ϏD#GR jIc?ig~zy[Iv1k)\$Mn=|»!?t~jnqa>S0|,EAqZE@@+uu+ocUHLxcwZ +t?yޜLA>cVEy;YpRiGfkz85摧0#;)C'O`Fwz4Vv֒طh>?)h~x +V }Uf ?Twiӭh.<1ì{2?S+6/볜~zOoXǡfc?ի0n *Q=nBeZ"G61풎6m~YK7e0}E-Wi~n1P1?ޏ?L|y#fSm>}#?Wy1Gˏі+&?ORNl}зPIy]m8J#[k# +ۏ1ц@j54݁B[mb?No`z~RCq_F-*.v>Ѩ" [1S)GgIME;93Vgڋtt} }~䮌0>|-v?r1cQ|>c-K#:='sUd>?~EGO}|~ңLc3>6=Ük (~|N?~CG1Rc,zG`ycY׋ǚ)|E=gֿ_ #S(u*܋ )E~RNZ +H ̴@bg}֍SqhQyl_s5ܾ6B'N6G6A5NjJe +nbF@cڍV2:̑D9QBݔR|]t.fsc-]?͎Ƙ>?{2S&IVSg ayy8z>5,f=BSTZ?FJpiuL2qLA=;oրڋ)~L?mFg%a20~^#8TFX)r"ZIji2G Hy.iR]׏<~8ToSN9}vvK[՞=j}ob.ޞJLuGöGac-[ۏQjkmQU(eJ2|!4Bd꫕B.߀y1_i a@@v9Fѥ2+&^#-5D&>?+T8t?F~"a?}H+a?3GÕJoQبI5W&N~6"Wֿ@I&s߳1gUZݎ53׽&N\z~P9ɨF?&&^z<*c%RU[_[ FEE~SR;5?Kޤv?V^OSE^stN1JK^1h&]c|8F +pkU6~OjMPJ=*cD?\#Z{tpmï>ګU*(_2(%.ReOGj!Uy; D}14ɣ?e4ʁqa&?fA|@">|2?+!~̮R s?WpюMHPW_L?SnS [Z\#whnuEGǓ ̫~=E*`\#086-~*Q{EJL(I|.c'mx/&?[TǢJQ7wݏwYêړ&|BUv_?6ǒ莏~ؗX>:{)>gcT =OcJ-A?XtcM ;>q~vM զ??OJ5Jeǃ4~@cylOe+KԺ}"ۀEddq2cZcp>./:MBˤ! {#n" ]8a=9>G?̝AJa-ޗkmH制L'=1SÆ$O?I銸e4F#6)nqe?~1W MX>>2,TIw?c +FT8zH=jcN龿0<6ѧG9. F +U?dI]6WnVmzc>O q߽9SO_AW3=3b0.շg"S_#8V.}I#$aM+Y݌MP~N?Tn^ߒ)>]X8kz>DˎE +^?J L4:svҠKc:*UcNdv ǚ1uDݗ̺, SӶ+X&=hF|-2UMgk£x{OBdM *h}71{/H4 w'O}̺c?4z1ZG%5PzY*Ŀo^;'R#ir(F?TɉU֓g!5ojg*%*"ˎo4c~z}pGD^k"O*K&=>d*'Ht:sy#_?1P^#+ͯ5iÂ_L?8G #I72[I$'aK&=^Xn}pS?'^k +bl!7a=c'~M6m'V + ~']f{RS;cXRHIͫ'>¿hD+@ GIbIM :GOiBHspe] J#6ǨLj5~'BQ*yGƶvhDO%#ꡎI'>¿ hBazٔxQWM'9s">`"yھcL<‹4K&e#Xj,E6~I6o +M8BɎV#D}gpEԗlDȉ~!(>ɏd֥G)\*x{sXB:T} •i?Pc8=T`^{ GY}Bc?Rg ϲcUYq">a8bi,j#r'T8r߹/|5(?G0}\xd1{(?6~'hsv&? JT}3&o`tzɨ1nql? KQ'I`:h?c +?v ϲc*Ʒ/ՁP?tHq3 ϲck2T}*,">)1z}q;RQkƣī{/TYWwo?b8?_15SB=ޯ|gOKGV*>ЏE]fYi#A}gx2T~5hG5m:tWJQ*'y+B>Ęc< +|T~ ۭG׃+ɞm׾7?O?_JpuhG]y &|e&?O١OWɯI#2;?lz}O[Q}`7#O:>49ğܜ&?_ J#2ڵj X~}N}եN#wՒu|x UMqӸlj'v'eճ?%Tl,ɫA>`~LHV}U~~z>s|ݏ)  +G3%e|sj1~3|‡ +)xīaQQ]Oj:Ӥ[|#C|]=1:!e_t WWembtmea0>4GʹvZ>a: y\%\cTRt-15͏=~F;uD̳k#ss>ɏ :Ўv0U`_+f6El9LyhCW%f=-1l}V'UC*>ЄyWQɿ#}R3'cլ;<5WkcwQ~oo?j<)jWR#dzIZr2z= V*y0 ->Ϭ~1̬M"?OGF7b*O+QwaJ_D=Gº-d\sZG.dݳ)cQ">эmu0OpROEHpg?M"S#z5_'#I}|8^z$׭O:5$OnVaX:-c?z ^=$U*}!'$ROДHqN[%{?qȧT] ?z֏G't7Pʽ~?9dG3s(砠*yF?uUc148o$pzQ*?SU~Ӈ'_GXLk֣ +UPlG}BzsO lu57WcH +\:$ZP%]Yi{jD?l#wQ"G TT.eOq[ U|r7}>?r#TzFUa~yjqPx6}cq:Ge[~1d7r, ^?Cㄫiv)?x%AFVZ~8?G0eZo1-]cɢMfcGzdv'XY?| <~=WB)EysHn>:\/{zmb6m+䕳`Z% ~eT";m^" +P$X;| 'ҒcW|-\eGm` %!Bݣ{R{vx鿘8U~WgTzwb,&p@xxFI;$ 3ө_Ǣ P}0aH }:[`<\Ñ<⅔_c&X߳ٯԶo K(hԸSw)<.A;ηcWȰs!9Rj\ܶx*,?&-RLPM#@&S0uvp5 l_sHMK9ȶ?*ҸMHŽ.Fz)=H,EzGjM^5PU)lO&hUa%hƕc5J:l"y^ 誩#dsp9L|V?MR?· c2}g{d'GkBIDqMz D +t%ojT~ hr)?ic%* ~ꏰ-8'Q)lbWT QUxL~&?"^z~Oxq\1"̈H_)w5J"i#QP1O*8J~ |FlM"j|՟ǸԻӎe +cC(vyy?#mB30~m<~stn~-g6?gtHfzzx9p\z"n6aϷgwP=ˌ+:nN:?GN9ȷ4ws#hSgl}ˏqY٤\hz&9ENBx)??WK8^nx4mTb/Hr? aQ5zbEQȹi}BS@ѿ@k}?A9kuuJxlAbš~Sx_#˰?܌DG?wYd55I1D +;e?ӝG0>HDR3D_?\([ylF2A?* rο_YO'cE%8}.9Se˟!iʷ-I2r5:[ʎ]HOqqPOM~W8eyf]4w?PN^WM?-?dGJ(2j€qSBv5S4;. +E5`_8OH53 #a5|jTcK73f?#E7=V=>O IaM_0~>LcFQ~qVGH!"~cp̷̗¼GmeL,#G̾gOH.*A@3>+,=rG4~H|}G81?o(8? cQ揰 Б~c?) NN5i|7(?2_4z?)ZlXӥN BzBoq?%pPQTU>H'K";?o7?~˟#{!Uk~%K~1l>W1# ~J[J +=ǠӚzx-]8u̟ =$HO?%JB@Ԥ}7<4{Rlqy?ģH|}~1-F[pI 3Iie,S׷?@qGpW0)O2(:]NzC`G`Ut+Ĺu2(NSH͏h?_*$~0)H]RH?|~+I']q1gf\*R׉,_*<ӤЂvǤIhGpT׵ʲeoRϳ4}% 1P??@yFM^QY{rިsI'ǨwgǘgpaH~T~-𔟁w[s1(SCg1 TSr_piM1= N(^o +K c jNPBrCGcP'xd%}+52mOΘ@_u-_ӏƕ!/SG27>8 SŖcL~~4O?z HoNQxRfCFROP~W*'L'9D '<kҍ|sqE?+ԟ?*2'$CbjgyS'ވgN){; V8ʢ6y^2?'kߔ6)J*yE?M/IqvT)#0IcHb[ r?FREyq~~kȟc?(XK_܏eie pa~+q֤?>?iAJb'taG4n KyqH ~j_x/ŷ_^ ?܏D;TҤ>ג$-tk:GL#gGZݷvУ{v|ԭI#nDo~P$ί-VծE +a<q8ʣrI#XnKj+Z^6#(.#~F3?iR_'zc'F?li,uJkU*'^CGr_#c'ޣF;iO wCq=0 ے# ~QbO0GZ[B8ӏ5#%J=QuR?2t" ?q?)X+?6cu &뎞>q8| g@)w84{` Z224Ư/ott(G"׈׏ݒN _1i2&HOL؀u|~~a$،{ M=\ڏ>ȎՈ-c/֟ܨ)_T-_^7duHGK|r S> L{*)z7!'qk]$߸ec;Mɿ\{UQ=~9ɟQfKV5,ϸw!ҕbMwO?ӏ]C=~-ߊpc~9ia4<_q,>ю$>ȄN#QlpOذx6K}oٶR1MzXXlю3U|m_{y#d#1Mì~=ЛI0ucUjceӊO%: { sW?~z =CY3/wF=^l _ǟ6RяP=P[6<ه޻hM 3~?8jGPoaEbhf bH$c̾U>s*㣴ϊ}=% LyG $Pqq`^#s`HďtyxJ8xGGKUV1Cv7=xlТcQ F{c?iD! '~fH9s-꯻;v?DZ:}cseqM}onッ?#~Ri[o[~)Gp2DrGc)=ew>#u| Jcڲ,vGR@9x47Y[<[?`Ǚ^Jx]ǥz}uN@I.=t

    ~>|c%7'\~ +JZ$n78axD~{E ??baJnjpl($slz%w<+QR41Z{ãv".eдP0m)ɽLrg& 'i<~1S@t1{$ZP??d}11hZcQJF?q;;Vq>DzPf<;bm?1D~[Ipg1|"  ?VT~4fk=q$vA~gL>T5v+qhiq7) +cS&l}?18H41& "֫^G0f<- ?>pf~GUꌄA@%<NJfʚM&@LyAjRMm1w51 +ǃo9roc$n]Ge>x==$D\ƒ4[һ[i{< vP~Bu(Zܴ) .Ua:=3 rleE7oǁT{sït:FMԒ>{ǰ7&]$XH>VI1쥫B:WkB.O(p<?̱BQVM,|J^GB#MO$RHÈ|ێ\~JHqʺלEEpT3qgnyGQ`#?$Gq?BY=2z'{&M`jʿKH7(<}Q$ByY>b¿z |]JqX9GB(WWO-!kGcؗw)_?}*.Z1囔zAUA#i$c#?<u4G =q|0nJGీPT€?pNJ>aC7Un{=S=K Q8 <1$qڨN # +8nO,WKR=qM +wOxkꩰ;8)?ӏ_&sc:b:r=BF:N?LWGT ѳOi +˭8IzWW?~|뎄PgїYdM?ӏO0Ij|%_ǻ5̨{d1'q2O<=b9j. Y{&G!xq?ӏɓy;e_~|Xg0F_yyvBfޟ"UO2=q8fx|iSW~cTI=kYT`\42CaԻm~DNsL +#)?h~08z>[#Ujpzc8M:b߹Gβ>Z~az_U޿;z >+)L ӀI>G3~ZVTY聪F2'py ϰ=q\ѷ; +#f:~co +9m*tkd_ss t~|K?9G`|}SVfF̔MQ`s6s+K(>,|PMgC.% +}N=7g.s]^Ti#;Cxi6M(kSꂢj+caʆC`ǗRwQ'7, 4ٟK?Ne?~$6=Ff6ѬQ~Ц/z֦}={R;~*10N߸/'CT@h΍8^1Χ*='%_юjJ^1q:mEA7|(6` +Y/#-"5: +_c:OGTn)ۇm?#J(sSE +U!S/?~8dW@;Svu#/^8FB&vq>wLecm{;eЛ += +T]W펁Z#Dz4>2 ֗3{gR:WcR!P`5T\t|e›1ǫz+1V[Yw=_OwbɟRqLˉ*qk1^XXcf0?)|qCq1pK=_?+b}qz):R}HbTs]tmWb" cb7s*ʟqB˥Mop@G\՘(F=1kONt3V|3RFju&ՙ(C +O GYqq~-rh8uFƝm;Tnn,TazsQaZ\ L'Hcp{;pRh63 AZ Ozs|Cc%IM}~7Hկcj;z"H$._%x:{zB0~9RAs*C$R0cƲflGOPljM5_!ߴ:Დ?*4տ_F랚)B=z=s[t^)?{^dRf:ņKij5~1ܜ=:ZO_,݌G3q'ᯑ=/D;Z?s9Ra8kr.SY1#:gЊY[XqLsCҏ?}Kc7ѿ]~?ĵ\v)ڎncgʠ7F ]uJR8o[ +]\wKc^g̎OsqD#Jg9[`n_Nf_k1rGroXbS>#_M#*K[x0}љc +>{?#I|k֯<Pd*O_ӎ UPH (}=|e>s9W&\,N=2bN~1S#B>F?IS+ʿy\pOwV]ђW|Kbq]3%lL(Gp+O3a_28N??R~1fa#z)dXIGy14Xj?ǒ +\G׭*7p[ ?XEmb/mls*VOG҉Ӹkֿ38s(Լz?ecC-ʘ75:k#,`P䖏z̬>?^YZ.:iUX}YU5qk?E0mJ&T~=SKcM"|Y|~g1o5"s`Z1 +ۖiYB6H~ij0v< 3lzC媪܈H^U.0ٶ;RiI٧Ocr󻕷B>[6 +Lbm|"ZJL6?C,֧'EBMoaNVްDsɐ| } O)v#DwLz8K}z?Iu7U|X~y P B?Ií_P\^B?G\G%zq^(Xٙaƿ{G4<X$~13/JxgNT)ìUjr`cڝRLy+>[֮<:hG)Kd[7,s2_q1S)SìTp5|M$Z-Oq)2$nHO=׉  ћ`|:ynISאJ-kcfMt1*xKˏ=]wG::`&Sme&רcH[h>,߁(ۏ_EfX> {Q!Hڟ#A?/S]p 8I_ͦZaJ];I||* N)plԸT#0S֯4V mGY+}[8qV,GzXoGN3Hg?dwo]~F+?V?XGN5G+Cg&-矮?*sjGzTh_N'Ŷ>N]1켙 . _ӏΉ*OhSF'k%kwvr<[|AbZ?J/еz=ں`˵$G|G~;O~+UWOX[)q+ɐR/wc9}Z?vX5_mޏҽU1okHQxqq\;v?*ҿ5_mޏ]Jj^hOd+=ǰsgrGrTW_k ''{v?&Hs=dn>-#òlb]UZ2~X W3ɯG~[XG2:l͔/%krcW-yd|Ls +b\GN ,Z'n>YÒ?z'LB9N'wG}>TƝD?ތudTԫ#M`xʫ\XpBUP%Ah:E~=x`N=gG v݁*<U%½|c=Ϳ? &N˷WkʗhQR?NJ>tk򄮝̿wď@rL2;8=l~>'O$Y~P>Saglz~|O}cX:H_T*AWG޸VME}XF?S̹#Ut Ct>A_c?c?T*F=DW. (ɰu?#O(?2\~B]Ro?}7!?;??}Gߔ}up%hw[Ϲ@GmeVcݯèI<ֳ4+?=1q@#=$ (NRdM1VcJx)#0?h0k|F@۹H<R1Rj o07f#p3VӃm}鏯#T'͉}'#LF/8Z 7>?~3"KN,D>N?3/GXfE:(@Lo,wѓ G|i2q=%[1JU#G%(Z#}IJhG} q#>}=IǨP6 ~F"W}AAT߆Q^ T.X>|z&RHi< zu[1$ &:Q:o ߍ'}_$}WHP'fM\txfǂ3j7.=> +SBs V%J=P(Q&2>1Ubi_¹Sa?yLc,'#.rG1kScW>ڿ/VO %[gEOMxuyz+ Ej?߆}~1n.GtZ_;3oܿGh";C?яU;W.G ju&O^65=h\]N`m_qVGO%j#4~"f}~1VO-iC~>I#?'0|%2?sɔk'?pДA1Ndm_~i)#9aX S'z=d\At? \j`Vj}B8ea7S <ܨoNfFιrGsSq?7}ww֍|Lu6Y )M\jc!?d~HγV}FSy: i)q()̓}~1O7 +MaTd5"QG`^dW4=B>j:MKg*BG7-#1КϴQz'/xNCߌv +`V Q|?%BƪE{񵁖`xiT脒H|q요qhEa1NM$%S⾍l' + +LF8h<s']hNM~{_mc9N! 5/w֞2sğq6{ '7m g_i+i$ ?OW yL!~ݿO˛}EiJ&&b¤ `\U'N{dz*N&1L }͘_WyDT~Jp[P|<_م4G(Ǖ՞_ą§T[h+)R>jU͇4A6op}RwGl]ae., EFWp1ZjHo!Ou +HZI'i$a*iAxj)iV:':ҟ\ؖE%E +BBI + 5R +)r}Q*>YkxYEQ*%IK#ďAT).?sU!Vɏ6Ϯ;[u:u{?|ItEHm~pRp}o4UWcXUܿڏÎ~1z$6Mzo(9iH?l~SRj<_zCk8|wGeI7-qlxha5-A҆~pz^s*+tw cY'>*U.pxNVf[^kwGdUiDx[Ϳ,~2_Y ΀,Ry cJH)6t.?3<`FjjXMS1ǣLri| HN~?'<@SnI`v<ը.8>~2*#d-1(8҅~4Q桃_OT혔Y@)Qdزޛ1%s^#};)!&In/vbi_cẀϳ +#+Tz]btjidqԐ}翉sU5 +?=b`g:s3XɏÒƣ%Qҝ3h}fLrlq~1Uy?9LS[>ЏF 'KҐ99.}jI?5(44G>?,ґauo1?£:Eؠ3\}) 5?ϲ`V!OB9f'pOoyesi?яq*?9%r=q܎O|ǩߏ's-3&10Dgib: qcsU:{H{ +Q??~U$-}!m1M$w.rF朱"Jy~U=O?ˍpW'ZJ^?$O8ǝ8VO]RϟG˙&@|SKVcβ7rS#ͼ+@N:1&G5Vڮ" +N9F~#bͻ OjIfJZ~R?1̼$mz#UԸ4B"܎jR'<ġD^R= ~ FBޜX`X(B` eG?3U !5$&X1ooGڵ|`7 NKcy?}IBvOv>D[ݾXas^~N-Je?WROgCQ'7W3Wߜq5N~L@q >`u}~JwIaIeZ.=c<rvTs? k.+O'w?'~No#rR.Gz ++0<0;`yC? ]ÿ́c_+pcD\c8G08 +Per9oj\7~ -cWK{Pీ=ߨǘ',?v586 g^us~jpKg0Wc^w=b~Or k 7o1u1qA*1ά@cI0D &G+> ޸Է {8*]?3iҤ67RGc'];̏~qKwu @mqܯ~?fCsotP$'qO޲_?O,*7սI~q^HJARm~|=8va>'U'O OިxqP2g?l vxlɶ G_)ݟy_}tɪu,G|gcJ?l{}rNj"0#I_7tڀ hErcͨy/I"?BPVa!2kr=H6}Gc&2ЫI$ۮs +F@`d=GsĎGq0LdG _l' TmtcIR&~ϲ~p6j#FJt c?eu++ _ +׫k,@uNk;:;mv=? M|Gԫq04 +cC2?cγs݆\ڣv뫊ͷ CUfb,GnoEa@\BOJAk*+r505eQԹ[P)-/8ϑB + +B-5?] 3ՒWcY~⟷!ڟM|:Tf Cec%"|`~0"P[!zS|K/0̞Ƹ=z;=dGU#fZP3l-lfx-} +Tn=ЗTּrFOYcOp}9'#Wk*<ЛrlV?1֣ԙ${s򲿧a]υj #Kp*)J>ϵY&?qإ7#GJdzU])oO=qǃqh|罟zlϭQ_Bcڤ((Dz5?!Ϸc?d џǢ3I?Tx~nOn}j\]g_D8MBQCJ۾я?eCq.TGgtAY{T~Qszcj~Kn?uI?7w |Ty8ԗr15L}3A& T}3* 6~ǂ0 (Gʪ3UOALEǩy9}GNTgԨIaG7Dߥ>^pIlitӰw:DHfkd5\>E6|N~1殅?8wK#R?ц)ػxLmԟB= +ᕍL~8񵟹'qNZB5G7͏ݏg ~`Nr[j5?ϭQz *s_mzc9o_~'OτJ,j=f@ 7c>$N<5)9ZSkԨ!bZGq?ӏ_Juw'Q^ԨR"o77GzSh% 3aS88JxOj\zT#&uECGc= މ>_~:ߴ?TH]W rٜO}g=O`ǧ'~iO~#OT^G,AbayWHεqf8Z߶?ePj1ꮅ=M>Nmls0~npJ<&;.N*QRpd ~ô!=` 4a{QAF_T#s/c>HBG5.t[?;d^Jr#]şUł}[Gc1ugOF?GJ9Uoj5w. 1qk2MsU<@!LlͲH%EZ>Cg2xt:RP>"NPQe!vIQ <]JӁK(@CWR:;uv'T>BԯX2=v6ZBtȹܞϪ7G!NU,v9Km% +n܏HWaL2VT^,_\Xa_=`&/w[?deޏ`{sg1.zvyWgPNʧiax56T:Ŝ?#eC:MH&C{2Ie`ٽuA&N{p~1%Ҟ}VbƭYJEU}šk4qWe'X =!$3GH&{VM{$1v?ҿ";`G`dVNд2Ms`IQV{|'q $wc?L3=-v̚Y/eF][IА76ly㕼IKWHXc`)?)H~1ڶj??THQ)c3&Mao36/_|qdX8@J]} ɞ0"!f4I1{ +WH35IJ +-%*쨁R,(F]/<UA&iߊR@^RA;^ G7R [Tplq%L7Ry\GTVrgBr#X Y"cO)i6ѳqL-M&GnxGz=tEFFz\hFKY8/F=2?sG&u- )7>E8QmΞ pU!2xjG?9YZ}FsM>vc%z *$'OQRQo'LF=QWύ|)O(F| O~> =qiQao0nTw#bLJ;6J@@0؟\t ,MWƹtd6LY-$k'$N:ZuD^GR-\eRRwqA(@Q6H_Oz&כLi |~oNFwx=kZ UHKQWI +ti8TRGNk9Ry^ ObH4׮KQֳ?~VmkR'M #M%( +F 1}:z0[2TEdknͨ 6m82W !ސ~ +7P񪏺,Ay|@ᨭay!F0ReBRKm=H +D:YT6$3 ݢ{㌷t[SU5KA?j=f(toѝ  8<,c*A;o(}6H lTJsKJH yA*8[BV\I ߗσKCig1ΧNp!jyeeYﮱYu^' ›3*̫Xhuǒk46+J0Cz+rkTMc%%6Ok?EZ)u!W>=9*' +H ݭ[0-rnTu"Ղ_~pkWq8ڥ6*BBǠ Mt/~h[Rtͥ~LVm-G?HT,]޶QY1*H_7ͥhmtP^k$͖V=JJ3\u +cJH)e'?B-S)P)*C[;$RaN<(d>К`!?؄uCoSGzqR&Qu$> 'R? @ ԿwNiEDN:꽺zG[}9A٤~LjLfGqtt@z?F#Ҋ|i_V]vGeQ&֎Bqt?ޏia݅tGs@wE~>S% 8~yJ'u=-~_% zcAgTYCޱ֪.7;~SLxla=_v:N|HM7:v-1F/s .CCGLOZV*m[ɏu()U:¼&U}XPl_!YR4ʲc9A8R ⣷:yYsy4~putPM&BR!ZnE{~ᣂpRlsFHt~ГTf9hU=>rd!2kч-$w>Uoݑ_ WN:|fGBJm_ӏTVݵ?d~ k$U(3?ҚG#>J;ɮ>8ry>_%L\F>ɔlk Ϗu{2j?Q \aSk A0Ǹ<>aO CTT,\) saE+CB TvJZč1U);QR2)<bIIn{'~8>wOT~c^d@^W~ΣB&?ܝ(S-H㑼`3\0fBcW[fnɸǔ}tԊIܶTc'e,1n]W?xC՞ORPɚW@RVHbT?&}h~L7DϼFD9ɬz?Gs`u)?-9.liE4ޏT?UV.8:lEuj)b!q:eg/r2\`qU +UQ.?™rC_t3Er<ۢ~>*?Ȝ +8R[Ln}SU\;tNU~RoG?8N6L3ǚew.9UzFerO`]#'+ޤA :F>R`>ݼEq H>#Pr"T?n?Frr_e?bL9ϴZEgpId.[wIc M"ٗ%2d\[Yʅ 65~'JJvk&XJZ߯lEʣ8^\s|-~1Cr)2MzMQY_QYHXMpf=* 6Ǔ. lu'Sqҕ}-2W6GJU&?*^)Ա5_o}T6tx)lJvgC^%%mWEǠZcjw@-G$s[t 𼴺}<B\JXN\u|-\ l7=Zm?S ˙@X1I Rr­2$7Un0N4A!E?t, :?Flt%R2I9JzZlRuidȉPp8tY^nXkH?|{5 (|Jy'1V#9Rww~1QQCQ1Gɰ.\<ƳՈX;AW;k{Z±ë?' +K+?(@ ,GȔ#*xbOP?.hh<6式cYh1М/(~A.9Fk)/+gOV?_Ҝb^yrfo#ӁP=Y?ƳL I1UbBb2xnۈ9"ox_ҡGai!Uj}o'g##SVO$Gi5aY3b?&&M2\[o_t}K&/sF?C'/@.TdqAtVR\qo \`z*Kd<^I k?|~ZEHT`:$z֠L)'sFWAKg19\$,CSRUȥ>&B HZrKKc3Xrݿբ9,X2U֢_B@9)4G5OkͥEJ5$׶9g*[` +ֵaTB +59O3U'ocƦKr +A%(fRP@&6 Y7-a+_qtCXph? +?#w?+:CZIE%*A(OqOɹE=Z y}q7WL \(KɴW/U{X#Ą&[<۔X'Wh\ KFJUkr߽M}?nIXj,q:><6I٥ܛnK(_ͣ9$3kRsVdZ?M"A;)GbsHЬyIf~ÏUcy{-?}? +RأyەOjQ?U?&k_ZGKXzcpX?'1W.XuMk=N#D_#ҩ? &UciWUS/;pʅbJUndqhԩSN) \J*Kslh+/RO%-C弱ʥ1L^K&=deX\|!=!@}Mt VFߖ$ +rByYt-qGܨiRL5DR㊾TU =j5VЫ/#‹SyC^epo*NC}ʇ1FdRMMѢl`j&VwjBn"8}=M\s4bהu%:&:NAqB֫{c:>^Zn9XPyVm}M4΍,׈2T.HZO"R}E0MbNa:|TLX_.UϠ-eSIh=BuӎqC|Pǩ柴CVHbœm +K~>X}MR痘1 19[h<ҚROi~0Әf.Tx:EI~M{( )&WB~J ʡ[T鰒яEbiCy,ZMg+*BUɐ7ݒYX_vIVdBVQa:.:bK;H5;TS//*2g['hwtæ:|Z +7w}."J=MҖ7Gd9,JYfѝ=$UUA.MKt+C\"gRn?tm@$|92É6GPUUfkyŝTO>`XRU\)`$>bs2 8lII9q$v@#Q1N :5ƤR)iĥ%(pJH6#)tJjPd[o,lGSi +n[g$ ,-ְ%IXPcb,ET?.60i66c4Z5Hqĕ\)D>jIA]@DkZܨ&ePj]YMp6B,H`8\Aaι)x4]O/XYҏ)Nvޅi걏5dZ ;,Mh,_C^pVcTÄzӴ9H4<\ ͂y:)y4jUBF-\\B8ᙦ9-cNCQhWCn)^Wpfi敝$q7DDۃIO?QŮ"6륣Z1אGuk>_=2^xmH-ÍNg. +Jq3"@/3=7 ({Vpv教v`f;α bkEhV{1*𒒦Vse%,~UtLpJAPaU7>$o {m n^dv3,rA.qJ*+IF.MTT>,[aNH|D7.'eCi'֫ǰ`nI>T+-$o]./=+Ӥ~BȔ.JJRq]b`霁?'֗fV}D&M|s"kF?}R/Gws({2T(7')f=V}xTtKtYUX4;j%cRG8RujZ_y@֛2z5-#2-b\BVB߬~*L$ln6 /' $rǑ HPE[P\3M{_lDu#xFnBWZu)!'I +㇬&i}ğL7ߥ͜%sOgݡJs`^HWr`_IƐFҽR-a2&7Paq'UJk(z)ʖN7 MP7LkSys ̡y<G&~HVZeb۟+Z>v#ʤ?]O4K1'W*oy7Tj Z.94il {q(K>eM{!EzP.~KΏɬ2R1ptڿm[Ecs/tSM*:=ԮX +*z:$7m˿twmvTT۶KHq.Tߘ7>vbǤԾ %VT^sL(z m7nG f:ӪR8-*6#0%&Ǒ*"8 O=pKRAPR;Pمlҡoc׈ @лcCEjdTCkBRJrKdXPX4촗e;$ +S~O׹8FLJA6Jnuu~f!~~%OI.U5Ylpv1B㡀c5-QYMmKWʁ`Y\F9?3@Ve*cëh0e+4WF3?0z5S!~ձ‰%n~BN%u/!ENƉdy)y:SR-nV8c LKv%“l>FD|p3;0pYC5- 0^djr˙QHM;l +RX\x!7]5GpԱ׈oU*R  QyG#ҒU.&>2 +M|̫TY›rV?8g:KēJIV :#*w*=!F11 +Q0O +LoxrپOcս9\(~1v!fCYٺ' /%ӻ8MmTwf8R@c+`h MύטmCBJr7*7%keN.Ó%+i#$)./sO=֢9m;i 7񶰜BQQDI$j#޹*_92p#}·HzSN [DPL9Z11aJ0.a)<;13P}>$$#IUA5)x&=m>[̬PELŽ_15R|ow/ړU?Nhd6=SDWkWO:?%LF}Y2,ǸÓ|WkZGOCfC W̑Olr4bO +0 OBcZ_VgGs eSs*0_WT^i?#LtkW`,~ȧUIUsvUַI  _AZjR T~筣l᭠|8K(Wun2a&%^{ {6\a?>7c֜lv/ݸP9' +qo`HG:,c4څ8PִIQ uPIL'a#'tQ${uirn wLx(fq?s6UvP{mDtA Ìe>ZRV()? SåJ@nm7LZBcuX_Ca W&٬VgV+ 6iiR!C*o!YMnHpqj'2OHH#Qxrեz*{ҵtd^Uu v)ua$*=bt 0~Eδ׈7)?D?Iu?I{`,qH{ibլ?< -0[*6j3N/$iCC\z fRL\ɝg0tB:uoX)M0DSQ":P)?jE>sVU! `RDF2EC`RLboF6SOkkm=P5"fqQdxt{LrY4v zw*U?mQ*S$%X u俋9'ZjRI"U`x͏OI2nNJLҍ!jMt2e(z>zK/=7G?<Ǻ$)fOwR*R^&KܣM +Q4;ed&@ yGi2ţԟ&~y>1:0{d{HtǨ.{ 1&X= a5`9m%~JK uF [ѥh׸_Lg%)nT6Cgx9%˫W=ێaIH{ݼM4sXr",͏ͣeM͍ԓfĎO|1j9RQFtAa3 }!E5nџRw%HZT>nmʰRy_e83݉RQf@X!CR݂}Hb6VT@8c<% +#H̸یj]K|Ԩ2[^%鱣v2YuRl~<'c[ang)pJ Uh,51쥜 57лH&]L jmeaPfIv3a3(q>e"%%)o.{ $4q$J@c]\m}1+-T"ۋQ#F0iD_*PO2a^;8!*]j<}a%MfL[s>ORs('Oq0P @8W5 >μQM +޸%M7öfraMjY +l nq"YK+i%gXodXNnb[RzY)C8.R|aoBi֚ [lSb ~q,&H+UZzåJvHEZ6+ua X!4R2鶼x^6y+{RGV^y; )cwRxx2jO'2 +Q1*% +)+AЂ6;sy-̚Df;}{eXwcyݺ(%r- WGEkS]+$̛.g4jmE' Ua8 ,r|X*<ЛAI#LCSXjQ‚uI #MiAQl8M@ ΥQ]uO[TO|qdS(| WLxXC.oeC!KVʮtJMˌs$4ȉHZS~}bV d@bIH."PLa) 3N8⚺J1 T! )@ɹJGUWᄖ!o) pBٓa + olHt1| *Q?! Q-+ni6U})r)Pfx읣}T(m.25X'ѯ|+%7RW,Dk%$@veD{#QW4)iHp 2'7>A  |,kQY>\ǛCCMj9Dzq1$ {Go#S +Tz[7뙴)9G=qw4@rq#A41k?F6ʴR=sLV0e_k]JQ'ߗQ9LIgS6J?L}F?֣04z\~)M;xc{R|SeZIfЮ6sK7r]ŸKXֳun-[o$,$^= &&Ă==Cwz)m*B1rIN? Z]8zr-FĹO>l6%kL >Π7PSY~5"ÓmjI[Ou 9PuekZGeGH'X6I Nxr ffeѓT›`qS.g>m9W~(FRZT7j^C㦕YzHpACc I"'~_K(LXP;`H#m+l:Cyr|"5N-~<Ja |<7H9+XaKi JI"驉WRMMpmb:R3t'\ K_Bea)Qkk+;QvY9Qyw-0{nW˶!O{m0UeExX\g5A0܋WdI=C3seJ]Vz 3?@y q-S0?Glb}ԧVONXn%MGXEp7#6SqbRż0y&Ó~.ed鹿~s]W.6 +KQ,gZ7.J y˹NQ32Ff Y}m;U5UtP甓em}o N gTK6MDx>W2q{ +osy +kD o1qCKn^Lb&p1;(aYv)O"N0L,[_6HSQR؎zqe4tl};VJXA5rtJ'@Ù%I|ꉎGʤa +udqkg#_-4W8&E!Fc'1yߜ>e2bhA~8'Ki{1/&p=P1OS%>txLmj:? +Ldܫ a#uFg +˒m"HDUK>L9lwcJQhH %)F)G@g l՜VTma8.*~?b9,N NZ6 Ra #CD2,8X' 0Vq0$ +^VE'u@~g!}b 6<6d&!Q‚/?BeiShPC yi+7V"jTR ēسɵ#|:<&bDe2/eCI^y** `G;} J6ۋsO|VQ4f"v\^GhK̬=N+_rGb{LNēbY~H,E +Qív&& ) n5mcj^Zj-6NoR;bcNdnD 7l +8nazT0nn]Dw?"Mp,V%’mn1( {s5c;;FaZ3yw𱿬Gx8|ec<-+wztԞou4rՇUxo8rl YHtm6:dƏ61(RU{u_' HYW J}G+|j <Ы!S4@ԥ'3%Uia’s$!E@&uVW&k $7aE>>N0b J&azܞF&)iXM2'1OiX(ң=n{Ww53OT90^~Еq< ɿ*![n)aY{_Oį*(N?AyO3,Vp8):ĔPwH L9ԴL?Wb)m;!h,-G 9?tme4461'tez%~pEci +6DkKEđ)&CubΧmLv6qDL*@J\F$[*q+Ccf/Re@+o?%:g?$Ga )'^4#6V*mےThRsHH{ڶј[N;PPAoTJT{PƐ6jxkfKe%ž+2 +qZ{\ 1+8,j[vXy?OP"H 2۔<ڳ?Hx'E)KSkv-, +G'3;_9?ō#&:W6k%w3+;|~eډ<$h<KBGV1[il̳)m+ب&0?uL;94e)cQv:~ S_׸kLv5$gQQy"9w]<rk2Ƨ6ge muP 뿉 ”/?=1fzPۘG詪rjTrΞGְa0hb0&Ny6l?!`:ڡ1CI9]A jT}O]Njd:$*i$dWR"SX|?UI'Kxԓ2{)_YK.6T:$0T|vc^JvbE|[;*tlRߔ}օr=1RKEe% S]@mV>=e;܄w䠥q7/0;IR4=G_ly\O|GU0LY_mUWI1@Ne&BJ?%4(,r +=7m-O&ӚSɱ%Oŷ,U?ATe(YP&޿/ +V䪮RG?n).qH(d2MIqAр7, +͛}ڏ O> qe#S=aӱ$>]rR7Y4VkݗJmZv\5pԅ'tG{fRo-jSNJ{QI/}ǎy14ԕeNYLg$(\?,{H mR47UTVΓO"g?41VP7je4`IH'ًivZ@},H'H5 +KOD+CmU9MTB&COT!LIevE.l%eO8?8C_T\Q*D>둠x'q1ri)m)f3wc7q4!qDJDŔA$X;Yri3ؑn]߃I8.Z;)G`yCjcfѡ;ۀ~0sιZNyyRhUғ}l˘IcCœxeU3SHʓr3e3F:Ŭgi(MR/[Ɩ]fB[θ8 J'5,W>ʊnoIpT8FѴoD-I]H[1k?Pypޚj^heXxGS5%Kdzt2lAen6};(έMMQQd*p~IPt[{-F + R?8v"$nzORXZ +ECe׆y8qTU5Bdmܤ^l|bcjk4i%6uN +ޘvcA`_kIXKIm]s[9|VBo&<槙C==:|yBqlP. % j_c8!0u +3=3WzMXؤ#S7k9tLLc~ 6Sl6&H]k^$ffŤt'yKn(|xA4ChKI*,Ü 2 iC[:³='Tebrvyê( "BmoQ}Γ6OxP}B8Q]؎g촴;JD!cU#gbYzf䒓{ٛ*Г5z_4cgp[n3puN8~=Cr(h "L ~yKr2`[`#Γ)5&Іm("J_4%樔PnQٓ*>c8yޘ$5Nsjt$+uzrm +u䟸_Fۉ2jhH]]`Wf_ʔ&ihn@uҫz@HR7-HGDxn(S +$hohz`m{[EJ:j0]TRMIFCMԽUrT[e8U)@?QGq-bO!v]-@: 7oLqW\Y!!g0I7>:DLX%fiOBSXd@@4{:5 Mmr*<=v }v7 Us%)TI̅)e= U {5XH9U Oڋp1 2Xa +-I6&*O8{Oʑ u_FRv+*$FÉ}ȴ EqMv6 쒻۾;%q<2S[%E#118H:o@8*R.rc O2G-S2$2Y׽ aVkh7=^Tu&'1)q9z­ Y#M#O}[ 4JrD]KIAR#4(2s85k!l +̙aJSA5[ԉǐgQVI\BR}}'SŦERK*|U͜}R`2|/Lc*;%)Unw* +7M؂M̭p-@;uwrжj‹'MB9 %nQ >&Ct%A7D.0$B][O[TO-IF>{;Tr^rK b6q>f| )C|øxʩRsk{^ӎ%Í3OZqg)͕#O|ohmPk+ӧKmOGlb̔={0/_6q4f#u=aliT&:j37dtk{zvG\ 9WmIRJ'u*+ {MUa]Z9AB&R[M$P~UXML;`,.JU`}>gcNI"yU/2]~)e. +qgJ{-l?0'KRJ@@[nHt&ϲX":`8Cev񚵇6.ǣW4JTX'xj0=`|/BQTi'v߹-q 7Tᘈyq8J +l+CeoCH:B*$=Ѩv:ىpҢ/ǁ"<\֨"HJJ? 7 J mv>p" 9):R Yx۶Ou)S[%\*cM6ŵ[jÆCgJeKC X*!`MCP#pOo 7$V-ucKsO6fЂ,}Fѷn}4e0+E=nbbKRcCP!/3Z + w!kH샔Dn) +oĬaiLtcʀtsbIIIuC0YU26nɳڦ$GI~a*jTmW"]Ru9j[VG-#ʱuvH@r1I GN c]6)cHhؓ(|8\[5 Ztȸ#C_螥V*y^ +vYr0=\e +ؑFg +DO{򡓥$2N).$%$%h5 IGL4L|K'}ɛLJ\&È{"ᾐ(7̰JP,xA+(4g4UN)?2AڲJs"xemQR!>V ӎP!ec1.(ۏJa1O@r9Bʵf_' + }?yASRE6`wbJ/q"#$F_Z4=3xj-GFI׏Ǹx4N ^%'I\,sր?spZA>i;<48e伛{mh +[)BeԀhEy$k0M,IjMQU;WDw~1N13#L'ZFcƅ:i)C3 i@b7 +۷pqu +~U≿.pgʪ5q8Qɇ `;o(y%&70xI8k h+ %%C Ϙk bM891YiU6,Z/4Dufsdy5QBn` 8/ Ia?ML6FiN"m7sՁp>ŊrVcB"T-ľؾ{n|Q~'~4nRֵYZ蔩>Cۦp v;tI6m>^* bHko+-C@/wïQS$<#=[<-;*R;=bh;uWHJ ȨBpK]tdJJ\;>YOeg|5]~("(s +NKC=,w%X[ 9ˎ̓R@ 廯) ˚bUܟ]y3u !!^YRNeؖN +s7'͠-…t[Gr\_$)t:*}~0k֝.|!E):M&:]YagM~['sPR~V2Y_5zuw# +hR>@+;,[IKL }2mVd=vR)\iKTAѫ3:PJWZ6E3 \SZNf%;zB\c$4E0?#:k >TRʈ#knζʃkXk,S;/K.4s<ӌ$AEe'U5WfZ'\/060n@~%L%%܊Wc3i7˟3:TL8HJ&{CL'(Rf]LdBe+*QPrWCܳ|RڼvW=;knp˫`4MKu]:fɘһ(}mJQb؋p@S`RJyφ?n(nGx^nR{VP-*UvNX48rpq )B^6Od&fk\<4jp"oCGtVDvHe>lTrUM8'NpgŐɵI!QIHl0\'Wy#X|++b߶3f +a W6% 1ę'GN0ܔumԬBJQ;I0m,G?XHM nGH͐n;8KN~1(?ovzXVpʄx[.)AYI胄.l#ۉqCe(kۮgRmbA;~ +'Kzu)q SIa=7tGLJ>@oRwJP.$M[pyq}HNk[R“Oǚ TBRkZZsˍf*b e\]^].ttYwuw}9jEYȤ8 U'uyF-ȯ\h[3D [rx}P*Qɗrv!=V8s&0+g)[7jI&@8]P- +ܩoE$Wa9.@,$laa3m WdXn*fcVf9dֆkY֨j{Jh| ?0;&5edbfKbLc)[Q.OqVヌ231Y)r/1:鈧 uZ# ڂ& k<. .m;^<^րR+yfmӵyUsqгɺVr;}2*KvG;ѱxIGcT9pT|r1*O~ß,JTĶMҺ-mR"ОWٸjIpcS?ʟFjA +FY@]nHORc\s\l*jlz:lɌI(JrY(ZWu%@^ֿ? + +Umń y)Y5O٩GBKPP)p3d;1̃&,D$)*VEǮ($ .Z F,JNJTyce.f@MIk3)P*]oZR +Rqkjȅ ϟN)ٔL̖eHalukZ[+lHRm.VUysz<:͋KvԀ5P]^-RH_e-8Ve,!Rd I<{i˪= וPC)UJoP]WO#nhO/k ֚(7e=$ʃ߾FqQ4Œ0ΚU*bcp#6;} +ڙ G幷v@K 4oOtc!OMؖ/3s~ilk9fP%n5P>յ-j6aT,]4h;̖ e:osJxpm5?ԤYZA7ʔ [ l!E,-0|:UV1m y|@ד[rC]hZJrg+AԤw !L=~Ӫ'$6SkW%Jvܲ;v' %iG u,agu­s?0%)kIQN 7'|aE&H +WG?u%:V=\#`:k~a9?+"~`vߖiEJ@Tl_+`EɛJnRaeٔ{7'dOKIPݖ=sc)mā-J)nKnMǑ?LGG̀΀~!%\bdZcbK +ަ)s$%?XFz̟5PA-?8?]ȧQi}pfuq t,OH^B@EN\|{G`P,xfYk63[ylǔz'@-rc8$졯>1ޗB:~&s}DīM2J~G c껓]}ǪTT(٩@yE+ǫ&a!)yy0'baR$Z'o4Olt:U&S(*>5!'V'Z=G݅e;"P6wO9^2Ј&4ٗР2u&f[*Y>B;B4}=hi9Vr檥8|NIA_]J&qG"ࣿ$4QIx&t*Q2M8mk$q*riZyÃJqUɩ=>DB͚G}$(#=<}30 +S-2&I2U-IxJfT+ 1?~,K>lg<ljGT&,W5q!t7!Ӝ+PKpr#狀m6*Y*&čGI aiE;bUp|G I*- C[\yBZʏa|\q%Xz;ng't2-v'?̈́3~ wY#fvq>wJ k$jABh2r/gGsz}TmgSmE*tt}橴s]ue#:Ґ-|`\`x3*ݒI +Xnki *3bXuԳBHH$b!?'z4o +KOIe8V(,||sQCBN4X5 g_qWiIlhR)d-#@6'Q FSSW"clDG8fC"6rdٴxGU9[tU@j:%#Dw+r7MC]dqGӁ,+fUe '} ظBG!V.qso%>RGp=0rK%1"ή\,}j8m +P9nf7 0]apaP:-gǫզ#b=Ґ؎<U֯وbuS*qAfNVRaˮq <:Av Mxpe#/C0+f0m[ܓoekP2p)*j"~) >IMϝ6 R.Zߞt2)a/i85.):#pR8% "NhYǏ!~ $X&XlUBa@m.dDs"bogԡ,h 2e+ܪfW)畩o"Bj<1'짰+Q>cOtIj\)f$76;uh--~=%2~ahH wԺ.m\V^tMN ,i xiL@t$Uw7 WZltl+эRGw4NeKLNJ-PڔA$-Ie(Q8o9I'L4Q2727\Qx[oRc "uǙi1bTe0 &RYp! XIpy)@ýȺqmr/pd(Hr7Ǵ俆'-4'XL*4nG!hZjyȓKQ% >R-E wG +׬~ZNaQi~.{􅮐_Y nϬR[{ZVhmegI>BmMEi;^EZ +бůDғg*m#F2)Jܕ()b`C>ܜ&Oa Tx k sJȿg=rGm'MH w'2KVAZ,VrHQ}zbcGvUyЩ1lƈۜPOk؞mJJ],Je(yf@V5I*̔$%G; w0=mM%'̜O^Oԭ3,@۬@6WTN^@y[.$෪f$Z†qI"lEskl:V`[fMEFВ]&ihpbRTӋ(JеzbSTmAM~|Z +;l +EMZWN!*eReh7 8X=byS/@8kB]yIm;6UC*M£/1.%B B3PSդNy$T#mɱ Sj^ kU&j* fImzH"Q7cqEI[./:IJzįR.C@ܩ84( H*`, d*,J8)kP Mԥ('S֘aK/Vd- X@{\;BrpǟQpIBVq.6 M!K)*\K*B)j 3&6~j}>^)͙R$om|+:a笛hsl42}-'oWڙPC܈:5*],:/ǘL.%)R-8ݟ)=?Yx(434][@"T}C33.dHAU>RZ'*~)V*7%H^fLxiSqU%"eyZQ&>7ڪ-ĒA>u{a"o|Xe[f̔˥=nqRzL"$BRU=[,!. 94pY:۷#.|y7}֫ofYhŴpTOza>n`̝|Ѣ@71&#{LVH |ƛj=rnNSԑ$6oPa:I9zA#|Ü~\ZOhVmRJc6V.i@8lPԒѷ/T$-Iْ!PvbW!ei8nJ(NH7֙m@S2Ri 2Il.,nΤ ~eώ} 2rx$LN<&Ƚr³ + n_1odp)MO庺Ù('[[ b q|A&Kȡ)RqҔoI׬d-} PQ+:8Ce5E*)#| M$(YV0OOHʮ/VS,80ÍӝnJ*C<»8 +#q]T%i +U#FX(n9b9ZV=dTe{%Ğ +IiI-6G)_W.0RF6="Xu7KPvY•qҕC C/Hꋉ!̷s1o7RPhyO j,^4S.?ֵ3-f }U') Zs;I8 +*%M/Iĕ^’zcXCw}%]~´Q<#H.* JB t;@P2p&PRb!HpBWZrmsDIĭFUvWmG|d6⧥wRTu6s,rI$̵0-$X@RR[ƞ3X\wp4YEsc +,Λn2xw¾.° a5lۛ1L'Cx䓜=ZIq`201&FO8z.fwܡPQ$գgUVnȻ|!.\K Xhe)md?}t>%գAɏ³wfdhާܵ ;/s|q7 ȩٲTr{` +a%v_bݰ/]I +*VGs3a-*5cILB܍&fE +m@|7 mzT;p~+O$$zc.$d +p: rzO|XR~ȟOqƈm:Fy+~8e5*iP H#h0tn2\ fk5< +a)2s"::\QCɚd=CǐZEq.WH檠GfC>qG45|Y8r,*<ԃMD'>7BsrYqpێs׷lyU ʯ,cٗ÷#:FFDqt ,$[0bqhf}n2iu.Q\SOn6Z I6>bO͸r\Avԫ*.)Zmt;.ѱJs=a9D$2F?wNk%L +ʥ埒K/6% fbDхCnN?͒[H=Vu*B~j~uwz*@JF3ߤ +F6^seJ0ܧQ+ mww*|d,Gp\q]dʏ*NESW 7wꇺ+~ *ųJKµ 7:uR75_An'ŪOhO8zJ2d#D'UP;uQkh TڬTSTZHA)=Vwwuԣզ63N}tŕ-'kw)J7=,- +fQa(_S.yPE)e3,Qn4'ҢIIK$AjRxw*>r]٥~7V.4#kiӶIkHF"I|!t |V:Dk +>L9՗OaI'ye}gGTO0-kQːy{-W+8RnqLÚ {M!XSYӫ% 68 6kRsE],'4O8ht4%[ӊ!P4&TVĪa<:X nb=WdʜR~>XK4"j|bjTTY )LKl-mGrOB7y/G+Y#nK$"mלK:!70D8zFYl*q +~`^Nq ”ԕ'MBMH%hn`c&0WLtXP9@w'I :zbwTZJ$.ͧU*!ȩPMa_>)4> QGfɆcz}&U芏&̢ZյG6~ +ŴgQ6"h`$_ rfnЃdhZ)TBj&\ Ms>gbּCɳveҔX +Q;9^ +, (ELUSHM8xq- NmȹvRV _m  ۰3pW?L*KmcxzSs]+[hP:sPm-iGӶM +*:f2.&ﲿĨo +~qepO R>1`j8RJTT48Uq)% e jALæ KRu) + u#Ͽ8A590G1BӹAP=:bʼ4&e޵v+pdJ#wo\jaԊzu6tX.w*-KlXv |n›u+@׾-R*Quܬèq|[$olNSء:{w)6)>$9L0h1\*RITYԀ !^GHZ,4y<-o+1Lq-Je%=Y[aSNF]rVM$#h" +s$xUAe,;5Wne袟#0ըWi 8䨳3ʒto L=lD-pAD+7CUZQf | M눪w93t#;/x ?(8]eS(36#$rx%%_65oFZܥS*$NGN]FwRRr׹VJ]TRI{Kdqg~py lM<_Y}eGQk.anZD}v4[=1LbT&ZXhe=J-{ԯKVu +ud+P@==)Zjs[*OWd~&9j~bXtRĭ?0 IuInU=5 M);q*(E*J"4*q|B+Y؞᜺ӪHqTy0'CGu>242ouDI8)3uaK}<<7yGa6Ro\!t-JGVQaD|o/:'bOD)]#Xewo+A,5th8PvDUP!$G]Ϋ2[%BN8BTJ3}߄UjJ[pM/]D|>P=9 65P ҽ6hEzi$>kqf6*2O互nyܣk?Hql\rCI,yaJ膩8(X+ s8yas +CuWz^X|\mOFa ,j@VXe,ꢂ@)M͂R;KҽȜ{\:\L7_ťJmXY @h/U6BPdOd)z*54TꏼorVy?&^ѵeߙxnbʖ@<ȷXK,7jm>](WpОRO[ʍy',ǚ}CqI/'e(o6+yf|FRZRu #^R;*R{j{(qEmF$yzb@Juipp TVlqEQjV +S%)oZzYtl.KRB-)a&>xgQqUi $o}@;BW{;]ǔVއzq1Ɇ:ZuyT q\m!MX-meM".& +MZ2)>@@m[RJQ=q]Zt"=Rh2VBZ.ID:L@GJ>E֧"x3SQ DzWČj] cP|wk|i557eѹ)m;%DE^_I,6RA,$Bnk0Id(XY>}*8I"o֌ ^#;ʬO-ksm bYJϓSbA;-hZmB$U6*6L]) {q[L<>{QIV#+~UrIO8NԚ4] 1*ʦ0ŸKܫTʟʄ*'50æ4KJDJ%<:Xl1(ggJFE$r0WxJ#~z鑞dyĻ-nj$฾ݒv +GR\ĠMCi 7:ʘPJJA /̊[pu ?p$!Yn;*#éT$· ;,I ~ÆM -k$~rm5zjk N=+* .]$l9YDRhpҢKTa _r*SwA$@$d.B<C+~N[,T +ij! p8+ڗy9I13EM (?!ot+qtxY6?PC2;GЧsMip G,)>UΗVSaZl{|?ѽVVg~*Y##U%j +ae*-o/āŹ(U`0,\aџi̸Tj.G1NUD% &qv)fY<GE1s/hU FKIbLJ2W[ydD%(<S|Ɔ#,/#d~Jl$jq6ӱ]7iB"zbG4_-g` }4&1N]nx)oM 4 +f;߸Yu~#WǢ~Q]Ei(<.UA*4<7Ix|# +3y l [MBwV4;D'}#$f Y.P$V'E%$ǦB֚cB]o)«-yJB7[)RL Kt$\&PQq6t|'Xz^F1(T%ZsY*Q˥m! yOT(ghU}wC+MŻ)$a3.%/6Gϰ:x0RLJJ^-EI&$O,)I].) ,H1Ή|K;7|ܐiV oW me(wQ)P"KƳiUJ-|a?l`$Q!a8j)y"'Ie]'礷oUY;$ɿ5J2T|o >y:Tslfe*(7ÒR)7UeeJu'sȈCm\1Jar.7 +PbU5/1(SUq{[[Balsp +UD+zzjOt1=B2WyIX7{KHn=0.>bKx\W=r!'5,y?D(L] Wz7G o$ʸf̼G.AH7W._Ui<%( +K +A V\m=ǰS +JZ~>Ī´،(lt#x~R³u ::f ;5iC x:Q4-E '#c@ ~9{O8ñ21KS9%PGfQz309s&UxOÖ[O ## gU*Fڠ-*meҒcA"J4ΥYzՒF1^t$pCJŹ(A 0͚))Uy K%cD"t?, +N͝o+ -kOjÖKTbmen +ckt= +2d?IJy=nnO9%eYRHGhIד:⊁V(@ԞM4&.K!>}e3v4 6bjRIB(O}̼e$ P!qU*+ij\4ʰI=Z"*XIڥNV/{vvjˏ5h][M1s+Pd;m f MҨ**ShRBSrBWvġYɩ F_nIJIIaʭ:j-KITAREM·{V +g/T"BX (7JwcPzaO`yGUry[Kpdf ,8ډ $kئ;(%$+{]NQh/S8hw#k<8{4!{HJCa.`9ACWɲ}l_{KeN Z$pzaIJ㧮xb3rUɾ4e" Q2߈Gn<ħ1+ێE/y;C!nR\J]R<=RmZIlsi)?le`5/c(Jء8׾#ZE&DP '3&٤M6!aՠn h|g&ZmR7l 1[)3+<[%* N>_MCRT[N`%E%*kaor|Tj4 +|>0+l1'y-d@p -6%1N;=MrajqJre%KR jOʈ3>Î#ǫ4R +RK,O%,Z.2 B_YoWԗ0Z^`)U%e*Sz6 Jx ag,fHr +F;cRr=&[m!1vfre@B_r>qߜoь6 !A2}qdFCC?hZCBS#g_lb'ՠQs$\Hg_)|~Z<[T`Rt섒GȤw逫f=~h8ʴrySċg= #N1wM2Wk%J$n8[Mm >H=[2HjtQ4)q;>C6H1Lꆻ#Uem6 r3m.0]6:Ȳ[l\QP'yJV]M΀q1\P6u@RAНT@ Fjvb[Dɲ\% PKm&IfUiД\]51)7?p*ij=%ϥRJ1EJXBTQ:V*)Bf4(\FAUq. uVd&T"NYLksǕC/fA?6_ڤcKG(@#6Ze4ڄjVN.6A%6Vl(n8ړFtȺJ\?eS'sh>'e0f=*BXJ`oznI8ka26 9_\+ךjDF)]ڥ [<Zp`7TЁ71 MW} b=$!Mδ n"C. +8ߜMnt aGK =L(lr]V;H(Q7\#<9lL:|o^"$F?aGBI8U{R˹ʰaVR}HH+H)Z`ye'<CKY؛D(˞CLyܒA]Knyo r ᬵ)}Cc ($pħ0#P}Qk:kkAeL|t40P*DjB#UoU1ar +,PO8}РJPo4%Oq{JeUhpX}*h.yXr ҭХgXnPk)R!Ԝd ~QePQJPO=i/7ON?$b6mҤRFA>LQDn)EKYR1Е-r*%L#E}a!DE5=teEi,ȫ: + +F;%!H,r$>%Ԧn-(XvRM79&K/$l6|5Ns]=ZR`YH'-*k]1S+n2?dڪRn}|>̴"皵$%i.-=˔6|VݹF4gYnÏsj}>AKOƿ2BU}VnKMd$Zd%󶷕O+r҅|R-G8osӲl|ÎV=Y[AͱOM@ķH5\V^n7=9e(4=P1]%#*KRZBR@NߚtmetӅᰬB N;f*qvl_Aj:?0]yPp..oZ&HJA;({kTٹqGQuRةq$ c*h&P SGOY&H`He)H?l4H3S]o1;Fb $Xs<늰E5d^"ۨwt1zTxu5"?]K{p+xUҜ%D~CKhgPjDZ(eg7a)nB5;,}ٗҦB#R 1V%WA,6W2.; Ɍ\Rۨ"l;Fu۳A iAWg^pfޢs6>%KkQJR Oޏ3eNb3Mu\9A53Z.~ Sһu#r{Nf#^[p]vK68~!7"LO +}k@A_Mxeqm'7~h,z8PA("q?fڔ+I)<ɴ#Tvؾ=u"@쇞PmYAqũ\O zRjIGhVfE<ꒆҒT%)rI&/H:~~&pY}lke +|>!{|,pH|{Ƚ7Fǫz~gFBv^0GPP";FNu)'B/3"49o^S[o4"8xya3G~3CӟnqSrq甔)#|m: +UQsV_Z8Hp>^jWq2>=R)%S5]-NměR$^)D?wM "^dͯJg$InB=TH+=L\ , CͼX s⹔hkd?5.NŇ%;7A$˹kcØ&+nhH<$a'p7cOAnX*R@W蔨s=Ě= o !Ɨ[^Q>4T`r\E!Iu1rQk-v&{NWRZ1ǘQ5k2O64uʇt*\֚.9o0P1k:\yQP*II4*?x!<90"3˧|g $̵`Ro2i>tZ0*OO*PGJ>ƪujH$qa[9Ewd xƈ36Ofa0;Vb[WZn5n( ꖛ F#uuie'h&ݾ^.8 V*:q-DGu)*+RSdk6m:T֗=IeHH'%Aav&,0&Ft4;P7Hѩm3䒮4: 7" ^/f2_[$W1rVZdpH"OLʔwQǧJؑmRflNyNVMR}g{ 4:NİP%$T ɷ$qZxβ˿!¦RUQ)IT0"T2X_Uw}6S"YKl%~DEiNbLs, +c*;ܒGuG:۸K`zZQiZOq>ΐ8Y#~[ w>ʐnIRGSn0X?)(+dT2J٤(Ԫ$$?pX pS%:AQ0Q.6S)_3TSmjl)j@]4ӗUarL:Š_+0NF݂t-0Kլ?(ʒ'$)k 4.N6Uձ7afֳVH- .M:N$%Ǫv &,ovJma*BP^9I& +-)[6y%mMq'zKTъړkA,^;Yjuqr8i.EjIu%=5iTyͬ ҡkk\Dʍ',d ln.e|V{8Օ7|~yF2B`Tt'DuL,SlvɘqI +af֮^ӥ[SIPIyjuRe7֔$pB+0g$VeO8ˬ2T}f- {~~ECe^W*!B[ .[QڔPM>T>H]^_WT/'ދV깅,>c.(eŁTNחQ*$ۍHZ)%' L$8 nSlY… +k Lr&?'$͉U,IlTx O$@9Vӳj N|#Bu iK,K;@*&# +62k3pMbڕTydXdgEr>RnQYjŦo49k3u@T*m9)`j% +ꕇ֙qnO&҅^,v t/QLI/ɺtn2V['<:} JO&p`;{%_4oS,*'(C.J<>!:~ o$]q"Ꚗ̇+VP6>X9Q 6}oxD)*WFrkjJY +J SjֽlvRvi7ߟ,2Q_@:DFqrBNiO%Q{#h*6+ǃ6;C?6VRu8~ȔuӤfsS_J77㷦#Id>"p[#`J)]ԓ 6psRnR-bDžY{09o0xRf,Xu@+I"Î;a8^F+HRT&݉=8B*y7MiUU.%Ů"S`U{{v_ ]y$YlB5Ft0iC6<|*fNhP:C77l!L[e(CZJob#g#c7*Qy8R&YS`',5S|-}rtd\7DBu$\[V)ɨm i芵]LQ^RI&ںS{%<l1*Y m,0O–\q#rTlޘDGhμʊRM M4-a}I +Px)2r6&25,GW#{H'tI98I Ja<zQuKZ2uVNEv6W*Z]L!Mҡ'#'/Ϥ%WwxVQ&z(A&&!sYTruǗF-N777Qi0\J9pY#=N&%Gtڲ37%`~ќ  T'@LĔe +v qBs-|*ʓoQL +r1Ww/:jUL_?PVhiY¯RSH*9e +qO`RćN+q.R/T 6:'Eyp)9>TNں r 6Ӏzȴ+I)R6U6RV~=`{cTTo 8҈t':* BJHTb;U +qAqA +}K3ARд_6fѣ4jܳ hc"X|ғ܎őƭMٷlu|v ‹s27Aho'5Eb+|(P7)]sxziMɖ@e i(cˋ!(OS1OmKZ#q Y +$ xZ) +; uʣKamhSGd=(/ԵKڒ\ n-L(swZ,JvM,/j3 w.ux(yQJ5=J +?9OiH;:P"!K[yvIʯKzev̭@vQM~F.Nu,G +/.2u(i4קK6SO6SqA('I1M n(h8'ЛsuVP.cNwxԶIqՓ?H7ˁ#XnRvaE"RU9@O@4Ay>)EXaj)]5TKA`(ZfIJr:C⑅^UQ)ڂ_B&[mS o <b477S])YAJ! 6X#8[ ʚqEJ +(HiYjKHi; +eb}fP.Rdf{(*ꎼnoiv:UmCuȥH +A$r0}- ||~h[se)q'q:J#.T~a +SjM!.ԭB6aMj2-j;_ls5.\ME/Tq/%NJz)m+(s+J +J`/BnwM0ʤj (ұT3re_MH-Q~i'өXh2 Wq&[GG櫲țd{>L|[_Cp1+Ojqkrgm9V<5JI0V!Rְrғ$w˺ `_tԂ †`c6po +n)D3Υl8ɅZMPfQqa nA)J<1)6m-\Ǧ| Iԡ)Rx}ZO]=Qo2H\_؝*sYũK(O1DҋE¬иA$-|6PPE6Y; wt<:j"T3yAЄ*QjtݠWrGeB%r>Ar޶Q:TP|o9?*J5d^̷C2N +)w%:ra7tv’9R?v9Ԅ{j #dk^ob4Q54*+hpt}A(JdxKSI>3W fHm: @uG)O4¬-.:2"d*L$s"ƤDz{$+,+ao.nxf[?)f71ac\/"H ՗ڑm@)! KHg_tNuISV˄KOȎUnm𛑤afWƮ̮> V&ݿtC€P[/hnZb)I:{}Y1nCQ6Q-: +& E>}lk#4<>LVjI5R'[):%Jە}DM<>\WM291iKoT@ZlCQ;ہYēJʷs*AqJo'nğ`^Gc-V +uyl¶ +R3-78KOک$ @@Wʅ1<:PvkϢ{gȏѓ\tiG:D}@~ʂzJG8ڟԦi'#.㌰ch0;6bBG3s!@ŒϹRJ''S, &;?nj^'X!4i$S ,QZr +Y*Ry78u}ImjbeBD9mP7; 7LnuR[m.%%wG*RM30䲗H PH2RRϓcSl QM ;\ȕfXuL[fag07hYJNҠ/۽ XuyRSΑS>D])*NigDUᶥZk(: KmљO>`Rm'臂9:.Dsn 8G@:-{ƻ|JJMǡ…mm#]a06'WXbq4BСb䇖ځI˫I5_eRm+ii B A"ojv=9չ*JKN7 ;m}1HBiʝо_!XreY:3goޔ1hJ$-hӭ!?%`kFB +9 Sa[r9b?2@ZT~T]ZC_iPiwڗ6Lh(KjTmǪ(f\'#<㲫4eBIR04L`aK@Z/PMh<$i6Vt3R* +1%6.;TTR^H)#Bxr"LL,Nƌbi*5\maĮ[)9mpw^.Zzyp/9ۙ Ri6u@*}`rsk|8lQ%DsfRO3zbDi^Sx3)z%IL+%.h(Vʁ1K:h*+0̙D>!ApLi˷iG;aU,fɾ}`-NҢR@)d \5{H"9$-2t>S˻+0\eԖB!I:GvbnuZf9N8L}VH@ܻ Q S)HD&m>^1u%;WGͦBO^-MWѩ݈tGYCe-}HË*bfR[ ʠ*Q<:'++AR71z?$##g*s"mQt*HGgWw- p^qQ/RYJS" ÄDktxƽ?P[PNRdYd*Be1C$S8Jmh,踸X8Ҁ܄qV 4_^/7 [a J=NZ(ߖ!]jBrv校'2OeUK,KMrSϚ}K\IHsQkʝ FVf[N:RH zީǀ:56M|KFe(-HRkJ,X< ׆[3Sk+u6Po rMrjIw;8r+65Qs1q!rr'K$ +ɷ +^z +8eĦfMMKNpG”5b.ߤ_^ v&,#M\sd('I?z)>ћ$0]HB/cќMj5.J[\%B[I@!+fb^ܩ\cRҔ1L V<ߕq +I7Ao3cFK陙qE^K Un.}$J6@lNka"bAjЍĭzr$w/6"˽:u t]j%\u )-LerKJP&+P"Y9P:0D`\o\X=)')sjLw2W%RO5/_aM!)Y.m9q-!_mHc Yv9YU׏:Nyu4Pi"hm +uƗcsH+Q$a'PӪ5&ᚋj~:T,(_}gӠv6#v0؉5m: ܧ% QSJ=Bye +qr!hK-gl>ts늙TTi[gBiVN`^BG}SĤT-8E㷑iVVmc2Yt2P ?XLBrPP +ROGGqS᦮ xZ(LJQn;Ce+)O jUT4*.$_S8zM5%urYO9 Z:GYf; }/+|,Se.2/d<FM2:MU#|,;u2KyͿ檯lQG@>'0}us*ͧHaaC?1}L` 1MPQـm8~ES >Q*>GëT1,>tM8>mRx^`~DԪ֖WFXJm쎧_70+ኌT;ۇЄ fӁeP2pJv6Jo8S8;9nѻmW2k9_O-,Z3+? B0˴CHmUFQdA8*SK}}[?v"S"P`dNLE^|)nZ_S'DmW"Nق)Ų|(^-dW={yԫ->ٿiyi oSj"fIl!׬ejBWqdYV (mx!ZrS=UAnUwIW-q<%tX $!Pml{;ITDPv(H0 y[H5T,pRXbg$4P]E +<zZZ +\QF&KfBJmsڕCa6Î4{s\ kWs , +}W&Dg-DʘEԖJ}Ev"i !D n-x{2vM+;_S/*KRi4x+NSKK\5FTw҂C_IP.ąD.-{a]Q ypm46[MPoUdTXT\/(JJZSj(% )A)9x'iěWYy܀>DQ KfsK-ruJUPC"-#%(>:6=öfS>ZG8FzOLZJFCUZQ/>ѽ\&̬]ƍ$Զzm TuҼ1% +P@ "èVro|31"<,V"˗H[.Wµ[X +ڤiJfdD&xt/[?4~յW%uNDDq<:(E;FfM},K˲GXP{':eHb +3G΅T_KJ(-D[bG0.aҚ5JڑS RJqxSH|%'9L !~1↲~&"ijIm2+D0 R|!Ykܶ:rZo-q ad <{&ԵΤgѷB њ,@iMEscSǔ#4%k~dzZ"΃`~d~zTS2íRڲv#XnHw,ܼRS9,RllW_iQPkm# ^y4d*UY&R&i7l4${qO-,s.VՉ +CD#I^6$vxYs U+`X`ɷbT?= RYK21~ܻ fq + 7X}Ŕ( LA#+ʴП8O:C 3 +Ô? I73 iQ@E@;3iБxlPsǦ")nb^ NfR}w, RXY%gg&ޣ P xZ8HU%olcNyLS(Ęx핪R(H{pqY <- 1ɂTN =u̓{[r;̀X\n#鄞i#HqM7%!C0@GC[ ҈ +N- 2|ˉ jlTH;jbD^O$vVS.]^,|#1R4߬AŐa+3l,\?e*aAV 6k~Cjm':ɎIoֱr^P9-hi`7{Gk\X9&*n7I?a \ËF^)PrMa +3ʺI̛u ہM˔T*Źt( +CFC]5]k:7KmЇ\A{0;}ip/pf:}8T +zIj.˹gσu" +8K\z~\RKzd-Z%T2!d{ C6ԨS͹ǥ!i>:v_p4 ̨nFa +}\y{a.SK< ,{-k>2h:e T$ƣƷ*Ry'~\2 c2yGnA]pp#g pT*٩e}["=`oؤM]R #JYmaUa)7r9G}R1']CM{/;& +F + &jN/IBL^PHVe;c>P4Lb=uUX^3)ŕ<1uu!DeXcfAL0BP$g:n'c;hee(&@cCYUOe?XG*MyB-rl;JecBfz|ξBiZeF(&أŊ㈒9D<=8 KH;O~ ҬEf9nKSzJW0eGZaqkf",H'%dwU!kJEV~)+7"*XqVj]H 7yčϯrJJ"ؕnx,K$KMdD^:Pe*:q蹖Uy~q +Gvc*}%CaYN ;A#]ba~Ms]PjpBb"0YPhb'm9UcJ{,ۚ+3 +\**Cj} +A@ʅ,w&NѩpFLeLRJNpW{_ \yd3(r[m7#3 KM,:m٤. NMvO]e2j<NYg)j:! (^mǫΥ=ۃ +r3-niCi6*Toj ,R-GtX柿M 4jRy +BeC^7d]cI O}^6J\f֯\b9c6NB$!$!E6-'bAJTt):}<<"UpҊ6I@"^ E9⭘6#܎pFjeB))Dn䕭 AӐT&ܟL~(tW|,!_E զoɳnRP@8N>%[&.Uh >cIr#b86\T[Rz7%@EDz,tV<-f$Ιfl_i%JRYB +A56Ϝ2,j,6JI*8#j.vv6Lx,* +@{G3&XKyrAyOPehKӈ?gm $ dꛝ!u&t߇*>#8c-#2U'%y|'v)ҟÛeD)zcfREW!IW<PFUNE9(kCZdFlPmy\6 M!`iӲRbrbQjŪ8R?֩C`.JX#&.gRWZ)}RUrk.Bt,KsfCg-p;RU}%\u}|z.n3jr5dn*Ye%P>E\Sp"=qD]I IZ?#0YH͕)63 )p0)*~ŮJj +Iύ! +fL< 1GpXC* +mA,XiNQe.82I9Nh}D;zFiZQd(|@wڃp⬂Vҵ)aWUGVBf0n;Kx-)ZI '8cA/)挸^vOhe`q%_-d%a$A$ Yt#%Фz|+J éPr$sJ +ٳ4*n8(d˩Mk N:;?mM+l+\j>F֝,D4m/ƦPu.9oMГ8k+qq~L϶Ngu'*NCMVҾS^['42fUj΅T&8d$Gy$},8M~ݾXF[!;k i2iOhwb.He֔Z B.BBGwӯ?W *sbQ6eJ/\E`fWTπqC^I>B z瓣(9Oi6SS5[IXL%MJP (*K!$]gc )%I*`Ml9Cs$.}?hpR\-}kÈ@f"Y]մ,\ ?ȬH=7yB?Bpن7KIKMbh6OeL\2z2u2"v @jEZl"ϰF`HDH>r']wQfQ,IۙEtg icO7!]<|oΚ\@Lr#MQQ蝾rqP>ZUR4=mzq _ޣɆ3d|@;.-c1*/rHqA>֖|,l&#I=!ښOO(2p85Zu]#1*-ϒЯrC{ q55*+W&b,&qe<+d)]ص6I{vS VWHZaD@;yk.xS0y&Oǧ ~Zw9bԅm@٦VG̔uLYp .~Wp3Ij`:'TrhET22*L!s)w䅆@)R\3%[oӖVЋjsMd`^v=ј)u$(q(JucTo#uchNTVnw35JKB7٫7` L%O N׶UHh9_EX0-_nY$6fG3,"þ$WH>A24ys}ʜ.EEvOq_1DS 5v䂔 8\=~RsEV擿8&N4x*mR~iDy>ePIP1#Dj@դ4וO ȍ)]m`9Vj-hI$n +FmC͙'SSCPJrPXΔ=Dv2712k8mkI]m[`/%AI!+i[qФ8WigGgasNĽR(1qaiG([ҟPqU +|F-8_E02ܔ1]"DV'( U~[ڒcA-Qz9+RHik ĂA7(2JRn ژqvÌOW0(f7)pYJ-pBr۠5D^cǝ%D- ˳N4RHUv67oR[#ٸu>Ԍa1GUA jv[PJ96GkAuCLU)0`$2J-4EcMSXmҼlRY?dhN4`egy&n0`J ߪxʻ$3BTƑHw+*R8Rz%4Ze@ +`ŽB9z7 噶*m)FCSj$eRIJfi~x̳Gm^PPqH$M7ʿ aRR 'Z9Vi~ \H=[R~/F`e*ss#p)AR .߅R| ++ +x;~:Axm0+GmJdiBCwP3*]w)L!)TO?&R3Xx$}M}8@u*=[bwy_7<-*U'qg:FK93am%LR,AK~xY4JB3O\Ĭ{ +ᯆfRR̼U ,<Se)e&Tn|Č"O =՝I.m1e Wc]b Q`qqFJ? J-f_$ztyjQhOrT+\7=Kv O05KRDǥ&2wb2@RAlUo}B;NqJ@O5N^TZH]A2ڕ@ND쒔x]Gsy:kȆ%IZ*N\ef qJ[wIӗNp'^ME6?:q#R~榦X2HCe IQ͔ %K a$L˰K0ʝQaU6x?]QN+J[%o͍jԠ۲ e.@!S2f.m.O 1RYfm%VRI8mRY.Ǿ<^c8G# +R5Y_[%+)J:'2or6$bܣ'i-ԔYmlOoq@8Z2nTRU74B;0J.y{Ys ?%W%>T-^Ν*9j+yReA&,d=H=usl$,,{t+Vꈂ%L4yeh LXQ}Chy BMez?fBY;34ܰDιޚJKAi=ZјHͪFROfUS!Ɓ*@"wTsK6u 7WP )zلnJYiJ%KvwV[Q%;YZ[MitJa aROyqd*70jQe~j* +I%1.($9z;Y޻,D2㐸Ip 8mMјa9QU{#8OdH#\It̩%̐v!ʆ^EY^^G; ƏvL"T>Mk)>a~8Ït• VCJNà 8euŊq%Vi@C( {ωi[i@jPԭK";бh/a'Tϰ{R@_{wF/1(yI2,_˒/> LEQS~ɿ3e,>j^+*y?$OK%'#!XZb[8%Qk[JluO$}C][ɩ[SB#L5 +P-/G#SR|%ZwzD,2H*A O)ACʲb 3iKJFݡomG\XsCj/E<Ϯ# +ihKueB+X[Ma0k2E:Qn6> RBc&6?8\O% +FkvC9} +HncX/ͦOKRQI%;u%+ Ia+ SkGS8lbU wHQ쳈L/UTBkI5 n4:Bz:VwQO$I2|bXf$ĸnO=Vd)rnGkk +Q5@G<ʷ{Wq IeK˯Ee[<@qwM]1S}VJ x~KTF s>Ff:va}=q𡚈T<}.0\]A*lGu#l!15 + Ly.3wv]j\9sĴ#kG9! VWP`%%*蔁{u gZ?NU-I ˩Mґe+YP +U]I:|A੎a+Iځb\&vV!eZI& WMS2z̳ =bVJg"g"HdH4Xe ++EC&Rto=mHі?X[B˂ >mi _u1iq"F? +XxS 16,! 6>T +?ti:J\ +JW 'ɪ6>w MOow$H:Tv(#=fAU.P˟HeoE JEy5Z[@\ +#Єcqњ3{%J\t&,PMGᅋ HKtQ*WhqRI[(pGJRƉ(RK 850R8%jTj]i1ڇPliqiUIܯR2TGB˘_xIPj"Sbl㫑e}QP#6JLŶبp8iX}iw*RD])ld'n>NK*03;4ei!+AZ!6:,H쫏X^ Bo*-q8]S1yJ[0 o6|$P ,̰R,Ɯ|p6JJMmAQ 2VT lʛۇߤ8h-`uYK%lK#S+RRҀ(P*)m%_l}RS Teq)=5=9Je] +7"!ЇuH+ʕ8ÂrArfAW @;$Q͔q*J,Vg>+q7rmۏ1Y%,0l>P\{iq:܀o= +bfn9IdS( B@Bsn +Pk+Q՛c6TrH"I)*u-ٔ~W0Zh*<hē/!͗9{\_xLApiIu0RHyJ'_"}3H=F*D[\fBFfH9Tmlc>Ng5(]9d- .|wefY4E=u ye-tR& .q(qJB*%#)z 4T +U3 SR#-dwmkХ(I=->B< }БkG MYYv&f'{^4W)4tj>ᅀʈRA Ǵ!rhE riF[9';z~CV4kp$K%W!J i0ą~ώOhY&&uZPLt%:f>踒U'|ifzlRjH!h末>KL8ψp %#̜M)sD r b"bQ/)j6KiQ xzJޛ%TvLik&|$\<byU%J]:kC V 7ZvI=Ok0uev`PBph֛_HX"6fˉhu>gܛ|OD}[rŵqupBD}#)VkT3QQA6h}/f~uԪM.}neД6Zlާae݉ -P_3fg*ɱ_D҇ΉmLd.S4ꭼzlċCHtJ\&J:$p6M ޓEbz{%@IQ*Y^''l*HɳQ"i-W>g +w0p=5(<8ߏ ɹ:Nk-{A{FK(ג%͔ŖF$؟dO6jD5M@hBUͭ:(aOXmmF]3< +SdQoE4]Pp[ʘK*"!%9>|7I.TTj<\_%, C'9^Ńi +{U1 cGЭ[}}w1BmXUDSpy)o٥έ"?*U%YZsIqaPWX4y:J-tL4ۜlk>VÚ,ZZpmhߤեie|fN u NWB`{v.^텨<#Ǽh!k o|i;S%vg'lLܶhV@6;'WCE^{ĕlHn+IRɸArl%0ꘒHe-G;'KmͪR9s/da4$uJ(+Ԝ|[ofUdwciw%Kmŷ-W7O0Hnm2Sʥ%\zfj0]d\'no/SIU)V`/om{k^͜ũU[ eZȸJF$ZH4"iJN'ٴ7i ۾?x~VgɔYYVlmps{(k3N$Wd(0ܖ]H,Ac“RLabGqS;N9Vnc:EII[jJvX̕ ln,}ѣyU<-P*1q.$m5Da9؞਒_N5 S1:f"k 4)P'k|c_Rb#MAX6*]UcJMl!9.Gx$}jHUT smoEP~7I<^he iY$_'Jb'AìMh,<vZl$M(2j0|W,^M~L1kV9nrnDmnf 9rCҋn#qhؙIw=RC@#ȞyYscGgj5diCLj +CI$ŦU>AORX:زoc1w9uoۊJ[tòQ|c/?+yĿm'͔l)G9ӺhtdJb9v",E _zMt? +m) +ޥoű|Eƾ0Ft }\{Sn~L(Nh =rAi*n R<sK&ݘo>Q.x>] .,qܪma~Urkg8zҶn%;G=.ݖ)@'H* yfVmhPbUɝ& _R0m} k +v14g'-PnBB[%B &Wq%Y_VV+i<1?fKg&*iu-+˯dkbS\V8RR~w)0vJiCHR#v庋J ?ѝu(PWi9Akp@#_iӴI1 -9:ixjB>zZnmci̴wRpsm>Ϻ;JE]S'MKeĠz#`^P7#‰"[lq4.\BD'OmcRً`zJΝ.\[Iű$S_H@=?)~..YwlATimN +jmIZPܨw=fPѾ"پ%𔪀̵1JR@& \M4nb'C"4D8*$še>Jז|HNnp I).˴_MᔋF0a˹(aНqK,.(Q7$nqYnTEKmNI(cƿ JXH + +>/Tu5ZCjX5m7Z|GH3rFNMSunIp%hZG̐l1fu#V|ET>u5cu(R=d͞ȺRi ZE 6V2d.&*vu~Hmre4EE&MrU_DT\[j]"Sem]Jz‘(@\t`i *n*0x6үDŽ㉠R[N iEyS)FT_ǵ'O_ TI6>[XE$w?v f8tJ>:H FP=W]eTTÎ(r6DLڂAJW(zjR~- 98w \t\)̳ںr;?k-v D?%[y: .ugPg4Y!!5~qI~xRcPgpN&[A< 5IVSܼ㧌G?L95JuPӞ4fMIRJw%ituhGXHAZ& ʲEa<3* :jfRq'Krmq,ꂵLݍ)*`Ui$z2 I]o`}[cx__Z@-rDڀ'*~M]'mRmT6*EԆ1{6>P)^(  !42$B﹕-y!1x{: *Ed:7F{ƒo ɦITN/ېH'HUx<וP7#΋1;! UУm e%fJ]:kp b-(x-T<$CTb`Vna -WLX|o^L|rqm hA* J"3:c^,!IB=qflmgd1D >Q0! \o%[K78sX䍼v,-d}y z-4^t+ A>ѹo 0$/qb9!{*9Sm8UĬD(9z+}6pwg8"Dh%.i@V8瓎9Gc\㱅e7#^s*^ mnG|$ur"&;W +6ZĻgXiD +.#^$XU38}_D@;B}n 5OdRA,8:2mqi T}@Fij蕷a!9}arl a1i7V&-zNu ʁu\8#U t̰)ٴFb-sm4*7}9t:ǝ(Y@T;5Ւ8GH+0R8J~hI@!9I *L mqRjSU, 9 "44^t 2*y >`2қu7>xpHQg 0~"PhHG!5˧2Gek*PS2ЯWO(hfE:G3 #/o +,u696OhB'Q̸fw.Ry87ǡui7,)]IGMWA9j!qg\)k +t#k +mB|Ӕ٪K-&Dv52a ޕla]OFv}.9]r[r=͇rKN1YHm%vsORd2ݦG5Q IH5͓-?`@~ 8uI:ף Qp4ܩ.$8ҊnR})1x8X>=^d&YevM$k[^ +<ԆIVVRAqP;䤞鵽|1t5np̕!I!m-i@ډ)RH Ajt) L]BqVް?e[$5;'"w[k0yȦ׹=i3,N)#.TR?uGdvS:-d@ꓩ +Vqʄ!#$XbǓe|FDiƄoZ}7bk6(B%ex!|TNca93SKX!qFs,}1NvESq[Z|V7u˱rQiv |EA?s++W6mRQ&N_~6gIUp|CiLqi|*ys$۷'GIQMkyZj5$[Jj/DGwuIJuJl-#АprVJE:?HqHL5iecG/"|͠(a%Q ;[$a0SP)Qg%JK*SRAO.1k,AY[@~T9 +/B\i] Yrb sK4'Fv}:\i, a FP)kC+_Nj"* tzd 8d&ta\wxj)/a"~1S76NL6R\EҤEVxf3m2*u +>Ygr0kPukqhӭ)u8tMbw2G-I5M3Ϲ +a3q, @|_زw]^[f(ޣ͔Tlb*OQ4VI2 ͫ+p7ek.(?`:y+Ng;Zu# +2MЯhZ)D&]瘙lACC]=DOc֙OLw=vR~EYla)?Rxe^z82r͵r/l픩?Ҽ)C'0M1c劚S~CJ6;,4p\S@s +O)sPdLY +nA.uu8m: c~[l%H*al37V}+eJH%JXwڤM@(a&nz0fni%HJҢ@">Q1ICoU.͐P{rtS.PRx HToHKJ7",|UDfNQd̩ 'ǻ/k1"aLYY9ʈ l(I_/̆2.T|bD1KD9VT4Pv#($!3f CIt*@OKW#5\G)L^Gx$kyuH$s1DeQUACm߰9*oO.̛dَ4_\L [neoj"ݓRʋ i{Q;PH{E`;A}%q2ҟH̓fSZC~mI +It29}Ecb`aA0.:]^~AB"]* oG88MmA^K6$* +}bK@S02(M.ڤ/sz|u +%wΩՓu(TZN)%ɒJJ{>]0RR1Ւ-^G~3 +$yŢf5W4lXbPs:frv]>^-?Lh[R5 +ks,L:%짻*B~b 0jE5{6'[p]'UGT6WFZa*/XukIt9CҶMW22_ɛ>T iLMֵ_ +$ V Qe0꒔\f _:e%2@ƥ3m +[Nl*Nj>=u)}{Z)NhQ)h$k{IIj7 B鎻& Lv`i +A锬FXT No\ \13J.[$m9+ui銬'#qn8 +l FnYNrYTZTr7*mnH>Pun\ŗdZ[$rmr9Ȑ?x^x: +l/k9b0*@4sa6nqodZR:\pB6]-nxb.h!1w֚du؞:o +5QnyUŅ턉 Z;N`9æKɳ4*V6Mu:)*2?FI8e<"{ -:Z>g1SWsL}n*+!3RŠzVO(ؑzۚ_݈NFY@j:$A%-^mE%HXW6Jq&eAU[k\tnJ~-_ׂ@x0#H_fi/ӳ(eOkCiʀ? 8XMW\6U,OZ?t>%V:jW*I]q)^*BFՔl8ɖBi^CO#APU&Զ%.]3wU +J=-i(Aޢ<e}4<6i +OJ3e5* Rє64{R +mkz'cqGv01.p2$k onW5jfI1h~ea>W8㛘nTG2mEZ b\4gCaG@v<@܁hObr/ṈZ((-EIZ7:zOkVR+Bmn]L:QgSb CR杬VJVͫ:4%E$yӽ"Vae\M.#JRGJw-Ǐ; b5VLJ.Ӈs%Zaa1,L^ ˴2r l!駣:Ui.C'6nr ;;4s@i(iw MS-0q--G7+b&tօ$obmiؠEWYXW1)9TL̗BC#k- B'aob % m@H!$jIlaǥVJRI:a˔/ݮj XfCm,Gԥ\@N!mQ){J1&`z{;l~h4VUISw-lXxmR=e h&2iRUBO'b7;/K/ 71&Ѥeܷmx^TSze"{|il+L"I MR).mNn>mbSbYmR/lA'X[#_|^o)(F͌8|S*Ȅ\!ԭ;mp[E*|D@{1Rܥ:۟$lv60tAA"`Q9j2լ1a*(ZOF,*)IsgBqj3Gt)å\h &jԼR +vqLJԵ4yB$H>C CZ/ן=f@߄8_Zn'u-60e93Yʃ~j-r+%V]q9#(Җ`JSo;~ya&*M6 7S<_.2kJmWk\J/vC~[[AbnOZdP<ԧAiFmV> 7)\ !$-JE[ a–֣^UN/#qm"! [ U]Aώ;+CsoL%a3R髩R![p۩'@Xsezl|#wljo'&IjٔT2ӊx6muкȫSِ[Øei67{cΉX{ XNA؃7[D,}90N+説Y + +0C 67J=5j|Utxu*B37pV;;o>>~KmiO@9'_Mfgq9jnpFFvMRRub1IثV|1j[i#2T7QH)*Ȳ:Yt$pvHRA60_u^H"1RšJrH=Xir\[y\pm+hA/-qj;n/b,[NJ8Ԣjb^\T:ӯPxSp69fH$[ú?_(}(~0&5Ee؇N+M#J'*Zq a#B YD9ă@RUv͵16JFd*=q;-)%_2& |TjijΉ% ^M[TiI}F(&,PB/ P$Qexͅtj%@؋pI$ ( a9-a)PTƈQu7v)*|5}=UPs%AaM%dR{a[/PSl<-oSVe38Дu-;'99%41bJ'],$:VGFxܚIWmf;(Gx%sgT,%VG+Zha&ACBjh]GVv1KFL*R)an\-^nVtX&4bmauw_n'~c֫.^6'aJvիsfye\~ln%i&$y5Cd W6"EɽM[ Īr7floG9$k>1!Z J%Әhb2bEN8ʼ\#^ 4"*fu6ߣBjVۉLm#ЎOc;O#hZ9UcίHL? TeԠYȮ`PЎ PjNQ 0*M>RдXpRaF4Om" +w}4zG}jԦfܗ[KKnȣIL*t(R/O#Ԧ,ȗj2rR/'u+55YP79F7a8˒XB&Y?Eiw,;*\55&Lvo?aaQ.gb>›'I  N*U5ebڝ!hUV,fe>#+ylEeprC:rHJ'-cB Yp[.I6&ڴW#Jpl 6ڍoۿ|Y7P`- *]vQbsaob=+ka#P\Sy\V>-6PQ>kr8rNt[P|rK+)WnJj٢TOI}\P`uED$.mp1ׇFGqA!)̛hpMrtaJ\Buem3+-$$RrBIE9O5>;)iv1@rKV +7(ܫb;2}_TQ>Jӵ4GpG3Rw=>s?DG +a'5O)QR'FZ}Ҡ8+H~VâBNDOG8J}v0'T>2hI25I'Pڏeč,o:ѸvPf%7.>D?1'f#ZT\$n>1% ]?tX.k˘a%Cil@Vr O$m +?é9 OE$zq0W[1 HW0A4b6OZydJ}Pjf^Mi! @SM6W8P|. eH@SN\I Idn&IYf;\%_͆h2"uF\4n6Y>"t2_iKu۟CMLAO[H￶'K8mGZO4&#SΚZ! (z{mHI'޸)"FQ)Q8]UI3"W6DvpisBrv"$DČzBBP:~IaVHJVek+=3e=IBG礝yTmٕMШ*[dr +c੖j?Kq<p ˾+qҔZޘdY q:CΖOɥѝ*PW5I!nj:;JcL~`NGҸ].R6 sM&ؗFV?!Se?tY5`:wE±_p̠ ml8w O&wN:5vd)T$_E@d|_wڟa=sR[g+hEP7)*x]ԯbc.IJإ,9v,NK.2Od,@v&%4+  C'񒺶(* Ğ'}JtJ%ֹd",}THڜ+RP:حGd;.H+G7PBvEց!Q _%ɹD`>&<* +s;zaW eد)@>R\d4Ve]mG~aV]eV_ݻ}ݻJL6K% Z(Z-ۯ(߾ň'C% ʥ?%8X#p̉eI#؁M(H*FU҇ml{M{*4JՊt\bÓ.>Q?v#c6$v@` +y*^hߔ~0TL칷)憬|.@ECZ~*-SqF2FA;9*Nb'HۋeR8{pV%PjNHcJ@Mu6=BbreveLVYMЂR.RUZ +Rn$_Ikk>&^NҺ,O rN_!p~C=P]ϩ0٫c,@&fU*3gU+YXt("*w@?̀r8z*Mh˼r&ZRjە- d Gk(z[q+&X7w Ԩ+j`<زT-SP}˙ JKiE6A)KI6w1Jn#@i{ LɀesLl.@ +Ӈ(Y +nZܕONǚ6Z-V!XJXõ6ؙ*FWFe%7q&OzPj`ᓴ8C7Дm3KcIig$ԭH0Kd|Izd6vH1ZF^LbZw25 6ڎ,(h6?)KWCFre\6Ѓxq*Iʛ_"QPnYlVZlBPRom#nf o"ܨN7O;!+qARøر@pSJ\M!a >a 8܄Hޜ*7zzZDXHK(CJm%ECUiɵʍ }";/6yBv,åMM}GM! #NklMv{&d6"?QWoJqJT?tI22˦iQRn`$-!AkZ{أ!s t$$TB$ؓeLV[REդ47*Z +ITw>tQMu^Ou36qw9h"H$*'n:UNxDfYYCPvꄔt3ȤBТtĨ%\eN-G̙kEB_i ޒ q|X wT*W;Zxy/?tFXXWYՍmu%]Vּ͔jVӳ%uJMK1{5o Ԇw$~` q;Gfꂔ%II߆HmM16nbeҜÁ96&ě3B-3f$'ꏈcIjI fQJ12ir-d+/J-//* DaED . m#^5MѬ:PZH(ZhRH#>!DBٓb=etJ.ƕ7:E$RRABzX <3m1/(T啶Ф{:Eܝ ]'aSΩRIlVs 25N8N[L̠I(8H̴!=ڍ#/d4JگR\ἷYsab#)q;OK%)yĮֹ5{c.?¡ <$GbEa/Z2\j.>Qtt±]qw}ҍ# ycفJ.m57 +U%:qv#n)ҫ_pӷXHU3ieO)@駺7r+z8RRE\Ԣ8ۘ):l+;O,jH+t\[L%*"{"[$+6:iʺ }"`w_U3.*('!^rӘ1b%{dj2܄B(ŵXv㈺aJJd ;lo~Q7b9YC "6rak 8$)Hl(!>je/8nW490; ]Ɇt&nB&} ÅH΂AT*6϶A[A.tf + I#i>D|5+b),Bhr%\p,c=86̎)G4L$_bvq!W-2j$[7Oim,xBtG E#lÀvKϡS#!O+4AGIYnϙ}ҷm\n EhZf 5aGlj ID>)aC+d/p>$A2HD4KhN`RR)j9G:<fI=p) W]*hҥ<ՀV2 OwQcOвK:Z"Iڧmu!$:%ܛVVTy[ui +T:, xKI\7!)`IB0QEz +a*bЛО'sQ'oCu'ʧXݰ\}@=JQ'R8ASP?[aTG18UҐp? 5Ќ M+S.V@3xL.hX[ib[ +m. 1{I{k;PUjJayRHRe +w{ e F?d3p+0AU+S'Ns8؋(sxy6Na;IRTۨX}P7zT K^mžFo\1b)XfeNH1}zXUchE>wG$zʐl}4NWbT{jtDRw?NM=+"44R{$ 7//tfN\z5 + -ɕJB;Gqg.)\9G| qgNIHe9 ^4A=x^Z9$TzJk  ;젂Ҳ ٺt: ]J9_w(ddQ(aa|4۳NKrh.JJP&lsv< +#Lri2[LJGZHT.N9jEвNs-¤B aK*˕Mo:ʓ&lJx2ՄD;-!X†zhT|/G+z?I3]ze^ Z4Qr[ξNgVl-p15l:tA +`\O 3em +=I:0 Wk6wcq{JG +PAZsduhv{Z{7_-ˈ6''vRc(n]8+X2JTwYj% #pڕP7uN3n sE.yr@ZS*d/EPoKfnvNKT@q9W\)TJ;.[tʴhoew-OSgFYIf>cp=$*15D)E%M[QRśmN0<~wL2HhtMD{2'^! ?iw_cFfݦeI_jBב$.MjY٦tX>JK ﺔ;ha+6{~N +K訣 Jōq8`ɤ"+l3tҩFݩRe}ZxD95B@d;RRn7-$m[^:fii9Ty". RZhF[9?Ϊv_AP?7aD 3~1 ꗖ $_>>zpj o(ma/cA76XW~Ka6}W &"=K9c4 \rGyvad?}UYq +IZ `DARpH6 ;B^9݃a PJvqf՛hk xUҒVHm'p)>aIǺ/)Ǎ23d)[ԧTK +VG/vCiPvp,6Goq>XXι&&7Զȸ(Z@bR UU1n֑O4)O(+@W2B9•`|)2C}Vpמ!srrFEE,>pKẹ32w>+l|똴xtS)Rkg?tP:&"قH$& $|qzbg]Y>i:Xnvτ) ;c`up0M +[ S7ZJӰcU&g.cX]iI9Fw=4߯4\DIWH8KøuFDh,c9:v}0[g-ּF9g}&=?ymz1~IjoYJ%jP* ?K +-7 ZVlJ>m2ԕ`6]];+&8MҰyYJ3$ MͭgOPzv#yQ٪7d'ImXM5{H6"@w>fcΏZޠaH@ur%G'6U̓h|㠥A1_øE^4ƆAsÝ~4MXiL /B\I0U&I XnLa* 5-2EI> +HG-B0.<%pv q8p*DlLp{-$pN L[:hza=?Bq-S$:<v"pL>,YA#qɜmk~3/Kf뛘rQ՛]IP$juE;rl'|'!H˺|#ѽFr-<40b}-.eW.+N lv:~diݖL&1W8Jv!lGPWZp3ʠyh"r_-0Q+Դ&Z_.(JmFQ* H\~%%=Âfs&GK,wC +];X9D_PRC f$T滥ĩ!iPc!̌=P*m!>eG"}ăK3Mm6w&;*nu-rUԫs̢ JwқQmu,u-^dIN+pCՔZ#w0uHVrVf<$gIZ $YʁtG),d4TJ$q y`1)D=?Oy{iuhx^]6dRSx XktYF/fY!OʬemJqVJ- phD~s|Ӭ +⬂|&JG|oeOs?t6 ~׍*QS *|Pm3uDEIGQt +}Ve.A?yN8ݕ~qƒc^SCb<˗ÙP}~P鎮rkiR&Bȵ܍s%bS(R|c2ӊ`d)'e~1\1n&*VqU5JVcNr_7i@nΠj!#u ~"%CƑI6,\jAy|T%J,ɕPBx {RaRd:#trӅTȹ//0yTOz[j<ΰ#f +2R*OSn2 Z~f̬tZ)_pđ~|.OxEr=mE:[roiYy:$}dv j:H'3q*A(ךJB3YGGuF>ji7Ֆ$uP錽GZj +a! :SAo8I, f2~jU.ԍd٬QgQsaCqnO0pJKa>LqA%#0+.Z^e faY<*<5ysCPdA*!J-[\P?1đ;v\JJBT yc1'@a3u+OVV,JEN g;QuC%5.Vݔfd:8ϥvkԳt/L̳LNwuVR7.&1\e)dͺu/է^[Kw4fBˬIm𕹃1KP^& q;OLSmi7$7Vŝ#h)Daꇔ*MIPT/ه@ԥTm#\ؗcH33TCra{Mq{a:0cә,Un@9z!')J^~KǼ甒I9RJx$ؔZ$[N+ZRUER.RS&aZi=wOyBYZO.CFH O(=rIHory&UcK[HR]1 :H{&H͕G*UxPˆҹG p"5o}>ו5&bšp\]68T9Yt ,ui m&?ae&\Kw̜6U5ٛѣFjUitzLeHu%Ÿ[-Q r|t?$2Rά! ˹:k7'9jKJ;s֋\ت~^(yۺ2NVR;)RLF}.B}TYSyڅAŻ!ȩ;YeK)rM0Ž4ҁvЁ1$4jZ1Ԟ"tq T.2TZ̝2: /7ӇVw *C:T[d(ۃǦ!is1d)`h 1 fhulNNxfba))5~RnGH߫&FzCk +qZ{L3Ș:d)›?(BVĊ擵sB豿*v?"1 Ya‡pI6RHW#h\'JӨP^lJOhXRNM`u-u\kMݙAZORDp 4d"a̪ޱIKڛS &sn% E#%eѓBP N|ќ̂ѡLyD\{*X y#8adHw`YQ6រҥ`uQFƟhʪ +[068۶ǮФI[B{O*,FRqrRMP%9O1](2qJ[Y+ +d)$ txQNPp-ohizK +O}jLa9+dnZc<_inT^ul,BeVݔP [웦c*^׶hgPdhRs.cmu1))==uVD&-5!AҰh i<2N!$0Ye{*ZQ;`'PtQMdD%='%ڦ],6Wdt߬*ZH])Hܗ!" RSh!OFup H +Z+ +mvmJ6xhr7Ƞ  *Gnx8XiNn!E9騆ʻ^mYłԂnmu!(TZJ$yD w*ݮx}0ʧH&Qq&t*oӦ&¤d%E;9NKĖH}|Nz0a^ĥHNMb&]i%S\쁐nqXqJm[s] .|cV4@Av͚(N5#2f, J,1 RҖo+c[7MҨKgBn~Mi552}mϤSR9)iyeImIBCaDfPM wi-Jj +4X!BD(bE,CT9hkR +K=JZ H>3[Gp?Yso:GVm N)7bN$gG1)pk%ÖrT8&SVHREE c<@JlB_RI\Ú&xh-~oɩSnYO\4rHYY&H̵Br[J,a +IPi@RՕ*Rå*H#m}Qх0dJ3y?*u>rU{ 2ܺMo"R&FıZCmc~IC'~BA<)ZoU tJ\G—I+z1x^}"Q$9,pE}@uzdYo0݇|t Iߌ%io1ʕՒtc[C}tsRYa!GyF\#D^% Vd#{i e6 l8~5nq)>AhQ#@ GXiɉ՞dG⸲Vz/wCƉ&bA)Im}Q ܄\CIB’6aXk,>o6ۍ>[RJVF).2іcuiMRTGu@CsV\AB$X$čOA q=xrP,Z +%D ($P hIKH_{q.̒g /7P$DSYw~Sn0ICLP(70IJTlyhM>ef$8V?ˏT8m^;1 L*qGzϾ+r@;' ^K/Sf6iUڂG#J Ǣ(TD~1T[#H3:~u{n_e,xE~pZ>lP +Pa =0*Jjq68;O=:ϝi+-N45RVd(b) RsAG^34)-*ZV`GqHpF=̆%gLfO' #I*AQk)C0 }qv6 nӞBvЏtX2%- [n'A< =(>]-]xMG + TRI׳ڑ]NRb2ˡ)~" =EW'_xgJ^ucN&i)*5@rU\A`eBPS!tGt8ߌ0܈?bqyUQG|V$Zڲ9lG"6I c0<,?jL|Nq ̈ʴ9Y~:isJJ +BZO)qnO̊x_KItTʪ6Z&Y'6GJСpN[phJTb!kj5LbfJ젴lr20͙A[-G|/!VY@ *JpR^XP=hsI~CjVE&XZ) +ǽ%*> +u͐(Y0mġjEDns**H }qצ&NmUWfޚ)sKdqk$^[XMCT&,"xlKcrm7^#]1r :#=jO!?[f*r \'8G?\&ϋjsbk(#;JI)YfM.ۉ(R:-u4m,R($\q=KӕH*-xQ,iS4(A$r趄DqSz20MOpk;]mr@B줛1S|jJfЬ#bGHVЍ"9^-5[aJniz 3#3kXؕ,e\L5Y.NwRi"D +Pk˜OO Mŏ +8OO6ʌ#[Fe/˭HEOJS.XL2\.KօOVYG5̀,/[CޱG62pT'L϶TI:i'<эF&*e]d:2e.uҦZVLj x2/]}7\S-m>/qMEZe%^%/BO ;W26U[^"5tn÷8i6R!>}=b7> nj[Ia&T72}qL4\F3ܞ>-م jD%Zm`ORڈ99(kݩsr1&td h:$&Ѫ[l"7DU $7z[OIǧ*{$K{}vT }jYs:ӗ- Rb/{dG˭)>u|!Ĥ؞Rǩ/!G\aUJJb.A?vSh/HJX㉿|M3'x< :CgPO^=e#I)F(w^$CJ mʜRP>B،MH#N$¬Y%$;a+W~c9vE6:Sp<'$|+@EXM<ucNg.N~pE3)aip~[ +к.oVf/ħm-2B|vA^zESJs8GC2$\!z@~M1CA &U?EfC)3VMl.bTuLu n` cPnW*vVZre<q)I*oݑa47VU +PS'9GmIPkP;Ips_;Aȼ]kSMQ&XPD +{.}+0j>RcR2ܘPnKi܆\E } &t>T9Du:JO(uXj$pSN $w5nl=Y˴ۻߛojtN%tޕj=\wԞa])(W{'MzaklH8?E |T!">%#},7@(Wl'Ч? -9+-JJ-IvDa,t;rR:|Zw_G|hjJ+G|!N rI?nPvQ7k6ay|51iLp[/xgIqeC*u +PQ6XXtSzcV&BڝΒ  wͅG?Xc۬3?(ү *Hmw Pˡ + Pu$=0*JeҸٹ>͚WAaўq0DI ?qrkwW@Mt |Ujrð?g-8BQ`$纒veC_t);lD6ҿ+Gά2>f)~Y1\gͻ)_ IQ/KJ ]ըW%S%KZ*LΓ}E`j.u)w\zPO{_M݅|JJS޺ {V3+4Z`lh\2I֣ș.-@15< CT'+ afpKz~mFsT{"F䉽QfJb.Am`)m4>s-`D0YQ5 +i%,FTiԴi"৔j>hU;H^\CxC, +M2Xbj\7U>rS fktSs>uEK2kQԒUHrlK$rU5 <G6WZu0Ǣ8% + +D*S&:A&R*2n_iZObRHe^c0!$RJN6p1tIjZe[u3h E^ hX;xPLD WiuY딚z T+!i@|( +J2;‚gJCNsCzn8&Qg1߆Щ<Z!IWCOP2bBe'Dވm|SIf?&y֥9Z@qvG l=OrUbrSC&U>x);2 C4ұ2X,b1 +#䥓 AKI%j;zJ-DTY5,˒K47qz[ ֣JY|}(>^GⲜ.RY %n zBsBG;DpT'l;sIxl,D$d6Kq!2MK|_N)hAH*o$Km)*$rBsS1&S[fṈߘZ֦['9B)QAUjI$UuFSvW8ABKuf#Ǻ[<aDŽW0ik;X{pU$:6UBpZ66N7D bӡۨRDʩNW%%qYY >V^)MћeJZn?Ĝ.Q;DE=!t?I'5d̢N!%DGxWuSMJK\o ޤ%0S $|UG $LIrҭқ6CKtSUJ vqÑ%F#{k\6HPsf h) ![@|\12}hkX MvRwls-T*@ ,P҈ \- a (3'el$QJ rVfULRBk#gm H]#Ib*S2 S. +%G,xk +m}QAgZOusoQcԻB20ҭ~o)')*v"CT3Sx(L/fQcYJ&M'#n#r jO!) 5S.) s)O|Lk r-u ͸ӿ(9VS0m6lRXtZWV2ą=LrD_C?LiƔE6m#딼2SV+5DmiPy&ؘ1u٧5nQH9q@oF-AYplLlS m{f+g+MO\#yuн7.ۍ95$%dP;[0$M)4R= rJ2 +xg'ȌD8k P{ +,:l1wZL#>A POK[jx:xZF@$_bA~ .$h)vP7[]u +bqGl7ʻqqͱ[ +G*M]B@ZiSs*iKi!Ưpo ȗN+ba){+cXB̆H7gIl(7{[p:lb,}"Y%)J$r3Kt?PY.PU H)Vժ$ݯl5KMTĘ?]pIK \9ӭM'4t.2SNCj ;1āu%'UJje +}՝BvP6&(V7:dqd,ePU:yHF͔Yh 8Jev={ZRu1"4Fw^nJҧiO!I".)<-l„iKHI$ۀHĀ,.D$mb/[N"&Hߺc҅Qz|Prk{h#>*]Sg^`O +eiQ|8#i+mھ{w,'9QY2XBxgx]84NbZ۸R.fSme&Q6É[ֶmk9Ó.X"3Q,Ⱦأ ? +#HP#s>Bo7x<"/Ҋ( .8\t암)W$*^w8SٟPfĤ@Ir)i l9QXk&ZVAo i}ExC -jqqXJuA ''{m((;[BP,<\QQܛLWO J'Գ50"$DӉzeh+M ]RvMËjyLd'R$DDgLiqNYh"Ȱܥ+9Ѳ4fj!TU6pڞI$\p;񎠐#ǭxe,/, +Bz&bW7?N1Rc&)Fd:lxa/jJ,I~𐯇y7#|`ӮS^5XA nm +Ҁ%l(cZL"jRQC B1~)놞1L/e)K)/2ز_h'!c6<\.&r34 (D%KLJock$}і#u9Ѥ̻6jj͓_X:i#[︈cgQ]k[4T%0 )*AZ6@R}{Bͺ%;)Mq GHR;nap**Cs +Oo" f +2i**!VitJmKi.)j '16D-HܽUͯs'狂,=[Dd'SnjZiYI HM#[؎|z e9U=`S-˩ hx_(hҳ\LFJ+YԜv +PBK7[X맧yE6_&YQUskvGѡ}S } ;:`>ex1ڜv6{楃I$_*PF=G8M=;D1Vh ξTҲn 0#m8z1M͙]7E[0eyL7zJЛ +Dؚf#ku5˷NneCn =ݧ('//KW *_LCe+3KAJCCЖU/B\/WkmєӺuijE}B }>rA4#f3h/Rl=h)^g1M"o67FaOoBQnc\.:Wqe![Hb߄6[} "ֱ6^S$)&e\䂓3!0Fo9*HZHCatXu5dZwҖIEƀ?i +I^Fy$ ^r5% +H#?feG/1D'tJ1W%P >O6mWlcZ~GEzУ*9biv4V7܃=ӔUuslRUg-ݢAn;M+0:Eb\h<Ӭ- +E4 .9j5Ίk⯑jを%԰Ӆ"%JVPG TraAF.]}GW +hkwW$eɤՐc͌(I"8;:q.0Tg%XÂXJuߒ Ӿ9ƥrES0NG1&&"6"?8G`^@ZsV,oBͿ +Y5CNPj NmIq<}p2.6>}<IAI<40ːi3s PMͿĒ-̴OՅ\ȍTlWtI#lά +ckR˪aAi6 A0O$'/<OR%}2gXVoba@M~e!yIe{I6Qijhp,7 +3G9^g"'^#q:pOZӊJRT˱ӇOFϨ(-R#Om?U|~yk$xyD&t_.[,塜+UTfSQuf+i Bߋ%S#$)}1WLڞ]&Qy}b]r*Zs^&06e==5e=~FßL(I:4D[΄qtV.zCbk_~3sSIMc'!ɣBBRQ~'*vKv}r +rE6rhH \}jE>soNS*6\v2AqՐǩ"3Qy,`NܟP $7 /TJV %n+АHNuYbyV)E+EI( O{a|0ymrԣDcZ3"B^~O/Di|σeTm^ʜRF.EjHuJH\ .6Ol:'0{eHCiU+{Ixͤ!igW2ǡP\ZRm\$  $2H6tx_N(p 8}Pϥs$ISVG)ٔG4T\u^ +XLYj;1RpnhmP>hM6 󏷌e!JQ'@4(%*mllN04_$(̈y}*8XE63+yMZͭWܐ"7Caj>nJW! {/RXeo6W1qf(]E%=ٮ2r D3IXa] +OXV0)uܝ+xb6XhrreM)2q.AФ}q!]V$JrU9$n +M[5IyZNei-=Q\Hح_So*Ydz!t)ʆ[HGH%>)z5? iA"Z}GkG& f<$oY=hiG&DYh>}u662&|h7:D<1bگp$ޏ G"hD߈vaa9p{v"#7Q*tSDs߆\!I SnBG 7ӿts8.L2!Updd +iHrGiqjO '8Rci'h#cϗ ִy)Д͈/ +`W7{a|b0Йc2Hu*Uk!LkbXC!!MGqlx|{mLztSn*PLRrKOHI HxS} 3T]GmZrP;DI w9jcYb+Ga+JaԘϒ +2UYK0~(,vI2tKK/̛(Lf A?2m̄SHhRR<#j +Kܨ7xLK[YmS'ǝ!rOu_s.a,fӔDqSQn&TߚBEלDx W!%v)o$TpU,8&FT뎔-;"E~DoNEHޔe4:5>`oÒ/sQ?Cݏj)||sˣH6-QUٷp_*7hka俔2ʯKVTA' ,Hriשœ=O0O9 #TTSJ88#E6qCC:\f]iI +:2n7Sap_h׸m2זH,qhOz(O1L;Ÿj$aa5ZgF%?H6Fuw77L%o`ےƆhQi{UfY#F +mVBj=. AP{BFRg۠\ED6[vvZe%%*)Sk*A$/ rk)9r-E8F$ud$vFE=2΢mI"hFm3(SvT>RNfnmR:Y[P6Q2\RBM6zx KW·|ۋ3Z*4=JL9MS&זp(+pA<2GuVp"SJp8I  u%"Boylie +n +H>'y|P~ж$7+)Hyj&}\WT7_JP.!@}`A_Ht! +jĎe|:*oգ+` >kܰf):|X0o/[#82&'Gz;7Y3j-<'KI[9^p eH|"`BYG3W%qp/FkbŽ umңh6p Gl ZNUq4"PmkVKYI!~H xx?mcqW]`% +w>R< \3t:yS#7MnG.w'ᜪPSՋ- l-FtK*?Wm"_( ΁lku+R6*PWN,Rꊀ 3ԝSj4<@Gw+@Q}+Wēr9KȠH6OdcnՎMPsrE!R'=(OHmˆ& zvy9A)m + +NVa_ +ls)I:[Fߧa&hZvԪ=EnCPV)koD$K8qGͲ< +A"0!eˆxlJ}=%\܃8mF(V +M:^pǧF7MPeWڠ}BvJܲ*MfP~>3G[Dz=B(]Ro8$JmZ %I*/KAE*X4))C=&C (JK^bu +e a@i}=GX!T)(6, +TOٲzWKƷ3Gt\Fyt>!"g:NUxN~r,E˫ +?L%"ZdS%e!:ݒC"Rz sZ3QDLeÒsZJ) ɱ +9Jɥ<B) :iz!po{؍).[ɜuogeqʐ)RV'k͈"*FVna]>S[%8\qGT|[z[KVU Ch%"'Ę&8[xĹXenV^]RGp'{->~1D ^5aQE;a$hNܢ_OlS- `$^Ğ1W$އ,5 ΑJ2hAﶄGWܳiaTtŵAXPI"O~a.T9\hmW\ɰe7F:Hu#9fhbP ȜO&NuC3]-#!Jdl4B9z9g).ںNw" Q#*7hhD%V5`F3x3o\\z5 8)u;l4u $jua7EImS*C]i +P:(4G# (# `x咫N! :8lt1u8QUʀ8ApZ=,MMIYbUjLxZoKrbU9~ˁV1˹ŏ !I:C+kzS@ƇXiQF|eJؙ ?l;} +WBͳPǔ978535շ4PwQ4._Q=ZΚN#JxrYaR) +Z$ȶ$r=id8w OП5yEǨÆydӝKU!`re$4sR2e7,vbW>Z[i]aw[ͼAgדȃEF#NrCS} +'4PjP$ªN@V;<_ ;4֟WS%ߎ-N6|5Nbi~Q[cU%- +r0Lg3(t՜]*<*ѩYa|$ zɶԎExU:[(Ô:`"PvqY!)ԠT/`|Pc+6P}aJr&Ms-hJ#q+&ةKPܜ&bq&PfQ1 qT&XkԪ-f# |s`ԓ.toE2\\vZ_ﺥ%=B*pK|V1f)s/II:xjy2:{jpn}Gqt<4êO,p^`[ ">7(2f8 ZIxI 8hBqSY䑩Jn7:0'!3G,U36Yg~j !#T4YK'iPUEEVbCc56B2[A!!ymr}8LYHA&@JS}RFV)9$) …䬣${!Nx+ +u.:6(:\^A]3x. _t2|zm0cpW* &%q3J =BM9e%:YA>62d̵W!"~3CJ(?ǽi˔ xǏAb^^jt7I  g.! 8+ |K5Or}B9}1`TtlVmt9ztUB'VPY[ 0ɨ$05J=戹'2LYm%JfUR7ѲY"8gTZ˕O[@MT_$ő넉iQgp{O3xC㦒}!& ʻEv7@[,LݡQ»D4UOɆS{m R۷uuK= Q񵏶?Ig$l.G>cAÂ˒!Y$;s]1[)L[ֹ| )ɣó63 +~({Ֆ +3Z;rʾ&Ɇ +B-d~1:Ϭ~GҚ.Th: /?4)^e3aāм) %f^\9zOHMe-%<>_Z +Rh)l^ L@N8>Diƀ~$Fv·6'2??KeF/9ST9OgaXX?# 2Ɂ}u^tyV\%*!Ϯc0S۞jr1, ~; uÉ'?`M|Pȫ5,2 +©UcB#2Uˑq8ʗt,|cz+< Hd6}Z+OMH}$MɎ`qqlJeW8U ()HRHqGmxeBt/5+AI; Yd)Ŏ&DgtMM)%(@(7ʣvԔxM*$qd09.hHۂn˃A V= j6y . "s- ‡t`lrXPP.ED8Hƿ)#o3MY@Cn>8!glE*C,zfz-Ae ij>KZ q-!h:=¦chRldi$aOIYV#$H@ j@}$!c<8iOMm +BhS O:6a/ғAI=GZWOew(RHX!g 78UI餴ӹ|kH:\RsE1'%.Q 52J&AT9ԢrZ Z5vlQbMy->eJ, Q9),HVT~Y#Ϝ75 4PiTxcs:S_u~]ۦA6I'>|:S?mw7S|#Fy#b* | [z&AOŕD)4և*A4VbZj 2>b\U#]Zu<9"gCaYЕ-\>rԁQ~;'[5 c;O҇$ җ|__$b<čIWpQ{yz;N>[JR%,vTXnkNz0#[qIdH~mtx#pmG5r"=tϨ!c–(Kyun0k$ )ou\&nSfMV6dM> JAuHD iu^WdIpRaRW:}>AoE)K6ĝV//Wc,e{CĖ#ǔd! RF +yuXq:{ >KR(E* ?~'LQim$%Hk BA)O,*%oIxq&ƉIXl%6 YnC*\xIoTcSm׺!?\.pBrH*716ĎziFW~k˴ڕV5.d%U:|6op$BR$ryTڜZGa *QzޞyԥD$1Hjib]P{21$1q:>Nj:DH%6ڂwo݌83P!H7)xaAW.)gKOdLDO8lĔ!EFJBnpoR\qN%W +ISkp"aFBReeW$͎ZC~.p %-ٙJm + |q+toT.QdvI*-:,p\.I @atԍ_ўg$s'V5|H_rM΁~ +hT̴wkzZzƴjFxm8\R>e Po;% a<趥nxz4yڒ<пHҍ8FeM*؄X%E=GlIIDy^r+Vl3(yI"OUbBqˣ6?=8jK6[թ{>sqgl_Oe%o W%z015 <{tI'XWý[Kp)ݵ/Ș ~qíS$ZRm6TlQʃ*VDD fuTܧ]V?l'OdތD*50B>ˇxb :M߇7VWbtCFbsrAے eV$Il=-. %_ +A|ǂt1dLHlX$% r@(nŲPJV;$뎢 8M/.8R% odYZUnE^Lxh-z!aD<؊K)ɲX$:`t<).I¢@1ZӔI-)(Re %Bm)\[zdrJXC,hŒ{p.q3PnUrI9Zl|"U"U>26IVeh嘁x:9VZHm|%ʓ )$M%}`}v#4f87~t qhЄ6.9zH?ƪ46{OSdLB8򅐤2PdPmLvkK;J9&Ձk8@I>KL"BԹ:|y +@$^XuN(|Sa$vl`((Y銶ڊֆnZq~EY;ќ}Dc;8Z ?O)@|;}.7>D_?U%?0{Լ铡Ԧ;(UNƾ@$-d} G=RvHMu&6ep^q锎JUԒU 2e1ŒЂJȶⵂ2WӖL"v+YU/by G[4n8:횴NUm&rM}#;JBBm~Lxk>!$yu +dԋD'M]8:)RUfFAui[ZA2R2![Z"M RMC( #SyyG)>ͼa0KBG魠Yշ擙 լ j;o;"3$"A7OUr)*QV﹆[/4{Xߕ'-=yIV۩WZP_ȁo4?.4R"T na0;D_4 m-`덨|-ob>u7HMjƙ:Oi>v@g'%Adz t3GF|4҃EN2N!G]*}&JxZOoM++9S-2~GydrJ|o J]$ S:Q—ֆj(4H[ +mpt@I?ֺQ@6Rʶp|-=?O(yhe9Nyu$q' 5TPE6inZ*Miq[ڕ v[3R "9V+tTb6$nOphenئ:OuXKS>r.pf6^L iJ>h qJ}4,l4;g &P )-R/}wlֲQAri)) }))X*=_'/WSJkxD Ժ+Kv"dݮS9֌"MWXZP (Q>. LX@(}-/{$ /~9X/)*<(Y7i'8Xnn @8F+'*t[ox 0̶-846W|(? +lN]|JeZc&6Xq뎰9h%,įOtyJ1rBR^h7ퟻ? +kSj9ٷwB܄\_ħRQ$٫Pdpw^.3-GТ̫ Si2{Q|J+U?Y.'*J&>ijt z{g\ kPB5$\Rߴ˫zW{%W K+Rk5 +O}Z˕Uf "=j)H?dMA|J8{97Jwx֓a`t1 +H*LSE +EFmim|fK +@ƛ.Q.̌K Y7JOlKB&4JU!0ܪJ|5κ&酩VO.lyؔ84z5;fH&. 5m\0$|E&K/*QI$o~&aJC*S iã +RJiүza\˳/K[A +7H'Ac!ߓ(GSH6qn:-sIb \yݣ~: *yiS.9$͒j(Jzݜgm#;Z)+Ooᒢ) 8]h)g k=OZj T<ʺ>P L0U +)Imb9 AiWhyL˱.K%A*r 1\ i8P-ڷ[[C2I|M5Zv0YC!ۉ+ )7Н!z&s(HVvX}13nJH P!UU'&6Z'H'lA1%NZ[\oR.8| )d^NBj* Fs,:U?Bʹq~>~Xʲ*Abw>=13RhLR;_8Þ$&ZRAezħT,D Yy$JM˯nl2Xl"|;B:y8d?lY@ŵ.M+9bq,eFB> 4\ҴQTQH.NX JI$醵D9&bLKR්e{,{bMpLma֝4E^Fօ +OmZ٬hRifڶG{=m)[ $ 4M[ $q#R~GpK|JUZiRE>ZДਡ#@F.rFq!5 [q>OwV௾":BqYtG1Ҍ4\9¢Iz?V޴M9Eosl[1״CSx ;N:0caڢ9f's,w59z&z;7L [Io'P +8;:^TūQuc5jq,!?P@QSI&qTm#R $BTTXr)Ts[,Eql.⯾u!$IպJO7W\#X֜F}{Mߖ'V"5 +bUoNLހ;FBwx׾#I(n .^㞱Yq +p!O O+IsdmA[xU-eQi|vwCF3Oxmr5OYWtdMͥ`ǽ,gO.^G3}з@AQx8GF3mWړ!Ga] /A*+DsNN` .PY=H!+aw\I5me?D{T!LI='TF,[c/>?t7QƞsDDa@> 8}z=l%mr}x@W=ixUt״KyOxZ@Sm!` 6#XnDu˨G&6)0Șz̵f1L*SK1T6;nphG$)bϹ*2jQe)[_xRҖ`mm%BރIdD|_?0{ӜYĸڐlHu\({a‰~]m/ X\FR Y+X^ʶ9TrwBw\M2PoLB,2/ʊ, +>}E::$ $M+Of?91{jpfqܒ<~hLQnf L;h+2Cu5)M߷ 7ڃ LCy.]v07v?F0 !b."[Mڧ,雟b"GPb{PE&؁+QSz Es;1(9Z5B\NUNSiP>B-Ͳ(ȗJuH9/E +zkrJ4ij +-r867i!q#2<ԧM"0:k $҉D%V}Q4Bn=)/2?6<]]SO«HtC*a>(HWR2!( +J8受JF%BB<=bY]W RIg)6A+*u-/V MOW4rjҷRJJx(X,TO g褫}/S8ۙH0=[Duԛ~j4YyS;-05mWf]Sq+E5.P{#GXذIηHAGIIfwP[WAw1ܸ&7k?aInW;'GeZ#r107`ǩCC*:K2\+aD*}儡xSmm*ǜt9XE8M gg.Rѧ'tQЎB\K-p$.!%Kg N%=6ZCبeg1VlLT~jžCP}u5E + D۬6܍N%zD>Y + +˷/ 1] +RmLq\TY[nl״=9g ȫa&~EnGZURj%bHo*nj+[u N؜i&l)؝UTE צeQ3o6V%ziܘvG--NՊlm#S錚1jSB;UzaZ]u'R[*HsTS^$c)h91QmEq<6Tگǿ#(ElĘUcU xdMe%ͮ$x)V`pޚ +Hq?8Ƒf’PyI9/k}\Q%qrA]@ ]P֣\s?XU4LV{I'>Ȓdj7=;p%F(aUҔVE|,.B{5KbXU8ɑJˡ]X|q :۔R n7ްv1R*Qf3,PRT9x7tS3Psh[蒞:][A.V,&j"q tw\|8srIbD]]dą?"җo* 7kăyFE\Ř`O<ϖRe[>~xc2$֐˔%苟sv Ds5M!CBT.5!'ByDWp򆰢!pbC $@6Zo\ܫ}@3D H8Te.'\RHxV) (A# -W:¦}׃+qBAN@2[[jo$>?kJIf+ZUjkůxcUG:QZcYpTO*:ly8!Q<`ز\f˨xmحKNiyfN"%N Yj]i<‡ӄTbbitRFB@ +9U؈8_LaImn +)'BuӾa1ϣ [yB3Ay Bqf)͙`4c[i8[0Mqttn:k CfX?'֤s{I#]- +}(613u"OBұHn ,S,&*ǰINaq Yɐh>a|y,oӬ:%iܥb$ c(WO?d *? 8㡲cO+^IDӏu53n^O-[ǐUk6I'k{EA WiEA#Nzٜ6 + {Z,Cr! CM%;p ԋ5{?ff?tՇSO6)qO1P^Ve):$HԼ9s?tT:!TOv6Ʃ'G4KhYv֛ڇe$2In*5 #)?.5|!-ҭV<`qI"*RxXk5wV%Ng%*Z2q[⺤U<MJdn+\ xu*F])R7{}ISSZRq}Z**?'FhV:\QATQ,2*K J6 yĚ6*RJͷIb FD+mG$z.^~.ZҔ)ʫ Wa=OQ0'[|HinBP&\7ṯ}e%E(Hܛa=Q,68jI.Н"umm !k ^cu-E:jg9+ɥf !Bk`$ !"j|}Sko= +7Xh)]0,Þa0u3"ӭ)4]R XX7N`Mhu3CXxF*0XUrBEkGe Nf0+&Ե~6?|Wcye)(Al%T7)X\XpR9}ANƫ uyؔJEbIzX}Fl3>Q;M\ +V)JeH<5"? +Z]r91^X~4 J!cn skPRoS;tXY$PddۺдdyHr'--lڜUA8M¿>k5 ̶@8DGy\MCY:=RmhHQ+ȑ`qڔa[**j'#zg+$OCN($H b^kXi!)*If\VR6Xbae-{,+N0f*TG2XOHiz8ɱ#^zg#d"_HO )b~`Ιdk %&X7A~S.M{& +Lr] 79mc1`qnrS$,HOPoR(NFxLsቄ,$T/?|#?p9=c-e0{ERT#Pw! + +3i,!٬%+C5M^eqkXf'ԉ(`s_kFI$#x-Igu:*%.jԦԊHms#~Ržw)1/8¨BI+_]6VB +3.>:Kq؃kP;06rk:$Op6ވeT*:/*JΦZ(8kOe:{aN x]b;|$z j3jt #KK$ jNj.J͒8%#Dw5>ڮ.%2$,nJG(aDva1TJ*4[uw[L )?5)LNaIKIY2IY[ىj%n͢AyE&u qVFPIޣnלp"҅Z,WRskuKm6$rGckcx[KqE+"6׌~|m6=[k6Ǜ31-Evܬp91ʓM8T8RG˾;|'(LvhK.8%!䃐nE!=.I@y#x;ʼnlqζ(9ދX+JSG<~OX bL+ʢ,.,BQ܌RaTwqZ$l\o1/`GsRò JP6)1ä%JˑPLxJKܥv n27hRՑ9*85K"b2N]=)7+a_zS~TS,Q|;MӪNNkTROEPl-`ۛ(X,ctZlqnLW;{ ^U#PX ʥ^lإ@@h#CUiuS)Yd.:IS3 :#'>ړq<&y[)&n%f Vq?8OW+" +d_hK>BiCNc{H|7.ŵ{Z_fMRvEUͨ}4anκkK\xӘg|"Y?vQ-Jn[/x2, f}é(;y4%Td$[8G O8Rο7 W7pA1nePy>6{6¼mˇ66OPvT{4( c]eiul)ޫa F.;);JRTq+-](V+W J;OY 8ZشUjspT/{mTk'凞%I2cm$ӛp7`c{CI<aMrOe6 Ewije$rVG6 ѫrY)KkQ$[[w¼ĪGVH!/O3%[̑`ȹ[6ijc,RP8.;K+ {â7)W3Nbe5g%\ ELT90^lė +8u那U5vcl͈}j9JA*$ +w[ȮﭏjuJk +9[*,]o.xH3(TX(BaK_/@p|'S n8T/{m'QU 䴥Ŕ2)}r4R!ժV_yRxhXyӣZCKwe}nk-N&pwU(J`JR8]#UeLsT0= 3Z(6pUH_['hXCKeVDant;e:%0i ,} 9srS[CrbJBd +B` 78~V@qAĩBo~Z7HJJH N Rs>Q. 4XS@OX TR fP$v[T{,VD8 RWy;.j +A hvc@bVdS"rGt-R$% OR,.w:$3 oeJ7.ŏLiSR^eƊA &N:[2T@}Z,(a{kqo6Z% [nz-%@9ƻ_Vuԧ"2I/sW QR̛mSL#(לt + 2ۓo,L4ʨeʴwZ8O%1w.kl3oWZlX[Ȫ>nl~CpKIr*oK!Cs;'1)D"sgTLˍJL: ܥ|~ AjP`M2WŐ5׌9g0}-4PV:h9P) Qam JMnRymaA*cb&џ V]ҦQyy\NABcJ-DHdV?*U/焧cG6"sm)ZRwێQ8uӒ +\f̘ۖ8:$ ;$DRp8e&AfkOI򏄣m®.n-V3-'aoG $:V^!E(_Jmqu0Ts +"'>u1XFT˔:J-2^DT}+^(m#ˬ̦A֛t%IraHĿLɴ%(mNT҂se#(Vm/BgP-QqSA.Jv)*b.uR([MFqZؑ+8ǔ:DyA7Vh܏ rT4SK@|@-+ n҂R@{$N4V_X{3OŦ]H$kJt-ply#Vz;85̈@C$ݧe9qqa~/Wr`G-#ml,}Ar_М,?.zR*$ =(qS)!)2jY$ "qA@$t:m;!ƤDԕea%Fyj8; +Nb ]jY2OL#2),ܠ~IQhIjPG!̟EmTd̽t5ϕ?t\;{#SYˈo8TjK<=gKs1/2rgiivF +'ό8pKQX ʠJB\$GE3TZ=WnO7,VԨt;N>[fNyv/{̥H H)A*][[Y={3I@|ѵ3x:aE/_T]"$PnTtr6$CFtnp$H\^؍楥g2UmJB#4ۏZc*tβm;6jT .4W7CNi 8v rR/D͖}:녦Լ+PSN,!2Ԃj>Ti5+qGzM pݵ@ |:StiRmKAA_ +ThBoʛ~aJ| Yԍˤ:p 2I)9QX~ /DYSBRAV8jxy(in˥*qJ Sq/MVĨ[k_ |7ib%խOu]$6)P{㾠DyZ/4rG*at÷"Iu4K*P'Bs*BEJ{zaLΞ\lm%LSW_7Ov -[6M +>KH!ăUR%AUQw yr1Z$⊐,Pt +8Hq*In(TO(?,M;IP6thj +WAz= i)_d/H_O9t#Z|+ChgH[ҡvlu` +N@0 |5(km[unbS}|;a9Ƽ: @\ jnSTJr +ƜXIRl$ȟ'QQj` BF,N:佶tb\DeU_eeԛ|\zjAmcJ)M T˽eS"=1 9vV b}ux:ƆtKSuӪQ/Ǐ"M gFӠ1\"DZiͦj}ОasGG^@4ylVpqn[i)ɈanZ>SX󑐁YF3N;Yi2EiIqwr?信!]#ip 4x‹!u!2c77"w~)\G(d:˦XWf#j7#Ռ5]9r&ox':T2EL=b:e!:t&N5<ʚP̕$ :H4 (\ROei"RGӧRԞ.]L>٘AS5@CO.ہfL]6aG=xbLf`:7:qn8ruLPGo6Pʞ]cjtCEJui7Xv_Ӳ! +6¬iJ,7'1ͯa`{C_T^]@uJͿ|,@?>d-M~Ta'VN(DsVG=W"F( 5u7&3 !6TդqWV1"jJbj2b9 G|\kDF${c ӖҦ $M$i^ NmZ[ +=ˉO K0 Jv'p1Lj𖂐BcxfBͬabRzPyL4%'A%[۪3J\fA (+ ,]Ln"+KASU.pSqܥ+lgJ;j-싲Կ{r-5)8r+=\}CdY'q'bzw+i+Q I$ zᴗk +rx}(Bzn7P<4nt)zz&kNAMaTɴu{ln׹!UFLYBIyCK'D:.A8| J]h!`[忺,7_aΔ4ZS^\5dF@䤒ss# [>K"~YI#ϸqĕr$}U*TڈS^v|VytHa.l +q !&Αj*e8-CÇp0M|b+i SUUYŸᾁJRΜo۾վj,FB5S&|-]jڥ%].@6x(+4e*Oqקuf$kk{FV5 +嚘QK=hʵXf$ ܀"+kYB"6M?O-BԂǎ-%&Wl2jnm 4Bm$NgCzWDm-ZHrZZFFT4x$31B6PlFcSuZ 'M=&DSkR*iKi +RIIRII)& Y4 ŽCGl0w|HYm ;r3rىSV3w +w!M[hg=zTj +&|xOƈ2L.Dw\mIB֐+b2"Ҵ͚_[)"xEmۇޣ7?)V}ui!IBҢHZoby_joC5/R2)f8_JPh6T;6:Y$,:& g1yVm†PX{aꫤOVeUR%.BCeŕaA.t"IMax:?kžVpA FȺ9G6̦D +V+C@G$8? QyO, eRO raPAw +@Up5#I 'hsRv-)Im[ N)Dnqzzj4tW4'p;Pyǔdr r-Jd1%Jdk6ʗVh**WP}IZ@k3Wkǯ|xm/ VYu| +m/U=BǚN<' yw@V| +breC=$պ>.P!+ +{ylkF~r%j!%StAsclN^@zkkn:4:aȏXq`\pqˈKO/cmMOA=)L?,Uy1IWrkD*(,mU j @OI&rK1Fk-WP#BA j4Α`xrYR&ŏj2qKW Yvf)Jx\*QXE{KI*E>e,ӁV 7aA'NXB:2Lq~ܕ ՊUp c!y.-@XbIMm;8B5puh53x:JdY5*Gs5j~4w<vbmlUއK +Ԭti'[xi#S XݾdkRl &zOe % R]qB[@e܋$naoKVq]p_Rやr`pʝb,0Cm9mmjs%WBiQS-Ol̕ZtgNPteY +BX +ؔ>Ai`ʣoT5](̿zO?Dp;,F1R})UGzZ`U AN& BP.p'J\; mPӛ4ԫ,*+ؽ.UwX˧tWP$g9-Mxδir#ŚXJ'F2JyNcQj{i*5)MII" GMĭՀmwC3tR>7<ҼֱoxD@QWkBUdOZ2+'yjw6UXV`׎W61YqOIIS.m{ +S}^:ˠ A7lxeg9 ^gA'W^VEm6r@'%bș:'U9<4HuL>R|QtU}RТ))Ln)/Hy8B]/ f'a:EVYcPnI@'3Ӫ|͇xպf~~ky¥rIYXnEF-d$ IN'URyO+raDPlCT7WyK) ${mx)q038mz4ZIN8D+.ղk G6A|Zׇ}̔([z!̺ǎ[ Za=]=?8̧ȳn{?l(%D'L"irM&dZo ^Gn펂3M60( +wۉQ{I|4Okmr4T-Om(+$a`u:rv[% !Pchsm˜sY5bt4: +Zb7$N{j*Tj0r}ĉ,IKro0B+8S4J:yCΏ߯f%=t(eiIKHS,$+mnë\*fiͲnҵ!6-Pc6s4Tc9g4wmm0Jǟ-[IR^v\gTgƅ,2!!`^/$%>9٦Lz+ $ *ѐ#c&ݹ8Pdyqp}9K/К]II/6H-&.^rs]#M[Z?6U$RqH`K-IbG<\QܮZRIXhcΦBHnaǍ2[ROVq* !D魁qY:і|HJ::Ҵ^mm@h*yA^frf F]\y!p|du@RTBҠ2$PЛz#QQ:R +xp:vO)66 +펓EO6e]`c^)o0.ɿ[nfuICi!$+QEͳzgE"FJoR +u(ܔX{k뎺>(nzD~&);-[+y +Sulāp8(=L;I$1LnLd~`lKi4Ÿ85D('Df.g +R˓EϔWV:srFF\CX6%S)͠!)n`?}6.4W~zǞٷxԭv\(]yW'*7>DmzJu5Ĕ&KII@PN@2BVUf<ڼQlKW%W(aMMnݬn4$jbHd|T]܆F>-'1uѤW2\gL~BaK ܛ}fN!-$e7kGl\ 70qJFYԒ *.*).--7$ ۃߑZ,rA +e 7'W= |}"H7I[_ +y^;GJºMᲇXg18ؿ[R@ZJ_Ǧ:I *9w#\v/5BuFd8^V}a/6vhTB]+*[P~04Gb-Ԫ҂ɖq GUQbUe*Ok]#;9 +l5]RAO)8 _SjaFrIm*TT9Ԩ\~ko:E06ye2Ӂ$YIRoLq;S) UI"GH\\0"[mq搠߰EͷH֜!4hilɖbN);xJx&xH}JRRBM4, τr}RT/:d8!Kmpj!A#/[4$.DU4%I"&͡X] wi y5DA:ԡ/b>铔̌.LdEZRf+I@&êyJ.Iӳnl2;( EIO%N)9,p +,p6)N[eMJHLJTR#*t"uYMFP9Ԣzak + fԁ1gV> J[E`ȵ} | IeϪ͹ *`KJyQpYH% #WFPn{:/ȩ%>J +Ү!/$X`(]FPmr,-#H4Alv6{|<&ySWKjRɱ s9 +CzpkFX &+iS2kBn+qJmYMv1sFj:Tօ:JpQIM7QWP""&&&mpvFI JB RT. b(􎡪4DT1tr:%); I)6Sb|!+T;>͠G^JG8DTš{t6ڛRq@'kcQ*K)\Gm +'xRWC,RC?s+u&ú<0IHmڛB@THo`507RDzFFn\U^\ ڠHbqȆXp!)H*7+M7imM=ivKe/ͮa*69ëLLBuiD)$t_ +8gAu6ȶ_t4T&CHCj +QsMT B!eцFVX0ӵQݕ)ͩ͡)'vĝVXZNR.B_]:QmҬm$,Ҕ%$ظ +Wb} g W$-PGdJGn=#QiuiB +!oPT8i S.ӦQv,H+l Tœ= 8]MEWJm6=[12J8A50Z1Rv u3H@hsVvZx*|jE}3c'mu#BgLӺőJBs9S[w0w@K71s˙gO آ†\@r-\[kɵYCvbMce;xWmD3YNPV[iHb3 UW̫S֛gDmm,}Cx$dJBM:1I_[(+6 EK#Nr_u> +~5> kU >^'ĭ\zB/dU&{~RR6KdG:Rf?N$7&wL>>0RҘYtʯ*nzLlcmi~H4<4Q'cC:jysZjzae)ڄƚJy7@ (" &֎enD*hsJ4 6S*6JGy C[LP=k }@66V$]Av5)Ge*Wdp',ͧ_-J[`rҥ6p[}Ϫ<}=xPΛNfPE%$È <$-`~jg*RnmͿr\nG eEl=B".5Tll,|MQ: "Myaw` +6Y#`!Z8T|8 vE=Q.k B$<l|dMaIMt >$=v?ąo"? Pa}8Q hNpJ$%z~W&zc-Fn+WSP5-˞n$6Ԥ@(ōS6O)!&tS/E0#d.Uo<;Y3KK R[[-6.rI)'q78MɱL;Ci!m! :iOJAڥTjʹ.DY %nbP_ʒOlt$Y9Oc>ijxNpOH+# JIV IIt0hesۋx3n:ֵIzyʂnlp)UE0ŗWkh6+>/@a8a3OG!2o--1l IO?9g&GAQ {l*Yƚ / U&<m Fcכ/KSK`\i.eӼ^ZoO):"R+eOиw>@%_lH kMX5"}9ktkqBJoׄmcOT,HTɅ6Ps"@R֏'S.l}VĸȵbBj!@1VӾ>TM.?` .So#JU`AghXRypZZS0ꕉU9k0mn:)+*clJ˔"<\]^mlCJJ0L(ChJ͘% ́<*ۃ)mW[X1*|,z+aqpiPWZ 9u@$k Ti o :GodPPTVMTmۄရu6sGJ'pg?'ב2J۴=J=dlp'e_+B~e<^MnAAmh*ߐܜӀS!'nAIC=6Zc/TaǣRSNPߕckx6.v~Fu|7,36ZS:g}f;+1!\U%}Jsu*JO\Gᙔ3'h]\BTe0TbHʔ= CKsK:ۭ].4}Aq;XPV?V(i5Ol+嚭:LI-sX[Mҁ7M9K + '-Qaᷮ3ҺLQ.Z|Р)V_Љht\ + jbbe.JbH% CAaӷ()NdLߓ>ț*:ÕFqـVNTk$mH &Tuo+aTi܄&䭾7"ݏ?yI3eyIS*ڋ;Hʨ>zBut+]QeR\};֠[tKdϫgNz3uT)o#iAS.V=Aúң6\[{1]tM1 +R4'Īi~6 +N%ьNmҪ ,o8xG!HIB숾5/&=i3֥UˌvlOoPSǺ*U}Z?gMOEp"!{\^ fW&%'\ 129YHiHzYRK)#R)؃b ja^) Kj)#Ͽa +:}-uQ<8C4'[s[c]q_E5ZKQJ͔ڝJ~"!vP~D)mAnH7yZon1U&%; u+|! ^*#`7Ԙ%AU-Ge؎FԶ/9?:s:u(!#Z) YqfQ$ĝLV7ˬs&rvzHn>12t+ ]r`YO],5wopK2-<ʹO465 8-1: P^㍭L ԑ~xbJx:0*"ͯ{̧. ҨpߎRB()6@$MLe.,7A`^`1QGjS:DAҒff&9/G+씗c{nI8e":%.AcTw?' +%9(UmY=q_ym9*gsaV;y+A)H[(%@Ƃգ>}X&Ŀ[BM +̍Q^ +O #袪άwSRu#pE/:~gq0i?{jG1E>) ϘG3|ӠT`O|r9*(8%*SLni;[CI +/WaҤUdRf@R\jI mwF"Zvk|YƳ}N Jj)o+WN8RX)uNo,A +OXI:iedhhM.rk?fr?M5m_qbHIc KQ.ʬG 1 %Ћ,>!`"<;)aO6/Z@!(%$ mBߞɽo:W$)v35ʫ ︄sΝB*XayH{~JE-̂oGC m%Y`zikpRo_u+Nٽ4(ѴI +rx u:I;iL-Ĥv=cҽF;8㦶`J`n flAU+ЧS& '|(<).e ši NR5k}8ER)\j ܨ-\W2-5U-3izu,QۄM"R)$q-$jjDL">N+AAqwnN)'CaG{$vT/mp&mXO|᚜Fg%撴)Ң)*G=]rAO*%6뉚?% ;o ryö/1RwHAI.hs UNSrA7%]%TԖ$VB eI,]gHAXU'L_qДYS`)akAܢo{aQYd"UWXē}9ĭÞ6N|ԍ1e"}-4˄8RX &Voy=0CRBO簥@&<&S۟.c)ϖfQKG4gA\SXһúih,0mˎAdnH* ]!suni~qa:Mv^Ln2i}M:VTRB6I&ѱ7*HirR2L 76T c8SB_ʖԕ mLU4R%6=:zrQ!#3*QSLŌIqrk$u"Xub$v zbT%ʟI+u nӃNo59ڝOfea_R7}n"śxcHk?/Ջ[!.{$s{wk<6q%xBX)7 +>TGX#hڐrxJRՔpBm]'0Rx RBK"<^ +2v;ӝV0Ml:Coų%@UÀ +v/Macn:@!c"ܣP$ƾ",AI2FI$_7gCk_9:5=Dup)!ISk#: +H0O)Qj2vuj. *{^352 }b;"[F|:_xTe+e&ʳ$_CU`'-h tJ!̝aێҕ "B­r3gkp8ꒅ kSKa6&o;02D(r$5:UF3}Gz#a +ZR@Jxғ^m2XEҠge3(i9 6PԾ +DH̅X6}8fK))MF h m $y &P3k kBI VMDe.8և e{z;tf)mI}KpAm\E Yܵ }>^ `*ׁxG52^ìV(,a3b!pA%D%[vث^Qꎟuvm~+ROܷONeRܚ*)6)7=($iv v}km3nP''6~\\ƣx>\b9ڛDSTթA지JS*l >T\=ڔa}!ך'U1C5ҝ8Gu\Ȳ,fcs$pTjZX,@l*$L.AӏZgDښG촄6n-'UGLFR18Jj3 ~$\$z=V=![|Qͭů玨A/ ;ZLbS71 fGּ˜uXڛ#[xGJHɸ\a(xLFb)׋pR=8#c-ɔ+}r~ލMROk-ѦޖaI/rc +\Ҷ͔mhBԧϻLy/ M]{<קJIV✉&+eЖɸJnA^R] +瘼7 fh\iQ*[bd&i\ P;q _K˓3t̳65$a:Ce_lؕl$W%eC.(HNHLXn|bJI IwqВ9(*6ڝL!lPx,0Lٗkoc.fLCe%KZ@ե,$}6'+mI]|6SveN4xs‘ĕEH&_+(RBYH7P $x9䨎;1 Ժqa2rjaH!ZA 䛪|v-.趀R)} ŘZz%s܋_ˌf^'fՂ) {q2aMӻ()ǵ|hzî!J=Z{Ʒ;yLe:l>1)JB*7 9zXaJ[iJҢ5*Or@>CHgN#DdÎ;OIGJm Ut- ʋ&P'K="4ڛ`$8}z:RjYC'3eB\COiMti,MHóJ*vTm`OxBR;W (xbrB&]7"㒮 zMФXbSVKi3(4.yJQm ornI"Ǹ7.QPMқeMwi?pM2- m B X +@*qE!76 # 8 & #Kʝqhmn(!QL..⒟~oh1.ʲ(H$4Z֎iօrRd/wk ۏ W[*M6Bw6!%.&UmZRlv=cMaԿkی*Sݒ?]~U-=4JVJ6 +^ טfz~y0sn,w~ԍMnm9cVonU +raN}I&80͠~IxS ToQ鮹QNn{ਨiULa)]z*^<֭v':;a%%Xjdni{7=yKW2?TSP%#!JJ|V=n'>>Hk2C aGBs\vњ_o/Wô@eż +r^({\M7LJ&[4c- l sp,A eΡUt7͵wFA$JSpm2eL8O:u=}$Q3\ԖX hз mk]$ywJOYֲC섪T%s n틯99BH$~(VlIP"1Io#}1nFVgQzke1IZ|Bl,<—EɏXGne%=ϥPO"f*E2d +Pek!Z,. CU(Ҕ%btay41s.^l}b+ECHVfisn2lJ15֨縤f@ }DPG7ȊyA)q)$ALZ'ZKC0=.I-Xb"Sfi2BpV:BcbF$,ջ=.R?7?GeDxEQ2iKkfң' ۯ-"E-$8t:o 7HI [|}Ę ハW%mDq js)Q)Q׾6-OqmVl ҫ4t]ń~\QŗΩc(P$}F]:.m~,%LH4BS*ht*&$s2xB#͵=-ieLa۲wJ8at  +OҁhKQ+~q[iM\Xx]kvmRCqTP*<|ϰfS:wZawа Ӯ|VD.]tƗE̳#7}[$U0ԚR;:{6:ۆxCAIƭ,ud MQ>7Iٱʹ6{2qC7I?kh8>qln;c9f7V1#4Ϯ1䶈rae[P*:gRx=cH3E#Ľb0:il8'0Y.AK)$B8Rk+aE+$n AfvIˣV76~;ڰ9<{P7lc +a3Rn)Pn؋i6hUܽ"&{ls”9j+rocŤ.,/ʓZH = t):~Qq*xm?&귭$*m* :f.1,#*ʂ-@6F]͵#ӇK2[ )!6_z~вnN֨%Rʗ%EDby+Ibu-*#yk?ů)- vtt{3ThR}tBh@E%ŃpyuNӶa3t(Th+-IOR + UW!.pPرHmBe2TJFT1=2wAQBIRoa}/cK:_'4 hr#kKM>J8y`kKK.! N`z!@aI)'[|Q?NF!9)4*w9*cYbv,!r#{) RmbRON(T-8+A=!>VvMѶ )R$BIZ쩵1@r('hm[j=n<4Tb>@Jm`-`Rn-u*ZN] `A+3R^N#1.D_Ӽ~놠\+O7JF+#Um2:'J!M@Cl  ^p%EYtL6T/Ef|+1QyO8+7n|\'pP\{XZJH),ZHI܉ORwncZa~ǜq6;Y+RjJC/˄zm WcG^I\{k؂ز]=1_ ޺jWe%ͤ\um0#eQ $d~VAQW4@*w Qܵ!"+IY(!BK$(Ýi/"u ^qi ң{N׳<~S-@SU͇}ö93'HKYwD ,X5 ʮ#ԩT܋(?pD2aL,Y+_T}S&ejB$_.NSj:X6XVz]JKyKq*R|%;s86w*IX }/YT&@goDI*|ffbct 4μp* K-8җqXI޷gMXrðʐr.: N ^M]Դ^Ve`-, -+ ZHգ}FڥYiԮ$H <[n;"tj8[%قxD8.QKء!)Vl*0PM -dhq.g 4 qψ݈!cE9M9emn㾑3$fl<lFx TJVuבIQȻ$X;uY_ʐ̫R)4yCNTnInhОfFi7fETѳJZ +-*[I+IjA(_Q'nmvI6`-9ÆG:bL^%D]-],&ITTR"<(J#88h:lVEXW)[w܁)Fi+OV.GV$2͓C!hMR;u}-]ԥSGl!Bes u8VvZi*H*G$jxX\mu )^3w}BM0OˑR ҀBz8oOU(!#SPy8ҭ6H6SdI]iM1N>%)r+ ! q;,"7w[NnCR.8k+-ʝCjLr[BS +,]yBAnu!6rK[5(M +7$ԚKde*+'Ȁ>xNr[`j{Qq 5'"7UeϔM2 J̑$_%guQc+ TdwJ)WzE\1#njV\ZXөi:u tәYW1ez-ijHWnHJ>gPHL'poIZu<&X6[j +I3:˦qcՐB6hW+RZZ|5뎩MY6'0zwIi\?fqXn"& < ^*FT:[Qo.+,fF&uΜUz!9'B+qKPh. +s@WlT@xlw%WTG. o%%řy]K;Q#xBd:CˈjQ wl `~}E1É]\*ʼcg $KRχFUMg7+V&>›Bes-j7h}jqE$9`EFkEjT'/eӔHz@uMkn*s )gRTƇ[B2e wCg+WԪ8˲)9vt9B4/CwQcvƤ.PR;q>fY,m@C׾IUm}QS+QvJ("AIyy [!V :JCfh$2N@Jx0I(%%'5L.[oz,ؕ+{[&NK.Qͦ6ܭRUfG2sɧ̂5T'GBg=5<1܃}-?oY3JM*B>>x(>X@VV{piUdAT)%iӄDMYDyAWPwKLFtA^\԰OO.rlBl>q {ڔm@}JHVkuKKOV7T6D#[ \lꒀ*? t~|›&ru 'F Y]]nfI[UNcؗ*,u@r: + JOS&D ʔ+q0w׮G;5Z!y9~iUh5yR8q,31ӡ,"GVEa\%ŕ+%oňzfeYBA7i镥NrWGm~pZ q SUы7O 6|6֮q,fWԺ8uKyq jƗs~bicߍwdJl@6ǐ;("fxkK,yC'Ҁ6JT$ Q!4<!7 +Dqa’meTlBZIUWc*IRM$#Nr؆}hiaiBJS RNDk$W7\\p*R}O`8i{9R,HҐ7՗UX HB2|&$sQJ:Fzjj_GY-Z@+Rx>’Ǡ8vSpGf7f23LT.,>024H)_RuA 6)ͩ=X"k +f Ia)KCm M)%q1-+PS^OV v܈@Z{z"ˍPn·-I\<GƧ礲A;Gxd\<>)v={z!g8&Jڱf7A 4+JfI7q pZnj8$ҳQI0Vfϓ:Ať)`q9VËj橊bdnX)R:IPD-WO(z!,V|AФB\.IlT<䫶8PꖘRn bZ 0}['iN'P{~ m3ReZxCQ{lc;!*i,*䕺آ['mRM؜)3TCo?niYGt%Q@Fc-0aIiEhyWIFtR +7#ifjߒ<$ )>k.,'n;xăUU֭J)Uk0+5G24:^ȮO:KKmpI JPXaଽKXOЩԶQ](7*# +?cEA.>A')ɡ#,D\+aaL5iIP&;ZX`B7uS91m{) l Ws&$M ͑eM*uӯWq xl|$i)~Z=#+J6}Y30@R,@&='d"du_VYwi9[+-918cnҝSC~>X5z?Ts۝y܁XSd XPӌi -S T)XˮF')]~c[Uj̭n]RnjMԄOgNzVԼ2]ʬIsnxGQ6%?FJ]uIJK;rϲ1.P-i^ת[ ?e6ňO +.f&Jy1?"H^ QbM\bz%JiF2"e>T[mxv!t4PIvQ +;(Z="T1Z:HCYuh;Nus֔=(t^:4_pl!"I\S?Qǝ\`ZO=/jZԅ ۝? ّhTuuiU׷ܙ̳VWS*D4+JuK'e$woLfBip5؛0˙Z%dO}6\:i]iq?m:ě)<ԂH̫DfeӟUtt +iZa䚂KkZ DŸ斶BRR #2lTuÊ$ʿ.&7ŲVC(ʁ H:K]c,$M;K)wipq}$_e&|ҝ/$\k\GC͇('G}.Otq-5-*n&g&ܥ +HP<{/3iFa>C),$%*Z_$ۿ8y>ةEZik' Dmۻ3ҒRN9cTd.uY00Ԅ GR^@6Oa5ܺT!xa:hhODu|,մ;*C]hTʑ #QLg)?@~ZoO YI-$[ +l\i^̪aZ]n`Π;R:$$r<R,iY3ȸx>-2d)RKr0RV/bվ]4>˖2X^Ӛ:S,"Sm*m|Dܐ/*OKu"SG64_ǜ>( Hh\mNʊZj[j۫C Xo1E/R$f\Ԧt̷"ƄRRTnUeJUAbC5v㛤&c  tg0WCzۉK o[g aǯi9QqJ[[4:қq.?vi6+ +E4fEfKi6/,wڊIj;#הE(4 ˷Wx d/H,$9|;Oj +2c0 #fA*ʝJ K >^5.պ]d`8߄/Rϊx•E&KjSt67[ŲUu3GYPxjD 1|CJSIq"̗[nҔJAB;VJl=fW*JԔ&Q7:q2m1[.JR]qjw6we̫H I j4 )W̯]~ceȌ]ey BH |jqfԄ )JIVyۊJ&|oE5[i BVBAmIeRTIZiܥ0J/ޖ͉|ɾs)Pq5] #(VmNc6YtklBU߸Ir{;7pf`l 7MxqF[#-&G*^EC +nT)c~$tyvl(oH#"2*n-QXC뎶%Vi itp IhٟٻJȚ:Bv 1hImk٪ yǐn߽+z:CT%r-S/*[1$Dᔷָ!NooAU M]LҖS!A)Jl;j@DN(k:8Vr%۩(R@؎WJ,ApodeB~1"8SؕB90QlEqӚުgK +I p棁uA*k)uM, Xh/ hsfJ@4&dJ RMOo[²/n`mwd턥$lGyRa&vrR;}b#{J$ +u6>#C 6&-*C]amQ%'LHfŠJ'%&Moa0̨-ś'RyIk kn-*jD6FNѱj>!{үL/w#6KiJWM`` ylud)K)b5QQjU̷SDw]%< iW=ᤶE>m@"h}7[ZД7Fw9]eA&M8OtE4םZIyV,J.Ԁ4"'\94LЂ|@7(cDǼE(n*~n)̭š6)QXm'(FOvN&in[VĞ +Ovk{<9s +,Z.u0* t\ a{G6Ϝf]vUBY-|$&w#hR9Fd_S,fDe:G\BSuJZӧ%Ǹӛ!.'h7WC85h-I!I4&-pxxxąOieu!AblE.[jI1ƙc(,zSyՄr{ʸHTTz[k-sqx fVfU0⏸У{G$-%i +XzJX~*6,A'#"i4F5' 6ۗX?1asKwƕ(iGH]e)IgUMu7W ;'PtaR-5(,#L)䦔bQڔxZ+)zyBz,yIB[9AԨ _T#Յ+uLF!)vE<}H$s']HFO6l`I'UZTC={UBb-,A+2 o ~*FRy ha$g*d+.Uӽm"1JyDXڟdZlu:NӤ=irɾVtJTGj?`F1xNAUH "+>D0ү~c! -#J&n6^Oa7n*hu%ChrC6ؿ(W==tKl@AN?5<>|'K|#δ㞿{RzڢWm֊ +1n +(wGDG. '*NJo&[e?Ga=E_gujxh(H,4?Jt6ɾn<$!*Db&{QhwEXԟTL̹-A'JUw%PAxxeXU^n.u踐 T59Ji֚e>yD>l=)`KҬp{r,]ܟyb< +bmj_(#֣ +l< +߂ؘ5DI>#-8F礪LJKMG A6\qs}U,GS %.9nc/j,^BTWH3`κBUJu*<G?JrL6~}ԓ!,Jjr30k}ҼSb\q"N +}:/1\䷊SV/[3]Q5ӂnd}K?N"R>:,j}9jO: +K۞qkzvKG@:^ޘRDc%,-*Eb RAR?4Z5AM*+ kv>w39j0طuᇲ1?U9$#i%1QT:!+]5\nTYUm* %xR}? + +L^.773PRTSIz̄H.wocr'NU<4a_|-6K;XPo:ȝd(|svaO2Zwr=.H˒ڂ^.<s؜}IN8c6z#RMK-ff1KqJJp!$ڛgu6w%? +AZqM6\AZstzd(R̈,N¼;ͅ|cM9[N/=kCJކHb~OfEn3u+l<(;X,,$,T_'*][t8J⒉mܛ۟d%^"&bie=_{IiKYyqB*NI K\pTTIܶ}":cPMer PNS7:OY] +Q'erQ?ɑ"?J# lۋ5Z< ɗЕ_qB*P#oB$<.3N?k_荅*J?t7{X-͏U@*HٱHSJWïhzr}ЛQlsKCaoJjw_.TQgJcʣ@pBJG@P:Q%~$)hEl]i*\NKTӛ"G56* չ.0e+9ZPDVGmXNA_ԌY4fAnx JHR{((dM[y!LYZXW6l"}42'|u<|(J257ОfU#I 6 -<*YFeDBX\a9W4T뫲I̥oq=Mm:W2Թ$HuC&ґ{O$LV"JO߹uʴʃkt7 +HIҥ9}qӅ +:,Nb^eši!IRTAq2IZi_J*pGlX,Fyj ۾.?w)')9tC WrytK5=^(dtEQbW%NNxR^a J)aր}=j@f)q#wmJE֕)vjeCg2BpFRY7i86?tpMٵ;R}ZC +ͻ?Nt4 |Ժz.lO^g+ea Ԫnә)ݱ ?Z}O2]rXVTTGL"Ӥ[I IPyܐy^M,0VXt#өOّ&_SZcͪ9}'qOˆ;{\1?RC"jdͭmI\p0۟]@L4gbFW[)Y5y KKI %";w3ԺGzfQ8)G@9H}xuSO3*) u":e-n藢atUC#6CmyĞpn[(\Ӊja:_5:y7=YʔXI4ƝQ(*|AWM$\JkpDBYXtG_WRˡy)^ E}]ͼ +|Iw)+RHsXΫZuW/ 4!ld>x<Ω;F}=Jg{-Qۻl8 +rG;Ne: <9:J<;1_y~J6 +WZa3Jd Rt&6rZ՚ D4NMWp +$$K>9ua.)M$mxZ;9})U*}uDuI (&;"=WIL5"A4[pJAUGgDPo}@ǿhR9, ֔ uE{؛&JMʋLL2cR#B;!< 'Y{: +ΐqS`x Zh)@)I s Xoabbu4#3S݆H +C q)Hrze&696HpXmGL1KP)={}Q:m*!jn\=Q."аU&V\j vR/{oνOE5d]NXgN1M|Ԝڧd)D8BA=ڍ#]*b(>؟/QlT{}&|D8` _/2jŠWI*֑vL|܃>;S\NM;H#"d\e SnW m,.`9G L +k@a)q];myx+JiJa)2"D HyB;B 󊋈1CʡE* \+^gL!u dG,-6 +MR $jb9uEӝ [)ERG $}$[9/B<a/N!wp/]LX:@E>!֭TuW'r&G[N(A$G)xE61r.4V߅<6ast ?hM͠L-6~iVNe(% 7pغ6k]^?1DDz[R!ХGIě.Ĝk*JT:-u]:JC@CP +T-m,F T((ȐN ;R0K(ŶJwZU:.VdJ 1-ȶ9,:q1(@4j[L\R̳U(` 8嗬&{q9Rri&҂r>^82D/ڈdl!'0Nf6hA +PUעjӬ{Զkrl. 1<=D<#jJJDfI<2dx Z՜91-?,If ۇgNX=Pt̫Pva-ĪwARt"u+R LC)QCu':3+Q}:|hE(P1=UqS}JV&Rʔ4nW!;Ʌ?Tj*tK(ހ<1{8XHVU>^.N֮Pa +j\! |KYT/)S%@( #|ܼ\%Sˍ, toP׌ +VMm"6 +]: $lH0pϗ߹{ɴX'U&])C2hV$%)X 8|)|qpl~3 Y8ʖVиk{!lGKNl"~O%R::TÉyiԋ̮T*ݭ:3-aTxQ`@p\ˍqܭP8dc +ޡԋvA@~!bP]f;C' 3bE/T7)J}賯) +1~kete%%dA +"v(+nHNlH/hvW4T0#Uި9 V͠ʬ*O&t:V f*e6_cDg6S*pNxG>6[ZH9Oc_IB(*ha[P3)ym {5@AQ^Dr2t2[mS +!bƍᮖޒZT:*=yK馅Դ)ZeIt$ڈ[eqr!nr6]qM6̙| ) +u(^Ly[1+Q'whtIi]]]ri +Hd_չ,R-ˍÉ@XbqRn9-aEtcr1.R.*C`D!cD+5Rs nJRv-ېO짙0Gƒ)i$8ғn7 fIJീ㤬:RDJGq &)CSk2cݚu=#I2@)i QSJyrVOƯKmi(J~Rƒ+Ɋn@$L: 𒡚/+)I |#%kc\ @kK$ }Qʛ#]^- \ōAS4藓K9 s1nFnDR)rexk! ^ާ FH$nbOTAf@[YH$^k=¨Of9u"%֛R )H'~1]j%$JeAM*:Ö^Бg-v2vnr'"[ϊF,'Vww_FBΊGUG|HPPugA<9G=ZHVU)-$ JUΡ&Wj}7K/'i\G)R +'v$Ͳr +A1JF;y6v% /.]ԍ'~P,B 9 +:qMqSsmm,(E2.tISi}b@u?\ˋ9m!ZKʫ-u(@Q$#An4ĢTn'`1N=H&NE KiUt㿶ޗ:1m-Ԥ +<(1c .Q*ۃpG$' :j&J"EF +I NmF|!:Qk ōW1RQ6~$fV5YXL+ܻ(L螧ьSJy)"IDfkA%˲rBhO?>co4@x'ӷ^yT~mI>0aj}"Ri@Yґ.,M+?1"ʍ! <$ G$- +T "@eԾٜ92ӍIP{Fj!'^ri .RMsSyրң=ĕIMi.僁'*P6їipH"}³m*L K +n]<#Nsq +Hu U 0q$rT/q :ehEVaAiJ*ZV=ehEI>?}L=se֖B~ōi vD+b  l1o<ܪU5{L }xl4\tYQ! #x3YDWomI fS6Ĝ؊w4;|"$ܐ06ͷ(wG|Hlw&ٍl0F]23NJ6^X.SNDr6ҢÄ>5/ +u QUH7O4r$smHJE6jI<#G3~Р:J`N,uÃPM5Qӳi ZصYSHm[E9#!%/-}E]ۗ>OqqiOD,S᧪"cME"MY?#HFOkûeDžx}3L#[EHV$$䏵,Jз/oq)g8u窪,{1d'b<'.oZQÙ^4d@,puk[t]t!^3$ z;ibRb|ga?5>hZi"9q?S7>^ mͼ=UCR!OUwF!1Hl)kKJGk?~_rm9OcfeC,'Q0QK>Rh)|>P.V#Qo;[71UU$ۄ+fBy1f%WLgOΣ2+jZZ˕PdR>u97yLFXQra L6.& jd׾?HP2ޏ& 'oDlj2u8l+l6=6x߼ຑGBTH"5%d muAHBDy8rFUiTӵ'HRT qҹZM:aިc/'Jeq{Tbg~:.mr[c"o QO{mKc!]l<^c7&!+4~~kI}GZ?TqOƏIa%Z- aSWc.mLob6~qF 5M>;D7`&QJzp<E@|?X6MyZP!chJ KiOٻ\FY9~cI_XHɓk*quh 6I&~!gۍO8h#. +pFSl{bU}=6as8INDDf EC*Up>I]%]lz6f Ɠ~|E;d(^eG%_z᧊&nzф'9'6eK)Ár6WNց(?bκ&dв5)>b4l!8pTi8?4=y1 -sWcQm TumH =rp{)3VHOF"gj>\h*gUa9D9tUE(b)άmrT@)k״3qbd a&t1сb9Q<#qUu'fa;#rDT ,dmmFMD=(\HE.)Fy뭤tWzau+qR|Ż|4!5УQdzeWkq~9$eڽ㠣{Kd-B\'Ϯ?i.hm ~U2ypm8A-F˳$Gn fwE%%F' Ҝ8ț²3 +J7ŨǴ7Zb`&U)k\ˇ"AQy܁cvrF_Q8o+R U%${qSY6R$&k%) ~w;!hS**l)@hr-:R^DR{+mæi& <%3`76FŔjeTI%ۓP/;CԢV eis5u!C|6th9Uٹ-š8RINN(ER|f9, y;gfdeFBDP&%SP9JVRi9s_[$|+/sJx$m"z)繼s5DJה1RB̵\ԚXc ĒNě /l)%-)66N{"9Ź%HV7a}/âZ +ije.%3^_փpSbF?%~鸾JV\-7)HeI'o%E䰲Ko( Q*#Qtyiޘ),1մ-IZBT׍Gf^}L?C¸H@SZǓpFð'JR4z#jD?Uq% +[U˘}6$gݛz-2JDpTatˢ +N h)K,Ǟ<^N M-]k66LTY lM*1aSdi+jˆ MQap!q=E7ʢ |< K%maG]lMq4bj8iq!Coᮾ`ʾk5(,\J ͳReBˤ~I(IP>TJQ6\hԶj:IJB7VPi %V{x#K&i/̈́!(64*빹y*RR[eP>7Z[Bx*Q~8g< "I'BY(IRH$eډ4OPr"WXR |8OѦh1B_U'_IE5,i\'z0֫CɘIIn Jlsu}dê!T`Ny DXh 2t"ss%vw4[I6 U/9vۓIi@;KuJ\eZ R4eh*T9 Y=%It!)˼\EJ{[ʗQ-7Bˮ=!a¹V⒝\~G#lw7,%2]n tҤJH>1?IPYs-))@&V9kLV>_.gAr\!$U_-7ԡJ9RB"WQYuF-錗ߥZ91VR^"YoZmYRgf^ͪW7F=c.I.x$%({/ܣs*) +P$\~"}!pxq:_6 V%RI4Ip- J7DM`ZYZ8a_-Hu>#Ԁ|DßSJ@=)?EPCaC@}$EQq슁Jts5H%j,\\)[ I LP),Fh~ix$`I[c׽bYKQP$QCL uP`eiUZK˱$";m8VRP +@EfO; 4:dʂnae n.u>.feƍWqJTI +X#]:b\ݙX+j4l5#&-9 xK&Re24(;%n8JKrE#MúLD()_X2l6kJK<20=Yn-ii*Ȅܛi ^dU٘>5Z*V7(.(yc1LZIi}ASyTBG +T-[t9&[͑ĎC-AmcarS69].'s/0Xh(bٙ9*{$ tV^hgdHK|CEzc'HΉ)H:G|I=)P}E%4 #Fu[U!m)M6{ H S[g:ۯ_% + OtxI>U6ڣbVؖ?9ImkHA!j ";F[=պso MgK1UeHؾJlלӕl#(_{´-r(hcDł{xLEmLM1j779B̩Wo^[.FZT7#|q^?dkS؂8x\JԠA<2?1U50qh~ }+g +ufU.=J2 +TYEE(֧p<CQTBxq5tFUd icPFU(UxEind|Ҫ#I &˾"p;VaoEa8] "V5uI oTTYX(ZObcZ+=Yͺ\#&_>[&?'beɵ/ N6#gاX哛4ZQEϒgYmĤU%ZT-wPo7O`H0PpCo!-&JСV\_'1$n5(OѦ>Sn6T$G冲QYp)uq\V7#R'jRF=BmB0S7q,\Br)CVĘj_5Pm~ 6 _]9&/< jcTXϳ<6f.Sܘiԃ+}5iTjK%hZI>=æ֘i@qqpxEvSݑt`1VaN$-vW$؃M#5+,'S-(BA=֠8O?s3L!ZAVdɸw $s<$Lj6r@bH1$rFD~X +ٗ-!$PEt)*R p z%KQ[^=1->L}׺JJ+k)^YVBN9C[He9?UHPTV]#1"YA0 +[FM?)^]VyZ.j~RIL8BeЎ]^zԉqkS“J[zԒPRwg}sI,TNuWZ}.˷AjIK8f^q +y)P ) +%JY2;L5q+(HfMYRpLi*RB xE-rJcOtH*QY\T*):RHÉ,5TlYK:9kܘ*iRU }hb7:|I)-?qPdY|'2~pO9FgYS&SRM6A=t76ҵ&䖿\FJ" +\]K[]rdlDOvVaGU?!_mN:ow[УTCO\ }$fmy),G!U>~NTA ly9G{qUё(&-K4A6.zݭ7%eeY0e,\dw@̻ + b<ԥY#0ҔY9> #9t_#7 ~l.mZE%CzY + 7ѕp*Aoýb?9m늅-'KJET;sS+(׺?IQNꅔmi0|TjC!E6n~v:Ss~=2q>f МL)aB9,Pܕ!J:t: |po +KZJJx11T)<~/fx +Fp^r)\n'%]Y1кDŽ%Kcv?UmsşQ~y#ܣS +Y~tmA??״9H $r*%<=~j1;"8߁2? +6q[RpO<:JYv8_&˞R.bpuRt))ʅBE+u` ;NlDpKXL jY9YoXiz~ + +W=,'L@+'ɧqeO{!3bB@9$ \VmO8Q2QH7D ߧ Q!,yL\ؗ?05Pr.XQBc:02Y1^ zgXl%ݔ(:Z0IIGaSiP>&HH5./cއ_QԟsJ<>3Ug~3'4;xTxW<jn,r!nJl|RRdDrM-É.)y [\_"pϛYp/THCR6u^lLRmlJTxR{T}8#彛12fA)8һnnA߂iCsFoF؂*0\dS%PQ *m%h[c|}O^=Y'Uǂ ݐlDM<=%TxIRIӇ|Bxnj^A5 rBnQWԡӜ$lkFQj%I K ^y=^gb:ϰ\$UW=-%HLo}ȧR+q'>&џ8m#þz#KS*Pv=C,h<ؑRR.,?6'ˬB~Q!^j(fPO"TǑaٴ;R]S K +$$xVYyv-@-s0B̙yY7SY\uԴ-&pGm+VQ,1q ­mn6nEoIPr"kcswG$9pGH^vE!ja64% +C:[?n1*e*hI%ںU.w {)Z[%f}L=_=Zq #UfBREВM1*1Q*RTDq%#z<[#-Ւ4)Y R{D946JJНy^Is4y$R/ IWI]6w K)dl䚤:d +$NIcsKVQV*#3@- %9Քn0ը<ꯛ[wD'kL^e.G8gWV_t[Kb=>Tu:*y~3q#$ru7LhmЂ mJJUsrNtM + +7F>i YE n}AH[N:){ǃ3jR8<| Gɹa}; ˎ-2m"!Gšu-PpK33%( )"mG.QȘQ;RrI>@cÔ\)$g%.h +RӾcZ䳝J ԓJLxTbh2k:)ۅòG3 +?K&@:Rp߬I[5Kp->''}OuLV@ #hڔ$-o14+Qx>`6>ϸ\qJZnTTO:=s{D,I!fG3 +""e<$|J#U}Bbt*nW穅:u0D6pt/0yɤ!J3|ulpsp/?!ïeE#ሂJ XVB-ni2A=YH6Wژ'QIRո#fX \\JfCu)vH5=+P"Y!PqnCA𬵴)7#HVmjmxo65^*3hn)-&)7tUP\KkL ChlGBYaI̓'dJ~8ynԛjQ>I1CW*JUᲣ+#63 6fҩȎ.,wX.xm9Ĝ=0{1"@=cK!YMy>LeX5.^)imܞxn>glfm=̮df$vXwwZtp%: er-넙Gдƺ -hˠf' e*p +I9&>~byDh )칥YD`8Txο=IPa]Rҕ-WH u]RfLȔDXY6@<‘,Ӛ I*8ƢZnmfraՐ,<哦]=Pkdz K:;0k!f>}eIIgmCByÏJJJMɹu"jɰJ@9JMiI*ʤnA(j$]4ZmRZ %S*T:Y ^`8pOORm|7O蔖jròo R̻ VeMU.ngnVaPڑ ,l"BI! Ͷ^b؝BvSJz‹XM #eFٮHs.?EajLJ䰴~ ȹQK~ŕ+Hj.$=<:h5,}=qHr%\p;+2`)Rma|NE􄟣 +fNϽF.,҄j[=OŲy<(S=@Rs{qM1DAR.rCHGƐuj1rAJ}Aw#dxRnb}v :Y@)Vǝ'[[dmCrӡJmЏ,!Ӫ.S +H6=;NLH!Ɣɲ\W .}(Uy%) ;`o"wBZ95j]/+o5 hԁu(U$At<8+[b*JL.I~)7n>nu/J3 YZe.r<^rjθkR.ʖxFNq0S-%H +6߾(N8 +bzJM.k3n>BzM@ncD4GK-#-KL-x+JN#Y=LgRҒr7Џxw; ><{C_ըKd6^ +NfmKJ7Z@${QPggl&̟zQ +YiHB @W{r-īԶy LftloeK6tٌ9QT4&ҔkN_#T ,Pks7fj+QQx [ P3\qͬ%KWV9805VDFوrwOȲO{zam-PW9r2$^5w8HBTO ʝFdX#[{^1abm%XaktIL'ʿ9OP~W}PjP᭎B3E7I}QzSh&T;3M$H,ޝ:K[Pf jhcc]:򲭱My|?)BZ~~xlCjMbUfJJB'o:g&RNf!F5)$)PÎNb߃t/05 +AA'bT-~cWj>XRVMn:Jґ\qI-L8ˍ(kyFV}%mD~T-2U7tdE׷q2=a +}v9zZ7E{Xܟ7;|S::&)6* Б^uy>+kHXe0㏵.TH-8 ԛ9a7)'[ wEK0:IQFXU!˭ndn7 mL|&d{$ +"ۃ#hv:)pht6$0~kԛjƗI)7 (i특zD7JC]'ر ي"r.O^nJV㙲 N0Ȕs+)T,Iwkqf!&C&DYr]z^Np nP3*nK=Q<9pМ0c2'F +nE ˱/j+[HIwXTȢl*M9G ĞZKskl6Zl6Hʔ*7N(nfi>+ˣimD_4e'n`~hHʢM崁`#% Eյ)FdJߘLͶCRRn)RܧEcD[%E-)R}RP9 |FgfRscñ3 5Pm6/:>r:$n "-&1m:fօLEp\7x6(dNcpA["C9PPԕҕ v3hvjބg#ӜmBK}7XZjǕI(gNۍ-b8GNC(4L 'B)%H7H6DZ)eR0>$ΫꎟQ*CwR %Kᒜ3eiL`>[:9ETG ē^Ӈ֗~t*w?w ;sH?LBBWG*Y?K_#wI$gj_+c*>trqTEWP&bQ&xK?o#d#Ո 8HL}1* _"7l̤%fB>JKMwqBۏ@7=yr$N(Wg!}%*7č+1GlTceJ9VܛcHXds!-^%1p4gH :-}u42$uJajk*tٌV! ^8Vf .X\6:m4t`rlqniDq&@qD#؏Htosn͠B'{,Rp)Ze[ҕZA@=+E?MRDk!υ2 p +\u49DpFMVt9ZrHܛ w$6f=+0cIL!E+;­(n-L=Jͷ:}HLIC +.YrPIc}տf*G˒{1w'0F̹y-)qK$>V͸bY߬y4XszcLJzԬ/$}dTڞ@8kTOi>(_:<|yĥFo{ ,b=Q6m^;3oȏ%|65NU[j6 +HĥEA~w +R.ztW\]o$&Ưou:O&<>1ه姿Xj]mko=Չ>J7}* |o=((H!4g|}ȓ䊿1ݿǃ(q\`9!Ϫإ9r:~{_}Q9eGԘ2>9TC,ϼq0>"6@ *&<y 'p'0֫/-e& + ;N7Uq鹕d}+RsVo$hSw6U-!Y.)<lC{a+8䶉:r;GBJSTVB )'Js OdGTY\} EC3MBQH FP!eǿՖݐ +i-,RJ@67D' T}>&NC +,~lZj0r()*牷"q 7Ra4wrxuV-#Y}<m̪RAbN[xB/iUw<& AVIpqc +R-r_~Pc Hed8*kg^G˘"!G(eQXI@[ͭmO\$r-ܒpՕ3!MJ ktf-m9MJB묶e-'2.ZtHHAϰ#'{̅-i;)dO8u(.b)΀ H{M5(FܬҪ4OZ-J>cM'JdvgK|PVsmT2e)SYwjR=VN׉Ҵf|C2R]sfV'9Fŵ>C!zfI'1$I`jR2B9:oR@#YwIԑ.ڀeLxN6!TN`4T.O=1x'eZRЙRI,\uqBOSTrQ%QS1LM n)GxMYZfVFm |@AIh`߷ <-)c83UD2_t@:?aԤmB)&7swb?]P&%S,3 Uh5=L}E=Q5IN+{qRJ,6 1@q>&bra•6t% )G2^e|{WyJ)A FbPt;ju[c9yXkY^K#'E$-jG-\)P#QYYEp(:5032X 4̼(*MRoGp,,@$6*.;/fÄA&;=;ãMD2-!Ī qKyOh+COS4! %TE5Y !n4M)rU +o|PuN)GM$%z~S +l&spu+v 2qAg\fS.3kvdm3p2LնRIHH]w'GəfUvZiS?rܨ +/̉WղI +#BstJAsn:ĕԲV%*t;D:=,j\[q@.8Qgj0!E+*-}T{=i)o]2vDT˚uusnsUR3GԵ6UoI$x}i/"3e5$~$ (@j_DqW;p#ߡ.+S8^:S~aL_]HQluҴr!찘T:ߺ\)6+*XO {rq8Q͓N5yKe$`t^3e[' rnAugZmY:%nMb͵ #SV[Z3N">.ʎm*Iljby鴵.s9pB@7[[zCOmԩJ!"ZWÊa̓d,6r4Js%Z_KXIEUu9F>l=UF}K8BBn'܀Ek:4Sβ©K$$,7ITZ,sg/1eѮ3O~v6*sHqiVEiIī(Va`LE#P%IůnX8K 1>"qLXf\zzRaA*fO9>Z sT02`ꆄL DcJ;V7b-f9GR|AQ;JhI =@(]Μ6 +Zd6AK +AP{RZԗVl((csX#C< jshFwϏi~WCʕV#NBRғyʷ1פ 3jJvֵA[È,q q9:'4Ay%@ +%@+{HU+SWgeʣ + +J[K$qE |(^[3Lq+=!ae.5JUHTg,tz6NpjYyUTU"7X/sk]&K=6Ra;┤.Q qTK8OL3I)d@>qZNcJ˯V\686 ]o\WUuIRou 4ÔH)vSlRߛio~>P)pޥƔ95,̊U`I_6< !FQ) eXv+4-C˄*%M/JY2]i(6d#iIڛK )eGTx yC7 !pKL jk>BIG`;@~֪ ?QT*rf]\&wr>0,m,Zz?LSϦ΢#[{[q+I6YI$lWm|cB$$3NzIsaR(I;b!i_a v&BPT>k0ޘRI6| 7【`rT0Qm[lmEon)8ӲA9F[f򮕂n- ij>/R9\a8N.< UBg2t%;1BDpR{8|ZJGR}*S0*ױmq/5u5Nsm'HxDRۭRK.iNԐo1dFI„x-魢*e.Y)QǦ(“Gح3Ho2ȫ3fK1 x o6ll|'8PHIЕ{_>'"nPRmmPF莫.$J!r]ChBJ[QD]ӔRsqԣlm{IʹVUʳR9~|5<=jC6h(SI"ݍiS!b,>ح*vndQb Qrܫ:S8VIRnI8m! &,- + +yDN.1”:n6N_nH6h +'|-J7ff.@\hʞPjT.nۭ,|q]UƉH#r@!FCN/Vx(: ii 22$%)'Xyc$kR_0zɅNRfVމb>Y7$nw$]CTe8H/MS4R9 > KH ѵYC/ju*IaSmi!mIq'I<9Û +>3'PGRsh\T_9-H]nAIn$Yrt*X~^S#b6\;tp{RGPm||}FieDŽtjJ8q)JE*S}WL]HKb:UM-[P<$ px7IK !@-7QkGS]I ~03&\t ;ky_P˕A*46IC]ǴCjg *iӉAmyTKS(q*G-h)KنwMUQK2R-)LڐoKBsQSp|#k|4s+AI9fI6t8B]I *C0PKn4I=P#eDZAu%^,}43b28pTQRy i2T[ XTBmeC7uN ȕ6ٵ9QPڔ;~dNI!k%AiMmqb40@t\ +ksZm#!CSnabYaP:kmd{_5UЂlv c6 H3knQȶk7aCᨔB!! +!)p2HPTHO߈KJI(6HHJ'm#6lpq”uT_ŤpB/b,twٟ 6Mm֙n$:ki[ۉT"U6m-LHHqj ZHorZaW.`,҅(k"}-rTz<ۆj1N2J$n8P7 !iGȓ6mt<Ԣ5V'[ہ.M;(Pӄ3&9Tm^y +~rJW @TPb/7r[@ BR7{% &аČʑPbOuT :V͘=бCÓ퉚q(UdY:Bȹ]KM+HheUYiW_<+U1l\; B b/鈂z}ʃuêR?P2zQf嘊$?:5Rg1_-2s"qtR_99ҁr/ǾUNp?ibvMTq +mV!Hy/r+h 7>g[#ėC +B@X[xG +S$ُرM(Xvt~n,cn1.6tSЯ)qA(wuLu7)굣c +kr*#sIJ#~pTzӴnlF8@ZN]V= 3PE)AD;onx8t mgT'DE4TstA>uJV$J mʲҎ5GM e{K:JB2S-5ˣ<4Zl6U1Z,&m6m}5 +O1#eM:S)D!?)PW:B]I cyb*r56T +S /sgi^ߟo Z64:'*"Jgk +ɴS* ](MTH68xd2&e:^GvN`5@]IM4s@YJn v'1'9LU=ߒP-c%cʖA!*\ CnfByk}FwaOέmUflI%TnI ouAUӽRf"+ҩИUKwBWm؛w4|(5r%I΢n `<rm,jĭȦCeםyM86,e:ok$#m ҳ6kV˒%?)<)TչIaY8% G\=8?< +Hn~1ԗ@ZS5!! HH(߅o_Snd(VwUO@?w#vM%/| ?=)pbBVS +ysVK*8$qEŢAVPʲNeJ3ݖl>%Z{bUr=|ɶ\ÑnAĬ%|zoT۔=$Z3i~aKQ"nBщ +ST +qjkZJ>Q"r=Ll{YYܟ׏Ui9jCTD0}\|$)#Ǐۋ-Z"}r}?tJY%Xb?LI#{Ӎ6/d&>\{MD%dVAٞ IQ  Rn !uR*H"l\|CST-Uj_Cw#,j =ϏvYΕ-!J-mf$)>ʖz2פQ ܟ[5[I_?/87ǃ2OF[k:Blev8難,sޘ7KoIQNmֳxzL +6FJ! $,\HO{yS\#9pHtSm)~6VI6)K=xCMP.diN[ ?<q]#iMo}SZhQ[gH4:{U#jGcXyk[N^&PUp a dLJˉJND@(MdLzZX-=RXHڥZs1TߚSYHKum- +jOU:ZeQPO'" +lؘg@j7CSJJY<5 ܤ8TRv 62t{#t̼Z ZfV$jhˋ]%IȠ +'.Rlt7 +Vzʪ +m-?i +wN.AU`Iۧd:ԝinent2xn@Iɡ(Z) +RV4MԢ c}3uݬ13əP(<6R2mI'i牚i-Yo03EmUU'ǜmF4 JԶYwMI{GzߡtakZQlUQ 7r\"ſPL +&ܜQaT~%tYr_t'g~zޒjmDD4!9:e)V(W=əJby-JQܞjf,vtJRrR.}-f7S蒕l!pi إ#(4'ےRok!@1L47QOEئ=l,$s+Uؒ@*I%'<3xCS:(+ʹڔ%)Rww5N،Pl&TٗBa]ht8@] +">_5V]ґ~gƒ}1צ!bj()YIFB%hNd:Yl(eUk!LN:$^(+*AKr ECCm4Κ說w)Rn!J˔gךHtYe}Sde:%_k-i6*VJ[a)( +@ + _w3_.t[Nu Ve︹pFYC`:DNc90FlfORʬs)DD}tR֪S TGnLBΘQ7Ґvy8ht}"jeP{A :I p?]fľk(r_TYy3)4TlpJD/JT=?ҬNaƕ.1u9m6~]TqLz֐Zq9UdV  (b8mB$v4A8q)}RD$,J @jjN).8TM'Q0JF yZ7Q$&$N)<윽fR6b*b\xNG(qvL$msyd yr_q,G{uūjR88[e%N.Oy/~dUq6 $PJFE0}>(ps^qԺt" VƁ/"zpVFYG[pǀFQʣ&(8&sRЄg<87XJCqQlC*}Em{6K׶3x* "PsRQS9}bjA/"H +^RR kxVVÝw֊f*7!(gpiNc{-?x4%J\H/j4g.͔f͍7|joGJ;~RA¥Nl +Z(r"Mu9ҵLzȊDjL!/)7ͮb f t;\GyOG~z+\M8y k$vVGwhE4ڇKSM*Sx,hSI!^Om p2neʝP&RF~Qr*<}sBۑWmH |yS[*I[M onu߿s̼j}{:/),I;Zq$(]*pR +2 uԍw&J1ɕEK>hGܫ.b钮m9k&QD3Iy{:,d2t T%iF3J3:m{ ._}EןfH^2JEmWRvw}1[:9"2澅|.7 zbB!* 'K+D=,ژqH(@tf-u"Q=;T(W:ÓTnrنJMFC\v֕, ɲ.\Mr8sq:Zlpͯch#4Y +(AV<3Vc HܛJ2j+ʂB[ Pd:k*Wr:Ϥr;Ab:XPTA.5"(x)%$xW,Pmq{#W%m&C jibۅ!`t jls~On޸r G!ERxGYdֈ +< +a!l79F!&QI?)(z'Nc*s*]o菎4^Trj GH*Ka_ {?,|Y9\O{:r0=vf]d̶\o{jRlNR s&6fk*WF+=љ}'K>r~OquUSʴ2_TPa()ősu{b=ձ,GVKP! ꒔d)i<$@|Cz4K07qR끙\5W ՞s}6S2ړA($&'t>0STHCC6[iKHK蒝U2AtJu(*?C2dLJRGEʐۈ'TGtJnr&bfVu%@'pc6aQ[җ3HrcImoP iʃ v)Gu)^31Bl9\6_Ų4$),Smma::ŁIHR[^DK#|I5&H~ڃʀ:'zwZݱse\ց,龜HU&7Djnym6̬eZWZ +Y@'*<=Jjǔ˕ +HPΩ 3s6(QC3tdKalѕ8{yZh-gecHh_quJ`4#!jRQ?; 1L=iȖqk"ʬQ5Bhk-32)J6-;6b*^Uro+3z2̻ɨL[e7Z$;o,%6V@St1ijI(aZFK84)Rܩ\+PJRm,5:C2vJ[b빞r$J1KcpDV¿ |.zDV> +BR E(__]O4tY˜px~؆biΒgP Ye,K +#2wGdys +r"*y|V䠢8,-a))ejm~PSZBAOVoM2I]~L'u$ Xw{>}ˠ ;'UpCѬm?-E?R|1JNwQhn$ -F.&Bo-}%5'mane9L y@n{c溑uG\Rd}УMLU\.kdtt?t̯ +CHn~cJsEX=8KBoC\ֆ,KtQ K&NX)z)9lX%$qtx3j}gq +)MI{vT)rs6 JKݒ s1FQ#Шf~%\|ܮv.;#MS'3vBDXnDYk$~980z.ʒf+ixk̰mX! JUp}UW猶sw-X`<`Ђyp븏\C ꢝ@x+1&A&Kͥ2_ʎh%-T2RO ;8G.C.6':n r@:;mms}`46i _rSVvAndz5|;4fTvB~a̳"ָ`3 3&478jHM:IȅJJ~jIzJyejf? d"BP;j?iCぉm$.`<|-`'E#ۗ",87>θj;LBJB]/{o;8S}fI,ДGG>qTJ M¶Yg C71Z"!Gc!Q)!!M>=u{ Jo9yR A pAZ}s{4X*QYd5)Ԧ&hB8P8t˺ *Q$rdE k)o}Ć]QGZ}kRTEqGpKEmܰJ9+C.Y* Q;~2鞚K i!7H-i]2QB dBne$|Ep&[ jT 6 CZұTw9ep_D=,Z(W&L% eLm.XfQg +u#/PV<ܞao`n=M&ULܔ3_W`p8RJh̔ *nUǾy][`u7s9[p8L>öIOSE͍A)PWiLU_T +>m q-!d8>qCK \%WBG1nRڑs8%im:BkOd"FXrQ+ZDFbSm8Y1Q'P :bJN \CӕS)v-cպr*e'~vǾ8}.Za.xDrP;ㆩ$lŽDŽWD}eT{'Hy+pb鞯v{l݇PjTs? kv Q3M*Z8Cq WUy8nb%$Or1VyPGo h/FmM1˟ĂhCbY)6|rа\'2Nec@}gSh7Yz `PN41:K(X79THf)ǎG}-,׶VjޕeJpJA z(O#s^NgemgP2[OXJָPUr{Z\beUYu/.(-qA*ım%*IŽ' ye()ZJB픤klU}eB v%Yқe2TTxY\bI23 "Q Dz/h`Nʘ J='(XStXyI)eqJ8v>]}+QI+ &݈){fB'q 2JAƜDe@`KIC̹(q +DT/Ii2w+7QK5m6GD]LJ!2iJ6/|R +Λ6$i~5Y(zVQVYaeaZhs0JX{nu#un3]_7W֏}=Ĵ)JS`gA.܋$6 ԭ;j%զ pl"JH +rQ'MKaw*UZ}Բn@nM;bJH"uMLBĿoU}qcr.zDo\&e=Vu q^{Sa SA vZJH2UIYK(EQz)Di'@ex֊J mm.qd8 wrW]*eX*+Zu7#"`iX`a ?͕85m79_Q4|jyku<ɹpN2~j*p,G!;0›=r o:rLO^tW|#ي'*9juཷmI%'tYI8XX9Z:jMͭ$)r϶UYKw(ud p&2fjvT.G|~FOv_`!BWVzb&i#NY??S)={'|P}dwKyrڞl>(L<{EFCO\Igck&O&c4 o 8ITDh}L[$ Edqb8\! '@_S=oFҥlJ8fO{5n2M5SԜS Y1fL~GE4{I0 +vyC9ܼUaN9,w>Nl=' +S6waoۻH6tҭxZlkHQܬE@WPoA ߎkul[0A|idm3B;j, 7kjFX?Y>#/?k v'[O|?)S'nھa?&'0mL{ݍK )Y-I%AU'xt%+TB_2nioqZ^)nJ{bb:Z]'"A®꣔Ա!|jU]oqb6ʼni^U곑/?3-JuE۱aiPPc&kë +H6`L$nt68>"7XoI΂3q!ԕy-Gr@ + 0?BT) n}>c:SA'#΋2ueKN$$^Wn@#϶Ikh#؋cYKv=51ʂmSB۟1 |Z£<`|8h}Ϋx4$~YRYGӷT]>r~_WE"ryGOһ`wB Vya-GQOd*Xꖱ܅VG@q*?JKͷROaL+ :|"T*܌(M%$)xRK=dxC΃\p™Ǟ!Uu\U* uF*[rŰmdr^s5E%?=8G>,? $K8Ye%?WHO;X"I?}ـx\Ԓbѹ,}ޜYoA ϤjD#+FnUll [P( +R|a&m-;:PjJo7eБ{?1J#Kr}4@(h;ij˒M\ZC23 >O,*Rn-D_7W/"6=e8)|@xE{YY'{vԢJΛ2,:!Ɣ@v0IME oxnKT[pL))%*oc +2 NfLy%Gqw2`(-s`mq|BMfY@;Xyzb`U(}."ksYD,*a_`1kIfCt +sO*Kh2ʣ*H#%)7&دt!q|Z$m|AsJSJ=GxZniiW&leEC)* ҃y/S}L^e!N5vvBoW-2bh^+IY"<21nmnw% +_`~/<("8ID5fZT'xV+TY)+ٺ[A͠)ـ<Ѥ&&TH tE1_R뮴Q ÛT# d/? |'S(bij5i}IBt<ۚq BB>%$v8h0~ 4UJ\cMHf3h'Rfȃl^djotƦfԖ>Mlq8▨jY(zbVBREN8$Vj mM)OߏRhK8 uJmۇRiWXƗ_)Z$;?J4ePBE:ZVѲ\ç3~Hr[P+7[a.Y'2'=),JVẒVl>q SԲ\PRBMpSGh B\N-L2|Kb +R +nlBFw^JR^g}n ċ<b{sL{A:a᠆C^Y$ SJ7@gQ@t1SsOmwsai 9sD~[ ^V:YJZ LirX=*Sb;M #N8&'*@  Lwh5M^JMO I$,ZjN^{عO55gf\1\@Sp)iܟ(F=MSաeZ+=<()tkƝ!J:;tS⳽'adA!vϻk܄yw#q4ImeyV군H'('oj^V$Dԉ\meC+6JI[H#.?/O6"ҷOkK|I;~D>SU=Kfeq%~úAo7ΏKe8._'s{(vM{kj2KJ} _T<&(Jq gNdj.;}]8DԴuءZ)<F +JĤҩ#چB{JR >C5) qT(CQ}4t9c<9&˰Ju$$8Dk:.9]NUrI54$zE p|Msrj.d<3\9l#y6ks/Wt8[LQ6XiOKʫR +VvRtoHIRӤSb┉~. a{`8Ar!`u>0).(x[6@Ci\6ZIѰ Ggr"Zk7]Yo>YaDeӋaNM:Pn,8 +/[X]r @1/+˸ +UI(ENze?EJ)ptjvbx;Zθ(r8MAO26w'9gI.Ja45RlOT +udIDFUTiG)a&P/ϑ譺<ěҹ~'2'B::9)֍?9N% |̸J{O4vQRaĥ},T$XpQ$LYK)mF`xxՓ0ku77-2('~L)xP~%( @&n.ϑ%Wt#RFM~s彁}'b唔|eK1+>Ai2ZCA*05[Mt +o2_mK +7ʵ'25WՕ ͬLAr9;KɥDz]Ju6jEnJ )Pb2ԋe\ 퍜zdw炗~0I#pNl%Md61@=A6"E lM}NI8OvIl-(tB'LRuX+I\c,i՜Ce嵖Vs*GN,uֲ =ٞ"׺~h)Rk4>BKg. I+es2ʓ*ͥܟ3ڤP]ŗ&Vٱbdvq +em}k<8łl%r1)HJGWPRK"ׯt6נEt\rG)\$LTLJ[B/a{ x" &Gv}Q+͓9Јɂ3q9e4Z +@'2$#5OGL +3ea9)$uj.TE8pT^u$) :H)`x!YTDr.[F LT ΦP2AB:ܡePk GWV(@[U+o7W!JTt(lyZZW4򆞈zVUOjPHZZ:*NRWu |d!*~Qee(Lc4a[s:Ґ>_L9d(: +3k@LۀAF1rje˥aRWtl*M;rF%vK*RRSr~EU7eyl5 "*!闗[ߍT4ĥ7;Wo,{ԨP겛q#} g hxK .Z,Τ\-a娨v#ܝ_vd 009l|5 w-j#P+J/CZs#&\jqFn(ۏvh 5pL]\LunRR6Kxt:nA > ~YvJ.|cbv5m:~`9Sxꯤ+7E/<Yb FjnKɥ*&YvK S$qc*~j#W\Bā6;PeMiDT$B҄ Ki XGHCj pqlas}wJxxEq4Bˊ*&I:kQҷ4-C ZrP׌u\|wXiGh  䔨؟_ 6\^nf:hE!tj4dV$߰ŠrZa{]&`$ܻG dXv4 CJ$Wyj*̄˭,Vr,"7é3.AbǗ G|.'C!M[H~|vz6~EvKQbs QpOtiĭ6zRGTI)M 7>&I1SO-TRYJ: HRyoHrh G-+7U\SM6g!$ΨkmXg>ch@&iH>9so)#RV^nL-A!A)"BJ CATr,v^ܣX*hDFKf#%ƒ,w 87^ LL$$'bn$ {E7mHTu@6x鯦DŽL ԑL`a-PۂSu(7/ewQ1u^s4ԦڅQNP;w!eHlދQDTXhs*!Do~"%?QTha%։Qq+E\7%8 -ՇFy+l2ޅ6cM~GEE$| +Y֋SOa烲ϥ\j +|wWfhYHR/{]9Ց^{w9Umn"zҾse)\lYeJ}쭵v>%2gKx\S? e(Y9ȸ2R0N +<|6ӟ2.8^96T|/C؟HO',U4rdڵ\CfKĮC췡H>-QW9韡Y4b&cKVPm'm@G &in`B&Tp*EC-fK0$gj*PlѦi^)EǮa)kC Ssr4% +-۷k yZԫ4G1>|µ?SͲп vD*~}HEs:D!J4i||\~{OL%eIX e#ha,< +mbM?= +YRs7Et{bKN)I=0;soG֥MgZ_AmyӪ߫QKTOa2|gTӗbqQjƝ( +t^@7 i()c]m&gVڵhQ4B(+k N&˞}V<njEqѹT\XIl)̄nCb~cZmsGJ%mREJSr\@Vuru06 JJI0J'=JڏK/؅E8A I#p$?4R vP슃 +tIEґ{1 +T*NN,!9jSi9$l*HyJY 8"s0jSJCtPGfn#ZímEOP)>h^` .vMzeևO((5c%U9Wޫ PI 'UJJ"W\7&iObDgm#vDGfJ+quj.SnPijHL{C](TDDs/Rȹ$&USC]_cyT&?w"kҶ9f $_c? ѫ뿮}=K!y<ݭ0əYu$e$l<$J'rT zSh'SZl.-W@3jWWS? ?η_pS`<:CIH(W$?~.;7aTͱj#:[eB?XGLI4}S(a뾢'Qtk)A{\2;btH'<|O>opxLKwtVl49.<څbಢ8:B2߇<.HmQbS水:peW7EIb60o1Nl LфiL4)@;phox ՖTE=༢Ci(K {c^~w$!'oj4O7lv/-c*ZZ4,=F7 )I}< +u|I81%U',?_Vъ?k YT\[>0"?`o|@U&@3|y'7DŽ!4<f6%_aElv0a?7p_yhϩ~1Պ c'8GL_q>HեS +}OJ=жrRI7>j?ω[YsIwtK|6R90aWScXe}Q|+Ԏgo +5 ?ӧRcCnJXNP$1(۶=QT0hz@"A1_uQ4(ٛ<ӘbTB[@ߙ?7%٨إU<ܨPw>[؏@*cl6M??uv2~&m';qIa,Tm2pbY>T19jU~M[Tc6> SX1)b0J_ +)rHGߪ>e#,FRE**[Hx.KgW B|[~-zYe[R{H$L(zlA([RqQ\d"}JFŭ@Bx eK(Gb*Mi8ʮVcYv\t]%r)A?$!jzǵ3.ȗA8R,7ɒRGmaB+"Y b\$fQMsfA-^opO1j",m-*zɷk)M(qx=[WSĢ\t$48bAF(ly X*ҙlŒcb3rSKK,hS0JKYR7zk_כ14i3֚NJV.~6p!^0ǵ + "a D50ҿ>Iڥ}/ThLzTuT+a'h?;[p;Sc}|^Gf[Ćr01su6] CՇ4 +1qW|cGj P4ʂn4: <4v#ǢCLDӸl-ψU ܫ՛ahǞr/'^VAI;ITҕ"Ͷ(}m$#qfS27 +󙄌7A +AV2D/fMқ< y9*mǔs34RmnqłB[,%Hܒ}ӎ3xr|%c)%'ROeJ)g A-&U_iK)*+VI$qq2zK0[䆼ڊ֮x cѹdaSE?ܬĩinVP{SgѧҪ&3Od|Ar1SuGuQC杢 nM2̩W2M̛Ǧ4X>5jSqqM9ҮZ_AI!N:)$".GUf0Rf/HaJTGam|Y{`6ƣ˯&r[X%:MT]W.RM+=/YHUdE}'1OIjM:,ov;q:ęꫬjfH~SY}^jӒʜm%*r*M+SG\A^Lum p=13i-''B4+?W/(:R I\sV_bZG)iCZu͓Od>n;rh6G&E241WjTx;}~Oi)6R Js^k[Knr +[S2e+[4:ٱ)甞a~0RҺљ_ZxDg<^w3/&NpSgE+j/ + dlt'RXMyI48ܑ iAHܞd~,`.}$OJ7Z6+YzEzy:Xw*n Lқ[p8%e޲Kj#N/TtSC{lmOi?Oȧ<(rr9wHl;@5nbziPqNZSJTHjط[Gv@"))KŊ3iK\!\Hې:{nM:Xk1R#SJ84u %j '5xb&Ŝ e5"!^$$cqd +>Xz7t%Ap ٔ@[BsÓK(ܒ|s,n'4-!-6_{*HR66ϬJֺ=Zj\$:ˇr%$Ƴah.زP-mT\ӥ5*Ӵin+S2MlIȔ:@1vRH>CNhAyv0NuZ"EΝnf uSt&UZJHl$}~3G;t )reBgBme>,>!/@f|$SrLCjAWDd9{NԦܜT$Rmל=cJ aJ7JR8nO"Єk I1D.*9-'+J*AQ)m7ʔ%$XejSW_ق'*Qاe Nup`Dz}.n~ψ~qcp--]8W98=T|*oVVSf[An*=5h2=J3)0vvm֯U6/$u0gHMamTXIQvWrI+zX)z|/KWŒ gdenfeS9N3d_GU֨\[HËXfRKN.b :..wFhl|[}kg)Ut#sWj"yĺ + HUnc1z@Ó*myn2RT|t!a;*3iAcTb2 mε!\4M$[1闽qDA|4@^A$/k:m- `q4e޻S{ H{-/f&[D/eJ%R: Tb>#o2ŭip 1å;TJKo0Ф]+Zu#1>ɳdlS(ˤ7pa-PJ\%:ⅶ+JRSrv R59:VFXf/w78UJX"}ujkSm(J2*7q9R* o1oZJ>#qJk #s5PdŮ ;PZnum8]cd-JGnBmjxbI$-ԟISm(glʩloG3Le+Jw7T +(R5N_̽Jh2$r$ܟLmEIUAAܭnzw]ڋk)7&f\hq!aX̀-h^ޝ*Ǫz<1%)+RP~Xz]ig!jtHԪЫD$.ޘ?f:fE]0+zr PT$Wqdqv$7*Ivlg^.)En rN\@%Pn6}brbqӕ*m=q0NZVo/T-O믡%-P!?a6<Nٍ`4(ZUmB܋JԒ +I;BZ4X5M-ĵlw8 ɥo9 ([#gaЛt%< +B ?c>Jl=I +gqV y$"Yj%9?S[JQJ Wﳣ6kF7RLVTse[$ 9ė_K9NzbHb|uJ\QZ/qt!i_-Pq_lAGm~8@@&{h":5I^J%HpT&؞Ս7ꚕC(RS$p,YnZTl +H6$mt)6:ícl5t38jtH߇J1m4 ^Ң}*wOu+ +SM 92~n6uoz$ I&x):GuMU|!~: mE;,;ZݱXbvZ ^wYjbw$.ё'5CbJ' w$U.l]}RWm#̧^O2JJ ꕧycS-0V<>y'a.7oFj $1o2d[M5] α hΝgQf 9ok2 "]lbǑjI6T"ޯEDG=HmmK:!=nimRi{^ʘ 0T Cmڀ%``*qFea2˲wh$ +BBGTmlTOI6K&ú=+ȯ(J!FHAk~|2`\쏜u#3ΜĒd6I*o[o, +ī2faĝ# 5U2\fh *4(KjR"$r,@>DbDuBur|Ǿ$f\SvTRn!kHk5Z_ +PSW}ϩvefȾ[؛ainZ;4Y7{ }145w-H*o>:T*w $}pnU i$lAm BR/r5T(lv6r1ZFCJ6ha @7K9GR +xI{}O=2IZզ}:23% 2&n6&-Y}Juڛ2mlGTB{mm +'bR?'9B)L+Pn-n= ?$U[|-ba_ޜ4X$\EDm@1%z +:JTj0 +WS6Jۼ XR]1lA@ DJte|DŽV.eIS1F+IgiHZ\I ;"##$ZR\p&Fz!a1 Q\3%rv]l4(l TT,O$Pf+8|,tX3e6K?{=1QYj>^=t̬msp|ع*h${u䨓{;'!rRe q6;;k]MꞞfXud5 r}<(-6Iȭw|Fa\qVm{ ÃNzʳBZ*9d R{)<=;suӺO!p1@scv=K1,/\u>|M GܡiBhÔ}- i^h#nP biSd{['4~oxDME(E>jB@jOd9&Uv~d/U yFeH)n3x+MJdO<9sRt$p@*_GAN3Kc6d:9$eQ7Hc~!}H3(bMaz{VQD l1pfc ͡8VBUn)'xYi +lNDŽfFXJ;QWNZͮ::rjDX?&I#1*Р*%+s/~^LjH5yt <aCE)yĺNsxXL7y2DYSKY SS +w}F#8-rlD 9.< ~L4M)['LRJXz?Qc F%*X~jդ2ʏĶmIoz& +Y4lpnG+C25mO>`R|(zGNT4 +|5E^I}tHtF EU0?Ҙj~2,o'u~WǘS=Еs#3F_woы Xt&MaQʡ"]/u.=R?9ʯ'ΩzL n볚M:y)њ9BPhA1d'/i= +A\^#Y>"9s,?kaM%$v!Jc#/_G~C:F qzTzWCݧ̠1].6_H( qb6+ )VNal6SmXؓŬ.mU|rm& 0 &:!)' " `uP\a?<%֔s6A'u$Q6F(M][=h,)l&;cnE«`EXAm^!!d)MnQ~.HЛ44yCi $ 7ӌ5+%OO#t>0opI rJO+ 793zSOx13VҼFY"ۗYWie?ޏz+CuNp.ױ],u*aE,;!(0oA?WʍC2][minrR?&8dTtB J ,}` Iħ?=>³?6IJnV7nF;2 ++=#Ou/ʶ SlIYDh G􌀉*U'焑U+"+wy[.d|y?}tEC)W]E)]C*\[qgwSG#8x5ݿf7C/'ĩGMG?LH}6NRkUp+1G /3?XOG jX>ơ3G$ORKb꿐avB%9uS<>PT-4vC)uz!Yn-gGmOtCX}ы"KB~T˷Să M lϟg/Օý 1 +;GG<ǸC +-@ ;PRM &,1+,h$HmHJR씍T$<,MHxՅ`yߚD%E!D"iuM*Ic}LZ$SKI ek!6m!QẛnM,xҪLXD̹̅\ȎTʡb7&%uG AIyGt%.Ys T-ǟT:9gkiknB6(m;E펤}tB'5IE9AEjP;Z0YTR׼ǘoG}q2b+!:&Yǎۋ5VhkSH/ +58 M:Ee'8KXODƪ K"RU46WԴ-qsjKy; S6 ylz8qz %LSFNͅĽH.]uXf*Y!&7)vjv +Lsr{w @[eJҔVd.I&-hQnE DOƕ Wړ?_4ƴ֠ axn*X=Pߣ[}¾-7+] ;N;]1[z\IDiT7QH):c쵠 QܭLJ:%0R'qq焷~Ok3NNkS%3K]k ,ih3/`Px(2en7*uBG3u7^\fRЖs*Se{2Srv\*^`I0ڄ( ے>69O.w|k~Ƚ;n!1'2bNt6u +6 vM)u1PydxYPzPjX;p7(v" |6ɱI9H9hBieixpJe{)CͫB FzuFB ҠA -PxJ{}uZdT3X7R:Gk 1уl.qզ藖l70A)iGBwR\1ֶgMI˦Dj1-sĸ)MByP*"7Q $hU- M@V3ukZMJGx|DlB$a.EY~[˖򒩅0T؝9.2 Jony/" +[h!VU%x)Wjϧݎ12fhSHd 05͘G +@mw1 'f}4󙩚e@[D[œwZDR#My-0TIQB { $ +rXL+Kܒ=CɲZ +)'rxk*$+ :2˅Œ,Se8iBAE&hvALb Du +{;mQ#9\ bJG>mEФ%7}:kW( +%*[]kKyuPe[^R@tO@گM ][ M +۔Û (xK6Ze.!yTSu#3&3i. FDɜKyIpu+)NR7op)zHRL_ԧE)|$q醕{$ +A Vu 68A+JNL T@RSEDXAZ,J[I m~xhTj$8V Ez}jZJOLd%T.JSv-=1זb{9{۶#ɪϢ o  iMKО!&L*RY:ueh %79n;//4 +GRu&Kiؕ MW+=I9~'=4E Bs7 |_nU%8jsO8pyVRSbSkb<infΡ2QYTXg/R=k.'DOal [ǿhh2\87Dqq>%c i\ JBJt) P{kډӭ79hKjlMꢪ,vD)AqC7#+FآbYnA!FrzG5 А;!CGѼӯOaהY}/{r3װHNr(zNMP@ H=FDJf08Bզ@aa-_|խӣMuIvJVֹ>wB8]5 i*7)M}˄4fOO(`MhrR&aeJ.T-@/qoOnnMdͧJ%'[+}4=1&pʕŷPU7FuH})qԞ?Lf)m6D(&^zddIYF=cǁǝt (Xkpe| i%I7'[-nA2;駺&g(5y9u)״RUiIM ZR=5UՌەO{UR\1sе-B)~l^$5KuWb&֊{'*{(8' u)zY H6\JR E ?$u +>jLIN_GJ6&q͎ }[:+F%_h^_jH,%r-7О=%i +q$:q4+cE=JrI㗁Ѐu3̜ ڣt90.p~?uS㽻}q╕(S5.}c2m!ftȎEC6*厾H@C.2D0$~]>'ڍG8: sϮM + f1(E…"9CO-nIL~BO#DlOUdn[ &~"֭l?E@ncY :Qk^Cnq*͖JPʔGpxe )rN~<3ӒfF~*R.tS6]-KM-]i\=tC2?).fRaMA6f0={ $yeME5':>% +R;fkxmL7W4"[P.^ѐM7E]aOé$ ĝ%"mϰ +n_{aH˙L'3PU6|#:O0aHTOk ),(r 龑p0RO0(yRiq +BQ# =]}U)6rUTT#XͼE#=&R:5H'nq8ɩ!Ԩ%\FF^~PJ +“&۩Ko6UXRlb!{n:OM9:tԪkDiޕ ~x%JՃ'^#q JܒoBoabYK @ʩ,dϚRy^TCQ:1gnmIlzz,r? ViSd-ڹ&"Xabtg@h˼9RlOuD_)iRm ?ȳA*Sc*a"RѢO#&)lJB7uu3(?°{! Y*=W8N>5ܻ[lJmZ}صd +)G }*NERN!}k]RiP>K" )*J '߾ּ#']o j<^:\Ol*?3[G1=`$'&m1NL*~Jt!ڣ(n"ꃙLb^ Վ9k~O?K\mt5Ad[FWT/sUn}û9a‹\Q(O?~>Ԥ8Q? +W}6WWX'MW=. eIV:9-^'G4X͠/u*k |T}Q8yx=!>'7F*Y=|mv!wUytE>~4ZS5.O +/S@#]|xLSc?ɆBg]?m2StSn'>.8O'q#Y_eMa]jBOaWB. S.1`'BAg kč^mA(ܤ/Rn06,,{zkA'za 5m ۛr gQwh#9 ycUx#W Š\oO"Q刻-]G=tζ;HVxO$-VgRr5!;w{oАMۥCjZ2džĨ!!? <\&}ر}`a~SH]U6Ν۟Ln.tiۢ'*&S-{u@ȓ!I19/[D*PF\3P_ 6WnRRZT)"ڂ4;}[,UzSҝrEIi6f clZqIq _,A6>n'GU}=CHa`7_jɺ::z"z¦=uJ_wHSo)^K2X5/ /ʔRۼkG8.Se 7zd@&q~8 H&يBI]ʿy侤c\t$Z7RRO ܆XT8e$ 3ZmbMGu52 +H-#kG(Z$Gi9WnMαʚG/66RPjRcb9N8)CT'n=i MV.>"swGjs+B+62X{\B4DJGUJ]i'{URAV#qg%PI:ms=qq[%%TF>mq|&3 Y3."3iV7ߌ#O(Zh]_mI "g xu!7's>g*"&Ak}%$ᶨ}ro|\>URRJHo̝H3 + #N*J}( FYc2sZs-#^oF:Iraǔl)oI'o‹c@nV2ڔHSi@3jI6T \0fcٕKSZ.!N-[% H&VʑQD$\: YZdr@ۻp~XX*Xa6,8luj(Có7-63$ehc'ֵcK2Œ({XJҐ(\wc +$h裗6 +PNXJre4Ii.+Z |@MƄBX5-h%Uv1(ChQf2uN9tQM>q6-GܝB:ՇQTjlc)fJilePsܞpjܰpHUJuD&ވ8IlY#\$VǧH4Wq=+ CKU & +ϛޯD~{p!#AeZu +쳕 1$ Bu󶖴?$_˾ |P@$:mz@j#EdXH_7ƈTkC(Y JI=7%'71N \0z2tiqn-=Q5 +Bsޢ]U`;S2lR|7-+w$CIJ,jLK!z66t|0T ,v|6.!UdrxcY{0Xk NpIIr=1ݮ9[yoJnsar` +w^^)ZZfEM˕r( tȺߒe!{q~$@:m=Z4_GTܗ]rURrK2*$^ą&͸ٚX6BH) @l3itt6+D}ЀqY]rZlSWi>;rR<pMȵJUgdRW}c}t֜c DƣA=-6OHb~BZ/6G1I#Ůne3'Ш . Ix@RT0Gy9V4P(Dc{WA0SN!`)Drj|IqiK m;xGSVeMȹ&!ܫn0- ۜI)1#ÊH*R}ش%(3s}MӅ#H^T58!*l|&ۑ )'eUIxuZ rx\AUJe}rnz X慤:Nbi,]G|DW/JZKQSUW=ϖ4פYn>yB@B v>lAf悐f:@chM=&F[hȧ_IiMWfǛZ,3ZͰJU#.,Ab:Jy+FŨ$|(Xd)(pRݴNrjd[e!XJcpZiĶ]} +Rm HT3VFEEsw"Sm6~<{Ll&f `Anuy;)@J$/*fP.4IEֲߌAmҙy5IGuDwƩĔ- + +Ƨ*}ϔ%AHpA>Es%@"KL^+6q 9#_ʳeCi0ߤKØ_=$# +2PK#Os_=/`o8bg2IɉRiLr>-&P7 Ԥ$JV^ N& inJ'EZqmƝ:֓綗Oi Űf!PVf(ȂvF~A R%*SkH +Nn=b:Ů BK@o}/fJ}m3ֻ/boz/e'gfpܬT ՄY= +$oa-ԿRf53(txrCnIm/w 템+ѽbRmp,ko9D۵kU pq9 Vcߵo;W웶6.e'[1}i{R)IK6 +K%cű Y դ<c:,Fzr}Wɸ9]K2Υ$'6_ L]?7FjTGTݦTnj%*UZMa pu^jEN-!!lETyKBH }L=+MMM:L+ ێ(;^#4- 1;/G$)~pߔpH^ac#qFՕeҽ}ƒ yYJGfG6UӼ}&)0AK;Wă-$Uv0IZk0qmQ򳡓&ZT-t<6qJG9SG[IfT{>wJ^8njT3Ae~{8i5*5JTZZ 5XR}~ JH ²oTu'M^_ o{\cM&iu׵bn7*$vA6;RS&^f\K6q64ep7lS,mb*R-:@* =ٸG26- /B~H/ro{ǮNZTФu +h!7;_&Ǧݛa9Meh,N4 rU*KV Ͼԙ\ +AqVCQ0.ХȄ+6J Y<i,כu *d!>Dk#:Ot\=2f_ڒbPKHARO#s rs'16+U GDVIG8r;Й˰8_[VUxί*]8昍d)~&TގlĭҾrm7,qq! ͠/wWG.^2 tA2 r]5Rۿ Roŭ}%=zmr "5^#ɋ i蔨po\TJ C4R4H2Jm%*Iz ) SCOit̓{DRf:T*Yc3ZjXRkFB#ˌ^,KH{gT99@ʿ4ȃ/oy!Oi+O]&sWnIPvPU %͟3\H:.P7_ +TV qʶ9qW2,.x51 y<7SUf]qWR.)KL2BK*m@ +GoU>IZ rГo# |:j2YA/W.0V6:wZvڜOR-LX\BXᐅ˨_łF"]-IA1f2t`}hYQH?L*켫w{2 ?5oC*QRd'qC +OBc$)Ix?}=n3H>Ǩ$dj¿,}?62:֎>0:sW%l193/O~8I3UeuOʣ4*?PJ76?pzWR!% D,r +VF3B1_jJzvpGpƷa&nB[O~ħ56~?5u_C}p֓6u>"oԉa :QcΒ$bFAUD[~?baf)?>&]PfԣD|(c`S6M'3?L5 +"!Cjy +-ŀ8"]1n0ƺˤ't^< +팮o+fD+%IP>M$W(ݴH#TYRbW8K[A p97᪢R "h5J8<𐣡e dמpv]29a2@\Ǟ!e0)pQ BeRnn5~U)xA+f KmeR~б-L}Qfܗ_Qxa5.ePx{WZZ$'I8-Mt[p) zùqhˎ)H<5̟RTcgsD=TiF+E e?Q1u- +!DM9a`Xтg +B{F8?DXh*?~o W; v6 @߇p +??WcL+/{k?1oC,'[ҜG11Rq!U|*b;ͩf~\6<*+(?>~{XEEy{OC)%(Iۈ/BM$z +牕H2el1 +m2~?TBK{lt2Ԗ?`z jya)A@<qwG4?v&&1Jْph{Dxu{ܖc3&=Kd_$J#٢z=So%}Ѕn&bFʈjHqZ֋s{¦[]v"e zlPDSߏ?ϋSMGU}bwQ~)L7gO >N^m;N@ܣq<$^@D{'$IG*ubXT*NZ6;kW$/;đYCɐ9$ޔ(_6\lw:[.Uf0r"Ӱd (Nz.p'&KDr<6Ξ%eofOCA)BIQO7_3Ɯoq#vUP{P>ztTFo0P6CN) hpoGY et́eݍ'_+qm q[z6~W>J`qP7?@1FtsŚ0 NE>d0Rk; אQO#:O*y|PMW*ŏR$m~~&jEi̻$I-S ; ۜUN,Ѧ|E)ms_@.} Μ IN։ΏvJm{w\#îBh_aclW&q:}]B4 zȴ;WEi9tߙEP-( sJVkvK)km7Rau 9vaWÊODw_mIp/"Q/U(200,Ub"mmMY.aHCeuu 6Eկ ;Z۹s +7CrRJ`V&&PHWf^ޛDL*5 + *EȐMB7 l q􋉆. [S8e=OwǸfKRIJHC *Ϸ |mizɕZLv7*xٱHdy c"ďWn&s:w fϾ,M];(HB 91r.<TO7$0E3MXQ6/4-Rn߹,qfodm=>rúj_; 5-<黶yUyLҊx& lY1QUj)甥FRVM0Gd>5n-\02[ 8EDXus*gZP8<˵gu6xXl nivq$ޗ8j--ˍH€@J2`Hq{Oxg=i_JU[:RTۉ1͛(xkTԜAU9e JE=͎HH^-9\ ,gA)Q-ttת-%|j.b.S|6V*tBT< +@#Q +`T4i)9JIPT<Cawih)!p%iF8B{2${'naMa2 +e] N κOל7),h͟"i?7GNMA1MD E9qM,Sb5:C{<8i횓:7.uH sGE">U~_t&:7!,Y֢9p-܌wI ܻ +H)7""%L.Te97{dUyPJRY$NGm-Rd.Jr +gQR9mW_sq`H>`_0zNV9_Ͻ*HBIJ +N}{\GCV:+jdHU1\a`!nx—HYmk\(p8T:Zn@'lgн79i`\SM0uFp%iokmb^М#8Pb=I]>\).eԀoWc5]M:oJ +nMmbFͣ0N$x-BTA$e_PF$j5TT(qN%2| RGN5"LIJSpj6Ihmy)|%j>i6B}+*K +TS2P 8 +1ZR +#PF. [ 88j8n}-n}49ۨǕRи:XQiBȂm{dNvx\˱10_QKe$ f M49O9j~lPU1T}(S]$N, I f*9ɷ I;|Ge;Ainn^^]!Pr97:sm$}14^K)zB_2 @$p ÞMWq8V!|) ( ^|HTU2ƝA;ޑL<*e6Bcm-&ù;Il"VTժ!VI( ?3SZṖǐؑj )H SOd] ɮ/$ P[nKɖr.i`/M.z˕zK~)ARJ7ou+BM{8k^Pn&)-Iԑ(4Ԑ6t"mq BKMCy <@]@!Mq~ܻ Q GҪPB5Q6J@$/rNq1m3Pb.#ۉ^7rnxrOnQ/~t'TA'>sYrbỵNJ) IJAl5r>\)[DG6PАܞG?,iBՉ,3O[NRyE("=i7+J oAK=:UiBi)31{8 +ŵ *+=4CM<J3#"}Ybif8]1#tiC)P #Q&E8pt E;b@戥$;Ӗ1vLJ)ͭG⳷y[3!92yUTg: %{д $>е9ri HQ +)7㯾ri3V5cEq4mH_Xi7QeRH`״úh9;SrC?͔䖞[ق2$!H$4WOaɃLKa:7%$^&iivji$Jn? EvD@J[GPr)L:&RBBEx G4ۨ35E&R(@>"[52vJVU ҆ +z{4ۋ$DY ++_*e-(a +m9MIA˗q#`AܢOrq4qyB}Nceej=Sc" '[S ,LͬNb:oΎۋJ +Yyw 'gH1O.ym]J*  4gHI$u _.I%Fx6RfTPZ{A3LMݔi)Z%*RJI6^z!{ -B +BV@Q*@~!ߊ+Ti7i ˉyߔ,7]*.3t9'Xexԯw7!EISINRTI~撶>W>)"? #hq:l5<[N$KQkLQ6n t4 Uo$ S"q[pVo~|~G1.]0ќ\& F#gƗթ<#L$GҊVr?8V~A؃~M4c/% 2Z"ŷE+ -ǯSҔU`>.Zk=;[vFU%:Cҟ=׌󇷾3svM.˖C5מ޽ܥ*AK\&kPWn0O4ⲁWd><?_*RW2;*MVJO@uׅ_ߕ(-euT>ܩhn+Cq6&W Fb7G>C*5P_[t~1czr)3ZL),ȤvJ-'vuhQe1+Mi +H;֐mҴO#lM + R x ;1$:Z:3RLKKBH) +{^Q#sFZ4H !WqQp;cPz"ǢeRX+ ZFn胫Ԑ6I8>zQN@p0,4'+S*Q +mԲn,>X-o64 ]Kn]e#`Xg^<:ӓnC0)drXH{l"i+ZTܩgi[8%$;RΥ#B@)G6zcgǓhX=nghRUS!G)X%>Ediyd@#6T8*\XwBSIgEepH-sSsnu X5$.L2ٸidO QU-&m7%LGK6H=&I̻\/,a]NGE8,HN; },>Je,rbp,ʥ|;%!3DG]~Iln7Y{ohebChi BR`R8b ujDu"[e#\pIԓ$5KV8R{X]n;cOejAt\_T."Sn:JF{RK (LSB9 +PkXuv H9={Qr;) lRamkeEϊKpd˔-%,B˯M8uuH)oA9R/i֕=A,'BK.,F įJ,%'K. +NxZ.[QԽGNá, g (p;|*)Ik8O%6vQ +"~TXa*UF|i ! [wh|D/SD8Ui7x$X*qҤ^]1JV +7h}S?OBX,rNuwyy\=*eSƳ UL)Sl nd~p:yNbR՘N!)++sFY6l?8~I&o]eIP-'O +CWjVA9L;gC 1[z;.J(ɫA/17O|0jt UlRR-w`~? ]Gk2ȘF٨EMS̋8BIMʆmđ,%mĝЩ;|sq]y"XCjP\%&*m^vyF4OKkvk1_e3c!.sACLƟB$h:O@O(a[@=bJ*ώ]<?mE#nn U-(,E>",H,ccæ=: +,M9RN?y_ZJ~GHkf?ڪ#?RjX.ǟىX?!6O.3]ϛ>H즲bϦ"ׅ|aK*L,40q>$TVDOSЫR&Ľ mgVI'u"#)9?Id> >y@!?ڛ3)4-ޠ.}~]z-;7^ 뺰ZՆGc50McO8jGֈPd1ڸqC-1*іӏ({|p:}+1E!H{No)}U~'0njGsfhڭdW--~@!8Oa?|2dDI{2½JP>ՄZ&K*Z a£{_܎G8N$'_jmiIVQ~ؙlu6Sgg<{_b:.͈7ҔiXIF cϑݭa 2m$'lr۾8 ]a.㸣p~82!}Da.o:D9j"4v'݅YGmU+dv;]:e AiH?WCFHp,7]}GόLRuwbHEk;^[: Xօ +Q>3t<Oqu[RbF# +yA+XnJ~oOk]Q|GnPz"ʮ yY?*ZP$}8EQezTOWOW=DdyAT+7UdghLs*'%C9GJG}*K?A pkǩ뻘xGD'ҕZkspgݭfW&,kJtd~>< ?yc#"XP?q.q?c&QG?5eXSu~/8>E_pSF~WmRSCn`C-*lOoۋm{:qZ TsL4Хe}_i%ﳃ)lEviȋJB.8~ui $eK&fVAxNԤ(juy >HWyBP2i3UVWO:mHb~@RP\3n'A])8+s@GHJZSԋf9",5V@itR m>fTBm)+/H5DŽ7S[{/ T7uDq{ UnFXsR~,$]D9sXgkWH&Cحd|1aV=dPTyj|b0SP|w qq;RJ/E۩@EPk<ʕҦ!e|D14Axi0ܹIJo3g=j1W}/QĀCE%o06lA;B['ݱ\񬔶6(6)#Pn.wx{<-,t Nu4+MfE<5)[hmt Ɨ3:TZε8>>3Y_{(ܕv <8dʲk @'*0+3w ae)H, +u"mCd~tLuT6#VB~Mk6On#1`YO̺[}7nvu!NR)JA\!'djMT(UX\$;}q}~ԍbia̓kXg<4AmnsD;SFaYRuߺO*r2WWe vThC}v UM2ʨN +Y]@D//J?Ii)'-<=$KaܶNz) %RTW7cP ~oRMຼK+4[̸RX-Թvq‰PBco7V`g]F^a6G*owEcG7;îG ͬC +2 ^RLn_Zuj{_@rizw=&$.LFĕ;05%6mf®#<k ='v(i0ʞS7\U$N< M*uEkuetX%$ 8&ޫ؝i'DN /hH?/ɔi0lfSn+t_'ã`esL8hlk_SU2{$$}km%! [ +F +x4P34%1KKT%(Ti34O֝G/߸Y lkÃ򃚥Tj蚧-+[%NJ:jf.h5z"jva;F8l\w#4*If2Ti-Zan DȀXBMkbt%gYa :\I0meĨJr`mǧOfpqLBl4]m}mY2_MaEÙFx,CAIXL34.íuFv_7 q yƕ!:wgphRր-LljR"glv^z HpRJ/[z=aG-ee$Iq;e ͦi⓯lPɳXjllxrNmu93W}Jc@k34N!e'nx[/3`߅d_Q(geܗVx(7@ƭҳ~zbB3])CSnc0ٰAu}d/OKieIm (l)u̵J̓`#%(ޕ'M&FT]! uCvA zQ#YEaӨ`aAZ1 \([!)ka]Wu6P 4ryGe#2 Q%' 71CF><6(6TZ9׺[A S9Yl m'bV>FL+r-9YVvKbn B[Gs: Ma +JFw֭\IYzSp|xo1Jr)M#l{ Y}/}yEɺׯFU"%:)hJ!>sA%Djf ;sI+B UAi*J}*] QoXj .Iy{JS'.= +-Zk*[i BFarNsϪqRuFT( Ĕ6\0s8~VʐJuh +UU6c\e^>Pi*,N<Su2OVDXF.Zȴyh,#%GZRSsX\WU') Dz54.H=nڏ=!+>l;4kkvQАNQѽwՕk)s~3uhl-LÓO,%bb8_ TI%u&p$larFE(ؐ.ʅy8~T*9uJxRv"SC쭑XFU̴rdOMPw r<&[TiV@r_mD:Ն\Se|ĒF1ъQ^|ȼIR֡E1m}b^&(ClƧGHJB~{\$uZEzfio Gޜ!,SK(T4I%jEUSJEj16#u"a +Y_UrKJ*$yhΩT%cW&/.\6/E=:S0RiS܅:F{7 &  ؐ .5V +In)?fw%̩0eVPE|Ժrb9w$9j0kRMܔ.!fKȚv]PjmʉM%Ε#f*\63'ReI_?He)q!9AV0Ԃ%Օ D{1K8˵7:Ųi+hTI{BVRͨNv{Sm\#6r.ɇ$ԢLGil01[-")e5!)䭷$}pd@\ 岦mpurB8A&MUȱ9 n. +MA~_k6JOc< + K@9QҽRaiY G C.!mj u)W!x8fAxIJfȹ:\M T՝t6du7.Bt- /JAP[T;3@Ⱥgԥ( c5A`Q.SJRR.֢8?\S+5Fn]V妃iFJB͖xϦ)`M+R77 t+*Yz :㯢3OQ> V ·)S^G7[^*.QevDz*VSqcnKw1 rkyJ + 3G|x8R5=~+&LWysN$c*p#I 7%m'i6'R8,hb:t>.ʀZHsxwA8" ޜ3 a[Z{2{_hJi/H76Ia=jKAmxVm PcenIӠ|Ih} +,oHq+u2mqn!@K#$6Оw=G +-rSrl%t0L6dn6¿k7jve˒̈yq#|GzJ*(Xt(,hF-$*WH.Nu +K@hy(X/~(=S( ͈ %_T4ZMxbsBm74#pXJgO.Jg[jǚ5ctGSQS2 +期Zm>X6o~Wt2tҨ,ɠh1mmK\\6۹#+h1re*] DwpVK@8$~1}0wA48{ỳxfGW];_>-tCV Vmkc#ijWx[Yi}h KV),])+&ۨx{WȯUA昪d Am7LiAjxe.tÖQ J0 PaJsqW6Q:p ܚzX[Z|Dpn .F$B)X JTn>HqF.^kYv:_ eDzJ Ēd'uJ8uѧzwj)$^Ҵ%"o +g]h3=^ !#:6(ppHN`h@ֽ +'zu +շHé)tLRV> Yhph"YSۖib33rtΠ l&_op|K*h3^hJRf:ȵL=PSv{LIfYRl:(%@HΦG OSqɌ,V\BIǝlev/~7J/G9q֧HJjMASHH9pGه } }~ :YLᶡu2;FH)Tt0Hˍ$UnjO~rH}_C/C-jxb_¯j+_,@AzoZR~3GjQ6ٳKа UivOz8{#$jaM~}8yjB1 9F{c, XBOaoP=yG/&,΋PJfP$k(e[> mBj9,ޣ-D(loTdQ163<(N)SIJ6e#  ""p]XEPk? ֕vHHtmf!'jy7s5"EFX[/4̭&q _n&\V*#̜Лe+@1)iRn)$CБ̫nOa$|X}L#mRpD;MNP]i\^;BLE̪}?WJob꜆Hj}\~I܏ÑW4]cѤ= Oү&?乳c 2Mo'#Z%TEW-@w\#PING[?x#̜<[XGt~zL -땯CS.7uJa_phTەolauҕ ̵?.ȳ+J9Tw>8ZUv6w(-A M`Y+cP:m +_8.&}3qU3SCU8.GZG*?%[䫩+ 9bILXԵNӤ%h_đMZu_@\QPyenߤ~qt(zvD|b*ʾPC퇨k,6ǞR +tevjN}NWRA,0)mZ^>%M.fXP~+CC/%/V=DG8ʠR⊆y4=ϩZJS,KDdd$6!>KbŲ-Ujc/,'#:WW.@<t7+չPJRt !@9gFZ4Mɱ}1H䖔1 gTJ{?i|n*Vܴ cpn9KW6U+ fJ4@ BzBU*dTXÿ-}ރ{նڅG;8,4HSuTuhRN7#aU'SdԐcUltA|1ℭ)׊"Sfj,2–Rs-IH|f+&@.Ku߄T$i)6ߎQ._d$Opyr -S&f +b4\q$ =̌ЭYΰ^ɆxelR6{}1},tĭ$B{)FpIQ"6p|[&AKK6i@ېPY֝弖+[c0KIZx ('}f ;[W“)%֠:BmJUIћ b#;9%k dXFd/X ōdmb${94?Fg4dΖrUa.>%$~{ LT}vJҠo^!p6c=qn( EE25U*yu] +pw(e(N⠀REO'Ӌ +†@mO(% H I'@Vw3*4+Wb<ס-dΜAQQD|ϿBY)JBAi8#5E nb{>"NgҢHumi +R>YmAo@d.2Ԑ"Gұ+:÷z.>t,8W";$ia_5RvMr'ҡa)LkppP>+#=ɚ;4KdX!HJ̞F%/E4쇮mj5*`6`vx'8?!bj:6-{#-"it.GV>DCn ~'4lSHQ)gDξri?"XS5oI!k*;QNIPJǝ&Hnea%"ڛ5oJ}U+e-^q%ƎL6|lr׶ +9K#SVZ`"\F`HH(=WP̖ЄlH:G:jղMXA~O;E;e4ZXA.K>j +@QEVv+[6 +{,O|2e-I}vRVu{6Id6ew $v*<[ܵ]Y_H9`|a\ɉfˇ};dyvrQuJ쟙Æ:,I8G }Z =G>&H.& $qa|AԞuYd?BE-of2wp$^kT{v"{ AڡՍ3%p ~SiW"Qā0Ӹv$ *>~::Q[f=g:IELO:ha>+^T{+_-]`[oT&ƏJd$IH'~8S8} +ϩEپÑSQ o' P6[2q,:'(A7eV7rhTt+ӆtGjeGUu&8'pR+gcϸ.ԃn<@kcCKxM)@mR}1􃂥<Ж/($]"J`nR ䷋e<ʕiA-0*Rn +$ jxE{+YZ*F%&&"SS 5.,CJRHgV4IKCٔn.'N8 .fR 'nmwd,9,㕩Mڗ$n;JȊ:+*K=2$i )ljeKKH;yV +rRJNm /l7- /FĬK̡s2t˸I#)PUMڗ1zOHX)H]H]lS#R3EtI \ēMi$ZS Aزz-M2~g@7pԠ{D) UH<UKMf^Z! d%R-p d/IZP;sz%RoOIkir-7%հZ?aL+T,Wso? 2K_aXxf9\zd0$-WՋ$}V;͒=f6OїјF3-Ż"-*P#ԋ,0k}3;6zSW|iBGnIC~QzumPC,Ġ}pLT6\4R#E~[@ +qjn8P|HSs,BxynmI *5>crt;ܕXqgH928X1߽, U%`)d~x=_XAu_%)lw0> Tu>k +W26~\6z%QQSJQarTHxe'RU`=W3GbETuBh=YxZ 6fSpnUzLKdʎu$6k[Ң.:Q2a +uML&}0l-s2Ӫt%F@.sߔ6:cy__16)`n6]w) +r{v7֜O%76 ]i⎂[P +< +j|-̳q+)cǵooP0t&zv +[{)9+((ԛU/1>  IiW* 4RHݵpsXfr^eY4) +e_&IpRSnX]KNPһS0U6 Eteڑ)zJ&7+_{fN_72 l<7Fd5kS@>MZ[.U\#cIJ)pLS +C(HoD-˽҇@$9>p>Qr_@BTJfUfJD6$K2 #Ud3 +X1ZoseUfBxيB.BGpnhSŊ̐2ormk}[aᙧScܫ8+u?W)ɴvSx=Sx=OpoU4 +s&XCLϙ'eF-X2m䐰Ne\Q,+`KФ̌#+Ǩp8`<|}n!A&Ì-6 $ɷhXGhxHQ^#xmTƨ2mUOm~"Y-/A(تJ#̀#q>bj"Xk"yr;bTܧTdWH%m'$++AJ*B +Vbi+K-&A+"Liuբ-yT,J=fj+BRmuJLs%N-$AJp#\wuzKϴUzTK1g7KWov#,X0e̘*.b2 nBGk Ftmt+PKd8a%bl*T>N+'CDithNٿީg\G%DGaXI:z1dVuȳ!>pmRlI VUV"a!`)$r?MK.]e cEZ( +T5$\(wN:P1EYJ%*[@Gm.)(X$k )C4xm#T pQDoaդ6o4t0OHRP~dti,Ԯjռ9@.H _4.+A9=2"v֛t&IL6Ugp >InGۘY/fmidŐ5b"9t/p?o< PMx9)&F>)O~g=XBBTYoe+?d-?Bo-MRL&]:QZSo I[^:Χ*ϫ9םx46t-!PE nH?]RzBFwl38b8w7J{TWKNa2Yo(L:Z$rVboTˮM֡BKM#< +?Bl[DK&tBi-S.ɚ]f fJLF-ѷıl}1LRD[h5#7>(RI!~er- \J)4-jSSV0MS$N4y[ B~ikK5 !WsVjLdw=Q=jNn>/6[ncux[LOaOZ4:9KkI,@vAV8J#vح%SRɶW>Â<9>Ѵ2)N[i6fa2r:6(votYV(:1u4:E*-Gw{DuN\M?URAcEi69IX +1H&גJb;"ɐ?Df8zdA +c`ou+,,GO})czjL DF{[ɾkq!v$rԆiUK!M +w] g:t dǦ$k*r[z~|M֘j˲2 \JNjlC1+4'.x#5,dl^%\E2nǍ#t" D"w ^݊V]POeF9ʃ0|B:pl? i&cP7Tb猜 se)=+> Vd<#,=ױըoDcN7MKR +״G*܌ljۋOenybewf%VH,֞ˮ-.2I IZ{)>MµC&Bҭ>!5YE$@6uLˉaA"3ED;.?خ!nh (zR-,eRnoT#,L%*zK(EO{֩bQ4Ź7Hsf +xIM߆Q|n8wmr>fB0̒Oe!-&ew#˟4qZSiěz}jS_ιL{s8!SPN'}~kHek]N;;1/ Kss5Ke{ޜEŶ3}s +O&cjeBǯr:n+l7?w8!Djb)`~^YJ`If1q#\h!JI?Xҋ(5]GXIbNd(??c,L$^N xf~!B U0^24Ex{ǖ eCD$6xw|:qBjRW iOc{|cΉMn׺V}(6;X~+G9P]kӑ̅JM:/dG@jlA.?U@Ѥ*|Mc AGuԛ'~8%՟"\Da_Lzqӳ֡jmUM> )m+@!#Ы Z$%kaɅ<?X֥S)*u@qj rD 5yCҜwk]bnyGy A04@?)\#_|"]rWrc!/E]^d@ds x^(볩t%}S\ m=I?37Z_Lk ~T^jEBaZڰĂ/eMln|PjC \j\P ]kvޜcGp.”%#1;I>q Uʋm4hK3yvTJJ$4FT<嫴wÉ!ZPa%OdHPiiM,,Y1Pqn[:t ҝ>tYE'2tvEUt5\Gn&%E#dq- $l{k63a1XTN:H&>!e:>rdH˙WJ\APq'g86-Z?Tqڅ&jM8ҾkR@Bc6PyE6 +BRT7Ďh=ASZQS + +A Az m1ԺH TIqoV-SnwGaܬ[:EL5A}-8PAsuUJMР,_&<ܫ¢\ii"ce[)ynQmԴY8ĺ9H3IMVt Ci7:$m7|ՍC}XvOu\IKi y'y5 ܛ*$$v(":yK#@mZeHmh(jnwoM2!q7-]j?3J%&;" tm9t J@I)ցbK.I +]nA6DD/)*|LK8JۥJHn7Q_mb;047![ȸ !R)*JMżyQROTڊʷ YiˇlH6N+=s%YʜIJnt̢,b,맽As\au8Ɉf~q+]R@xFVJvBKg㼝< Cu}6-XbM)bn)eu-9(X%Q4)m6UǒtӀmrtDBqS;TK0V7 +x}9ǴX%-6;JVvH&j^Bc4{͚S Q*xw6OcB +ce^RM/"G3V155on=BTrJrӃ;VU?Fy&łv$7{iHeS BH˧Y p #=8T̢'gYFE8ONemڝNuvQ$FH5"$[-+2r*{1BPYY/D)h]!'ņ79nF>;-S*#0𝧷4Qn¥&Sw<E=z:341MI&E-5]Ñd.ckJT9匳K(RoPzpF|JAFSn.\%ވ} iHǷW>nj۬2$f Remi m%!!_ +}qzQnvyT-J%Z?Z'Zl((ib4] 쌗 %EźZɺ}O ǗOTVy:a{&_Z TK' lIǤq$J\ l|6$ɹ6㦮%1쉓Kī:BN[*'mO-0e(u,eŶU "lR=*a%>-ciyqDzZc޴e[kWO߆i 6 ;ɹ’nTU68KO|7$! IAH&Q!vӀU+nTf%${XZОp$m9*P?Սrh P}7 _n/l;#H;Sp!xBl0O=St2JNp,#M&rĸT`@@MM&RDd)ILNF[Dfm]$uHZ.B\f$_Uvi7/*QeŒP%fR3N&qXjD ZPl ;#W 2UVfZmw> .nqUFgI㍴Xtɳ'DVLK氕':E[ {V+4i*MFB=;@xl68[slXޏ:Bb%JP֬ؒu#2kԔLgZP6me?3I1MlPGX\Q̥ nvkg~`cAjl)Ը.szeYlh.H|v}$Ŕmx+򭈒M>!&@R6 k߿|{Pəd2)خ5_[f)S}Ϧ!?YZlH/2i|:CBa33%ҵ^nb(۔2I{`2]&QSQݵCC<^XRvt24J+f)&8܁  BabΩ. “nzDun +JrK(ܔ*9ZW{o,JιQ&mƹA 38I R;eaߒfi$f)l)#UNrpʕ*K2; EĽ#.ߓD|єxot\ZfQ%/ɆA}6 2aՋ* urص\ؗih6v"EBl!!g<$}#!f4ćXqTG< Z<}βK,5»kIgtiCVTּ5'+sxa;١ө ,˲>haI'냙&PSX+t~~"Ma6XFTTQq"]jOT>!, [M}\ɡf|ѥΠfjk>I(*wty?l5.?dRT%a@RBtߏ|902.V׾E0x],1$77oX uvF !ZQEa0 ;ELJJլz)dW a33lsz=Dlm(-?A[&^(d!a;nGaijZ00z{qN]VeIԓ-w2\YKݐ.L%;c}p$es +ЛR8Z<-E}>QT=FGt>`Nҝ.n-[((nvʙK)x已%Ic*AMxg-H996ġHcÖH /}09$ڵ "M?tDN_}-b.qyIcQmR5Tk5:jWS x2_v%6u׺UZ[E)%ΘrPQjM_qD] ={>e1+LRG|!TOh b%4{2PRFCMR=@{#+fHJu,n<% bn'-<caTh.˻vFdFwF`ʢQ5W&r:(V,9Q>xx􋌥YK-}'.U-m*aO&KQ.J4Y\ `PIV(d}htzF&dO!qR7qFHɢOLL=YZRؖFfY(Ie\q3k)-%O۫7Օr۵|a}b9{@:Zg,e:#1!,em.䄩j'P^˷SEV~bN6䟞F-ʁs΋0L؁ڍLl8lV6>qH$%;IZm 鍦̋ICvJRܒI'ƮevPe h 5d? +i*@xaI>AÊzdɲT5'w0<'uh{)7IdKE UK`|TlxpwQ +QBRU=FT*Q1#Zokwwx-.*Me-*OP"XpHw>YKWWI/|BGlR3)%Ŵ7ToPfEm~D5Mc +bm>J!XfY)\ӂd@;&=rXhuVNnQSڔXMrQW&'*ZdOfknbVRp5H՘QCy5.Zn :n +THQ@Y Sˌkפr( vixGh @[x(]IX ny% Hywoǔ# +Ȼvt{eAIkQ,龃Ҿjb*EUT$]d ̶dw%J&caƳxLRYJYOhD)h8$V`ӅYHmIeRsR:VMVG+xmN-J2 +iTʐqń}t[R|Zf)IqM886=*y{Qw"~۸U+"fejB-ipۘ/=DНzZU L0\8jBv*mH 'o|gz]KJnnyMU,8ܠR +HXmr= M~ZmvRЫIQ) n=QiڏAd-ܻP&8GY+? +{y6Wؑ`pG~Ui-7-_ǜ]L{O WMm-SGHr$EVnQ"C]CS94JVk9 +#*g5 +mm.}4:5[9NC;68 }ADF *Vk K*N@d6e- YIJPTO5QBRYiʅO9,{JnhKGʳ_EvDklX}ث&jd-Hz!--O.T1GJ5<.d}`pѦeg-§Fi!! j۷bqhlU(aq }@sĝcSjL3I%J\Jb>x*51Tr%?b13)cR}G ivR4 +xi^mԤGnTd:,GȎoڒ 4J,IoZ;S*uBClw#&:"ȴ'PzANhNVkiDO-:)'qQ>0 ox氥Qi]L,m1ftޓuˁ:̄eě)ƔgԤ=Zݖ8f] et频~'#IeeٶMB6+-:o&z]ȽCH3\q+"Z;$w}qX5PSCL̏{i˥wWC>sVW_6$s{14se "L[ ~%–6>e}9ò2҆V̟l51AѴ84g.nr!}rttJV6`|;MAaևfk8Gpe$O{l":xYUv FvrTB$`)cp|UGH#~T/Pc%ۣţGHչۘjU4QSrJA{G5o+.8 +ete絿Ԙw2tUVg +"f\Rt~{=13OeC&X2:"ڹU% q7w+0?XXm#3RCwhmO "Ц 7ǝ$(K=mV2x '{ WO~F=ڏ8eŹvϞhޞáWOR@cKLI!3Pl:"V {MICdd#jOn&?^R@(s~# '*3GgTeIJB=A~C&Aܐm0yf &cOX)fs+jހ>JctFt̄`=<#7:FgSj +[*'$f)S;~bE ̘rsӁ$)Nxs ̬@r>q%'2dUj]nL iO s^`NQԤeW*B)tʉ#"]Y [%.X|HDꍠ%z?جa՟\D4+)? ׵)e>&v!@ϔȕTǢ5U1<sp jEi|D +‹zIm9|v>#n*W81m6Mt2՟@6y+NEy2mvOa q4R|~'l[!٨0Z7GLl|9W'^خ6tY n.]ACw:<@#jA*\tkU=huo/mzdxic.НFxO\R,M2ٚmS)D6>^v$L PQr{,<,:FTpQVzMujS/R%CY[RmǝO\mȯT:/lkT.;2u?(1Ygrs 6sS:w| PPm3"p׷(_-4/N[栐;](BMI'lCWk:KvQ}[aXpRCsŒrxp&ZHnyA~\U~Qɒ3CNz)Qػ % >XZMu8ixPXuT,7/njZ5*=j.X K$m9*A_Ѽ%&6:~0u;OOTeRB@̒,@t0GLqU^:@iǿ1O!ǿ 807F0ZIqVN@C^~e:*@@6þCtKZ[|EI)DyP a恠Ⱥtrku|*pd%-$+#"ΓQ4j(x0!HʳnDW^&Li 4G )${mvAYrDZEf֤6R孻*gʆ%{;_OMIr+"i9U x`Q_T$̶Ip ȿ @|:{9C_h*F+)\ʀ[?6=D6Ss쩇 +Ox(cO= rADi\3iʎNsĦd:,AH;ͼn<,K 2{̛Žm|D{8ZRt A 3] ,Du^Ob= +WGJnIkuSXq՟5$WA뎹 bxhTGiC)*QpM@;㡭$2u +Nb5=b! ҥ^bJXW.ɄkmZ Et}nis ԥ}?HhF`yV6 9rgː1f"zURnμskAL"⊪V l쿦4k1në@n`J(uLkb|iwjHӨ5E]TơHK}ʭzy +r"0sЋ +ge.8i& 6 +S_ά&Ug]d՟ᔞHms:{fD "!2Te$]aņ )YIOV]&u1%2T.[ul!a"ROaaWAYFI՜QSK[{v ŲSQKa,62; ^VenN30ZB%-$$nl w/`V~+R] 9+@unTk +eKI[jIvUb?TU!B(sB# j +Nj _I.+#^]H)'[>J>7kzP2ޟdT٘mW#W[ & \cNR, +OiJY:B+7/ +&K3_S T/h7\ܒ&ːgTJPjZ@P6 ry2”$a}6ם-#&&+2_(/Η<qi}եIᵋ)>_pVu3 #=,Kf<9w\ uS2Tl~OZPIP7UkYTipďMa(=yxA 6TWw E;2icjӴK ʔ}~g=$ܨxǫ B i%DNs1_}`jw]^yҋ2$"Jr萎O8a֩UiiyU8n;t)=B&I +C`bI)J Lܫ % +7lD(t6n}:9~lqE(PrA0\. +Rl|FWs>8tK!; ZUuy,24'[W,;!I:.TW2^ڔCe낢OecW8nZQKu* {9-%8BSmJNmyF{1P ~h[ -0RT plA}g3uG#1J9j\cGՂT,=1kz? 4ڣrq:tC 2:>www7E]8&ABBj@W6*AF}dQjcΨ"s-d z~R @Tӳ-RE) +֧/d |a3.p@Mt:??2KRRKt%+RV.oU_R<|]WMnR]6V6ڕr76o@*ܳ +\X6m!4feI"|aSjlNų>J +?JȍFuFl +U+̐eR($a玚)) ąg!LLyEn,-^~}jZT7ozi0/8@HGZ|J/fl 1 PӗQ6ciw3OmAk \n4$}Ҏg,Ec2ң&MZy$}qS+_Z|7ORکq&Q\VBhid\ߓty2 VZ r~Yd{-' +`i3SiFٝL}5,cEA +`Jܒdu-W=e),-@-XILx\_XԞ+l_[mXPqAJdc +tԴJ@P@IPM߿?<2N:BHI7(0̚Vn@/TR*3/gZQ6$`tҝ56-)R%}0捌 6BCM5 +3GYw# li&t"lXx;&\Ԭ|߬CKļI|bIlm !Ç.ux\1]i3&%}Ds.BkǷ:vOdzd6>ȅKDeRҴ|IR JŹXI +Ђ BLXA +씨~AnilNSy IԅHH>rTJJ6dTGkxRJl .=bbtR-m RoqYGM9 & Nv:}ŧmuu+ykfzۗ߂DK[nyigK' ԭ-nmץVu&8s1$g+Ls %-%/!hJ(HJRA'SZT I؋[a8uKxC0Pr[@ChXu.۷%jCHI!`gQ+AryRU+YRhGMDhR#%ЧRoP%eҕ$b$mmaC~6B^yef*(þR tDǺlJBwrm8MURѿgQ舒QsnrXjԛkk_~%on$!WCʣ,Rm"ͥkUCC+Jy9DŜnv2I)Bd([ w]T|!e8BĪ$6IMx g\﯏ϥ(AJ;$G[xjXiZRO{-0ˠ'-#F MͥPTs#Km ! +Xo:^J>s8 55Gr*RPQ;,=;ºf-pٖUΗ}AOo8o2i9C!y)VE{ׯP`XGOK 9sGuIr@F:#?ށ׺U q""SSj V~Ҽ/썦 DB3&Ne vS`7\UɌxʪ1ef\fR m:P"mK2-,tW)corDi,RMFd؍=PqL:}CU(Rm̎y9ԭhE?I`'#f*K)uŹ-Iw)o 6JyuFPS@mRKn)wsa~0DC/BRԆrBk/c\I& ?~$e Xa/ʼ&PlAǴvV[Ŋ(]bN1qQQvJRkHkĬsS) *CΕ@ 6* /.PQ$9J5ES032JlܒPUrly˙>FNyex#/6( A":BW)hIZPl WM]ʼnIݞ[sIL"ٓ:zS?&D܃ii) )'t,l(h4vT9|LrRg3vC^kH\1:13`+-=tE +g5I'>ۊXXɄ*e77R5l&g3| +Q0),>HBéRJċNyՋ˾AOCǢz7C8TD"떛쬗Tҹw!OC=%Gc)$-tfNd!dA3e['RBvƽzCeU2s-4 CF[WCDy9A'IΝ:;b3V\,K#x{uӼv6 +2/Y**;L~VB]ov\= +71ລ%Y\9ѓ%IiԤn8ᵔJw㠰̬̖@ muզd2t)֙C RزvRƄM p9>Yi:I7/ +9%(*1\8m}moL.UzZ "|oFUa#AT6BlTL/KSֳw#z8le7s۝H"b}/4C_?Ԇe|F-lw%nd`Yok>-c451 >H,6te,]W~kv|J쵓bq2BRBB|X~FKX.L/PI*Qae z˘QRQ:I$3W5[ tL<7 +H_FKzFbgjoy!M8N(6Ԁz͡0mK9Ȳ8{-KUI WGT?WG3t%*hKvXI)?2~x(M ?&Tv"]4)bؓEj7kJ貑캙3˰9Ya6k; 朗$Z?ML4FB¬VoYr-߼'b6 +Ŗ=]"Q0em=rQhnG%CͷJ|"Sx*gٛAڒPT +TsmsxLTC:5Ft6 +# +@ݗHo1,t/ +HJ`AI QE.Sd"~򊣡)S2U +=EG0&#/]ș~RKp+Ih?MvtCM2[GG>\t^17tłMq5@M%3>LM^'W"_l*$v4}IW=cJa\. IZ\>"`vUBZG2pNuiD9NO!nGR3exߐeECd-,OӚz  V&7*'ү|K  w$)f:s#X# M'օ5Iu){6ʙo6{FN:W9n|#j6ujο>tl +#Gpi|\ ets3O}ñKM$b0cQ΢|!Iu-Ba%s'cEG7叩/C">!Ʊ UHHWWfl_,Ul!QFOPR</L7@PQ  ýrŻ3NvpΪn9cn5qdL-g7ff7pu8x|1:ϏrУ +Zq+җj/[ˏPNO5q[|Hp?vSɋqKF0.?ii6טɷI*#"s_ ,^?D}}jڟΟӅ7JԧWg,=\YZ'h&+d"R0Q ޸ +lIP* ʕJRZێ9\ Mh ؈"a J7M7Km ]`bxFF@ՋY32eE*܃b.hXbꒈaMnVe] +~WC^RU"kU\J +%.'d|I1*4`m1bY|m昚qS4mviGvȒQ5ݬaH~!*;NL9I 9Q:ǵN{@)emd0SD'j`0dmGJ#T)ŞÞPiþpP#U mnޥ#5b\gL#Տ*3bKtCKLɹ=JaϊŧL¥;F V']0H#YN"QLj}DR}9#DdJU?`b-:>|yKh묏]b!Ocm7N1+9) Yޚ Jl{namb#@PUIt'90n\ +UwMYH s޿|;qJ6B^kRg'QUaDrRE%b4ECiPYMӸRdOh-4-yďS&7~E{4J?hi,8j9_ǎ*ܪnUEHiґ2ou6t y߇ADLIC+#T~cN>蝚S3qOx[v~\YS~`TLiG ZB뷐F?TIO!Hz +KcB;:.0󕹥KH0J :*iӆ<]m2'SvHVus0]yF8TEVH=F@Y Rz6EXzɎq:շ>W[L +J$}q~:._e,J*1;2'`H4ʵҔf)a k[S}2cG_HP'FVB:EtY\ +kMc0 +Q "Bi<_vg.Dpa:(P 5-9՚Qk2]JT{ DEmaa\TfsJs+A?+IKrP`Nmn}~xSyxzɶosH2XJ$cY& 72dKcVڔ>g%-fR OU]l,'Bܝ Ϩ[Q]+YBs5Q OqrwH貞AEi \4l5h(AP*#":&o3ZLNv{o$ [zi;~ +^ %'Ѵ[.u2* oݍHbDhșj+M+\OSu yXb.{|KSyݴ-9X=O +|M$Vܞ;^\u9Hԟ. GB'HlPq~'wtUH|->.@V5H{aC0>d%n +㵱{4QK]HH +i(:|PpU>2%bBUVlUjS[,?*ciym[y'үRiM*ڤhȲc9C96U:R*V;^HXv?b(HW1OxJ> + WsDvSClrGvRMRRKho$*d@^ox=C{Arȴ% +fQUw ܑpØw*A:\5A lokk]#8S*T)J'cڰׅξz9SYUMJjpKW$~{-DVTOCŘvFҁ:B@PNN ꇦ2-URܒR\kJW;OlxI-ٵڝmn$#*Ԣm"[r=0i-!% +R(XamoQI ˝J,Z)uv)aUb7 u1⊄4t)aIivCֿ+IgS!R@եAs&-p||CG&΅BD*FJ^MM+i )$-* YiΕf$ׁ@i`"\~S%gR7ܡꏯZGMe8(-\R* zG +uAu|WTP 6'&i;1*)`)/>Q/"z;zPɳip,e;q1# +I+=QR Rd#q5UuUiˤnTʔ21*Ҡ2djNA2ҚFm!ˬx qϟe%q(J ]!5,7Eb/ce$KKn+eE+ nF"m cl66U,Zc${zXZr^}|HmnP~/AkJJl-B{KCB<ᾤ@NULvmA-)ƩάGy͝Е86܋ tyJQGB=t72 ytL:A M<Ԏ3% `eAAm$ۺH#"TlcmGN ߌ9> ;Bufm.\ ogmZ̹^p~56P\)jXwpAKR6<&I[T%RМk@6 g Ls :l EґݢaZLV-*Jnܒsm\SU>SY:qZ%EZ*tjv([ ry[b9Bxr +Zv5 ;S?CN :MI:m<{-(IQ( I9эz*re^Vb +y>dZe"EI(J4 xs̩F[\[)V&-;6n(+aaiB6_}kQ_\s xm)PII@~Boq~k ɶ0Y*ruEO +Hԥ ۾U=4HQ+'ڛSAnҒABq$");g|袲ي© OnEV8ڬ[a9] ;b*=rACoi 31F҈7CNvՊ)G&aKb:ڥ<{h>aYY>ڔɦcʓ JU߁Xu>Y)idM*3h6$, T/15?R..BH?! J/"e-@'x"+7101fq&Ʈ:?<.c3 vFihPZ6Leoə%HuA#8B͢p!$5h H9[`\oLtKW#XkSLʄuˆj2)+@ Rl-; :ĹNE^ _Näھ/Pdp<[rno <ѤyTa!+IJz|#JX'5®RmC\<]ֶsN45z-i1[r$Qp +$ X|pKq!+J/{PE-f9^k,gT_DdR$ +J+*'omC=ZIHd[aA3*ڞ$}V\N[ ~>=OzFb ns`Ac +u}mŐEuhG71[^5᭧ + tZ LA$}}?tzRӗ#o|~cէ?E [4~Hs*qX $F1ȷy +7G_A̱\㮰۫޷T7 +_o.pRx$ ^ɹWjMq+A)'ij2B^:3rXu&(q }ҊNDBӁq-uK dRR.)RR}wDt껡RZgN8r1Kv?Gh~EnO ylaP6tÏJyNAcGyb6q1FՊ&XNSR*`,3xQ;@NX*h + yVtHY)<7IRSFaޗ@םU=BnLVϭ[gQS ?鲙YzX6 ; _a +XJ5:~%@pc 8N1q'Qz"2T^i̝uߒRϠvka"Quf6Oݍ(Xn=19 hAiΡj(ZQ &ۋDه<3eSʥB^i.Ĭ(qn*v#sX~y֥ 4ևs}u q +p2Y +.sKz7*=&$sf8D,}V̉f5{ʅC@-k62M%}rfCi!Bn,o0rze@q*R}PJwnIR$IƛXM\3!L"S!ߞ;G +X/E[fvwDR.ea 6zQpy%Q#I5O@aͲsJ(q,=jCEY@AH^*%)"mf\*+mϦ,N[S%<ߵc-&J'ɧ(q2@F#1Τs?GO&A \jbE}Vs8>?qWB~WHzZ751yR"b>rm,Ew1V_hT fHGo;_ U鄴&gGUb%ԡWIY7W~OcjU2i7]# -AF K[`~n֏zէJu v6C.\vګ|-(*GHEM:hCE"pSBIL<]$kո3ҽJe++7It LiYV 2Gb36nuA"ӵRNSca% mȰ7vgiÚ'2tI -6wADwا[o, eR}!HWyE.Q +kX6bIu1e6!YD:$Zmf}_6Aj|)M[_]ymWW C K<(w8 Awy{j1=g#E"P:?A?7p +xdM\مD76,cJ'Nn['en}N/jLanX|E`Fw;\_WO̦~P:N IW8幏pftq5 @{#=DS-!6Rm=B^hG{Q>?ɱ6ִYg}-/ؕe_)Ԙu7xxD%Xq:gO썦Swus4!k> [K KM4Zr!Jt$ `iE[[3FRo cs.oԑQLl(.; Ʀ쪤:Y^B[6qnuu zeF1ݚ7((!|M8َy_{>4f, ҁa~3Vvmα\f!$KsJlQhM{.+¨W񭒷Fsbv:\<maf5;!'Z{ 6[*fA(۳fR{xE=-RĦA[*ZBwOqlD} ShC qh| ʸ:q-'l3i8C +ZLJn徭rLCAnrM T# KOG_RPte,l Jim pŌN% n[b{w8Z|+7:إ!G*IP܆5ZZHzRs i!17ND]Xmj4JTyݥ+P""G48qFZd% cE$1CIxq2vST+G};":CZUNJBc[vct*:CkDSt*lNFDBuYA$|RxiKHt/h,NDH~;<4J[$y @”% xa{,VkS5MMG}[:_ +dWVһWV@C GI8Fþ۩_⇉#Bz)J~9Q,oe,}s+,9Bs3":)l|c椼ٶqC/6+8ڶ)71ffjFM +, ?Xy6|K:[11.Z>iE3XI[e]l*Rdkkܔ~JܹhaKfj$\iP,a-U7FIeѭөwƞl/ M~1ɾޅ:hݫcةu(J _˟\x€Lz$T_]tgӒrn.lI\WmC67_rrԷFT+ A I-R*b$hoTQ!ZR>J||v:F)B]l#Bu(UDR axړ qeTI7$0v_TN_J7 :A !Ó~ye[SR)Bs5r>RG4bf|.&>1"ʘ!PhE|K3nnuSmE7 +n +ex#)YW'KM(& NnGXArNN[mlR[u B}q3ޏe&Ġi3HRRTZp"t+5(Z%SM +lA. (P/s-˕:M}l{"ixލvHI:9ak:t-酭duOp#l?CZegB]d)@bIBɷѴK][ ɧflnq{v Uxl :%WBU +I.bGb1zKRYlջp Ћ Z9-C&fJ)Z^JRin6䫋p{J!0SԸmFkjAFpҩ/JT|,QR~uHaɌi! *.ڒ߮UD'{ ^Oti5)Eq<Jbakz5UBfEZBd>rSm!J0W v;[Hz:qoPV̔h2c0r{| I$(>r.gV@IKǴ+e]d ]W A6&&4J R 2b9տ\kPg.S%Q#Ԙ}BTapG6ń+%eSIR Iۗ*s2;A"F&]2ۍr^q mBso6ԁ -3״W9Լ~#3CieHA2xѬ wN~eͯnD$=uGRm#"\qK¬JAuM%IRXP *QRPH[:RgzUBP(D!hn #z*R[%~pI:G@| DJÁoWnmړIRu?pW7+ S-X%*PV v%. +SM/ kƉ-GqRn,msK:&CqbΙt%璒!j)ڨ\oo7k/'V}):{o.˔'%jzD$)J~D6iuEMJ(a㉨mmƉVrA'YpJs[oR3lTOW5Hd(m2ϽRGTH} + _w$HpfxÿVieO:cک +VTJH ".Ì2{Yndjkf܋(N)}G"*fa(X}CR)x@5^RځL_J~B@>[ ?B|p|}x o1 iIZڔ/L/*VjaKv'Mw]Jee)IJ$ru&BObNw4ZVctw(e"`eq +łG#Fe! 7=Rc;4%[_n|=lUڛኴJH>腦^?/CLT‘e&v'$uz{gEӡ}mhvJN؂bU3 +l@CYVO-H +,|>2QDo͗찤TS ZQ`Z8 '$vVG#'袩KNmkr5W%g'!`H%I웂>~xf-E!^ɰqQz\ ]͈qYB7ɞvAK-ۉ +H \LTG&^S8wI$MpZ!Mb?TRTYRMrn/lr 0%I7J kq) %Bmh񾰮P(9:QYC8?H%Cu7djH.4mݛA9-Ɍ¸!u!婲ě(5bKa*P q +yť81E:nvJ 8BC2֝"!RRJ.%d'߸Cm;OqLJTwm^R6UdGLzCIU" Ru%8HQm7?xuwDýZr,e;/+\zmR.K%>1X72elf#JC[uI ){UJ#,$*亊I{jp?h'ZԪ\wR%KR 6= +νYZ  ~V0Drt!6nHOxaӛ}_Lr ;onm~,BIP==^ۿAQag٪L8'c@Si7"67nC Y) +pP_DuP6JOҟIe)*[i9AtK$Eˉ:Ȓ)e%ւ i>~)yjujm€F/D̒`A[?tR=M;:乳:~=kj7C%#O%\iʮ^6 7lj:Z~ -*doI2D[39AZw}XOȷq)AuuDNl8'XM%vSEDxbI?VTAՖS4,ejJk݀3O+9G߉ O W^SoԤl_[ibcw7%tJOXoJpӊ$Kp,{_33g%͒y.m J[ J2oG3ϫ;˹򬄸>_>=1R5tF^e-s#mOVnTx^5٣"̣l/'/F9)#Mb[]#09Jn2"n7\L&Yc΋)(qAeHk +9,N`>2Lju FzINI)2/+VOdY}U}k)8g_JcC rȿ-f'}=[P,$'YJ.җi9D(Ro|=z&$N9oϼC_&Oao$_w9bY%KRnHܡس:"//v'7rQ3"4Frʓei|Tw O|&(^З;59p8CֆۆޱRJL&0:}[Fԫ<̇Є&q=S޷?ԗj+x~lbEH&$[@\"2"OK+9I:%h (vO0Aٚ+hu3iq ډHo{̌Yɢmv7 4:UBŲ61f` P|~et9jPO'BT/c0ZN0Utٗ_.+.#&TvB/G;B#)Y'$<:U7u,F-[Nͅ+K@(V}9B6Gf]/ +عԲX;oG~493tQz4Mv {-:UH@iʸЎ"tya;m.E٢9̗$h.bG a:ůIU*򲣉\ 5RVBJ@ 'p03utV%ҙA!5IL(#eX_;GugX/8Ň)h$fʒap\TO!\\M(Cr.(Z׆!!SUYHև7 +h<<թ;է#)`EDze~P/H?)G SKa7TF=,JFj,tK4_itM +~=T-d]x%P_xGu/ʇp,W.p$ 4Nhs9Eĩf0Q˦"W)XK%)m$JҎe)'.UneOD7™)Tg\}!)-Xl;bKO=NemFr^ }/_.<7SCyWe3&zmB;ml.2]O0~)duwd|'oE+6B料vyJ RJtG#*2{%E)G~FzggJP!/n+Zqo)C $$i{ᄲ]VenLkĺi7HJQd)%"#ZJ>pic!Z[sZ +&"C_wTNSS^#(p0Hvw#cY/o%.ӧpRT3XI6$s9%ĀjÎSfAp$JUw3T4"IA*E8l oϞxW3]m +lO2Gg$\VWE&*f8RJPNd~-w:XξMRH=q1Z@7h7,H:4F~LKzV%0|A& J@W?<6C 2*r݀d߼A0riZ{hEթ,>N5Fz[vze J {OdC%jT.m*Tsbby;,C +[D+ҝryY\XCh-yȲ\7 lꂯUR Hqe6ĐuZ6"d|AP[q4ʙq /6=M3*(m5hŦW< K~-))Rw2EqTHm)* cϜ&[EmEVeNtE>V /|N-_yz"nNiw! +mb;8JS _zӑ[ p˩DemD5&NzګeŧEEc«}Rt{txr[H&سҽJ+w 9F N$2M:AK4,ySSaܭ*abYĤ%r $[+KH:s IbCτ^.G_;'S2J6ʰ:C[za>xROޱ?)D~EyI0"{QoOs6BhΓ664,A(c+P'%ɶVP +VR3/oh:sm8.V`{Xs@8 %.̲iJ3$ +66 j4"%>{;sF=Nu/JAa Sh*̷m6͗Ix~BDy +Fe[HsuTf$lx* x(Ϧls: SZ}3&PXOW$xu0ɟrf9ܩw(v8GkPM҄˧&Z"ae/7k] muҁ:r4[4*Ha6zlʚWsTHf|٦ܫ&K VyGL9$)EI˰_sz[4_P"'kb@SImN8t1P}S{G3SJ|W)ץJ]ۨv3O(D`% Fۉ^!O(*Kmb#ǀƮ[ tyZX)<&~|OCʊ4!`sYwwd:I)HXTB,r?#Tĺ_lZDc@2h_raA6lwAз%:ă~ ήfQ RJ/}>bj0 hvf'z $MA.0%PH[guW:waBH{NxGXSRcC'sMFqawa6i^Fliu&$_+/g)vH#PvP&ؙ}=_G =8-(>޽ӎt:y]fǃh2oIl:{o[m^OyƤҥp4<9JgRJ  +u %Y;h76#g*T+.~VZٍ +3JN+"}qUf["]{V[l;R>ch7Y%ڽ\+fTZG4$3(ܐ2mbR/L=y6S5k9-I(TRoͰTT̜Gu +w#(*MP߼%Lj*CJQO z8V˒(@\ֲH$aEn91}\j\b1{^wsطND%B/K } G^r赀v5uG2\!K ܳr9 +I4 +c +-(e*$[̨q\kY+p\8rE g&+K}ҧyeJ:)K7ē_|3Q{8UI FL9(@ç a9236RXr{ZծK0`?.-oẕw][heċ +AjQMf&w=׳J4KJ/`sBwĢ|F|(M7"$UHPWtpwnQ7y/J  pӄB)MEen8J<{ѪNX9 !eהY kvtPWeJ,316 + qfZyX=؎ر+s Upiy73J΅*H o@W 8DVK>ZJͲ6%Y\DٺvS6̔ Ϗb^n^[r?4bgԤq*{65'("W3 -HHh{}PCr jpZ!}8'wSId:Ȳ#QM\uM}AU 0Q(M=Ur# Ufs!}ɆcS! <7rn iz +fO[i۠Xۇ. Ϊ E9ڬ +ju{n bE]{{M#ȡA6]ۿ{c!G8!6.+:9㭿= +tl(uuZk0u[>hܐ{$jV췝m<8*q N*v51oK22Zuyz D[қsdKe* '*\[MLEOn1~a˚jEU2dkROƛ'lIK=0"u(Q6Q} q]Qe-=y%ECԉ[y8GVkH^"ΈZ5_M1ºvSn@w.۸=kŜ Ny!%\YEIE.s6Y4}b#>Sʨ9" +H"]6Ae8x=^-?OIDhKT Qn?[ +CW.l"gjtUJUմ4@ Ve'^mַRarJ)7O^x~ъ\:LHK3-'2[Y<t(u ߹7!u(xu.|ՍEI%7Hqw +J~_vrjU1d̀FP-W%N*1>ٱ`9$Ǡ @:XŭH%il|+fE;$IrK>+q7'\~ՕcK00Kd6u`&F^su95Vx-nǓ+MD~XRXWjGSa>jt1P7DBQIq +REs&U EM r .!)R4ו0f%E]j +77 [`$kSnO2[1.}=Rt7?BHZ\3\K&;J[zJC}mL#~WD=h;a ;2].%%G"I H,ҫ[褚&țHJ#bo!$sEgb1F0!viml"垕ODeG0Rݵkc[.t^.BF?!_ Ua__Q9Q"t$,l~ |\mNvJ[o"TVq$e"z  D]Ctn3nTKӑ'ħ;dOaJ5p{#M!S4޴r ӅzA_!(ʯJē̡҄ٚWia}Ӹ+QrT~(37~51YkbۈtrvZMcp>F|GH{G.J/;?.5Z!!S~nD̦zWb:{cαQS`G*4\,A$DI8>>)iʟc۬-^oE7yXF&Iɟ֋uT\bd%:~zhvapVSCסlI1Uo+1:0LsnG]`Afп hG ;aԴtf/t +Lq&RTMa5?t q7V];Y0J29'鿷fy4|GmPeџ(?ADv3ϼC /p0ЙUG]ʡ&ڂ?Xh*Eb{?DI\6.\o^F S +:HZ[UWif +"$[鄇L7Bv-tU) +]2D#甂m wF)R/2UN!}{>N~N29Evx ETyo(* 2BmjlniP<| oNi׏~<\,Ԡ-|3[Lb0?Oi߹(bt؜N֧JQfnic"VJc/'#J6TKa2>dR?u3͸m'7H:q]WUw}#2`ڒ9Vr[玪0IC%Qȿ8G5=Ԫ9qbL~lzR^-Y)7ִH|Z^l#"%QQP<1-gmBs $&@o~5UּFҪJ?96RMb[ %?.Tix};5T)\ifJ:5obٖm.i7Z{m+n{ +5 + P*ZԋnqYq]KM0>vFVZpxrkZrmäV6H'2m@sUTU +yRdJ ~cJ{v[h=^Kym`8DBxWHOG9R}r;_ԦQUm|Bi-nvXcksObڣܕB. πѥS,ߔ+JJ@ &MquQb)D, &"δz]C,Ό& rYm7;yIWēMԲdB,iq{Y92jrIwwDqWd7e#eOFӣ:S CZ>)KΨm?Du}Ƀm!8#HL@9զ\X8,F;iE:s9ʍCE*sjy|qkIlWz<$%{uY=n~ăOJl'0bQ:ARJBWszقXIEd[3pgR ݕ KxnR`BTGŕt"Hq,f ͵; i4](ARUo7 zԉK`wWP5<2w?A}TlT3ݶ׾)G.HmE Vxh*MW5,%]pj6ZyiʮԳ%!îpb P,l,Pq^kjtf[Fe5 _KHS%I$*^g]-.!}!9MQ 9R=Ax.r֨H˴\m&IBgGKG}C=twT>m/8ʙ]݆ac`I!ӈk2̆T$,(ٿ *Ӫ.#M)5u+-2.}B(Y*ZbSLtR/nߑ *tY'PvWb5^]֖)E^Fs>PytQhUy$t*,Jqͱ[j}41IrNj](5"/q=e%Ԓ{Q/3mRn#Tw'Ή vXB:ґ)~,f)H t)PST $m cҾ }>WS LK!+L͠+!B+|'m5ݩQ)ڡ3b[2ZR6ŬA$Vis!;EIAT|"5uѧU|n̨6"5eHRRGv6^`[ s%m Rz‘kIyE '6<"PA-T2iuԴY v]1rTy 4̗|$ 1n*4Cats\ #\.:'e/z*ʹ]!$e1 7{㇭:Ud 8څ! +g 1=@/xqA=?i%.XsُCԭ=bWTtH'[B7$n;])9 +r1}1OK6Tf!EZ ReD.óZrCYg3GӢ[z*&8BIo \!̧].Ӕ, 55 :P}7z1zzISen u6Τ8T2Vܫ+J!{~&˥ͺj_+Z,MJ*uO]-Ӳ5m-~'2}LK/Ѱ .eRP&Btô Хkox̸: 1R@ \/N)j*W$eZPSYY K- X[~q3 +͒/dl;N[X/ ~{]6*19ʚi\KiGoČ1xěN"[JtupuHt,4/4ITK2ϔP [h׹':2@&J$C0hD-әgv=E{h?^sra*!9*Vkf!~9>2#C&e6睄4,(=&# U ILj;~~:R-ԓ +:GP٦洤ySk7F|oAOQ+w +E + Zܐ|Pxz6~įepK%h5 ڢo#T:nvE$7uQZ8O!3R +mmvUk'I>CߤKEaa[h[Bi5)i^ eeV)5?LԚr4r<5%iR +i@VNe.o~&7J,RbHڬLK]M(j m0uՆFJ + 0ԥU) +JCIq@ 3i`)B ?yTegeIZb X0?Eq6/)Qub92$n"6.ڛV_Sn57}# Ŏ˒SM# H)6:zDw%`}P7! j@W2B BC} Ȏ8-o $\$ؑ`ABicZ}E330mĔ ZsC9XzJz8 J\dmp('H|"ʢIjqnfR`{a8f!m/k$3I +ˍM4AKR`Ӊs ;Yۇ@P0@x 'Uȣ߬v5?";<39ePIM}% MfŨ#5U\E=)@ïZ'#f'^*ܒWhziU ҦTE@z+RSеM%a*MmȰM" j3>fʥFY˵^iX|ʂE8"QrF҆g Jԋ{>;RY.MM5E³T9)6{hBjt ((mxiH̔ERH-OA=X[/,AI8ÉRA +[Cz T˭_sPp(dnnuhhZ'YI*0JM_a+%E?4ip-6 +KrZͻ$[N9CIz䛒mN!v#fл+EVBARt n +$lMxyVBTGe7= Ȩ\A񥟕n$T4)[Ʌ_Hy;]K;^MKZs ?(+[xYVд6[wqq]+tҖ!]x%Y COYTĤ\"V?&QJ*TPm/u'9V|o#'fR?vP{R">W[ھv=[z14SZ+ӻ-mGL3RqN.pCZ HRN7!dᚵ+1Wjcr#Tpڮ]"Exf*Ό8_w; e8 @\z-AƔ~q1U<ܽͼ(bq󐣰#U*#O\[GH%0ʀ)hF'QAJҙm7YG(klMx;JӉn`,,w *ӀMa 6dӝ24#%$ +|$ +ãu$6Ŷ~X5-Xk*\mcPlA I&RM#(a6S/6H-$^ 8UDy_;nd0@I$>au>s'\&6%LVgV|k +eJj݇#櫻c,3Mɢ©o8Gh7.vOAbdjYw΄\\sD{,U, lt . +WfjrG+Z7mf@ryq\F&,uB pTJJX8E%8ɒ@$wiEߎ*ߢDaҧz㍭\ +մu,"")PYk RO4}s3ʴ%CH#".I)o/̽fu)Zskz]Nˮ9JR\XzĩS⠥["C˿O7Fq6RR\RmmNT[N) +7x}ʥ*0Eβr|V"Y=n K66 ܓjHSk$Za~uJ(A77#3U9DCync8Ǻn8qʂ +O{c;RBRJM`BߏJU}c&=uxFYm&dU>%rnAN ߁_^-I)Z zD\A_4v +қ-] 9y×8 +tv5\S*@VoNWW3+wjCΡr=%e$ e6\&p\B +, +.?K*t!ɼVgeS-rn8$qR%>3'o>RFߌw`bZp6˙@:7EΒ@@+[̈́*(hՎ~l>NNΠ&7Ro\ (U(۟s؆'Mъ}?aTԋB未)ibWi`r`̲Nٕkw|l8+Ҩ϶"|2q,V0D(˺X'=Nu .MZJvstiѾANi莡#AVR xU(ߍrep6:F,c<4;&PBG!åHU3\zjsۻ2PkLh^&IiNKJCnc4.eIl[M'f B6;J)!cT >1.=wfJ{v(E D%ԦG>+Q" KK NDυ`,G7Or^A5.R)Adj/st\ߊKn>o$@d&d'=XU\; |0[Xߑ/A\dwuCܴ} ;n#=#eg{)TBq@MA>ysv{vtQ'8M=}k_Q3ox̏:=>fkwG +w)N# H*^Y䖂s87*5'=,ԉ+*C%P#XPr@{XF#Ͼ,n!X9 +K]Y ?D[WNTN"3y:#{pw}UwL=B֦t0? x0B`!InIO͵*:E?&tw+hqR6o|3Ȼ^E*Av8o{ژqL.˴yF3[ xCtm)&cH㸂ь9'ra4ݖ6F]ìn M +o/  J @_JROI qt$ 1(9=r+39Mp(rq!p+bP({)QfV×C({&OvרA(lq[ |lLpIXr$|?01J<7ECo%=h/` RofEZnbfK67-2k}R/~Uqʔ@GOiuDJoaWx${V6a3қS3r(P{:7@y$='Sy ?#*Eτ!3*L7I(̹۽Iq'9o7RxC, +ryJ0!=th<=ʶ} Մ}U k艳fsZc@D".又Sb8}q^U?M~\G#ldFla͊.Q$s8bJ=F3:RfH('i&cUIGBC4<\Yш +ِ;Iı2t}L9s똴:PqO؇02%HJ-nl>x^b|=WdHKɸHG攩N +d̝ui>6/ ؽ!5ycʢ]4&걽}#7r?Z<\M$>"t`gc!KTHs6'@H6>7&.\̿p;!XSB*L$3Z_}h%,B`yߎ̨CIIԤwXB^*Bq?NJ\y=S`nmYum,Zأ$%.͜S$[>= eqʀI +;EQY2b66VFF$m0TrH2K͂v-oNUo9[*QW,$j&4Y VSoFFmY!-KhVkRM1NNIYزx0aì: S̴o߿<Ĩyw+& iA%FŽ_%12$Nf;S[zDZjpvjI4ZRO7׺>Hy|6H7ǣDʒ~,䷔]-{1^horOX!%AGr:Soi҇>jaom5z; cI. ja/K88<^̧PJZ&RYJ|$CRV<B'+*"þ66zs[h4If$Z8<`#GpTQu@-GA ϙL@@vIǪ,yB2S`!evl-}I1u.RyQ`8<8[HhfsSxmQlܒxzJzί%_="LqnIWoz(Ŋ2G*Vw \@$=O It7zA, +U me}5QuI*3N=ǯOu+~ h1Ro|~pl(kIF.^dR<ґ`G"-b\+tǍ_O∲ө[CcrZ״8eutiKUb rDuP}1MJ.[CKqjzOQJVECOL"_gL +Z,TTMiW;zC{MiJmZs4ԧeҶ]Ң) s-TLl2vŃi +x D=QD +Bl9k, /p^O]昲Kim[_NT Fb$h >G:fDjW*Q}:Q ,I*do˴ (XhdlI<.TBg>cO|q8Xo늌L ;P3M>]N2c@C~Ml]oɟZnjU9 +}zR%լ]*k-o s"k͔/.! Mjc(H8Ԇv:3+\TMBLgJ[S3qGgjlp X=L 'I%kNRGiX &B^ZB%1.,JSȿ>#UAp> [lBlG +tp~W7>ngX=юOQG7$2ڦ/4H<ɿa!9P)Ε ׉< UrxpO/Oӏ{SfPs}jgD7~Z"_EClSLSfNoU% '*1AKCd(BT~.@uvuqMաέgXHQHFklM3`ӧƌAࠃq)vW<|?uXm^BO PBr5&a%e%X}-'ĒTf '(P޸PJ9> F +by? +Q;)H4KR/b(# P:D ӧe.&&e( +Qph*$&'֗%;*̋tشKKa6຀JEN0bE:\yi JxO8u)M#_YE76TZ-JRBr\(ҝ7:K(ң!rc 9 倥%}e_wcHAǕ45Qnj'n\a;<oAh.yq9-K!A(m/-Fg]ecQ!D @ ]zU6W1I @i]STdS+7'Cm,I : H08yRƍ曝kPU[{A71M(p#qI R)f ap~q +e,(裤Gé-Pn<8sMAeEN>% +Ѿb^|IU]<7ʕ +Ғj#eOT`Y9+@穿+%m!Nxks +/)%b>*f ,xa}eל {j:_]GU)fRRJ~ IP ՠGiV(H7V^[45 *shHUJ- +B S~8V(^qI)~l̚)>,2f8.I6Lc*==K$A6BQ7Ė+U:LRL"Qd$emHJvR u(\:yAJ Q{aƥ>-%$E9wi: "K)%m'_Y+7k>V?-tM)6l| +B#)L2;(jɞ +{MD YPfX'tžթJa@b=%8w _7r||w^c!Rqfx5 Y; ~ +V|jĬn4fA:ڵA}+Az?KߺL>?٦Pb"ʳ@T> fV5;2>}vu%: *Tom:Frm+@RXyϺ=S@b=t +=,KNIL<TYU7: xpY3clY̰,n +RmoU@Y?_ =Qj2SJKu&%պFT_ѱ{4gt(y?sa4H>GaA8^4>"a/覐|x=$@Kciӹpژ%m*BV^82 ̩h|}1k2 h%Gb9ҦeћB{)*mh&([NKrlmW E75!Ҥ2rӉZU۲UbZbrViVNPo +^Rq/0ÇLcI eTBTۊJVl:Ԃ/n"(MiQelMVe˜|Xr?.Sޤ߄q)Qce Oܞ zSs gT2y|R!:Y_5 M:lj";}-l>ؖyJi(X "ɹC\19&J +5űtCRm䔡/'"T-XjW>'O ezUIU"RJW%ҒJAGG2hu47Cv?ʙ2':4EbǣENv䰑pm VT͠J]>yo9N+fFl5oQߘm3b1yK0E8uuSx~T #(!(J*9e:|rH]\ve0J[_Q)m;P͒<&3rᆇW3C5@uꍀ)x1X#萧5qJ+U*?H $s eM3TIǴZqJ#FS63LiZ67ka,ژQP yFh%;X*w5)RĹNe|J;wuy/PW|X,I,ܽ~pZ’`Xm*H$U0н]8ڦ5uo|)%J z ,ݔN龊",ˡ}h(B7P_vٷQI#.+(qT6hpWŭiqKiրDаqxa*Visnp}}F.M/uI6=܌)6SDgWL8"&avRM8kn陦2E$ ,IOA{>F't.+%u +2SU@ߕ%f +ܧ"jʴ+Um,+~qhycQ[!M/1RaTnVݼZx{[O-G)YP[j?!}9';. J%$#O(Ta32hPzg(]IijP) V)d[.4[Ek(rP6' s) Qn#R"P%WR; BIu:P7cdy7l~7mo+ vb\-=)GpR&qxd;f'OJ]2M.÷03q9QT=&+ F4ANY1f.d8{E?Ql+M JVm􄡄Ib*VFMuT 6+Rִ<77OQ%KJ8y5+ +MdldMdƩH~H[8d_7MɳJWSGO8[ƸX=`ND/6`xxDIJ*˳QYyɜKw* cMn6$%Lx,1HRŽ `-;l@ϕ/}pTuJ}yOhn)ȲJARG}iR{'{DyݒfV%Թ"DP JHF%ZJA*׉olZ YP?lT1J7PP)lKv8BRr`u#Mu\ dK~rҚf2v@m }jjMriJZiZ+mO{H82H9@H-J aSDUTr8Y@(F]GwtgXz1ĉ|)%I}W 'noX#a-r5鸍gtlR] zf|1:?ZeZ?bA<ʊ*~WA_y6%9VA vKI$?ʏp}7bv0ϘpJ? Y|ޘwΊ:u_YduδTx?,!/'wƩ0jDW5tĥͨaҒ?>17??l+Vm@zaibȀy|tMs}U7i?Y^OoUS?amB֢w0Q_Ɇq-=RSDiRoZV$y; j#Ţݜr'0 '.Wߓ Önf>k.#I#r5^x^XVokIãڦ{}6kӡ%ESf=OTˊ*e_|\:ȫ.G*bm"8I<ȹ +-ʼ5|$eNgNi|eD Ɂ\)HPuv>aV!2dq:mTyUH#qMKaO҈&N SNEk+ȃ{bSjZKB䃔 +,DRE)uGmGK!Q|6Rp􍄄~1*LEYI˺xƆ'ս'@4h8?&%vSk܂>,A*vE4lA'5+8UeJ6 "ٙ>t8&G"ݸq3 2Mha_]G3]"?{\!ִIhY߿4hI3'!醄!.r*jQݟsiZ^xyu_#Ǟ|!*e@P+|نD'3+abU)+ڏ~=oXѠԥ42!_i!}k,SS?m~ =0M Uc;Ec%w,?'E_?T,xP}p!-LDxl<@iA0ʣvʷ7خ=kP# c}? %KWs{4—y}xXB=НIig-'Nd*#+f +t܍8$d@#CbґeqB3&SĵOx8+#8Ͼ8Vqi=1Zٻ/!)61jC<~8WX_@uX8NmbᩆАADpIra !<&( w~!ڸ֍R-rɌ.i$)kMK*'{!ǃhYPyN*J+KR+u9T8 +%D cNt,$G0z *>[YJR15gUhB[Ok֢cFW &+_KXJKC@BD=*guQ^K ɑ!n=}/ăЍS)d&X[x}ωJ c(d0>VZW7^hLLu*ZF[8$-sOd^ +N]>S2ڭs{ xٍV B}C@=T^TYJl4P.!2IARՠ`ZRF8 3ʫn֛i!k)Q 9ÌtqDGO?[DCd7'楒q0UW>f%V'=-y@>bb9O*9hn>,+2fD4 js`J Ź辉)LFxYVTtU+41K=rq*I@a&\ZTH̳qK<6{AHe*:IuܔV 7KLҒ{GT@Q|:aEwֵ/nÔt a;ڂ]T av$# ?569T@@{c  q520G+t#ci6 +qꇿ]icw\ʑT=ݘ$5ܩe +m`1bz(ZB KI1v12e!όitĐPH`($MU ߥ(SS\e&څCR=qO)2! +XHQP5""gqkE, \o%L/RjZdu.b2(lu:3ڡ%ӭAV[X#}D(]^ 8zC\êR%$ 6xrxq` *ygˠ:Se"]7 v6'K{Ejj5-CK%9!)םpK*$IȳKe,% %# *c2 } ͡K 7@O&#u +ǔcЄqq?rt8n"-P%r+:26u%WZ]^rm'X ꑙS9{~k+j?Rx~k҂(Ƈm#m +.ѧGٲt_ň8CSHM?=n1$HTTU2yܜ*t̫pck1"-8gt]7[3Y[fX @Mƚl@ 3&Hi032)QM6_/|.Py^y$ l,H/b)pv(C +QInhϼQ΁.IRH 9lnm"6N#NDH |E'@Mis kH陓AAk:rJu1$x- kp.4-GzH,3=LShZ|?]?P}N⚬6X).2D:GShKk +$f N&4<ʒ4n껃c{W XNLʋ@EBPRߖTwjd.0ȓXq+$2Ies~be99ꏮ +@K[>s @b=[y93^E~mwlXH&ڏyccZyc8?A GmA@9.=/´ T~Q{sLț~mCo1_\ x#BFQuY+\ ;"g0,` +htQPGSk-7ZKCYu_i܄! M(RG$@U0_YrJ*pV_m0FhIEB@"q“?p4:D[hV&J,덝 +# 5#h^)Vpy%HrB0НRϦyZ\%h؜:Jrm|slܐ S. ԅ +0he^a2yVDiJ)Aܠ~A^~ʝycU[2h:&56+XTy6p70 C*;$4bcI}X_,MB0> 1U>M'C,$*I,>.֥;r6 +fe0BHs{ɋо6tbѣUTÄ٥X7J3xirhS=Ψ˱\J\K)(Ĕxŋ!E7+{ eY2F+2}5 +J6R(\M Q]Lg>+.R7VO߆;M+"а{$kOq9Z~wkӌ:h~8ˤDЀG4vT;­@սeڎfiMEzLe0 " a*P 2֠;4LHa@V/}CSx#U>+*\B)Y@jnk2f;⺠O HX k!pI; U]s>DP%l! "Ew$Q$yQGm~sXc#nB$MsOr/?U ԈD1$zJ˳մ'Ng&g/3) |'i|# R5(eՔq0O9,r?tIXk鹋MWMmc/Fq#Njw)^ R&HOcoSqkp)g7kb$tj1ˌz/U ^W'w$3%.Q Ü?>ͯhdk2\.3  @#SG#5RQ49TF"*MXUܶ|䃷x#[.{tNT>a;]M/R󯜤}A3LyN%+f匯ëXu0j`eek+ΒJDeDpFtRT=lIZ3PIr\Ck~"l7)Ia&%L' +KyR{#[e8X96=GRR8Î@i)mZ줨 f / :̹.f~zXͱjY.:,8'g1m8I$vBmmb*&yD( '9(ےhh w,⹨:9챆WYm+o1qTEoLe$ŵ\`eb)x iHy\GLb.3]INAL7Sw*NkM<8Br@QGNp!<m.ܓ7[/,Z O) OUkhɴŮ]ZleYQZ(5=({Cy9Sjza"vJK !f)*Ei/eJ#(7q٭K0q~#x`6Vִ %G:ZQGZbįe-T5me6 #n C#?QCBlHkM:31&rTu\8_䔦IJ(D7Sk@ju"dzz3T6;|>PMNk I,?7&|Y!eHN@ ytRd ntn|H'TqVA2 Ԣvn+:9j">worHasƳt_ܖ +Hs&HY'W&rKm1z(tjfL+~|ߎ#sSQbܵ#-A Kj:~ʼOQ{w=EߜvZnUf︌!nF۞TyqS~ aAeU< D鏣aYaٝaћHyӳ)]?i]<9:0T?CzfxzuUR:gveBI/:NQk_5lvӨB ,[ ! 'j|4y46X˥n\f%$3עI.V檤ʲV +VRlIۜj4M`ȭ̏WGX lYl[ؚ2A_k:ī.H6kӓ3,% $ܒ &b}_r*Kq0RJR$fn# +T +geT۟):´W*ˀ5|gwMQLUI5%iPz*ij=UZŗ2^3SLZv~);~Hڢx[ qPzLg{d_`GP6YG/Cf&f9fu JGP IfnE&3U?(M-HX }yDo0X98zKO!œ`{()CƂ\hmb-حi>JM?(ޟ`^P1$@$3Ns.P mFkHbBj.!nrLNK+(^>/8bd^Ҕ`JHRn;"늨SWHP}|y$1Rii.PEfd˸Ry^YZ~BgBڕ$ ZJQw<2{X`,!Ac1"9M+XRx;W40 p\Rv7c6I$sm"J]ͲH#0 iu9E]1N7JETO=<:(mǪ]R!7x.7(B鿙Njͭ,7نm΍A=!>&OHmss G;XE&h&Y;OHȭakBE>X[(G88*4´*q@!R%ķͬP"d|PhN禔CAm7&Zʝfm2{)"•r&R-5k-_d;.|>);D5C/U#C-)iRU$<Jv+hEpPK'^SP{}z S@Kb:Mu#y›MV8#&KRx~ÊOKKLΠItqѴJ*j-P;{bʀÕuVB\M(]Ю($f)[XVsRIb4UyE$j~41!jx>rr#'62S'M,"nE{6j^O 볦qX%R +{t*% $;q1QɼD]8NK4{ IЩ-^XYC])7|@j-C,f?q?h4y.iS>G"F;qrmQx}/G ?xwt-*?I_>B+ SBYPxJh/o'!-[C|XΏo7;zD9ylxɂ|͡*G\>XBso+j?.9|~6# ੟祽C ԌߕPGIYãO'݄TʓgJ3`n6{m8lF+d=%g%׏6Jyt>#.f<]Lmyp! ǦhMwhx2ܛd_2$RUdb}=II v"X(//ߓ..K#B]v{~v5ԛ&C mbaK?xG^?]$nt ~Cw%#+NT K#kq[]MdT'O::ӽ-AQl&+D&}|GS%j2p +.]i ݷn6ߎRzceX#6CmX, +~\a&eY":#y_t|}"=%-I@8ܛ؄~0nM~Y"Ɯ)f{H>xn%wLfi\\tt|3%jΛ$"PUȀL[IiJ]tAtyJ 'OAvNuNyC@u1Y2s3vN[oDMxis׆Ho4˽6nKj +%JH +;s#Sv+?G!BTL+XIjtÇL0[Jx)M KII$!5x#$;f y7+,iq HIMK\a[NNۜ#u>׎&irc-l̮ԩt2! ib08/ne0$x@ǩ9SO9?ͅ)jD6W] 7t n?'SN9GǾ7eT{=3}k2* Mf7{ GXka{}a +TtJ)?_ҿ?# +?LGNFXykʉ.$p(-TmeW-N)"Ӗ؇7<IYH6eo610X{BEk$m?XFv(~ \ӢKi Ցi~MvbjEF1cgmuB \/ЅXǪ͔Lvӿ੮%G;93)HLHD6rɵ5^74D1oZ#̽7Xty.]NTIiJJw9o6bnY*tY-7ooYGsJSΔi|7\}(uK'@d̑AZZ-SmHc5) Cm'{ "RqKnb֥[$n0,TBI>ae:zcT^a>QuTQ*$э"Ò~DH!)":啝$c{҂JAJOh '} +RWຂ$iPG˜H7 ."VFavT\΄B)Ҳ@'b?s,I[ -m:ЏTS\Cj(` nrByb\EHiĤ&pZ<9R q6>ȂfmJiY]YU@~?\-}Bnǎҝ+r@qm*2ň$?3M +/u( ߐ z*|LVE!_1NZNԤs +TXi(ewlnt +0AeJʮ[+5tU?b&Rj:LRT7[' i.3xsWe&ǁ:B9#>R}$TYa)M2POvs[1+ s&ji:Vh+ q%9S⡤7z4b1\ee+r`Xtbru7Ul5M=2Glmn$6V9M"7 Xhev%'=}uQK)`˲\/::,R q Cɹʡ2)@ 2lr^ +VO a]5r'f)Y ;#M ꌚ%Shm;氨emGV:E Y*Q$_mwuAuR&Ff9KRΐqcL%<nT#l3Mـs%@Д]J>7?tڂigR΁76 N&nVa+RRh$|( <4%+/l?#&<؅h&)T7A + o:Bo)/\G\PV/^i׼v.,^{<uV[G܉_e! +u"j!6ePsCyM33:2j,ۏ0Olm<9JɡqKkk(/q̌ܢ, ?1/e$ckC/5(h*lZ\57[dE?"H<8%O`R OuԨ7sJ3&B--,̜˵֤ȏhS'c rqIfp UܤvZ%/$Y]fIl"Ǥ$ m)~~+700tNgq+p\zK!ƊU'#GN +=26Vì~v"EwK'LsB*- ƀޞ-))Qi:zS}!J$9q9Ε$j33XN}|:~eMSNqKQ+%m>Rl,⼓W`v$/弙%t gpl5!Vol1zPԛ6QY :OeYFO1}IJμ9gJV#unkޥ!ZfÝYJ{-?QM!-%-)~;Mp%ΡN0âzIS yBms6QEYfI5 +:Wp&[Օ\spy \{)ܤʆży̞1UUVuVI)(^:-g|p ۰ psn1*Y"\|fÄ=9$nZo&ʸM: xHKX+'5Q8Fz堣z^NokC5:n\K(I# +ki@@\Dﭚ'Og6ed(Jd|NJY[m@X.i6MܞCxpmևSЏ`b.qt3Kvϛctnk5d]^f:O,P#PhtVt&GIq@w}1e΍7 =e(9Xo"I{+{*Y70tM^]@ۜHӦEXவ.9]zzeNπ`|b9ڦ+U凓K;J'j ? $)8E*X_N94A,BMZҽO kIR%!2۷؏q(4Ԛs+3!Jn'aaWF'唏qLȻ;DC Lr2MQGWp0:IeDqJdm–8G0D7 +=ƛ7$^po~c?P@h HZ3 )Ng2GtN%!@ʸ%-e@QX.%V B"^Si@=RyTessM# KR~{JDC +{aNU6XͲ{GѬ#cChJRC)j+$7Bs?V.MMz$^?iWi9Y5&;B#(]]?a(AJQ1bLF) 23e<zR)F`Vv=mOιvTUj⃹ED}x:0t^w~Hx|AnNG ϙ9BtĄΊ]Aܙ0ZQW>qNJ9.x⓭?${'NGXxSd܃ey NtABcCt򃚣vP.1P\Is'[̦(xG .ֆh]Q()xe^sv`L&.(UdF]C:Ƙ߫[^Nδ6}؛utF5 +_[*IO!M|Q.OlͨiGp./VD(z( 9g7T{Ρ<)/! R ?8S*m +YїwӖytXtkt)9}?XRtq0mV2|Z I!rC+u֦Z3}83vfFܒ18iJHB-JY7 F `/ Q^ KSPuo\oIs_r>ɚ, !ID }!mcQX R:YvժƆHŔV#r)QJxtIT NsE-I. aۥ."#TNA⠗"v +o'qop/F"@ClϏ1J6n1tѓ8bX)7\VQr['l"Q#:֋uI-"e-FRI\@=7tnU%JoWR8sn =BBt?p<}q@B}SÈf x-tqr/B[yW6R0 Oą$88X^e7OVGUv%RPPhO`ڋs\2/e v:죧Fomqɋ ^iśY%6-^ÎzAzi\ + GӴ-^1W%7%V}1b皪Ӕɖү@bma^p:em!5֦b~Y ]]!¤[m@$LRʚJPB7: 5I>ĕ%e +)H:s:S)a3 +q*idX ʾL$ c l93 +R SÜ<%UiT M'z/-L! +Zؿh1QAUIH,K'ڞ7/+W4LPmQz/MʺPl Hq/Kqm%K[,f!&M}ms 4d}{![Q<dz:`lS JIQ6H[/%zO/bU jnIKON4]1'8gƐ +ke򕼃{^DՓ y :ٽE҅LpS'*E:<_ɤ}B[i<3Ri<_S3<҅='XSe%[#2/ʼn +oCrfQM=QXR|Qn9CjO]WZu/OI0ˑwTK- $Uo!.>IBpH6NC4Z u$$jntC}(c7p8;, +Kp)+_eFPȞ軺fBSZC#DaJl wiIRxpb{mhBR3Q%J&J$yu1Wu'HnmSFP8-]Έo6Slߒ篌F34JF{}#V}߹Z]\ ;Hl[%KRImjShZhJ)6=mPI6a5[{iT˔.–ĥ)Rt @x 4QuDu$ѵ1MnB"j>4)m:;D[^?Ԧ@jK( V@N,X--ž@*VRlJ+= Ȼt[פV W2Do/0۾fqgZc#0iU$)7}}eƩt_\LR OP bi"ҳr$/#"ܖ* -HV׍tseƄPQB" ۸d2[mXʚDKNxt95?]^51xYU|i-$FU P=<#vwQGMj-ñ PH |n1q XoSh:xgԥvPV'=cT * [)E+.; : tάvM5jǒ#(퉥чԽZK),͠Vk+ 'wpv}'Dt,ER43k4OZ6qeVP,ٳRSJ}a0 .'cpzF'#tkz$b';[cq +0擦:dFB~/JZSN&)"L: Ӆ,2NY; *(_$>v6]T@8\!nU2_Zؐ=M6D.i<kd ~\ڇhBKtԑPH71=V ۛˑN6ԅnuD-L)[\tP(i쉇 +!niܲf\*[𵻣k&ڙ}m%EJl rq֎Bԝ. ГuqXJ1#P-hWiwe"*ړu1Af%MbA\%#b9vQhcoD"iJk5àHIUS-\p2rf)M{W2my 6qI +" +GqBIO>:@K$qV_ʩ&b-2m| RH7YN^xmP ?Zc,Ga ΋AӜ +X\~Ջ5#@HjOUCvLGެuDlB &<&x,>G_Tc"mSJ)wjŭGlE<|L?XT#2~Wi|LEab2.tr )3?K{ްڡo+'s QUXE#]IshR#eo-оఈo@?MJ.IZKj̤(V8=GS O/!ϙ.Kv Df"#}/9(M)sς$ZB UVbG?Vm^ +VZƭ_SD!2w\ '09<]㝑:Ger{?|NYe*jdbW_GfRj~ɎeYG )jlk@C;܃l }lxu״`{y˛?6n?ǵNB ڤUYW7EЋ\6f&oɍ$BJZ1(SN84a.>)?T{ċ& 9TjrZV' p%nca s?XBW*L2HM+W>lB9lwԬnUVowv8O-mك7rAipHwp8VWQ#CBg'[:ӷXˡ$0{2ӟ\54x*U&9*5Um3eܢF'opw|[I>.ga)3p[% Z6kR_ HƟ)FިoNCm&iMR<8=B+ᦌjP:NۯQe#XnǐHl( vĵSh-ָV}K=KǩvCB20\B\B\{qնCNRoHvwEX]2=u% 9 u>ZMzYU$_$iߕ&*KCHjLWh5BZSaCT{8 oP\>D,}ec +tG^it4#VSmHXH$RXxq!cf$%!vJx6k1jueni>Q4OtƛZyO+2$I$b1wBT]V"r2[6ϺNror)>"b +xneA6[sEX;*ێ,R6 r& Xx-2) K9$j{rI+z3e*R[aG}²hG0emn. ӬmK7er[  a&\x˲ :EAM&b,|MN{|\TE|FGlgJ5E˭@*PCJmbu@ad-Ȳz<} 7P:>kT(Q-ThN>V"||dr#BXYU|[)A$N đV:0le ~aq鋨˙1g9We9O;#;H"m;q%|0d'IdYWۈ:v*S`Iaے@#?3mQl4wKCRn$ÅܤvwP$KkuaG(FDZX 9yR~GDo&J6 +I"+pl05L~2e$i\i'٫$n58R,,-\f3^jԤ-ҥ3:CNإĝVIíIfhmI*cݦ)$) A))RND1Ιt= LHsLtbƨ7"BIܓ`.0󐯢D)J`BFd%ɪE!,\#sm=Qad:@#Fa)ɼ+S-V;*IF* o1T LVΩFpXG4^Hw_h4l +Wc&Ý({ n1>eNUZ\B{P܋Œ/vYPT.q׀c~5G.q$x h샗LĐMŬlohSQrTݘ)JJZW4~EeJ JFP߄EmF7n¥Tˍ)Xe) 4oTe״Z'b< )!{#b +!,O2RF w햝vIyQIAj&lք-T۠-|b9Žz~RNDui O贅I1o~WSSj'[[,9D@.TW4-z3 !T-=Ҡ'DM:IN'gTG(RڞABgc# +OXM#|H >+@IǗ!S\UTvH/1x.. IWJ,sb~x[K(YPpJĐw3Q'];#H:4hQ%(ln4lɿ m]*fߙY BC** dkOl6ڝRHr87Q߈:HҤS8LuAi@kV\M Ћ wh3X*U41,"O@gA!i6Bv{C5bkRPI*UH$ s˗6 +̈́8)vSDtH E!BZi6ElRn;0ZJ xE./r#?E⹔YVGBZEfHR6x_kd)/:lÕ9E #pBTG+%k |'.d'p9dB8nf`ըy>ýy:!kKt̉MGpɿ;;KQJ; u*Xӌ -B)#z- ]D zTj-$tS <bp\PqHmUevH)Vjm>K.{W#qahr1<Vֆ% < u-~cc-kq6<Ңxƺ^9(&Ӻ~]kRoO>yZM̞XnTŽGCЧT@bwHNDCq=)e^/)VΑ^CR"T?#-6E`;[9`$%Gcݷ(ak.˛+[_t;Xn^u-/Dn;#Nȹ2pinaF$CJB!5rӓrϠY@ݽcHX O!7s+1`64KMC"j2_ ~<{TU49\EzEu+8ln +t.1'L](尻AJJlA)'\p'W@.Qr};.Fp J|)޵~z3S*uL:teQMfHQlq Mqx,A&8؛uV*Z X ?QÕ?z7NPU%}#S &e6xx5-#4[u TD8죽Q_4yexU{/Ĺ ++Q_JXan}M˝a mT2dW( 3y=Ε&ˍ2jl\-܆$BTk !.x{ !/)-,"r\waO$%T⦒oM*RU\okS5&D^W+YWܟ/&KaʁxM9:w 锴ikm$! oa읓frDhQ'g5q&_u Lc’a%U O"]OOP4} /D5+cp0ߌW Kuyz_$ZЛ BLd_~Q9ڿNn)  ژqYQatHپ e# %3oTizRbQ],%^PZT,,t6'O%Lb]ּKJ?F\/a*#9Su4Ҳ6!:s/FYl`5wLQ7mQl+blE5]{p~O lIR ȧ"Se"3޲id63acROP/R($wn"l6VR=nrO\1 VADt8gW pl}R흧;:2ybLtI!q5$m!DV"1&sw$v~1ͭw;f0}IAo8PJPB:/R7Is dLGPr=^NsaŠ!cr+Bl9.u#҂F qv\N"GHV?$um%D1FM2Vj>m-&=Sh_t#)تv,A-IB^)]Ce+ӱZүCrU4ue/ i :mV tJJ,JƇ$~6ۖ褐5A)'Ƨ5dDygxQRo׾Ji`qhqI<2k3-<\ت:D= @áce3 :X-EHXRI䌁N˵>I3T[JYO!jE1iCZ(FnaL'csy+&_ je A7du)jn4"nj6OLҪ,v$fӾ*b'wJwŇ< =z=yǒ3@TNܵ +Rˍ,dxCKSRrR*uĐQmUx% o_ը:Q@vt9j߼;6RBEUVt&Si$\.DBWTRO(l+W{*z$^"CZ0fx `n)<HOdLO)kNL֫kCڑэFKnioFhDԺunkRJ60t,PBȿ8msAYoKN8ڍa{(6AK !cJEsXqFty-:ƒ%DCs^Jįey= _Au/撓BWD ]RQT$])ew~W6\ɎHVP#Ӄ|!tC) Y¦dKߔ 9u:9eIYзMMCIb;ߒddR #}N0Xkqɍ7Dt+MJJ;cNoB}<݄}wU#Vu APOj;{/a36~}S1e00xݘx[HM"cwY@J~(ǿ:wko*O9>'4?-z#S[ rͼ%8?̊|~#+jū ]H{Y6pr9l7gau'b@H}3y; +<[l0*u pqlm9UG1CRqjr 1d֜4x8Ng>b'AOs,NY*utrs2Or#&Z$ ӚQ^П>1*b:Z żMpKԡ>n6`j$M ,mBEXMC8XM BFRmVd'94 e%LP9"8@lߜ5gGTkYL:A%(Mw Nؾ螔vPlzVTVc˾5Txº c:Z|7͏w7>񽵎쓙ۖ$$\ܕF%&Wgj~Q-B>LH-aֶiBF+)'2 :qgTF[ 4m&b8TˏÇӓq4jM\}> \7 NrΆ׾dsKxwb'c*5_1!tLkzsEU%M]U'E +:]\4~K"0I_1*}=pSpe﮿0BMhEw+ +E/@'l7)-Ǿ8֬'8p91=(0)Rmx-ZbaNT{Ͼ?IB#D+)+?Vu.$po@$}%{tf^_:P{5CLOOB́=\4f&69*tEy:B?M^ TCT&8yŒ7ZQQȰh8vQQyGOo`rI0,DKP2Ir^k}|mJ–>AŀIVJE9͜]ֻ8RS:6]sMOسM+s]V@CXg +o+Fqm@R@#,\,!YHtB/4ɦ4n&cA _!kX}dQ|{áq#!"HsN;z&'S+#>%7>*{]6(%Sέ׉6t7m6@-,_غHjPPQ +Y4B)ɝ))BYV *uWl?VSg*os6_cOt`AmߐZij JG$*v +ZׄH"J@re6I[]řt]dm6ytE>xJ܊ +*5)vQʒR :k oa#WEDW,%`9,Y+503OV:Ҕɂ>uGHoLg|mfsM UHT\JЃGQI<$p$xe}vYJOn44Ժ< +C*mJP)*Ů=pNjc0@ QMaԀ,vIl -[Z" jnU5lVH皍QTTҒln{Z=CsRMȹT(\_XDҿϋd4VloʔOl3&–{G +Mykmdmt[BdVe ZvJBSGB]>Ӡ:a-kċ <&݌qeUkf^ukJuSN:EJUqLFa.>̵G;͞JyVTapggp=8ěAŢBBHlvURjVLÂ=}.ITB6,J +HMpt>4}0MRS oĄ_qXanLRTy:hD'+.zq-'Wt$w[bԕk^zy*@$ŝŕò+ȲҐVO:i0fވ5h I^2 +tBBI'S>ҌϘIKvKq{jSQֳoX7#ՊK3n;M;K|w69-֒eJÕOgw&BbUZBXP|gs$&oT6ZH}/DNyk )7J@#Ξ!wjT3טJA@ }Huݐ\y +Y.-ϥݼ +IS\yTF[ {D9g ltjuqJ!,HhVe~JT`**t[*tc4)I2AãF$osChkP*&Uj:b|ExE/h6P#ˎ03$n5ӱV3-f I;&cd8.EUmB[ |JfyҪ$xkr,"kt%H.*g$u$4+m.4pY%C(_h*/-r͖Tr6Ql.yjm.j_vV{Rv"HO2;(wT0FS4*Mn') + +#TXa&"Jf\f-c + !%S2,T3H9oEvk]NY іR8Re$AŖW%q XRN:jjʲ%YRYr;hQRp + +U_n̷ a]6ZY"WAmŹĥ&X/JzV(&#-/bmF'8=?z:дQIqPUoH d/d}rISҪAl!S`ە$ud0eP=3 U. +pdSĀ*ܮ xVn:Li]HR};Iq8w^9DA/e$q1Lfc̜j_=@{:R= iz 8KA/)C6pK1첪)DXOx_lvo\V+P}Nz&ZaSPG`>\,t@‹+, }[G-Xx+.ˤʺu=^ޞ}Q9ˬlNX@ThRoȖ +XZI["J,RH _&@o@7 NlMҍbfzE\(S0GR@`kIu!M+1[(yvA%2+Z]XDȤoM*r̼>K뉟t-Rn7=6>;%]msoooDMt^CQQAJuH&IG糟Nki^Y?7ѤDnĔ%J)XQ,)'JSs<#%1 \m7BTJK:3$ +I,IJqid'(&1#Ӕ]a[tAs%;\K[NNby}EeǦ="Taj'' +I N L,!#3H6^qIJ.Tvy)]vS2BnJMm]KWi][Q/UT( WΩoպq)@­QZSF!j){Pu6RFarQLf4ϪIP mw lpi-'%Եj7R2yrHU|5#oCf~)ulEOYJlXa{P޼5cWUljLT>NפY>*:1*@O=p)RcO澞?&r"t>-$l| J _ƶKͷVXq(>vJ4-_U>m +) +-/`~W!V q豘ZN80G?P@F0s!5PTҲ-? +\eGQAjjQ$OtvMn7mثA7L2թ/>Up۬=^d8~R-M- 8JcJ?9\5SOæC?57>*hP{GӷBK4=i RkSj]>#|Yآ2TntJ@/\yQkpXG"/~- Kk. +f @S"$mK&Cry8mD勶 aG9+udI%X#+:|#ysHx#XM9ț=׾?iM ~o玤&x|tZ< +x$8?QTZ𔠦eAZ;amrGR6Zt9I$sY)$tVI*=qbfCUSelfНlv2aoSn;P柑 lǬcc$陧lE 8^Ʃ@ழhcں^N!J,>6 +'x%5ܫ ØV;Kp~NJcO/,$flcF=MP)vӥ< HUi$*zcX2.\p)8r86V\M:R!'BGG,bb^\(e((nQo v_)j]r5&j:vJ=Ϛ11T3."$y[{ee2r +بma^0aY*iJj. 8u$[pi‚H|݉FiS}ANQ#7՜c^1\Bsv,2^ +1#B{M3! Evz#(noĕv[I)t8It?\(>u-c>=J{neam}u 8RN ߁dOܓcnc2z#*ˬ:[0RHԃ+tEZ\clhIPCWGDz Y16s ~(4Kl]J<$sb:@BHO=ؐ;A=,-ǚ}]DNx_g@rd?%{b&3ln]'!O3&CǴ*65BFQ\ڂ\!@R $K71_1DZy9*ZH}^Ab473%edoUҩIMT)7'xFfj殳jo~SlJ/}Ӳ;-!*"&aN:bXu RP+7`HS8aO4!(eCaNb4Q*Rk6;E5:a4, ՚lHm.%D\N)>xw%T{'ᡇ*Y6\T>XƸ!4y}<(ʓe\Sj'DA*{/yȒ%YE %>m~Pab2Y*7c~n,xm슕}V ܚp,G"t8" +&rnV^(Nω8lLD2%-yjHQ3ޛΑO5^xxR[QzO 4t#dWN)fe&U'Q>ȖAUu43~odCb L9- +n +vp < Jb+ky +3l/툢g蒎IIZTT&f!XV=^dyLz,"Hi`lKl'VZBy㑊$ ڜNe^:㻞̡lugPm8~bl#Tm1RBIS7Q UnD:؂m4&Zô Kk~{M >}h:f668^rcU!\[a +oZIQfR}[N9Y26KT;M=uϦ*[{Et0e:i}#>n I7)++1Yj4XB%m=Uxk YA-" U!R7ϵ0mv6$&1nIR&oT3Lu=6jKhxu$XsQӕS!^Kn9IOuBVFi>3PE=-C^rA*I铪sF6|D`HmZIJZBʓ$ Zxs ι)7筯艞uHisv%LmyfV)+iA@HQ.! !W[Xu i:$zW%}0^;ϛ܎-:ey\&M$Yvd Tj%j*4yPu'M0bjU,f:21֐Rx̤XzyRkΜ-%oo ռh,+.k\4|Au:[$Guˡځ +" nciy:*&PG.]iqBBFnh1rvClJȥQb]+EljFSn(L\HID/\e,M-q"MdݟQL̅ +%wHӴPRO|3lڌ,!5ϭiLAGEa?ߪ9w&EQ[D<è2GXwxctٵ$*ذ,3&kpSTV-[ ʄ0ɽj)gYRG2,Z>|őj@PNھd{KϤIq>"pRGqE*KT'L': l[[x_pJrl}>uάTt;E&„QÅl6[ͧ[@ZOG+Yb +/EM[PYƟH6?]|'㴟L7ʭKKԓFq|v?ϏՄi + DS`B%CJ$8P@+RpΝw2}0x+nn)l֫ТQ02b0,~L'/p*?w$R< .s'?ǽqt,BGڭ#f5ÿ.OT%VWG3VO9'Jzm*lޘJ qnkj ̢?QSI}a"GE#cscڑXKHMRe +*8 ڒEݿmRY3DGaEK$á$Aqxh9`꛱g,|XSt~]sGs 6U[݋N(~\[ +r,t>1ħZ +okzx!/S^r;9t95,nJq+(SotDUu+LYsacP +A;>a$x"%Uf盖1PHL06GPF\%Q?Dxo˙-K;>݅Q>gxIyD4=4lshGJFxa##xg?Lĕ_I]0Lݧj[{!WqVcMRkhppևmi^|W&{}?Tn5E[0`-Jp%XG#?8B¦VO +-ryNEך"69c*􄐓 E۞'a:Y(JAf8M#> cK)ʩ+ߨc=Lsk_W~}:WOO [&7YDhE.'!ԕyu{q+}\tmP+]Dĵ|>=WGo͔=?t9e;ԗB3ҲKS*s3 + z|jܡ"] fO:r,p\iII9&PԴ*W*xH9)yd>i.UZU&Lyد9r|3[ +Pl"DefgoU͵u]Z7 +Yߵo럨Y.u9N!C궓-E5)2(XT>e{L4"bedZx #s'fepMN⒂ԫHP *6&h2\Ё͊e+>UyNlV l};GzL >IJ ' 1SmNoTGpnࡨ8>7)f̿)uaFl :Fv) Q#&[.= >uւReI6IK +qK6ڒ,#h2릶dZa딨Eڴy;ܒa#zT.8bdu %=F^-¥Zúl+* Co@s-)݄N +6iqQ-"XAإA%$r1LI[P' +ᓗ[($ӴSY ȼRVEs @5> vAR{ +t%Iwhf3iRWO6'V D=rg9T9 zb"lu&,H-#:R6Dt)n)JNܻαCi,]KW D@ɥ)9mW۶ Rmv omt= HBm*iM_PJH%:]kHܝ:NoOt<LbʂIw>X8?@Ɖm%}; Ӎ-rm#opF"c9?OIK)-*V5ĞB-taNW9 ++ꉨLӯ̤8 hM>|֒2eibms,\ +U=jM_&c;_Ct~JYSPO\jaC(ZM[ikduIV7ה(6^Mw"2Imeh +[xBW@cDS,˗_C}maͦfHvCH+yJQRy=鉲cKK5*t50G{iJԎf4,-k1OX~2{bURZQ{'U Z$ ++L ML} IlYy4:VEe3M;105 nsЮ>ŋä69>cDG8 !7mØc(=AqHJ/(~gG93e#:!o6¤;l~ Ōb14ƇZP2ZB,q#2m{t1Ûrdj9XKPdB%)ZڰǦ$RHr}9I{yG #H(Fċ_f0ܪR뭺\m,BHJ~~ϝ.sk(0n`HI&3CmDZCi '̂q޳/G/\e{v"V4L8+(M=b,RU^Ye2Jad-<'s,ꑵ?q[z ++M\s _Ӱ4+W ?GhɯԛU p\' =ÜGSRbY!#O'ԜY7fpR] YZ0;F/;({>  zs_(DqC^w6lGt;4uQVtAM +E@nHT?Uv *%5V\?9:"b>akKSmsyrw6 RNЃz_#!:&Py v☤m )%BR WE 4J:"'ƺUBJR 4e: MAdN4Sbs$i}"[F Tl;SQinUPKjFm@\_`L?XªS/%3˺|=,IԂJWJ+$[[ƞ6»KBwMbheQaΓSZiʊ UJ,̑.4Xȯ2P%NRMuC™'ҡezRl=tAѤHŦwTFC*JSʈ߹ aRI+vZM '(4I|4^G=Z+[)mVm{n+}%40eP$K.[sϺ{j@8ĝKGd0ro̞$$&jT8De?Q\US{yܝIg:? +e%qpcַ+hW(c?bgzTzk-Mڥ>~#b>LL"`l3x#0)YdW{$4I=(PzT]d:w!HXRH*IP=>eRH<#$+X̂,lcMU؊ hI(&.⾨h-r/FI3 lk~ru:sBD +;c{ 6<|pG G-dz yo\U5&dΗ!C }L G hZF邿Zp=҃xǓ=S=ZNX[Q0s}9ƿGOPn"]Nu ry$ tFAYDnHҙe&*>ͽ\>RZϫnFQjx;Z6nf/I<<- a~.ѾG0UEoɥP=Z.P[6kٜƒ8Z>ռSjyn[SvPAwDx-:kSijXI}dX^#aKihJ7T"!/!)pp'tD;DW nXH!IO"^RReԗ.-̓n>{r@,J " Lf|uDܑy)Uy%#bl*Kc N[uI^ +>X^ߕt$iln9\@/.Զ2˕Odr 'ckCxF2ES*6'iǘ4b@Ligrw)<;^~SNh8|2_(gKyҮ+jBBR}r"X'i-T)BrR #U#*֦v FPc8%*6:v>슡iBШp(Y,Tm)AFٗ . 4wNM'\T26;$%Z{EQT&2 NVQ3158R<4 yե dWX7VO|"o)lx'P/L5 +yOO'}#k t7*/-a(oA~6<]S׺ŭMNm/Rԯti+6J+Y?ú\y/RìZ[n';UB;)b~s-\R]r |qB'CxvKh7D}nZhje;IBb#礧aŃ*UQPs[WItrVsTQ5"L`mOQ?T]˥ʒ;"qڲJE잝jPd4hM۝Խ.ՊMW)KLXK.8 m'+BH'.,u)u p =bJMŐ⎩76cla+<'7L녧%Xl!A-((chh_^2b9)@t,/~~#Ye%P)JO iẛS'20Q$/Xnh@eUW)4m]JAVu~5sb5f|TYDI]EE{-,aneV8qHeV]>{DeˊN^1s-'1?Wu\-v \iîn4̓-MGoko'rP ?!x %oلgqDA*'qHt/`7宑a !?'9n8A) ikRRԝ6eUYo[d@EVLi6mdlMb9Tpcr-n:hr̲m}Od}Co:Kk(Qwۈ&'zDd@(-KC֠RCrV< +SR3gʥݭ˟8lUf[*u mC?ϟt"(^q?͟|[C}dD Ƕ-(0 4fˆsJív9h}SCv}~^6&aY=Z"c"! h}Q!X%Im(|,*9Y> +ͩ|4ts#2ꉖ;"wypZg{/8}j]?U08Ss qiʇ%^@}ww>^W|p9}I1e4=J>*В,<2슋2ъYn$m,hs~=E!͕a9ЫiFMF&EusnPF.GmzQM4dE$w\3 ׾o¹)N١~`i)O_*,LcbBʃe +]Mz";B[{ƽ(sŏ#m05*k,x lM<ӷW6F$ٵeS!5ixI#"L*Z,3JM$a3̢y?U!sQ6[OGGn{zш@n ;YWU{Rm8q,D~$Rđz-j7$ry@جFrs>#"r,hkaSBI ʅ˖ Fݬ'y?*%G,$?C$\l~s里W5,?񈇝4>urId<R$Oݾ[⥤ߙuM.ǾG^ȏg/x7j_$ͩĠQ/[`+^f,юs(ql"3`&I6>f)'{@P7xxHmnAEn&`AqDY1}/3FExIvB֥)nHƼ-,6 m}*}wmIbZxeua+;jd ~GKmvR,qdsF*d)X^$N?i1Rj-8Ark"8PxĞE'h2[Rz4zoԎDU:GLQ4zq IT}(ZBRFŇ 8hǿHW1)`8⺵<[B5ʢk.?/W1%;L%-@q(IˉVHUfWe8mN$eOj]bMx(-C7kԝMxwMrsmTYr="L&e!)K$ ǓsǦ +\!/!!:r}NčaVԙ'9 WdZRr4<5FVNO51&N6StʯJ!֪)߲n/醲l#AL4JAܡmnTRQ;$sٮU3iA٩j1P{|q1k˺ ZmJ J]-lrTJm +]*R Z"]lK.,nq8 V& ϖҨ q-,~6)%͇R71{{[Ghm4nhY`BA ^F7U:"9 zZa\_b 6qKX+05$p nܟa])ML>I`_"2ŗICiR;nq$=/Pr~ڣ:ua_tpQHP\T^LYUsZEu_þ$Z,I8- jLZA[Ke +JKIR $\\߄izLzm +Q:3ԥ4Xy4^A@xZ^Y>BVGU}/E"S$(g `ô O#JUOuf$U5 @_Ζ3]fiǛ6ju:ՖhQj2o.uQ+ +,FBoۭrP4 +^d0Lv@>jv26S [ ̤BA$66;q=5VD+ߔh'D=ItQQ믷˽.V'}*H%%iu cJ/bSM&rRihUL /dZ|ImU3N:IBZ Džu&on f_GF`&XʤqAԜ);$;PC,v HqᚨrL(Zaa܀o֡>ī d|]jRNl!"츥6Rtw>bGDM2 2)i@S[m݉$ZZ>gz~Ze \v%bv|ԺgNxu-:h@T.6<Fqٕ0\v<}1/Og/X҈]y6ma +,*"d-,] +H N@oNt!.q%&~OKY6}R6,Yih/q'n{LqAlHU(*E[J}W#TAY3k0P75+dz?i[NuG7uٲ_e296ݴ\Xost/L,[Bw1^,f Q$BM[4ΓSbTXjZCiZ`StH*^Kq4tVZr)-n%] @88ɞ3o.[9ʡ q(7C&=(1赪<v +Tmr*i)Q.s4r]mt8aAue>`9dğ3uHaMr`{/ i(D:wX&D1MlRem.6J ++#PZժvHy)"!#)%(Ҭ7=DOE\Np +IR9d)@I)=p(iQQ4#L$5if6b@OqZA@;9 _\Vb%K +]`$=[ŸBXΐFfÉS`ux QTh dURL̫s̝IƸ̢í!Tm1I%@xj3E]IY|~]GTkccch[<:Zمp̽XvIq$y!Uf}-4"~Hਭf|a)]ɹ8g)bWt]N]N)C #v;ԴI "_%iLJ-0R_.'*ŎP:yK.gMz5%§0y \Q+b\i?6!zW;8Ŕ=d,OYE7xum$2.22k4<БUO +ցq#2(a`e\3 o\-1Px+k=n/_r?_7̻5^2&'!ԅW!dvM /}fZܗp#Qr.ȫ#RP#NculWYQ6"H +v#q"(IxkvJGa&|Ąjy$q%FQ|tskkO2edyCHG<[IPO Zr=ImۏQo4]$ơUr3>tM=$L/P؟00RǶhfkɪEq,r(#˜V|R&Ԡmaj7$"CMw[ +o'u:F}e %!HpG }qÇncygS3j=Cjy(텉ᶃm(kAxi}GjW +M% $ `Œ #.ܓrLq)Ef-̬7M~ǮP#?m?W >|~~x#eqx#J^9֝ABЮA"q kxeڳ$؈SrEĺҊT +T7FXSv9iEyG4W~#'lYn6q? ؆'dULss"~-\PyhD.*m۬7ڗ[FU,~DԓHOi`tas~垜sIg~+F-$2Q68_KNHiIx؃e?3%Mz vƷO{ŧnbWR+y":چԜ lm Qӥh0Z[T|DlFB7*QnQ$$ +m#]Y +Q9 3UVl2''eԖrZT-KASdۼs+-ؔ\aqqha RQۇ42e{[`Zm|Y |Wq <#.c-FljkD4 +6n=+|O dV}.|f._4-HI•C1zGJm-6'{5'8H]!+)ʾ؋ +VV(Nڤm 8z@<޹,ۢ}Gd@UK)&DXyQ"KiI$ܔbFD: OT_O8]ʮr\{ャ,^< +C/庈E<"2_F3%23EN59)IDRO([wnhA̒/qx" viՑ(Vm/<)6B[Npְe#%DFJλq}a]%4j@wK.zɓog,F]*Y/%PZVS{%:o k(WڬF&]>,"|Iiy+SiVTsҥMͽcq0)%'t'J&z/cqOb7\i$eqe# sL9RY"z:ʙxeGuv Li LL2u-5&fU'8=S`<,= +I&|p;׶w &BURnWQa0:Ԣ//37KAɕ]J`xc2A.BsXin8 4inTRʰ.!N뙔Eu \a9SQP6BR_qĤdDqBH66$1us) 7JN廬5_,+^"Yo4rogR Iv}I6GK;ɽ2^@[; +lMAU!(^6[RKom}xG%mh8y|;[PDZ2RV qfz;e-ԾsIT# +c7r\#E%J)[{}q&K(f7NeXONlEÝz9xѫr>.7$bt}UR‰7 >)9OB&hl!x|,qD:.Ԡ 9$MNU{YZڢ͊ㅡ#1N,Kb'E8"k<''٤R.G HH\ܻ}r}ĊA*Fק-"~?ί͉gSS9|$rC{m= 2/:[ FScPQwOOHP5g8{ +=HkB3'nH`v|}I*d[icC#QI k$ %<-ua1iOg#h  +*d*޳ +DCu0_loG%75Tw/io8l~:IOW)mhwZxb[z6eĢPTH*?_&LJ{ل^"^CˮmF@3/`aVji2q'ݾ&~ +D}XX!O$JDwCmc)1RcU͑-ͅ#zϿ$|oq y*t{Wߍ3#OLba7Uo?!U~ф(X`JR w BG&u9ysf 25Fɜ /Ǎ%B5}+ O_F=83<) +ɿ8Z=LjiOobU’}ln-u02R%I,oCTv˭^I .};2DD:'lAT3EH--mCX)<E:GyTqLEV96=-Ck +fVsUAEn ikgB%&#ʉ#%}1X?_[pxaՉT%~eW0Hz c&JVdpX,_䬼I30.ťv``0ӟEs+a*\j"({}|daJG}]nQ9pKi`n"n}O |< K{*/H'^^$L`LWGHϤ^%)jSK`zL8zj1OGk , mS?C? $r)4ԛqѴ=?M^oժ4W?\2߳,(+[)ĉCM|tcMYhsrߨG2ܝV骜U$3U*!rb2\}1j]9O~Æ/N5jVQB~5L;ܕGӊvU~lG]~Ofz8-Y&GS2AIA#c4G(P}|#is4+P#@HPS8UrUɹM|e Xh9izra:j2Zx,\yؘb!":j\P>M`6-|eJ%uvBMT\4mlbUl%FPq6n{GetӲu($] n C&CrejlFlHǦ+m[#_ǝ ylEQ&i+}Ko0P @HxĞHn[||!I|KD|T4T@.b#[s7$0Գ +2o}l~{o-hV,]N꿧a βDm +yҡy#1B^9R~JJZO!D ݒC'B~pKuiYXqAYU"I{)IՊF_܄$8v ܐ8=3Qր +r\kӖ2sI ۟xIHS=.RMR + \sH,O U"00vLpivØVePE;m"Doutyl(]ؾx2I$l~8yGX}me A+iZXaԤmW$4}?'Ӱ˛u}j 9Jx\7qU'ISua3e3a)=j\]TbˡIz$ΰGc̼RUb4JZqPRN$}QY*)~m)ԷA(6|G>:C]8TT@EW! ԮwCc3z4b5:KrP`hpXD]8:49%lQ:vKͩUHSs Q+WŶ 섚=$ #_"<%PږR`&ֿ3_՞K4)F3 4-GӒFhQeMX̢yAX (SH~jXwF`AMɉ* M7R)'N:%:ZKMBR6Mzs[8jSVrF<a-W&<-o0WnaNFsů r( ɉigOi"ÌzjRVNy?( +IDG4ӒE03 \VB.TlIzg^13+a$mAR^3z?驎EB+Og:>%6+܊\ep_q6_.bgkI%<=1i03[7<:Ƌsj2s8ԝ{(p?z}՗_}VKQ'vMfa zyt7'aB 7/9rDzJ89Zӈ9_b-t}=^#YX8+2G :ߴLijtj!%_GRWFtN="-|͹)f:by2#3KIjI6 +•l+ې_\"p#\^]:zxG[UU~K ?<.X[`}hQS]|;;)E 8(]"gBX9[B-S);=)d7gi++Ry4>\+ɓ9E{'ES`e6ԅa +5c1 䱲Ї[ + 2-X!fzڜ6 +*_daVRU"e l$?p/F%4wlAV>_ҦRNRhUC/%.~m@}qkkIɜgAd!)$i:MF"IvUJ("ĜQe4UT̔].6(QF QYn akJjմ))0ZPfQsaqNo}ldܟZd^y_Ɠ1mE%UtF)5r%#=uOrԘz^5+.r % ٲ?BÏ *z7ϫed('jԛތp} VckFiswjyܸ4Q$f:LaopHJkδl5 QaG)g) 溋NԾ^|zJw>{[** +ap-9 [ z EH [J֟({R[ 4uWnifX"@֟^*it8۵#Iz +`,xaVVWʕ36iy>"fQkˇVGZfG{aܥ}ӌH[ra.*P#HY]IWOTPlԲHm#@î<.I7*GI~J{撙i7ʒV^tJF݁:voNj)H9sQqP2i&3 6q~[:B"pI&Ǥ~ JHxx W8Ǟl= A~h ۓ-Gx0s6[a?NuRR|$:㩉K);\T^Rw{؃BS=\hl.FX;§B@3*_b:y,B柜qTeL4X?X5'FU%2nz];6`nr6N\;D2Q",ylAL_vvU%ס&z䒇[p8ӟ_tz*<&hM +1+Ru+@9n-Y tA|N):߅0 +ya). E$ bͰ1% m%I~ ўN9&!MZXb.Uҡ 5&.EHl_%_ƴ̬0N m~.CtҦ +َ迤Y*&ibY.!n4wVДe(%;VV .LBju%+rF$-2E_^fQ$BO+3ȨO>j +J3e@\@R"?W}ΔGz$Gu(/~Q;6d*IuyJym?"!RS$€(@PѢ@3 'P+R +, SI h6$bE?E%ҬilV&ǑYN."f3&DP?;ԛMaͻFzAcJVW̦Ћqz*nU5Ud6h=8ts[*bs9ICeu[PN+ޜ4kH:TUXjM-~mIyZi6; E>0'HuSUJ -@JBHٖ{A1-Fu;hsJ](_lQtf8 + M&_}3peA%GA;Ԕ&;slf76ԍ)PTJQ{&әxz0袡NoC-0b͒GX`(!?~>XDǍ`%-Y)Ô*RI4Uf^Ze l4X|ځbIp/=?yqf,6. F`;IMHWZy@̲VO {ҩm(MReA6!nYnω0gᾔ("sk=Wwo!%S h^ю)YeXTƓlN)CuǡU#;* dWd<%qPhw򉻣fVt_8$NK<:]XҊƉfYu>Jy '$r/VYK"etn <ŠF>1.ͼаt)PЎZ.3m My{ Lwe-Ձ+%Sa KWeIAFsM25Bh5^%qc,ѨήˏF.#0TRmMa~g苬()aSJ@X[a哎r^Uڈ#],|+:=%FKbJ6;Qw۲!JIj(;Ӓh:F)7:HX|M6Ί1ŒHT V)9M:}-~>zVnZ 6y1e:-, +9}Б[g3^GBut$΄^wd*?0JٵyƓʾ\E {b HJ&%*:XUc-ʲ IH=%p#ˡA79ZfeJM7>iBE$^ێq̢/%Te]RR@Xh΋uW.S"Uc2T)[|X)'-`D<6wI;ßO&Sn+XWR>}[k+elwJB׶@.Q"gf;*Zs.RX:#O'ܓpH(EW:vUD:JP`MߝRRMDX{o .:'ӛ!dL~ԗʵ$ F& 휳kSYQ)2 oOp4t['#If4m=:D=SKSM%,:M+2yPT#Eʮ@_xk5C0[ILI;U2$ǂv>x})M { q3b?g.NU)[l8=\ȤH۸wAĔeG Oq Tΐ%R A8it ksX(6T>a5(3S!k?(m|㡲y)7Uc)ϥRN"}IGRz}dKnbSët*}D$?~xI`tk3Cֶ;>>=#xsB!8U(i88u_9ǜɱHvg<1eopV]XU/K2+L&=͟|ZBp"USoD+pBPw$FoQ +@\XRvm-]΋)=FtXeVلI> I|`r5av0b*ŴQh$j&8^f%}hnN5B!qy -%Ā zh']hvpSZ~?,mXuBΛ;GǴi߿(_nܽͅSN!txWPSO4L `(Y7[jT-!H(LTyd|w&)ZH1l!`Ǵ2Tx98[wBjk:c7Gv06^(_)R p@Q5Z*")7дEvP DM43b.:_0PVݼ z@#zk^#_Yܗm9N[x )9ie93y=@e]J pJU8oę:Z#O}?P^U|5C߮4q +OcDr)c*}'|Uy"Fg4WKrY zFOoTdօt70 JA*ʔsg /13QĵjVtZ?˕{}_8t}xuIVJ;u_XB ;oOj͏_W8ҟad&knk,H(m0ut՞nE\1%쀗Oc$V\6j["1dRtIDAga qG?T_ H˳"$Y)[R}`_m?'AXrRļmm)uƔ OYSsFGf|N]e=H:6 }ta⸣{&RO<86"VeO7Ry@+ Ӊr4F%;I@_xRa2:ǽ3Y:\r@k{Q- KRl\ E2RT7?@~He! .6= cl`t)mrF%:ij*p")]YRq1}qSi7#ƩMcU||o +cp\Ez! 6$NmRtFoV&NPIIԷa-Du+~~A{eT84@eE9t)ۅ7et3%b%:pOkO !ǜUӕBӵ+UYA;Cur`JUam&Gԁ7Is,xo"Wx8@x^EZܹ6 wt iln'x©b~zB{2༛ZWE|-J}m:){m&iU7EBL8qLY?<dIb7}@Z'z@FqATuDM;Ku,PjU:4&HC]e0~6ʒ( [laDHt wи^(Q4n`TK.;-UrTVU)RRUP "tY7^+͔ŗD_$cO\JbZCFQY lG:JŬ=S(c+^*Eĺ[I'vB*-75Vym_.h[N +VŅОKPspG?D嬶3A""Qi˰22Q՘_0(W )F͊MgibqZM c +by6THOn۸n;܈DfOjbȋ)imB~7R.l8 )#;_A8•$jxD&ƫQgeQI*Mj֡{){w4tԥ*0ܤ[4j@<">g^9@cIAeK@Y;E$yaDuA+IJBR@}ʴ*x_Cި|2}BDڂ!RyCJB6t:geo-YIS _>q _[/ Q[)+ 4)6~+NJIr%WrXx;6bcOW7<{l}$p$VT*V6b&|DGm N J6jNU|m*)̫oka: +RP +" ah6˳hm,$UUA SkP*,La]Kd&Fscl};$V҇` =Z*![6p}UQty.uJNWIT0'"qіٗ/ˆ)+q+>_1:lY+,7sq-lm~&AOcx)PF0+4YB1}R |1'^AK40W,ۊN!!]GT[DL36}zH=z͝t"TNdEhIvCN[%'q^԰.̐rVį-dk$z|T-Se;Lܡuw((}(UeBRT)ߓ*-B {A#Αݧ%(SGkT8g^O[.B4)L:UVRT;,ӦUۣN|C߉F-Pڂޓd!ho+UrPT!q[6ʉØmiJ^\y4%)l-4BkQP$.NdUaMbv-)*M1f0-WcAZ/JcVz).8Ī+:e'ub*X'U^4HR\㺥ollʋb]-̓q]/)MXfM9<27f JJJH@NeUW;!&>T=1c8B?z /B9r~rju.**7ڔ*R?UHHKzVʙv'Vq%%Ch4U'ZTT8;"GTw.~ᰉ֙JnX劾J~qMl9^(hAV\"4kJ]q[t5dVR~x]S>¥I}+3s6&Rx&.~m}l;hjfC(u +RHRH$ŧ0:);3K(-)*$G"|ҖV>j6ޠTA*D2e>k@>Dc:AӑxGXx+E|bS:fyT:]wXc$Za RI?*6Gs.F <]*E (]ӉMдŏQc7kc_N?B?`5U `v? 4~= Ȧ +TUeq.4&D)mGXy(v ʕ13 Rx#Vhʫ2}0U -C+O5f -UAͰ&R@H +\䔤,e_;^Ԙ5=l:80h*˷rInKdn Cjo>or;d %Q F-!3QiGʶ8n7(c6<~i) +쁺+d+\P +\ ,\[OF4ܘ0A*z @n R5^uMeJ<,m6 +%\a\$ !DBa`䒛|@FS0Oe1[BeT!o.QŚdT n$We7I#϶*O.z|[{|80Si'PjqLJ)Bp{lczEs(q) G̟ 1O7(Z@9xĹ՗tH9%ةBPP۟1)gU: _dОC*+0i-jVuɒE6S*ЏJn ʼnHNJRִ߈<mqעX%`k/Eg&ֹ.V`juH7W/()BlXQzN.S5Z#w۝9R όX9TqY̭ TV;$sm ArIn\y̖,lݸ\(DXfIs^fT{,N;ZVtvlFPpOce6ܵ9)(h첐~Z\:9}qڼM\fSLhr{׷8V%S!:9>v:)n!%bnjf)SrHKh)%`othJH˘h\Qn?bIPVxluGJu +s3!Ap8*EWR1Ӆ'pn"{Pz3_Srs + +tMƬ$xa!;Si}1)S~Zz|K!`]v>ә#5:m.C_MfJW,EN%gN0Si@^PLbp2T3 zKΡ3v-ke ؐB6U*JDo Xt9BrU.) !S`MNe)y9N`I]̣#,,˝MնjB|2 gG$>}: +PIk҄6߃JR3:yX*=%Rm;R-ME]R-GL8% iq9_AKћ.{[5MZМ ZGd K i5qؑm|od cBëc |7M)q O)=im`m Ge8-\Ȑw&`;ZIVzqMΖРԸFf0?G4zRo<7"{A_ {qfG谀noOmiYΞ^[ܶהy + ZTF:ԡ: y?=YQ ^oy W{p*b'rAq*XSYEӤ=xebJͯyiTI-(}QTVK)|EH`195TdnA92Z%@&" Y~2jL=:DM橒n$3&>: +LLHN)$8zEeEE% +ңI2:"B8|-!Mq83hZg-褹  EżD'ZVJBxh_xR/<=@s+m R', k"z+AgL2Znj[i*1GʉEGՌMeE<]:uoԭ  +wuOŵWG8jPT<Ƶ1OftAxP ;V O8\P';&Ѽ@Gzoas2T +B0RwƏgOu?3;`uH +Po>e_cDM 5tjq=wLqڿř?*KBz&-4Í埄?MqF鄇1L<^~3}9/Dbc3TI?5^wB'N!H 3} zmȐ҈́ͪ:B:EYlujQD}iB˘\Yt2NQpF+$a+xVT97KX:}q,^׷9Gz O"ċ 9L"x Kl#I&m59(ҏ;?|۠oۏ|Z=O,Ґ5^ZF58]nfٲ:%;~p~M2YCq 0ߧHp ؃FlXBMA>wԕo9^E$IR qۥUk]BwST+ځ$ٵBv<} R:-uĉRYY$) kqH|/kl5 mF_tJLDj"?UF_I>aG`QeŤ5!@D"}GYf(nTt6 BŽp}ʤjJ|Ó &ُ̰O>rIhrjal7Ui '?*Uh~0'j*$\~PTm'>S*c7Vd+S=2~h@*h^>.>>pIҋ~P~Ƃӫ$V}#t]Tu]L,5[l\]<{[ ha>YKi@Ga9$0VH1冄ɻ˿W8 O L9brsUiJ前x䖆cчeѱ *6:BiIC @r@>#Z޶Ol%{ }-nґ`5$Mt@ҞR^|%#%VUCF%~3CPn("<,>zH5*BSQX:w{cf iѿO/J:jvQģX׵cֽe6I/P(. ކo8\pHs_z\K.QI@وҝBD/ml8E1Wܻm˭IPB{\7oѥ +uc7W+4#kH%EդqtZWwM}a9sfTmm;:au$f}z~lu4%[^>G YXJv%hMFUɈĔ͕|iVK7Z0g:=&aʚ%ح&޴A*2a<_Le9* \U>R6,9epGT) +$fnoO[.{g5Ǵ2iSlP8-)R +O F mBV\9OZ_2DR~dߜ^>P%i3 +ܔ+%FenՐpX6/{mrVZ^d%M\АBlbUKuV RIWxҍ7(R@XfB*7'4]4XpZPˎ/CG#`V9 _LyU| z  Y+feJIciRyGv>&`uJ׸^]+)f)B +Jr֯*j_!8_>Lj<)VR +y Z؃D K8쭰JSH=Zmrei%VҫXZ譳aS"f_1-(րHJҢ O4#[u?Z>J."-)d]A+{bY$$X|!P5E9Y{^ξ^Ui„%Ω Br;(\~:zZdVYMO}^\WhiIm" f18S׵ ?[LL!WDfE6eh-Ͳ46_ N:A; +SQz)ns^ECO$ ˛;&ӢQBd6I%| F YE`DE488nô;2s<(:=9W'hhmP)IQ̢VQԍuxS 0ʽ +>7߹#G41~/}\( ~EɴlXmEV>OQ.Aɒr\q3!j(q$(~6V@,k\}pOLvVR9nI բR +J7|Ŕ3+S.{6J ؀\ȱNVE4HqIG};'%j(BIRrԄ*=U;)vR3N!NCjJBn"! +J}VsH{/BJMz#g8\)c-dÈ}Wt2GVȭ#7IiAսZөʃO ੐$@I{pHڑ%I1ip=CPX'hoH"1XfjVm%nvʽ"bJnGS&PZTn-/.iWPVRAm9aL6n,G+a'+:\Jk:8FGlVBLx`8``+ $s`<=($i ^utdzur<А}HeF؀y-oro픗3k_h0F|VvUR +\\q~9E*q ldU|{rgUm6VHXIАw)̣ɸI2dT!>H߻R#wpmGpՀSk׶lxmJyZstw\5<껠0ܵ6}HKp$n!,%)^mDS2- +H8hD~cg_h0@PN=2GvċmJU[Z?G?D?O|緒箤~4]/CX ߬+L2k2>9:X99铙OV=NR+;J* + qz_Ky}=S$2'p8! +p焨3uJlbͷQěU1wEtVڝJ% m('6QnW:(-dq$p)ڎG~M"C -^-RTEl}Bo:Aoil=a:CC7MɚT6n#PH'؍䴅u]e;*oK]dihqU}GS*:Šm+h̐ #BkEi}2Jt}1 $N@Vm\ҁDž((I c@{ +*X0R{YեIH PՇ,R:L?tkmH  E$we쓝_uO@$؂ n=P[ ԥ#+s + >q!^Ks R)+q6XOہ)ٵǂ1uOJfNmb ȑqo㱌Ӯjkq7-;TMpNN13H*~ԩ*M;/e-IOJ?ˉԜ%%&uQUthc !Tʀ]_[E֧H3*h-)!K +=`m}im1M1XsKJհTSߎ/pϔոXRy؁}Ve%$(qq{^,5 ;3,4gs1!yJnXr[r{ʼ/-n0 duL(s(bIUw& FX=B!-;J|@$[@OXv]W +Ǐ|\jNj 7Z36X$k ~h~Wt>rmkRdLh.jJ"c)+>P9 +Ȍ4_[o)d }DդfSO_BF* M6}z쎠af@ԗ/ڵՌXUQn]V⭰*$ c&/U]X],\38 IBe2 p>HNꄢbq>_\'˽WjuQNG9ޤb?T"̍o699¥LySuXJs,lu') ؎ IeMP; HZCJ#q}G")TϮ MvU*W]:EhvMA[n4!\U""MtzNѬiN,#௅ lGJWI!GmDP:eʐ~#ڒ4'm>hS&Ow)dژPkM]i!EX J=HY?G銤Tʄ|wx-ג@n +Jl,";`T6BrQLjJ_#8jyJZSv$Y P i{}b+~2U 9 4& [{\H?r=ͩ)ek9 {#S j꘨$ ++i~TPOB+ +"hb6bǙ66{=pMHuGt(}b *C_x/WQAy#N4:CK^4-!r{QԤwZYzE^@IĞ:F|B^Lyjޓu_c@2|AU)XsG%QjG1W +qR/+^DR"P躞hRS}5'5LAm¯d [h[b產\*# /aMS&C 0%* |8nHI&޸Nb5GsrreJ`w;^20èt8lEpظHZW|Q>RւHPou7U[M[7R½hIԫ?RTT )W;Te ;M}.&dҔGwmCGqAhsF)AyΔK԰W>>>uty6??J/\fuϚhd~GD|->`7ß:/r^4? 2&M +}MY @d§KWiO!K_GNi1H>\ iEcIJ+ fM-d.&Fb*TTcEՇ>J[reוRӈrPx6x|Og |% +^MqV8G])pU!X]$ɗO}FdZ#%8{̵ 4|:Dy#۷ _//dҭщ| al_VM\އ2¶OӶz)G^U7'h K%$шߒT;aK&v6w!GK!g"J)rdxai|~6o HoďZ%d)'w?:pN=0*YNqb>(nv&qOX3-Yv<bTZxSiU)i$ڸx^ඞ;Nb%{R3!\(zd4 ak1kz-3N6/eBU Ӂh_TO޲_G*U% [AhNS*Iuo`8ǿL^Q*4Gk'7riĒB$nlmhkfuF~'7U[mX:4X 9Ο<&+wPG Pi^,M3[$_( R3ߏj:(6Z ["7?Řr#ԭLES99>lʹп~nϤGOIwT. ;G%-<^VQyU+%*n nN组#> +SE\s'{!jFTNȓRP@ +KwY; + ; +[FZai~j2仜:džط2Q*lFP%EʕmOҴn8*BݝraJoX5<3Miu(w Ǜvz& S4;۞*ԩ+}ܐ&-9^mh!ONI|`|yH @8Zq-68\qkv7əEeIm'훡*+ ˥iKR u<71Ԥ\+9mh¨v =>xCE*Ǫ^+o I]"׵wKw-e(ڟiX߽PfMi\(nүbt:%ħCd#ТIfY-g)Z;³DT6 -*M +Sre:CLT|T#yrmvRe;0Of޳fbܻ'(9|!Yb6ڜiMB}t6{q?{1uzS R3Zb4M>XWeJrX\p:Dx)7&3^Ըr :Og䑱fŠdZ1]e(;4R 8l3݄t$Y\m2ێe:ETyP[N]iH;8o"a%Au-]\SvWszTPqban (ma ;Ez=3 ֗ L!HRZkrO +uy7HaFhW#ْP.n%\R &PZ#EP;qF&!Ajq5R)'HDvԫR% C[vm ҲmT]PH?$X_0Q +q~HNtƔ^~4aξM*[/Wj ^tqΡ)9rJ ="W2J{z"Q dޑs?:e*WTgK`R;6nEl8*ئJ} +EәK![YU+6MI[QCM6e2oM)ZVmd{(jFEA&![\kFKq1vX'kL-kXBn+2)꒕\[2UX}lz:U1"),29Bo03˹VإC)"!>;\mj ChF;q3+@DBa7HtX\&<⡮ZpN.ZLIq<v*r+H^B%S!Z2aj9 ; 4r +õcG 1~˙4嵖AweU@DGő,[.6lePb厨d6{m3Ϛ IWn䐥T*N%s)BHPiHؓB','>ZrQ$/2ەWĥ4:ufPiaͭFhݫٝy6bIZ~#zO$Ziao[cQT.G!_rߙ=,IE<mP$] _e1҆HJ$v 1((f4Iyk{GAHsѡ,۶??*6d:w`6VTnbbYPƓ:]^:H% h˓鹽B"tꅦI0ޟPR!rB=YQOЃ!T~,'&#ʹ=hA@ӪKGJ䟐p+[ҋՔtD'{/jJ(Iad43 xF>uA9y92L d<+h))T}SٚYk+_% +&'T2 MmV=зS=%n2jq$%nlۈ<؞bq|"_X!9=h;D)POHX+:u)8CIZ +}HpmEŒmջCkS)R W[sJZE'0"6IDW6~ }*F&iU~| +p[iJ)>KRk7,,7P>8r*I?VBJλ9k4>t3Gj+[QRA02#A%n\Mک7Τ3-tRog8TR ~]ߌ(.GPW/0BHVeh[hʟt/UF +V?ctE5-](ĺ<˲դVRͳhOe<uy8Ӑߩ&hB{kd+?nگ%:vSZSnEk8<՗$|!RKvS Kr[[񃭭xhlnrIv!i*A6AQ8QRї:T-+[Ir{itn)*PQ.ҬVq *P&-#֡ E$"J\ -{2hلf^QRy)ދqï .m7Tlc1ByF$r)lf;8qq[߰Q,OBV + +BRX_YV& bB(r7߁3t(j='?%UQ~Rn-r +MNڟLg<Ns.T A~p@7ijю ZiyZe3RAF[hVf eCqe[Yd 3vJu %& +z-R%qqy69o9HVnCŖ`~ۛ=46TgF9*NmE.!RuFck!bY +-=_Qڔs88Zmo? ?1sқ=)g1tZ=b{5*mZ,)i[' +ML.sagL#)iaO, V<{a j>S@lc(E7Rʨ9shK+:`-.Hϯ6rI>.+*څXb_v`H*eoxN1(c%Un&aÂH9r ltshT:^vU%ed y:P{UVr9~ ֞P4S evaWh +Cٶl(;>ݼ*K-3JHDG BOƇ*mJ\i7IR[sŭ^(2j=ِi@!_Jyc85UdA EޒOeQf{t/yv=vL;w)PyV0ڭS|c*l\xUL[>!FVGF8nfM-) K`~z-s'o@RHtZ+c1'& 7׹1ވWc>4b܈t}pr n{x^X}QT(TMXx}iǽFJ_FgrTyVӚU^9'T%xj 6'MG>e6KHRW.}M?ƱS?v"Af] p~Y=#`q<4K:3Zҫ;}~FS %LR;$1a $"+X ޸O!A@*ʼnu9LbNkim6ٓ= ]mⲿ3\M=)WDYڼի"õ'i5Hd Scp?88y$6OEGeNQRNپr:tz>>θeozOymr 5 hBֺb?NIUNVW:|%֧B?C-/+?Ҙ?|Cn*E#I^a ᶭTo|>gb Ut +s]d~"?_wa!t>Fy0\8k yHnRrh'"֧J$}XU"~MTyZB)P1ȼs͟‰4?'o!]%:?F+Hx-s>ᥟ5՟'$B^_FeG8)- >݅jX>tDE)J6 7GX|p,#%j +.uk R>D'_jV|HAZ 6;\إ6Q[%i5*p:'9j!W=Lm>ЯFR}'?-0TLrʽYiZc{*P3L(b1&BX}qbrj-J C98U9.[ZHJIWo_9)Ƈ עDZRWԁ{ѵZ]KJUN{L#T #E +x@loդ6 3IX)-IGZ[Oy@mAy&$z0ȗiYd *F?rN_bHJh@7}J!‚x- Ʋ|y鯇#FK)[.b&HdIRY )'v~1C`Y!Yy,?(UM +FRmd{z-KMBkPĸҞRx9dߎ~sIXQSNd-c#.~qwE=fe-pU E,ԳA[ZtiRATZdAM:ckiԥm+Mp̑ųu)uJr& Br nּ~=6eiq’n?h"vO.>DFy1ސR$;zƉᮖ$PʇRu"r ;T +Nڈ׼3ZSKY+al ڏTO"ÙBj'GZrӂާevnԂC%HNI==Kʙ:fg +'hXFbmaO'(*J/'$IYm%+)AUͲ$BI:kL~Z'SS3J:[JQwznm?J-SSs$K<[ORMy.:[h$=MZح`4wj :3JM7poC%aٕ]p~Du@%`XWЏ ia9CUzqpMᗈiI6mɷImb#bjnLD{ktx)m{a$1Z/CȳNvM@.PRB }9SrfKC`"b>ZRJmG[$K*V(*i7h{n-Ϝ.:w=*ZhU(cJT~d_X(Kxk'HNASe}}]KvP͹zH.GUٗ\6LJQ!E Gq,~eO̜ 5B8>5)JMؘp5yS2$>o8(чt/p;LENW`[3G?ߜ~rqlc y繂<) =*[eP]uõBEʔOalBE?+9I97j. JQ 1n,ݑNȑ^!Jmoܥ{\nX5 wB9wPD_ELԟFS8vlTy.jU } ditȍF,2!#c*9v~y˘Zqj*ZJI$Lfqa"? +X 6cp(+PJAqA lIP@[2eIpXQR͒/M/񓨙|ZF<7گy|xn +^iM -0ڛ})9ӑEI.q +ʹ8SMYl?D{bKVh,ZY%){6N[9I)XIW(MQY)JvTy5ZKlΈS#nN)(m.6P[%D +qW: 7MtlBVu c}bZ!0:4hH_H-EJKɑ@la{FJIeel9HtR{u!@l޾[}P]DžBᘡ.Z|su'/X@RR'lþ>:T 0X?yf[ZX*ɑ!N,n{] tEУbH\h4HNʽwVJ}Ju, t"pwz^}rrr 0˖m/m@)Wr/niSā3%4 +oPՐvpV}pAq-jAlHIOIr'9?T^m?8js[@?q4)NZvڝ BԠVKLjY䶅i^=?,E%jdrKʒAЀV7!A7 ]9(q̮7 m76f2O68-O*躜m+uҮT/5.1=~so:#jT7/P۲REzNCI$L_PHƫD>sTf:J(q<OR1YOe %>cTԛO{̻/MَbusR5eFocp~G<  +mPJO"oJ }#_!B­{{ƆUK'RʩWX!Ju~V6gߵI7(7d8U`8'0NUW[(QHRTmkjL|STs,Ss"J Gkzu'ԫRZ¬rBo`h7xKG*Ź_Q~d:h}fE)M[ !ee.6m +%xL. +Ol`}$$f ڶ P)F΅][龑ZK^,53%jJTܚ *wk'yK1Tr\fera۞u}h ,EHޞmҥ7ʫ 8v;y1(kg\Fa{\_[Lrc=Nu:]J\4Ԁ>x>$m?v NלmJʵ “d>ɸoVOy<z=EΒGTO.J~$%6C4< +{RcK#2f9mb;uI $%NhQ ,?0"BYlu6@"dI+cS-i-]]ZN{[)Ȑ''taUui} ا*ˢf[ژ/619R犛CFGEx̏ +Q >dXLX{WrCM+)i=aѐoGCU)<B^7hꉵuCMkK$F9Sy$3\ ~8 ək%-8> JۅJ>΀d~ MΨk0OdfW2EFq=99ˤ%p^oO%YMzB^}掄<혌S<놳eZJRZ )3H!¼pƔ5ܚQ!6RI6z|zh7Etu%)o4\V +ȀH&9I$7"mL^y1Rg.qVҦnnN]obPYWXRf)iouH> +m`!jĥS'Ñ崴M\lP'`LњIm}򙯴,I >>?T([ŪJ׿D4m0rbAҞ/L2(UwAm5J߲%pjU(FQ`%oLr-y8Gm(& +. +~ÛedHnc*+TlY7(O2zҞ[ŧVJw]Wq9pUR@bj!NS%[ ERlpƢ;.S$8#^c!DTgIR- ry^׍U2iKڐ <«SDpRɵ]n-KùP>jdPn>C ta +a-&zeX[GJ`YZE ?%*< ~ԫe$YX[f[(BRG\(lmPOdq=>`3&smN<^;_~FyiqЛ,MGP6]v:P +!)s|{lx)ߔ2t׮GXuzG_l!/\&Eʭ@zI;r$UjVbfYkBI f{AejΝZ# nVW#ށٖu$:}~OxFv)$a1@]:NHIP bsRb G&RΒ+-NR<3Ҵ"zO'+&56Ϝ,.Ƴbfh"&IDAꚖ8/ hnM@[=.aDXy 1)Wuh ۊ݈cE~44IUVWE^W` |3G)> (_#] +=RB89<&GmC >9TE!n%{< EL-7%Ymw -I3SS^z| vͧIJ[`: ' 4XDx1TM[z8hP~c4In~rCe᳣-R4qc: v# ڠQ~rqa(!YG1ؾ奾WӼ_}+&\ Wn7RG)u$eXWO\Y6~U3mHBtލ%VẠIH9)[IO\{ )j7.𵪦+Rs$"so!Gia&O:nXcꂁBpT}2ynzgU@T٪З0@mZz{٩qC?fiΰ~QY[6e&4U_)D:D*2g5*>x6,d_6YԅpU.*A $?H1wA σOJKT0*iT㢂GcVȏ<(I@CCӜs*eqX}bu@G%;F;ζ0UJ+\u_|' nLu +m;y$ ^Ny| "/'3wƆ28Rr|\pj[պրUf&z*Aώ!utW䨑Sƈj4NLn.>(GUE rbF{.MtXn6>j|ɾ5JAЄ{"pe}}!)קmk$jl{7p} +8ue, /;!ԭ]ۋ{([aI(p$@6=֩WzһrǼDVy؛ՐFSq{hH*"ci 8AbNn19~R|} +]lP~LXBVhRpc,d@:ngE!˥IPH<7 t90VٌّΦ>kl*z1I@LwiE![]I=V0ѱ3}󅂿U dۗCNarfX3}0PfMIHycأWϚ~\y R,KB+`FvT"4U@8MЦòbT/EYYOl7IIuCʴia }l? Vi+kA+&JI90~1$TV%qOĚ*E X(Sf_ &R=D:wT2L4TF]"b< 3)dP n+IR"o=RԷSVJ{iH$ͱ"#2d $l܂tBBRM jYjLɐo%Ckq +]%٠!:-s=k>LoH3M϶ۗOTFcDM;Wg&ScwT[xq(Rx~-beUub X9D|& +VyEyؒgT(ǝ[1*>h/gL"H6"T}KQ$nI~w#5CSa+RZ 5Wq)RěOHdB']Sm#+!M>HA Z}c*ll \ Ĝ8f@p47q RG ȑf?(jiU[Cd􆿨Oenh:}NF̰jl"! +5-N'i=ǭ:Hm :vQ%XlmFfalo7rmk)7Q;GH;?.5 NYs'.o(#0S 3# -i!(B,;;c򊕩1{o2ㄩJ%JQ7$I$IԘo?HK.Ŭa!z:j&XN1FZMIpyhqzL%7 Ij\mBYI)#zc2y@駇%'L0jrk +p'KJ)2:@6iWhfSFi9N7ךּkܞ+Śk4ؒ B:'b/ ޛ%Ua{1yeK\r22K>R~bӘx YzU%[jy|%HO(b{_ RFv-uIG% +IwX:VK5.!]w. +\#0UQ2}:!6^vk*uP[#jnm.9hvEoHU^ek]G*aN D %@B +WXô +A-4Xڌ vWlZTP6k([ zeZn܉HU?>&ˊRTHP:} 1t}DJMj2+̅ZUk.ee) HS%e +"*KO6 BT&?%iꤳt JRVRA!^,uaa$YR<ڂ†?n$ZBssO5Qe-R%BlEҮ[fM[Y>#qYt,(vc}5(5SZU9mWUx qXΓ"&4 @t_ĔeJ ~V2Z)%YX I5%$x2H$-^Q,T'͖e&jH4r$rHS-͓UOy?r*a-$[^@q^UOF:yҿ5ZvYjd%!@2$o !?{>DSpscnI$;ݴs]O'uLOW"Tm5[ Q5 +r!`|Ui$(s"RnznbrB*-KM] +QmtfLEY;.;IQ~d|"QT\8 +opUXu*Jv'!-ЎNcccvO;YYuA>Py)JvdwrJ ʭ@BrTJmDE7 ؛a1&R2g)JR3 l!=rjV ݬ3ܙDE 2!ANQA(9LӚR Ng%mM_s6Đ6IIiK:EߓKU * :֥̺乕9\ n+y\QnMϐ„!L:Tи<dЪgERu([r'TBᭀ맯fc̩b^g_8Fۣ(Z~H lI.#iNޓG"_!;z"ʎBm䌢eR{k]= +tp%َS̸AaJ{M! uOX,i5gY)EJ=H"-"$߭M4K=tdU`Js]@%ԚZZQ::B1!\tJb1$I&Z8_7e +r=;O>#nju:B\edӋoS ܶ>Wsg@sgtZ|8b[ZULLJ,IR`LG/'d $Ԉc">J®#$'IR.="+|JabZ(ʴJ +luXYg +R@P6M8|IꠒH&_ R\CJ/mbӎex$XVN9VyFLK@) +{GcnhbIV^E\vXSZÑS0e{lB ݏiƄ=T3 \v5>̙Womm:W +xfeT՞o7XuC*=SC )nqp m#~&M,OĺK[l5N_%5Moxʎ!U [$wtB"gYJI5?4B(->]O +k-ӞUv]Q7Q+Ӷm)V#HPz +\&~Qm=1%MuIilezx>%= Ӟی)):zo5c2+q R +T;0D1wuT(ke[6$؋y 17.'DٴPXtEr+(u4Jyd>.:JC|#98תSjuXJӡ6׆5~B]JҕbJoE338 KIl0%ŭg*t7Ɍ?)*,:y Q DmRԑxīB0 ,8 by膎f|-#]LKYJ)6.e![&\$khM3[R\+e*O={+ɂ~~"L}(xhϔVjp]dAUn&]NagZ# Xp>X +Je;9K=P.uX)b3N i-9|^.(Í% +y%@ Dүvw6k S}*Q%Î8[V +mE?j:%fވܡ%ЦonfUq +^Vu]gs ' +, +a|eHV+S+t8RQ}5kAZ)*`FCar^yk*$&D) K+$k-ʺ||LyV .um(l/<͆ j9N~мN')̶a#!}Uޮ;$E"ÅDNYw$ 4OR(PL,+JAB(Sl+W}=3b2:H,i3[hjQM-su ̫Ɉ)̫GόN܁~mGV4r3BUE72#$ܐ0se^뷝1W*#\7aR8w\/W.as% +MG_GMCKkvL eQS@W)ﶴ/>&W +sqSgr$O8Z$EFSo$)u Jly}k(;Uk ,.'*Zyκ[0ŀA, ''t-,ցUFYV2}\~ī}Q"l m'ÌcW[RNA14}_Ҥ^ju-]]rںt:Bt9or128WKt*+NJ"e%\FOP5PZmWJUb~ސm x ?>B JQM{߬ޫy..g3jDHT`,\x" \) I"6P؏.1V$m7)$6f굆^6Nrb<@ms}b)#oc侔Ϫ \^KRCMyxBԭUTP弥 ,[KDY+,1.eH= bLňrljC~˗t:Ja.8|c8N貳B +B^3 -=E,r +>x IJӵ>վ*X 'a 6#)< +J&"WC.l6''':h.`(}DF-8{>Vrqr岇]oZ.GEXuH#ד ,92F>7[&}AeeR8'L &;Kh|_ޏ'><Ԥ&+a* plihWxPn }9g?Ds)O:?̏好C-,xK8/8QbwiUQi?馀~!¦Xmx|ɇ"̯6[66F{|kq<ȫ?t-NNSX{aҝ/8cx-2iŽmnu>irH8mSl}&}ɏ4W517Z^\^RR*F$z[fEQi+D>?kvV1鯏Y\oL*r9?z8K?q\~C{tt7Ҩld!q;t3\sȩ*#luT.6DEG6I`8FRHj6-ovl'Z8լ +=v~ɔ~/H@ٳ^+ac+KLOF5n|8APU6ߎ+!kGb{:Ulob5o+F4%]H>XyP'RtX}1./H:>U,c)Nzadne 6%09ĀT@8髕3#0E:zL1}Љ/Deg&vBj¢Cl wZ tڌ#فO07GSS* &P?ID%@Y6mcX0­.`Cҳ9~6$"s/bR|[_#Ϙyǥ1jR_mچkںIRz_ĭ=7b>YɘY‡ T{܇. +![@ sx|=e6_tffe'.?фaSz^Q/\mՐU;7nNi#hҏqJotc.ovlM㧿JX ^7HFc!g:70֧~cc3 =R}Q[ 2k`?ʼnI?~-S9LFߵb2*Ctf*T@JG'#QZw!۟i_IƐdc䶕YNj=mܯsj}!N8T-늒KIS ;'0B]0Cg[y~αN~ϮUYT ۨHԥ[`ͥ_٨w1T^C<HQBJ,/u[EtP8S mEǂiW9%.9e6Eԑ'Ĉ)tDj)ЂPw̟ ,*.^0!Nf[Om3VRz[^@X8{OSfP)K2r Bō./BiP$ Aw 9$QJРn7)7#r}jbJd ]P.F[uפY@OuZMғ wE^'8U*m y)!BN4b;#. )dW_:,6hxFDJmnо䩐625{#c+)7Xup۴-k^ 6N֏/(/Z~Z\PmIF9qC\^FXv"m AT:U.ug6]rp8hN 65,C&ڜdCF?cJ.!AH>Fm͹E'8:¢R(>:_>--1Gk6@q-J'%]jr]eG( $RlI$=p%d0bQ2[6$%̲iZwqISw-dymV@'܋'9GӜ,X!u3rԹWT6z S[$-ȕ +]UyHm +I" ӈʲx櫟+C|wEmu) NSNrIIjk SͯJ +malX9:Ա +>RPlw 1*?SߩP`MpBVlZJObjFRMդgiRxɱYo(8Eoi)R\H @*jY2umEe>)H5 ,K<#.pz}q۴/_c_Rp}qqBʴj(SVq6Bq"RR7 ŤHhwչuNٸsw3=BӠjtJndiiJ-9*J>i IM qe7%wy0io'2(UPjiXtAZ cI\Z?n}GSJPv# 'K<6p|#^ymE'HPG![] x&F:g8\HJY[ED[rTo/{2T$fR-Xx<3 41QK%ꙣ6EO~Jr'h=ֈ֙o bҫ\ ҤG8i\U,[uABŮG(R˙RRdTRA)R ^Ϩ+{!.4dK {lEW8JTB{ohIqxp--HV˱Fq6V`P8/̀pywXp#4'9OXUq$vMLjg. ‰IP+}2^F\sќq*m`{mZƥ,`57*Q%Mq}]>CUf@IMx#aam/7QKY$ʛ!"H[qn6x66cMSb[Q8uL+: {|! nPBР7 +sO_5_^Mf}7;:yapR Π%h]|)FCjSdݘ׈Q +.gKb/,hv`M.(KDjzPPJZ#5WZ S!:C4,kw[{_u&iE]M^!L7LX޿LD 9 +Q}q4:*4ېi%~Mʃ$ncxVK0uM o8U{uӺ+kPrK6q)--/Gթ]sH.=I§JZ`Sŭ)IZɲ<v,YɖֵŻ(HxOLPA'R;Ξ跥!0ʦ&&:מo&\PumrH:\gYQI9&j +DF$:AN8S{y*I@vĭ^JF.䲐 _qCj^f,..LSC2HiPP͕g(:V.B)^#ky>eEJHYpx+BTH*'KvA.ey ?@C>QJ9VL>. )"V#vxI\U}G`@cr)s+LVo+eg +I p k{QM5l-{Ɛܶ+JСt&R\HRH FV fZ f#pc6Ehm.xn:=l|{ %72ct>%<5Ce@Ï~qyA"V2NLo T[q/\W67lEJȇS0AyP*G#H~-u'MxZ~ZPcYiĭlʕ7H4]OYf]f1ѹe;)>'.&V7a8VH!eAú's+2o?c:)fqw%;%pJR@#xR,+x!6Pz}Z@q%'aԽ1Dj|Pf,)K$pz9Oeԃo8}9a 3%KY S(DY޸*Oq0sD؟9^ۊo{mRյxI픻vU[NUռɗ,%TjIy.D""*BQLyL˱5%qcKa}RJF$%JnFrOV;|7J}BM323-x4EՔ f:YE%G#; +p/Zd8"D:t!Ih'rPUsr?nclfY^Fmodh +^@9r)`e$sbEri7K!CR;!ǖlV4omQ32eUL L6< 4{6[kI@ KΥ@8ҁA}(CNF"!rQn_i4j3)-zl[q  H<04òu*cbNI*}A$\`arI:'Cnv~O1/Qpt*HR)*RU8J7'wwgѷFSxju$XUms0da<  '"y`eH֋RBhm}VF`#P~I[ȮcI[{Cm +HgiR w.<7NκrWۉWrri&[InTSmŶr0ʞ8KW% BqٺVxC%i!$wiui8X݂]IT,A" vsfTFU}ROfO>عSE &I b[m䗘=YH)[$O~ B9|ۛ'0j.ŒٗAro2Z5Y%7ݭE9.tUBDV0xf,^`xr-2X)D[ێyIi'( +Wd{sFEIKa(3SS9lYJΈmDI %:6܂|_ 3*V9xD[{U"=)WzEw̭ܔ,>s a4& G—6:R#kl>xQJ`iT=e5 i/uCbm;#}xChZvA^,<яk \A$^^\6kPokeJb%/:1j{W&81lݮBbc2\F |PGu$fA3-Yh;ԛw.Y,0OTMF!l;VŖVMu07ɦzĎ˃7I8D2Gj0+ҟ$S"2e#Z +6:ko0%A7?#W:T Ca) MA4c7eJC5cԔ-֔.\EA؝dCa҅m!EĴѕ}E$qmm{B*ESmq +6)*I:e]u; Ɩ:f`oOCs=J9T +.P".@SM2CLVL."ū~X^BlJJU}-A6j߾Zm-MԞˌ(YE@6j~rӘَ-*{v(Z3vBmƔ#9%Hkm=juI](TY˂e( ]t*mM\*hҐ_VV˦d{yMӡW:#ܔӬ%-}IE$Ȩ)E"ا]!bc)GР\kMHx$ +M!EB:[XIN9)2fN`; mF#6 *aB@g=X[xfGe)d\XyѶcf^ә_J F.Nm+rR-#.$[9t7*rO+8vaDZ=S]; 9:%:'ۭ|lV,aĭ,3$'"aL[15OʘNU:\龅a l /eSJ3@ _'%4U~@O.ͧe"SS5Dqgm84Sy:[77r$kc6pTt%:y\'V02!<>w%ҋs+Vġḛ6aGrxU6\ʚdNkt[~nmNBy6C؝.'%\)gB64MQt@exkm;VY`|>28DLHew3}gČv8{f:K&e2p'0$:B?㢇xY 2$9P,ͦ5(j>c]9Tr}E㨑R¹MOl1ՠ!Dj•ߌui.X~0֜ar-Ȳ2,bHq$״._C3]M 39;qbU3%.@4E3:ш.WkmٞeT }ʸV~01_HN!RBp \oGj cUj&]mZ9 Rw0H'DfzVT% ($ۃoL!MNYJā }F*V +Dwʉ7p? y>yWHܨr,=[Wcg +{TExkLGw6HJj n +7j>8Y&ĩ$w:eZ#dgA*m] $~x.4pA6>!}2CHU:q8~[(ʒa-},Ԟ`͏Uu +.JIsnI8e +2ai.r"'~ tJɋepН֣nuJꭙhv% +[4%E$]n|l^2nJn^q޵TtOFs-NL4ۏ;袟)-SLn8V[)dK mz tN덿4ْGx Hsb׬|[1!\01=T*6z+${:35a-%qb`Na zoƃs18SGF$I~D83eZ,`(\ôh"X ltxk6EThwY%ΏBA(Z ʏ>X`Ǟ + HgIK-%^U1Unj1UR-P߬g/ iGV?f&VX'S?D O7}{T}H1]㏣M+ ίړ]'F(@LTF ձʧBRR(#A<LhgumpLTYPG|34 <$sTXknB(cʜJ)Ip_ "gSt.Z[h#b (RXk/\vP*HAmt- mcWbK 0[;a +Y"c?0uwA[I-py N{c?{J9Ml@ߚ;5s-LV|,HUwӆЮbbVwzLL*`c".3 {Zz;E )&퐡r!̱҉-.6HRH: z#֫R鎨%PA Q]y[ /㱆!l",c +r#"HTvΚ$-<ɐ%?LyyÿgpUV]V zח߉{/h\E2# .-h"}k@E0GVtt97UF ˇ1#/+jnUOkm.(L{tٕxBkdq'#yhW>'NtM>uB]drM"U/Yy:^Bt&xk2|\:54~u؂$;eK>&?AD:ߘ 7hex.,d&Pb+ԝ@񓃸Y OGT]YNӄҌؐQ6"m +1W b%eiDD%^q$vQ:ʵ;mX*r6FAdHX%<9'cP*o~D(A1n!N$6ծRRI:H>1eǿiW.fjϢL\+;KQ-ij{qlTLqњ)Qm1Vxiu:3:J#QqL¬! M7@w$^«/LΔBi(FvA![Rry'ޅǭ+URjWŤ@6m/Z)j3[Skë'lUbW2z%R  +TJ}Ѝ{Vh 6j5YHaR]@\z6K{B{1,O@I[g6@y׻c 9lVT@ zm Opʥ7m[/(ըJW77A=R)NwEFPy m|]Z _{q5o82}RN1  fAha"}֋s-]/2${s$k'ס +'[Gp':&qG-Rv\Ќ5MSJ~^itक[nzhcҏKnynN1j5i6mƮf껂bRXbfܕ6$)K~$L,;M,>q5FSup3kC4e>)eJ;.ly + q u&ǖpH46I!l7.,$CfM*Px QӤfJfu8ҟ},:JJUߞGn|oU.* )(H`|-kTiU|*i(! L+(;Cs:c:ґ|H4<^d1sBь(F۽ok^Lꦬo{8ty)RXf-Tp4S.( +X_ 9ă9-Zf8RؑT{~ʒ~’~,VPx0WLPW)4QJyx;c_Yz D!P%)D#rR9h#[Li77͛a0)FB +u1}4)Knlr`L.]z +G$ţ!O]Zx!i[*iU)G [ KJKյQ0%ULh(+k A;dõyKRԯ=JQQy$xzC1p"0Q (qo O0YP lԑ I!V! ̽ +L[Jx?yM1/NJ**͙Bܻwx'X#mXF* ~bXYyP#=as>uX)@[[e-A؞AnL}MEGʒ/anj0JR{@D~+Jl@'`ctuv"d( +kf>+znmE2&&IZzjt!ST`}+)êHs,)X^Yyz^Z Е ۻHGTH͡"?m16V{6nnO8YpJt%; ԶfE#CS%Zх1ȱ2\ZX!a$|I8xשŲr[Ph6܎7 eD ;|Uo|{nՅ[w99J5"lJ)Ӗ%Gi+aJX\}؁݉ֈ.^<(`TVIhMY +7FCJuR4V~3%"oV8Mcrl9\.QTc1Ef[!@ovg#$f^H*lxǼ&eިqӺ?yMƐʠUS!ŊӉdqT^\4Α'JANo 0G'N7\Pu"nA&*7vԻCmT &ms&HYikeǸBZAmtWԴ鮑!b;ȕ1? +d)˝r~7mɾ#F]V/IQa|Wie4 cj t=)RM&vۨ+&}HuCEF*ms\I"s6gG+H)7kLs̭[I2G\)_$kZGH8%#P&@=^ jF0*HtjF;j̗lTVV+dI bBs3:d^'Ӥټ,# ee2Q[KB]kru[Yw ݚS3 8ğ48MIg3^{)cޡ` I:cћnLpu3ؔ.Tn3u_]4Ɖ+/W=4]l.IHDFfl )6R8BlfY P 鷾6)xLA7*yPHmiGНB:E,FhѤ)ha#~m>V8fA˧2ċxk;J +'Uk&̱5r@imŻΚD2&CNّ +BW~nv*߉"$-YYoC2@[ZZ J̆Q#DBO^s2 rW>wW7~Jځ̎Pʘ.'"vt_o#t-Z]G@jCb=7h9,C RCV;Op|0+Tø1*e~ ΐp!a%I{)6ՖȽnE74TU) -'|=JOgIԀ,75I1"I&ۍQ=5?&4 bRH8n!rV픸#w\nhYVǒ\ibronބunUkǵ&55*T6 -;GgqR^dO,U~DPY¬S@bF8IG4RY!]-jAoܹ$Q6Z^eT"Y)}ɷ HB\! +$nn!֪ۡpm2R _R:}'5)a!b܀U8bδIk!!:@k}^GZnݷK*i!DӕC, ?A,y%Vd +qgv|9ʐl<w<|zLToZo_dPnb18M$ 7mթ[=6BM0S1/2@[WJRA D)Ս3hzAFRejBT@Z;T.<$*5 +ABr- ]51-eJ:W#]d=6FOJe]i `{IDbK +[*kޟT%,\wDW?S[!Ly댦}Y +cV)h+U56܃xzȋc>J7;6Kn9BJ61CW=qX*t 6 mVdժuj݉!. qP[_y67|$hPʢ-T~LȗP!V [xܟba2jB[J$)Ok~Z:3fWYo8ٵX,k)EQTy$6"~u(3{1(S#6Rl Wh khU0ix|(A6Ln$[h'P2" z?!I\& s}أǽ4FRu:îfPOuSdgyj\DX6V_plA).((M(ṅ&/?iJ캁u$ h5ߔKEԝ,ܺ'or?(NakvLtUL47qE@sSmKLP.l* Us H)kꓱXEU&h5^YOeWdAs:Sצ=k&M@m,ԠS8ZuYE)&aK 協@D&y̡ڑD=SrF* +K_db O q]yۅ9©!/SGSe1l;Ϟ'_&yynG/G*`BBE}MU0 %Yp8GR>?u*, 8vd|>n=%(8adq6/L|X踝M]D;|p#r/D08h87B=).eCy؋ϸ[XϤ{sn N[$aGQ $cɺ:?y ᾌW4dycIrڣE?۫RVQVEfEWY<[a'iΕ{Ƀ1_|{#vB-CXqcRsu `pE,!!_?,w#wq>GXi(GنGI$ͬԏA"j;=WZv-.GSރǎ78BdyqVO.\̻*A*:WHmc^@yUN8Ӯ.jԻe9T@F+^3/[YM2*K1%GJP8E+8]6u2 +uî1<6sG؆gOT΍ 8*="^]1 d*RFs/h.JA)wxh6_r1Rܥ_bwKC]e +#1juX`8%(4C$B)pxћKܟKGkhbT&m<_rhtێ);#N5Qi*0J?͋|.Eem}C$ăH1cMR+-'le-Wf>DF@]n=USp R}F%:{Ɠ#()7/eDeꮌZ君ST)Raׅ5"Cd "!i0쫨7XY?$Ҡ}B%ǯf__qZSPRQ6d;eY_|x >!|X>l*#ҢڕR'l4*ZJJw$$\_Q48=R'-q lX&Z}E"pdYh q*)2 PGxiRVq:Q7CH#[ x5 +O˫IJ[MJSnT(PNm`3i9\x4ݿ[8\#yJ2/9Z*QJXmz㒨Oe(߲B²[ub$l72k;O+&LtʾY-Z{48?,N!|+Ԃ3T#"$umW%.1mOwص |߅WvՉz4cB`2]j i>.Ym;Cq⛦d7"!scGwtU)眽PouMy `='$L)iGo =UW.pÕTZI@j?ƧƱR1γα?UqtNu.CPII?@PR~U<%&qt@s Ota"*@h"ڀԌڔ2LSt'FYqKJ4Hij]I1_*nHLrh.Ky)P?tj1I;L¡$$[ͳ#" x4&oQɇJA:(mO[Цi&fmD4- +ybЏ \8ҲL(6UMus+P/p(/;*A\j8$AUK4|e2$×"eN +|%RrRSnEqZ!!oSԜ<'&3\bk2Kv ˢJo{ E3UO7&T]7Inq[ԣ}[qlcKi0)m <wDO=MyTnOJFQTܬ̻K zBpkqmziX&Vq oZސ)hfmt1'9}HDtgحslFr5* +}6im~#UA{Œ?.]&m5;E枆>i,M §55TdFܾT9;+"'iM _kC԰ԝ;CJN.iVPvlv'I9sl'<`tsCbδt^܏<[F{8# N<$,Tj@da).5٦TW\<̻zdh*C ř8j%tz;W[:0){4V|vV*Sg ([1zr̵,*2l7yGc!HfnE8٤XaʉO?Dk5+0TVBRm@$ )'Cț^2s.t<4˔>J[&p/b9e _XGہ9BGpSAO8I]MGc{}Ѭ?C(V䒔K+ ujT7J1qXԌ'E&u\)[̱˓ٙ=b +x 'USh*KKlH㏞ 'Rq;sĵ +u7sF#NsD@|$Ír$$Z+071Eou`M[$'0fS?0lmT6xXC][%:Ah[^F/$4ҟK@UGs|"ͧ#JUq/T:h&\&q5aYvMc3.`6BHhHaM:J;{[i0^b{.LTXU[&Xa@+@Amn>LQ"MeٟyբMAh̆+6+H*94}ϾZJ)ufpb0y% W +Jҡ+{8w<0ӝūo6u  ]ڐ49n6Ebh' Ćs;zSUIey1,`;1V;vX/E,V%^u mKB)Qb)QS(W"QqѮ۫@ W1;zHӜSz=ZzۗzT}`[Mn .1D&s$ +)m*!v=ja3<,u Z!I:v R!]YJ)!a(̰Nr4 <i՝ЙtnBskIڥr +[nĨn1b)&BxDI<y=ئ8Q~5tmCFj50ZeIl.Sw H͇gWq2,A̵dm}R$ZB}x$Fe-=*dڠ؊}j g%R %W^P]]!GTbɑE a<-a P?aDkwڣqJ˔ECZ^WHVI>S]7 ן$5<ı. z-jCh<kGT6RN^;fѧ:"B-khd6VRyMN\;%)>0nS)wxCqң%4Lff EFdO Ͷ`Uu$LqwM Z!A1o**:V=i\*͕!!FQh )*p ^6u!'X$æf<5CJ<6i {~iR9, L1SSvS@C1I: (o)76OW v|:պ󍨁򓘐d e6_Ye|)i3]rG-*XN]/ + IKP=S7<lk]/LHTËRV6)Jt"^"&Lֈ!&QrS.#{?;Tǘ*jU|%Y.Jn;ja$)r l;-j!`SMJSp,T>x`UeMLAۺm}KnLVӑ*t'ރm%(Ch"ۖ % +u;LrO6IGZ(2juS θ9Rl=Ią131"RM*[peۙ5b/ +Rs+q/6JT EAL&F˴ h m  Ӌ_ GQifQK*MxZU^wͶ;PqO<-kQRԢTTNu&(R$aŌYEPH6%Z[˦6PA;i4,ID>Zma +t޳b94gUml~[2Q|J<#h؉j +1x;Te!n+! >>;\S5F@@OT{NR@-d_1~e.9w/Fe$Ti;PAl+ʸ hi/{$;2+t(As荞sa4g$rR6B +.$-jUHÎ^e\Y=IGP%OlVB3RVUğ1{ZPXJS/PPɾw )<[ړJ> q2rkb{DbicL'Ao7'Q->$ +$:,8m[*FUmT sǐ2WiT*XAj$-+24%nw~BJ@pIDԲ-֜BIq%6mvrnY'®R`90J[O{b˨Kd6#'3=YX)KY#[5Sq뗳m5 srL9.6vIIE]mnj B$b? H,B' )"jL&dRc][3 6+o +HR玷NU0pK;$RGm,8ԅ)$gFdzע+rMU4G1%*W[B~%OH5fӜ|R3{C5ֳd*ԟ5]=?#.TxLPubJA H`khsO乑 e@WxO:љ>PHJܤp|.;=ӞZb[[CPjA +t 䰡1Bf.[H-hiU0ʊlaÜpbi[FP8lŇ.,{⽺g>^d]BПD[$.+2@Cyv64#"ᴶ<若|("Z¥ мd4 +U )P +a^Z 8ľV^k&>#Bu)=2xq8Oa&\)gM ei[ Cr +PL#MWD$WlFf^%(0VɗOa6 J{]*zPSm͒nVt/#]jVaPBlt%> +ډJwMAo959|9!aKqJ]2BO`0(i9@ɶ z0,F߈?,:Oy la 9SJ[.?V#OSO@-*V~$\%UN)'b8P(ag bEṎ%.6YZB!@O鈁CZkk}mJ"HlJ`8Pmn @t%En-)mc#K:wU-T-&,&uO4]@Q=X +AnBlOk*2wrtHP9?SrUrʴ)7![E^]jtǩNoM3v}toSt$‚@"(z)Y v$aYl/a{wzL:)R?U]A0غZPޢ=(dz3|]uJR%--PMsfߦ.F@+^a7)Ckx 6-ISʒ(LHBFeȬ~$III$+뇴ác3K˜A %kor +ߙ}Žz?Ptz3\;&:m-~J~}' hlS~}9ABxE`hQW.Tp/$zca,f}?n"gF[Pq-–w-;>.*JkonBvIvH*>h&611:*K! %Ť)@/=}-{L:t?Vu%ӣA"ɓ!Տn!kOTm蔍_YFroЁ~֞CB8xtj@SIq`m2l4uN]C67-jnڂ#i-pRK%QGSbN9=r49Jt)VTxf9$߯KveӟcHNcBܧf&S2,A`^i93/4JX%2ObMj~J'pi쀟8ߤV!Q8\I-dV]KK!Gh\d&# +fdtM([ J.l'$^q̡•m+2%P"Vm t:WՎet\OVbj -i}II$lQTs.首+?*Nm7*7F[-ԔUtnh? _IbffuQ6bQ%Nk }Rճ:"ZX!RŒ#s *q.c+BEL+S;)2C]5;gӈII;~n‚4!oG[і>"UϨ8ͮø+`0P[*BX<6QWNeMv+Gūm 5"kj0Vhr {YUߏӜBuJu`;E[^㦼i} +HQͰO16"Zc'Ҝ$JV|n};|TgVAENÉ;%ε^ "@.;_zTEtI([#qͯaqdD4I)@O!RK@$QV3luҟ ȾE>hf΂fJ=o 0s?3zBOr Gp>ӤOECGJgXzeG?6옑JFa%^ܵ*#&hy@HBɲMLO%kq |7RX9[BS( + 6O$_^O1\ +"R.~bɊ[5&OI &@ķN_ZUDo |ONqVgQ 䪢nHCΕ8S }q5yq*>w;e.X/D}Vjjg$dڤ lB^qn)QBAm*#]RA)Ds0:^>~q%kM2d!(" +{[X}]Ri}g,"<) dz !q % &ԁiiuZsO:Е6LzMcyl-9.҂Ф77M;I +!98m 6r,ѥiy* 8ܖڸrem\!E*Y_k³(l,Zq*!'J\ȺhqMNskXp#@ᦿgSRc;i;_SfDt udğ4q:\s}wКބg:L̬9U=7j^ow~E*,8Y3 b}A_D!bߥ\s ӼJ:r%.&ڀ#Ng-}궛 W-wҜq#"D;$lTnWj*p2y0R}6t)_޶IpJPiS6Q5p$xj9ނ%73e {$jI[uɻ߾8&|2 x( zjl.hBUn8Z7mr}ЄTX\* ʢϵ)Dl#\1*NhY:| +yM`㞢?uء JzRZ|Ċ&U"rѴ4E ~v} bMzJT +Z,FoD\S}!ҕԻچX~֓vs<҃!c2U?{Ba%%!8HV=SY5!3qHŨ̙WFOZ%eii*ZX¤ ƉVИ.g;}ij\w/8w;7ǔ\re%*6$؅f?YF#xݹLrXAJ jZrm{-rtgC*-L^$: rB<.N:뇭[:pbAI+Sus?pFETЇD$xLFB|ϩw~&eܪ+<"ow q'C2%IXBv<]K}b:F&d(mxc_R. L&:=ߔ*޻}eQ29+P mJ8$j5LĒ;_hᴠS@l}ARP&ObPŇa41wO&J|}!zes0}ğU̽ҢM!ð%7mG@N #|#';^ƚRDLeO@a ژ,1.t>?t0$|c鑢 h$(LPG^gYY^iQ~K] Zh_ϓkD7{h|/8gNe1IfW}{zfV&Qo]t +nw٨ƿj*h+q;c)bLp~=7#{FUF^upFX2Lj[\u8@arzU> jjRܸ^ם} $f\IԤ@$/oEGiBZ߮8eCh!X lWo,q:%nÏ,J,ێd=$ġ<ԡ WNuTWUfQol{d5>D*P RBTÍq +9?Hv\vM۟-%H^rT7J8egWۄm I}q5 *(/p +xȤdI i:EzIM/˕!) <oL 0 2y;{p9D-k 9kd%*'}j\{DxP6Đ$pDC+p +uۘSyQ >VbMI2 NΗ տ.Gø|pJ +Y-8N#HII~t*ZBe"u(-r·BsX EBNfjKun:%qB]) +(?2|BThE.A:JILdFeJ-%.4)6BI5BK12)~YXS .䀮ǏLA +R3l a#=p$:%&\dsxL ._maӜ"LKG$">XdЦ2"Lulw4?>j\iGHvZSnCR^# ހU{SZC+jU`%'M{GiԓdPRR[o{x- ]]HoZ~:%5I;CH:DŽqXWiZk06- DةJ5>byÊE#@:'/ُc)Rb*)svZEܛRv-j$DsSh0͘h&#]>o 膛 ZrUA2Ss+pry m@#y@irD$6T"N]I;Bb^ƻ2RTz|Ii!>=Ӻ_ I_rPU0gfm-m.5 +ZQc% τC?lQ^N+(bDhιOK6TPmpxl'tBbL ۭM8\hl->t?(l1ZA3iX]ۗ +KLBDm=xp$VL 9@<":znnV1S&FCgBlE=VkC ܞ}\qkh6zn*"Ss$zu+y"Q4()i h ?L^^j~{[N8nr/8 y\Yf7Cw J6{"3e̻3]Uflx"OM1XK<ѓa),AH"|8%U.9-Xl-Д Vܳ-JRԭ2qNPri1Imϓ bΌ) ͬ6I= 6CoYK4vzd)R0- Q&vt>ƎIr;I&n m܁^>J`v#ݬK,)ZH:"(+e'faѥc$ïcA*>-_v䏑WFC3m;zASD{#vUE$Mƾ7ҺGF"̤ Qn (61)3RLs4$$G#;C9r[97 i4d,iS +--,6 @ ?X_ݰ&&]BADcަo +*t۴E1ʽ5ԴOOSvQT}ڧF۶FѻXœ4/<{7dS ґ0JEyHW5BGgh<$|hQ܋$#& +/ED[qCk_|$L*\t#T~]mKGK#^F ״[B%ORf jp%Ҝ85oRA۸_&h,)(tplRoZq1xp]ĪP[ɗyYV%7UW<\ J7oz-QN:땫4D7e yIIy@EXolsT) +uiB+q@_L7WX.V HIpCjdc!̧&IU: ÷X}6CF.O99̈́@O=hY]-Uss 7 .Kb63/O8VߪI᪬}$T%ԽSwou$&nǠ_ъc5R r{n'X ƪPh-XLvAMk0-څBFeeڲ-mʹ٣kȹN5I>E_U_t*5H=\=Wzit'% I ^sKK1ͦA]ZmN-u_o(+I1Rb3hX}B3aIf^uu)aaD6ʆCzKrs^bU[`Kp-J~(Q#ʕ~jndvIiZeL5.lnd)^a V쭀ZPq{Zˆ\+^_tjO¢m{ Ц5Z@ikXD*PIιj% OiQ֒C̼m,FkAeMNE+8)/E>ٔa)uy*R{u955nHsƦR +MJ̩6H\I+Y +V"ta4&C5տNcAӾEeP:`LhʩV<(G| +!(qu*8ZXuk~04 OM`45}=g>.5=ܳQ4pÉX 䢱bm3G|R=.Ӎ\Vr5^%jEUs?`$鷢pҜaS L= 2]]-E !:kuR[9#TjOb8"?,H= -eYNZYM9Gn}r'SSNPPUC~f( #(5 oc)W}(kcc1J܇ + +/#M2\"6"0삲Gj#옐 xڅf*INbIs|^9 &!G44@ ݴ?~e+]F{8ʢ=& 3J˷6.mlGbhkM)I +P"'(1nA#mP5#0>TG' +-z[L/}0̾m+x> +!³XW< ?7x]""C{!}OOK6TDqLo +5t' +s$}pKfWQG0LrVuB{9#l^>='Ts,pWUF-М=5vEˑihy`@vQpȟ9ijpa4- :#KN: +E H@?YѺ馱Sa )[E4 x{9]>Z Ў~=P"[B7\u_M +݌TP=7fs:^s(获Iv;*)l@6qq0ŲfLJUC9D{S;HXK}Gx٩yj- #*mӮb},]ȯ";hCQeB;9QFqAPRi?8i_A] JeJUܸmɉʽHH턤L/4RN-?D)bbGqVN~ro4WA."15nŧ!Mof[e:* g.F@>C KQ-\Cd!ITn2l8BsVզIEK8QEOIGTٴ?҉ /G)zR-߁fJa Tlr< 1=_;Ui7~~|>\Ox9Or$tUajЭ]#Ѝo[ 玲LY 9O- : W̄b8>6[a` ړ:QF9*"+qGǞO̯LCħvrE?1aӌ.}៾$'f}?mzA%)VM/i`mcUV$e߸GT}SĿx5&7{+~/GWdt6 M&ˍILU-(\ h҈}LMӖijq0 JwֽFC^*Қ IKf֣SbV[ "τ|w0M!^L3%O2CNf*r\>Iiۄ +nC + -xcDoڷ %:by,zi#_U0t#Dx0;/I_ǩ2^ӧ,lޤM,Q6Gq_E6O΋Q<$ +-mdlu7bG9$8Hno9qnH?!y|%SSw<zD8⒗*M3vOZ>a[W>[# D^a61>G5GFxTYR˳pF?N{Qv7cs;a{?!Eftr{e(7΅&y&5ct];Ǿ _ʽGQ2HtÑVu, V=5P[c"(~hֺHؔWRmdPۅi'O(g%pxɠw=SB:bi=40%̳Jl+ׂAb +JqKYZs>B-\V*" +H0û]":r֬}b.cʵe4GӤwm\$/%_H+IwK%Xvf;b)|}Znͷb7v=u"-vf([Zڭ1F%1T)Ϝ1|ڪ:_E'"2"_QGZ}JPp:pAǬK]|Ad~! /o2',IA̡mk,NO̢Tg%%NMKL9.R2[Ij@BNtQ#[1puz$GEi; )߂V+Ķ&tʏ;"Pln~G^Ю7:o5E#'Noq*zMԠ+U<>x;ͼG ~H;21rC 4@bqVI/"׿0o{CzzMOT*0˕IZPC$7kR b0Ř^DlMnq;٬abk@m{ Q󸕹&*Օ+!˜f7X\nfbTh Dرiv/- +HZ{x=,RO8pI$[cτr)YOwYFv~]ƤXz]ோpS{O}NQڟrla<1"oK]-$#nyEF:\itVuܝ9x\Bmo{ pIp;&]K/$k($d?G0 u5ϳRZe  d~ yNS~UD}iZ{Jij̅m &j*:(hANK;3GmE4-)q˩V:0{DlּD4 +6_QA&&ʃ V 66zx׫ȐdT;n >X C5*#sިV~졵A2۰C,wTȶĕXجMOYR1 +8m&ək2T:On VR%6R*pSrQ"0Mǡ\Pu(BefPR blXRv'ˑ7poB[IE}[W&‡]hϤ.ۣۉ,\&r MM\%CҺAOEO礳unduoHVQ|x|h1*ULlј%i;ҧیPQ +7ĽWu/շK)$h!6E(|HӬvkkq~TG܉NUHΣ.{h?;ſ2Rt'qn{@*y:x.m=wβ%e._0UVЗh,)I=VO_Xb %I Z/PZHʒX-u{b@Fӫnj=Iju6$ +JHfϺlys;Wq8j` + l$:EјvoRʣ}t6R]ܓT. dYuУ>Dp%OƬ[m>@hJ,FRu̠EDb@R*ܑǮ<ZTT q2=z5Yk3F-]Zz!,|{II+6}? 8g39E'Ht1Hya.&K8GbQ~2̸Kʙw[ZҒl,7kp,߭Jo.dkW亝.%Q-K6 6W0SN.dpQ$}}' =o2wك(23:ӥ% )]'+D5#P;HʥnR+ }LR{J#R~Q줿MaXF\̥F&bYwrP鶿]=b;>_Ij;x[j,mo\W*Ev9*晛*ӆ&JW"q*֌cýK֜d)O2)q NmҴ{l1_E"i-z6%>"{#t`tOVxZ +lIGKJON0iPۅ]TmN>0US%e$( [Ca J=y&^kOfbɽ}0w`iJJBBc"u{0IH΋zR>"83! gۅ''tvp KAi$CS) +@(P̕hAxh{29/-t3fUQ}-T ,}!HV~eAKnuV[Uψ4rNꑧ%jJrnL#'UA%J&ƔAmGbt@buQҋ&ֲz6WyTcx +RJAx|Huadhmm8BD8Rl"` _OK)KR,₲/i fReV~=[Zq.T(TO-4&]e Nf>r2w_Vi+"Ý[A)VMw(OIӬd4׹ }?銋C*ηӯٷRJ`m ?,J,sڏ#(*fA,:G#Eihj :N&,'ASlk4R.؜Te6Sr!&*n''[t) N0V2SPb +jIw݄W/~$m\6quTPE=p*6`xG5[WH }ͨh%*x.H2(wwaGc="ч\͵ 1rgYKo9k.q>~d|JjOT,TO27jE}l~@cem f]f*8JIp|ě%J??."膵J[=Ä WOpnODYbTԢҏT; !2RJBڗRMXQRT*+QU*Z +W +IyaBKc[@e8T,rw*YL+:A:ܝnUd9oFH $%ȈRRCC&ܞ1jOiiBxwC(||썯hԥ՞ ڛjBnwI:fVCa:]oX*OL +y%-ϲ&R,)2V:7^MsWq+R,NܦV (J:[IJA:uQ{֖昙4HWEЖ{}q0zv_-`EHL&II9H=>ڮŭCrI[5:9J.}}Hu9jsI}L| +;P 5.iL, +IzFhv"$ u(^WZX.6Ít.z4`8 [ڭ:r/1jTu>yx8yTȏ;b're,( \hu\MG& =JDGKSB4Nk2M6-87^h|f% Dp+Z]\$?qm4M2Ic3 qY@ CXg   \5QTE̋)2פ+'EJaA2]G!a]H2DeR$S2 B7 6==#@8F9jp# GyZxCO &/Œ ;-x)'rA@$}U~b"Z$6{aa:eO}(:ƅ8*R},.T + IܩĄ 3\MǛ-r q@|4;bQvna4nR;Rmo T:hYBjޏ%=S>\8"OJ'I>!YWV +s[q`V,i$RRBC\rdӦjzRBG +x[6+nHMÊhduSߦZBT>|lKYrCrNr!JD, ovӅiyG\pMI&1BV9m m(GV[2v>#&~PJō([O jW-j?-UTi ps\{;rZR]4ǪZ b ֑!URflΰ&pjB4S'sBTkEV*qj[ 6ЁSxj5 JvmbIK ݦeTJVBխ;Fq ?*1r^Tn2j>d+5)rcIufDQ)v+q;JT iזV"ЕUӆ9u&Qv@:]yjɒ\QDKi pyʑq:`6;DWeše'0Q̧IB-n GlBXt]H`UoO)z׿kWd\.~- \)Gk\9]_juTџIe~H6 +mBG]1lM]aR|C=GOɅ:.uIѤba)Q|d,]((E!D+1< !E]:$ɞK\#ŠT *$}y_~Q0qNemLoשˆu[q;@xDRT cc^IBiRTNB-[jд9 ?$"Ű&K{CWwr ):³#H4^0.lT{kG`1 J=bPx'4S +6j&&JB ]Xq3A+:|"H 'O[«2־Lꊮnra.53",$(*cB)q"K: g:*:T<"\MI{g" B)AK2{N$tK9wTg1T%_ a)śp8JIƈ.^N\R$ +=#ӚkiEV50! #% \-:#:Q92˪Anm(Z +y-٪ġAml$x>%/ߏJ@^#\܇G4zspΣ6_+<_K!sDd(ݐ4:- +,%R Af+ߐ B +J_hq>TR2)@9µrZ3lnM1ˀ|-Bu]rHChHՕ! $b,h\@Tթ.Ĕ)=6H,$&"gREC;H,/H>[ +L +mhX'B2;tQ|H! +}* PM1SF%:qPRAāO.[(\F[J\JT GtQZ}o6i0!'w[q?GTʒ }j\0ųK\X;4u1e:ܶ xRRޛ-?"J7Rֳu8KM*VRqn((#`r-ROe72OqBXy TSؕG3yUXGK0f>WM^4]"*6JW%]D ڀuq b +𑤸 + Qo%dd(:xjԭ| ZÿT){Cs= q6R|2m@I㷦*ZIe!o%}<:?TeN:XM&u6c id 7 q[}$XkT0Sʾ^ҏg\~ffEY+G|Hã1|3>Ai%@{X6 +6Rxî$iu܄20m.MΗ؍K[dvZ-U.UP8 @PN+OHS@s= Ӝ|-Wa#\P˨'}`tmVUޢUԼL!e{=[+"G#MR9O_7 ',Ԩ*d;#h=;J .̫RG~x.CJ.Ac(=#OyTU,9 L_e/yOhk3<ɿyz(XCbnq*'IV}svH:uu,h^qrBA !'`&\HRI>cTmȹ4eijiYnQG"JB* o!wQxzhY~?.Kb|9ގJA)6>bg682[}!2jr-M |vH;iFM.]5ZԴӭZKWG>JUJR2[%oHRHoA=aMMȎo!jHuu:a'btb:[HQz}5kFiM)2Xe`mknciLPPN#*dM{/YJ2s5_[fumx<}W)ZuSYU㊃R۪vϳH}S])Pޘ]KNFքpzcZxWj<9O ?F'. [shq@𸇊 U1(<7qL>]9 TWkmL3ďYE|ru>G*e?J_Êg?ˉkNyBbTG6:xi K&0t΋OЮBĢ/ %@p$d Taw^Āi{~7bU;zM?kIsIs2,~x+ WXTtx(?^޿4Pߏ{"uu}uP~И)Q芛je4oroÀ1зM_v>؋ILJ'?7J].%h +h{}ɿob#r]1#G<*e [?{j1% +Op5 1(@3+}~Dnf*-)C9}nqU +$"Cœt54\U#wޘv m=0Jϔi qj SRI ZȋUZ.xVWm̍b,&䓸ɹl.4vFa(K̭~8EN@);f!/MlqɹKXp]9j"^R_`cpaQ֣Ԣ4?҉8{=֓g{!Ujž{0ʍmu+6XW\8GI5rU0^>oUͰ&QC"fnUmsvZnCy {X̞ͫV >VWjNJYOGz}A9? xُISk\I_%n7ި_Ҋh]Z=}[ҖSv~ޗ#"}L|g6M(_U!6wU7E61,63-p?>S3$\aɃYtㆦr| =%$U%m^>zsgfN=&F +XY&?MG_'B/H[PIwmIti~Pp٣=ǀՖxo'w!qlB +o3uHDTմAGb)iK/*0з,,1as6"{UzU>\ßPܤIGXJ?$qc!fF3ib'edeR*% +.-m$͒%)לtܸIy$$) +k4S.BPG\˅ܒoxkZ#|Lu@M6HsWv>%e/cyD9yl/U)x{7ϩɐJTtY7^Մjc46)6$OuEt~殏sHS~"J\V.G#bdu:j 2mcP@RyltĩOSK("s"VBI"*ƅ'N:1Ryxxh]. +Cl]FhהX@LhD$9ssó'Y&bnio&2OƇA*qn Ŭ}9Vpy?x +]T+;ENNePP BФ摡K!dN4lJ)u|38IU}8M,!.5%No`$wTW z P`&ad\@VodNrB? UF07T?ZH?ڇWRԬV҆=oT#.pu\:AȾɢZC,]6jD[ODR„,D+Q7 +mNBl .:w +ƫQ̵x=NIjDBKr$!l~$nEZh77o3%ImVYlBRRo{* DR޹"K/C;QEPy8>fEHJSr@~FL.Mҗ4#ӼZ*;+0CΌR.@;V+* TSddq6pm?7H=S3*\Ie2ՋgoNKT"rP:-J`sE8LC5:CXVRT-bme_[ MĂMq$"((f!膐c%^wc)r2;iln~葰YIwD)F=xEj8ȰJ71a:ڥJDLj4qNRFR[Dzli7ۈZE:ʙqm_tWÒ]9C,!ii9Dh-4% N#3T3vPeqs5QS(R/CJ}H]nBosk&0-% JJRidTLkkaPIa.7V'̓JVAyQe AU{h6OLÒ48-4^P[ 2M$L5p&4FM8}Ɣ"_n{@Sp#aqv$Bn +qn-|0›:BG&eRKb 3j-3#v)ܐ$E,)V&TJ! +B#s +KV'H E<SI7Ũ>uV>0a>X.pKRN,)V\Ÿ$*)S: +xGG2-{N$@@: !E=JfHjf-Q׈Bm\aw̠ꗝI"p6un?Z'?-e(+}v&SJjT&3M7p5mb N9Y\5Tcd} ZYO +, ɷK-'))) +4u.UU))I޶T؄!-JX'"zlOtFEmЃ%g3K/.\ -K~I:qHgbs$j ʄڔ-#RvlKmWoA|NM(4 vzaٙ)g3#4N$Ig% ʅik(ԂmW0ޑrL(F;qK%a~5vQ}rzOi۬s捍 ffT u~ *s)ql3 q@h;x97ΚjDnaa%0bvW7L.I,~6jpno TӠfż]"ԓL&PP{^ڮ {+:74Y>Co{)E'>KBEIXોCTO!MϜ +{`hn{ ҐRd߷l]ћs#H\s8IX*'@Oy LZ/rIiipE>kokbbaig~.CM3d6AMƗI@UeS!ݛ*-)".6lП IjnBsqDr[t6@0&.VC [%(V'nXݭ5i(@\ﷁπ݉49g/OR}eMPBI"iq{@#{GcE )lE,d*,& -GJ֧6R1Ŷqª.IjpI9k\#Xp6fC˚gc̶߆@H=xp%&ka+KrqY׿Ԥjb.kS5 PZdž/J8 +@@7DC3h YEQRLulYNBo6K"Thm<<=e.R3 +1 bǹV<ط2OBQDnB'x՗.E跕06(l2SilvJzVRЫ_,zv*UI('lerR |8.)eĭ@AVH;X +&Bckђue7!6Z1!^RmM=qP{_R=4;ɗ7/|aʛY/ z\ C7_7M#MΚb5"D~PHJGb@s1SB5mHI$8%-:J <3^:]’m?{HpUđӞr0ˑe0%E v>cҘfAЊ[hH!CCٌ6T߆""je/wR缺SqKc┶ˌ:HmJ~.{l>†"_KX\6HI0SGثRB2ig3FNuNf(ԢD$%Lm(wVٺZYL Lyu!dqfl^^ǫRQ2ZnM$deBVaEqI U3A3TdL~FC񙣵Ej+sORVVۅ SÍWzXqH%Y€>|1gU"XMOj"r'+[vrY ֔Y9Ty< .~M&e!OR!)pm{Fwk?*d(Ёh2VNU )iIJ@7HeLUqAnM*U%L͂<5ߏ,G´4֥YJ)o:BVqߍ˭A($+1!Dk7$0e  HJ_)Q1A.-NQ %B۞q Ye-݆GNn;D"d2D7riUNKkKf]3LJ^5o_9lCr *m$" HJ|[+ M6y +s`}2&RY@ݷ+/(6e̯Ĺ֠yKbI*"* K + +؋F3 se$$רR@q[D|<ѣyKj6ة66'{㣢&Kby;ߺDZo<_%*PvTiRUqi.M~Eç΅LU!2îUқcΘ1Di&&K=bЖp.6 x[sh-$eU׋~rfIuyÍ6NY׫YֆR]CqTH2fR<`|;z8Ʃ?V%JBNP{$JGfpԓV#Chu9ukqshJeJ +-ne9JI%BD?2V nDV[؀ *Ǟ(rh-%I_@oi$Ʒ$"uSFQivq)m{ +H)R>Gx"φRBJr"?ĩ /+Ƨ4\iDhb:OSiIw0el" 熘R$2I*uEڬH&2 )Ԅm_7HKqmG4VM; 1GZS*KiYV9aqp/7Z]")9ȑJjJ6.?Xr v30DZm$Zv5'NenAuCGPH )(e[59b KiRS۟,J$^*XXMX)QNH +1^QqgEC ONi3n)M(սV6bHJBҭ@Q $"<ǔu}<ʔVڲnM#7-!RәDnoy6rVM2|Iu j9EkhRcُ|Ru/jWtWe! v Ib0JY.n62G:I-6{$htӾ5zwuW:7/yv ]~謩~(+SmZ-~Veڝ\6a*ڥs4F/pf]u9f]ec^t(~e6$oxZrdڟHC +XS$ߖ D(ē&J4H mNͳn)R) 8Kw,ooH66^l}CM0JNQpOx|=+sPnA.2Ƃo8 JUk"2GKsu7d3EZ(hGx-$~rd\2B()zB]4Kͬ؅[˾+wH"LϾSͮ\6;( +BIT/9lQe*6Ha`m6JV(",*zQ 3Me2cjZ\DڍrN4Q$ӷuh˸!@GMͬЅ!Y1;kWd7IYr'D3azS׿39Z5jA[5ӟh41֙6,D?/d&m{⍖z`D5ӵ7V{cȓV橋-uzJi9F\b&,¥<|>"? }W/qG}F P!bnmvr=Qԙsk#!Io]][Kj TiGŒ#Rv%XI&kE#fJkR#Kkm ,7fae]Y6<ԮJ|i5ҡ>P}oK}d_FLa2 $ 4.rL/ZKm%!)HhZ4 +ahPN۞TR/xꕪ9R57"#A"|"[y$;rˊ슔ө$/Qm2(=/8-m iCmuhڭSa*@Tt>3$i'6q=j%*ukuZ^&ZJ֢ Oڶo'y'C򆲶>,;[*αVLcҗ.'jbeS~UGyKY +oo/:sDa2kTMF)SRAB@N>Vd!1ir0P>'hcԛ}o_ +J|_ +* ~a}l*$k&dev))Fv$E~W|?O jje( 7Nݿ +S?M1UawT _aaNjq#H?׻Jk=Ɇ{ +J5U8 <ڢ.SX})>d[b)q@c +2|o;rC^\KcfQŠk8pbyeQ,8RNZ<){I)ߥQ®=q+\?CCZuOkk?|>Gm#a9'Azdjc88+ߚLIλGo3o3~VjV%gqV P9{㊧0-^>9wU<طb%g{H r:䗿*6|jt`mN/ҎG*:̎ iJ?> LˎE},غ(~ۭQhj"<){帽__d@<Ơ]HSn.E4[B9p]q]FҌP0 gȡА\ʒoxJ#՘BQ,Fﴓo qlVj kIݥ)=iC<9"~N.d6.Ed8^UAzG*+Z jC`%#gsDeY7}L[{Ʌdֹf>NL(ɫDd%}SrN*TRe}d$cԑ}a;nhh2mrCWU40ʁ.Tt%*P׼x#@iOmhX*$f!dFtqEJo0Ah9̛lnMU[Oҥmυ.];qQER+,,ĖaSɘjiJfzRKT?h>D`[jvD9G9~%ލNKxOyjRq۱QZFeIk)!Iab6#}D.3Du, IMB@"ĒSpHS[yj'& -z]dلY濁a#(G69F]!58D | $s(mf+0TIJAmi?Ť}[i7aOIbʡWkL=fɹj<(wY\_ [ˊP +ˡ4e1"spCpYqJ6?/\5e]cVF+D$P)seєMy6hz +]bRirȡ*9G%inhp5Rꋁ{N)qJԫ4ɸQŒTiJąq;`r)#e$yաƬ!H{x~xm%WԶB)ȜۧKb CUIpJZV_|MNu9b0p'z l- +Cn0s^P&iGQ +Q( (,ܤI +e HJI̤6K{J kDa}qtڥqq-)! 2QZG<߶*Ұј]Uop}"*PNk5 eKʦ\!@8( 8PyxTƂڦ^ا^~)#m,\[Ro#)rNԵ+toABC!RJ{!*>_.:&a iĥC:m<YF^ЖS}+!Bqы +Jx 9lӾ)҃=Q%&dkJVjnCH7LU,i8--ġk䝨ql_"M ^X*muZMrvJSpZ@in6r t&04).C\l:6u9Ama8ҥIJ0JZ.N Gqy<O%JI(J-n VH/ LV'VzW開)"{)=XELIˍf*C-!\n-)d^xMbzۆ<8jrۃi** xlDW[Qm}Oǖ*|" B Nw<!Gp=hgV=%$C5.fg+e{o_OP$ľx{m~#HZX5bF'RTt\99iF9o xPnn T<VnwM 0rjuFk~P2/"c)m0.2 œ@9<W3W'C~S!uMe(Z8',@tڑE)Zx[ǽFe^ +lF;3 +qV+Er}rZR P 딄s1<2L1ZHYJg}Ibzx~du#a!{7 +l*N9%V^Mh4rbGmahF\#9ft <Y a/Q4z* +!twsoDJ-[&_R+[hMu: o/Zk^ih35K6J-+# h$RU$h#,* ʅ9a +q$@%ED/|6fKI7Gt)JTo7ruWk8uNjC9%C5rH:7K':fnWC-!P%PbGzsȒ}/ 2Ts5$!WԺBCyyj!.r3Eےb3]*RaIXf$ַ>g )*sqgrwCrV3Ѥϼqg +JmTu^v#⠿=q"\Mi+Փ$+S˄g".JMpÛ?0lHH6B‘Lp7&'\cuzΐiοRƘ;i2U#+ 9[U9ABH6=VdJfDFdenAlq( 7U-RME Xs6,ZO98KRM]yq +Io8*mۅ)e;ZވIʮq`, ^87>H1QBΕ9uļ$I*Rᕫ1,!c웨\}mjuu+o886לtOIo Oߕ($$lӼFZuL@[.E *Zŕ`Tl&꿑9KQZ 8SH( soGiU1N{9d%Y@9"70eΘi:sW.ŠԆR8SŬ ǴEo)bԝ5Id萓!WɈ$ AZQ*P$tJ=6fHMR!HK)HnT<&z]+0=w:sVQU&&Yq(I'S 2'11}dDVP*Nʧ=Zk:;R)Dp2«'fZ m8Q-+-#)DU{]۞6 *# ѮfR]aϺKfܤT/iuQ|=ڒm"#0aǏ*x*n+P +"iF~vK2$I`\26HG.mooP)%-WUw?tz(vq.#ǜW|IU5v$J/V.{'^cf6l!a[Man|b6RչD%J7&>lۥ1Se,ֶ= Pmh I[jO=L1$yfIp%dA`:Rgrȃ5$ks +B$"wvZ^m{I.(%$\!8-\|R9ω[T'k:O4Rd %$߽s,FD\ܪEɥ;5k &m{y Yʖ[umxkjk+Z@ F&FM 1鏧Vf*D4Y HQ!*JrKːq͠uiIf TI"HIÁ/6nHq64zH2Vi]8x!Y2෻"bڹ ~+J,m}ƶFu54du?3#N.&tr:s46J(X҇OL Hyݵʻr[ÊGNST75z&o %۩n JjRoV#P#]vL'#/"BV鋘)KEDsu 7P8G$)R>Nbr")a܋ysL˴3vNl-)XFpR|40+5UMYIʄHJH ]9LWieY#K96{ڭ1!2p4TRlM.L33Dy(vS.%ѝqj.lIIΡ&ب_HJwI>bV$êiYe"Yq!VN +PW.;[PˊRֳ"AmіʌPZB*h/hl{M;V׌}'N n~]q+&M,ʐtu@hgH:Aj ]&w@SRVLu?r\}j¹"/+kfeO!:8S̪IxN5cY5RqmD9J|ԧ %zl^NC hB "\ܟ߱4]WgQZ{;[C59P.t?j8Rܞ'TV̩NoX橮%6R !YA<T꒵o(ߝk\Ѡdtm<۵A0WeII#eڔ6)Q - <5*M$$N#,/%~( 6@_ y}lz>*eSRױs:xGRU1:=,j4w [z~y>hG;UMrCf+x= +aii)Zn'OYo&)9:z^}Ա:;,!`LW-G&$y:akkkBUnSZO3CZ~buJ0%9T.-mETֳ :_aÃBEp!.6켻#2npmu0Gn2TUUdA#Aҝ{S.ԺK'1I*qHHRshq;G:4¥DyuV>ڑ:3e >ginjDm jMNcu'׈arZN{fZ»ZjTau_Nhs sW8 Եo-IsͰ֧Q)&qk]TTUHhPS%(JE/|N5DݳiK&tmNL>}.Jeqoeߺp鉶Vw7Mn{zb^j*ieO SM28rD㎐i4?orc̙9Q)lRTKH H]MNMM6iJV6:xG-q]d6I5QwZҥ%Q*()#@`Wf:ߛr{%`թ1!,+1≯iPWr-{Z(;c#}ureGRl e(muN%obMDByYlNH mC'.M~kD%r^m=1_zIipFXHS8i6[a,N\HZҌ%ǖM;߸k ㆪ7s)*uY}Rur@keBK{6?:ޔF,F^E7u`zuK*Ti FyG IIKc@zm] #qQL)>! X>' ߪ-kz!Uu[S©ösa6*&UTp"Խs~ʨBߙ' +KiCqI$z`[M΀wC1Յ!t?N$Ҙ2a +_XXqQ;E^kZ}I%&&Cs'o;Sd67'6> +EXKŒFq u]QBNRw'<*B\Ԡ*:U%ү@8&H撯5)Z[J,NucOB,'8<YHJE0T'V;(! ڑJ6?Lh;Lr@oEd]ZS)i)*)l aYcH˪Wzy + +m*qsn}-M +Ch!␤ dB|S37AL|cʊʝTe2,ʅȽ:wťQt2-eJK0aGNe kWu($qYjrʔ0i `eF+BM*Qx Fv䜭Lіi`::P)@%KՙTPG>5JVig\l,6:a>n2A\ii(a2ȁgW"˛z4"URJϮaLf RCn% !~}pKuYe-l}h42mݚeVY*OE %]nm ւ>l^ k*?} +I^ +tJP( =0 f +UvTG%;$-|gRedX֜I+I8Ƅ]gҠx|=Pصb\SSX6 _f?cxe:^7:ZsZ9TYS5I%5)|wR<[Str{9&78ʥB(XZX7)KR dyc>ih9O$N9(OlJS%}>TQʢp ) +\'ʜGQ㿣xgjmg9/?RQD&XdۭHe6+u%)X.᜖8n6pBEȿdGBь[Mϋ{] $_>k)c8gm @Rn +.8 ;k}b=_^u"mQ-5gXMP| 6bl|Z,CdYJVgS1PR"(Jo~nR +IJEy(ɈsK2@lI![bt|]'ҜkS $*ٕDz5q>mabX%Ξ*016vm'ia/)HOG;cCvoxy*uOai/Zǫ7T~G{OY -DDWM/=UD= vmdOeEZa -@7R</f,'1[2Sk:}s63mĢVl l"X'JxzQpz!$>;C>F9<e;60.R#Mmz=0]q1Qr?ΕExF+KHްτqYˠq`w91 +EVv+X? +z(fTvqV|k5UVE&0IW׏mQnR510h2ira*şbo ]i:U:rI?=M-rR=| *d<*6C/:UnMAkbjd髮{ W-|^$~qC~٩A9D^ iaT7q?X”}0ߟ':̟7(DT5 qvX[ 8hS]S .(k. ?6?QՅCyǷ1-eTM6-gMV??ˬ_C+i ma~/ 4bIԧJbTÎ(%^PQZ-_ ]uvks̑njҩwO^%Iep,󃺍 yaL?``O;=O)p+QRRToN0טB.{*R +h*)iK~@E w-:QM{>aQ+}P? xKtj&ҒsNVqjx|RpU^H} *r8{KzzD6r3AwRR?Vq Ly&֎L6x|Kt?fRŲm~#Ozۥ.q2rGfOYl]\u%dD{ǎ$9*$ؓST~iI3̔  v`OԦTR6 +Q)AP^d}kύ:{Rn,G4>:w6 DTdeEu)I?Pt0MK1 q#K1Nd0BU͸F'g S7ǑH8:ޢ)((jɽt94U(Y{!F}莸颲]`!qk);ԢH$XώòRgZJuINmdq2aYƒ]RRiqujGH2eJ8- &Ԕ%zX3mZ/~XRRjdhIr +PUbqIkKɉG,IQ*O!_AhUNzEXRXiZΕ8BmֈL%e,!g?xIl9o~MXeNߩgKI!8=R,]nt|LXk 9K[<4JQ"c-Գ]%O 8uM{Sf>F۸šZ? < m[]~p؃‘eKIʇw8ôwq [lܸf>ZnmƩ$yBgV]Vs˜ۉyFEcDyh-^7Ix”멚Cɧ;D~d¥ +P=0òI(q`(YIA="^PЧr{l% *)hK7eOsp,@\ + uJ*7$aƹk$J'px]G(Y >/Iҭvzq12,Ŭa3&ܪ^:5'q%NaYmtΦz̴cZ9(S +Vӊ6RI _aM9d|Wgxf-N~z%&ZS2! +H* Xxh ډNB#FiH`;_U)*EFC3o:eUG%bτnyJ46$)I=mGsY/*=? )*5()<ܗH)vo:PVޡM-D's~jvA`aeJL:-J{%rnsSKpq&SfFܸK㑆t365J +̞^V8xJ{Bױ<<9DsP%بX}1Rz>VEVj/.0YTu$\qMƶ=4U9:o̵QFcbR%A\T7%X%*XX$X$MテRFB3QNVTB.R@`t O2PA86NfW*fMs|1"7)ׂZ o8z5$F)ZEїU]J"pۺd$wa4`8uw'_CH)bN4 uWp)HBei.ecR)kjѣJ7쵀u)FͤwE4!"VDįY!Ǧ'2oO!" +P);RqZj#RNNp|.~p)CJkh9_@F󶛉-1g + Cnm ҸjNwF!LeM3rө@REc~zdI4I!*d*~r压7YJ=\2Ҋ~Ы?(}f m}O#n}_(vFމ%Bg&eiy'xySOscO8[m% )X`EfX4,T +4ʚ[k.6VPw|XOK1zMnok(hA!2M;蚰%d&jED?,K$ء-4: 7 眻DDjZXD E⸴%Qk~97;n98KR)R{]2ŮۆDe!HMI4ԖRTJRu]ʭ}l S'O ]-) H62?}G7i̭8 +T4!@ ?T?ns=GR,v& -cg4ҋfRh\Z|l3,ijTx' )KDZP8# 8N QXCN*e(N UM˓rl7 .VQVI ;6Ppdo$M>$WOO ߬vN~N# 1.ꍸ߭ZShH)Yд0#}>f#Do58c;R&PQ&^5Ӕ,$!#$_&6PT0:.ĔE6ut[vT$^}I TlU<¤KK*EU6RO,*O53,P"})^)#TIQf MƥRKbJRKHO`xqC.DʛP(Y7*}6@*fYcyXm;!0BV*'Q}m;LS\IRTTWT~o:ܫɕGmvQfIq-w+qD4ۖu;hC칈CmGE $K.~Xa,)5hm]Or)zyniK\ls{ n9|>YնP*He$RJ]~Xva2q4Ci2â:iB +|*?f#6Je! -$8YƌY)R.(aʹ1ޤ.U{l5ajmRRQ>$a'@413jTUjh? Z|.s6IR琅znp|FзXu P6ԓZFʙm>̲A'2zR]\Ep>[$(e'4WʸVmls[9%FSji$ n9/yrMomu#/L7fcن5-NR!:)AfpYe 5 Tʥ.S},JDU'0ZۭY&aț}ILLdq!VV: -IOT1tduJED״Op ZTrt.*5)!ei7ÉP=[u'.YB)uJi8s1eK &.ʱ=]uu 4'MA[R9q.8xl}5x~t^L`72R~oqIY +xa~ɪaKf .#ۀ.,7#OX|$]iGVZske"ڐ 7SjL(S%jf"̡sz!6fm,9'A7՚SM>F- ׼]GҨإSBh$XCh/OIz&VJ$rO2Npz->MDVbVaZd 7}0'*T{DZ"+4Buʄ'k~ju3JT E=6.J$V؜W u.m6QR<xoSάa񎺝rIMJTntGsLCLTX!LJ (Jn'Ftmr$: ƅ~E492E0Ɯ\r؈L\m/k'nuO+tl1myʗt),ihdmnJH ߏ`vqtfa6Pշ-Bx*5]T兠tRxه*tM"dJvSeI̅jӛTAt~ficP:{L,"Sbݷ(:994+ 6__;[XDz"biEhu)CRvZ3%cȃ#j\ZO'd4eMRVM )+C$7vIc<b\0*v}`қp&Ů@6Gk}ʇQC  6c-iK2 ˘);\)=t7Nf検!%Gд${a{H4:kk8DR̒cᷖ\>GYrߎ[ rrdmԑklC3(O\Q.K=6V"KܦJ INo-˘ȈLm6m*)WʤL1XVGVIg _Ɯ,"ېc1QA7Mccʱp'#H_:Wr|8"E߁DrJho#{'pg4}0aMߝBZۏ_[9;T#m,K\m B*+5vJ[m*qiVӗ2n;)CVfB2_5ƷDwմ>gMΦRUR=Wt(?Is/XU7(jJJY6 +PE zw`L=YV[WX5%F |P9h}$6ӡ`Hќz]@ObPlpE"Y7P +҉BV+Y/rR@  ;FYE(ݕ%&eK;k4R4(x׎U$<?IܵwCր-*Hv ƿ%ab}F>?MwN}f:wkQ$t|=\Q5w%{khˡ?>~okENևQTU vM;WTRA0NpN<׊'΋NlVO(}4Uo9-$ru^'>jL~JWlh6HQefu$\~Y>8$t-QོaZlLQ! +nBk̶G&:#!a1O6`>(pP9]tZϴQʏ*>PhEktԋ~}8j2E2߿ YlPԵ;%Ԃ~Rc(=C~ӋGg&;|Z"Ve{"Js%4@P  KMWURoO=ቜR,R+,+m[O UŽ-ximDZGBVHh+Oq|P)zܒ"aMTp}e+3个/I)FUZka/:׃- 6n9#08P0򖌧2VڊH>" +.J!_HU'K}mvH*$`{U=ќ?Dfx ̐ yu'SZ +o"e]cD~IY#*sOqGK¶QrUJR~KiܕʻzDR@QHmlGedZɵ +Su^fL-2^\o\Kq.kW+}2VDŁr@AvLW_F5K6 \KS,<\[JHqZ +HO"-K%WS J + 7JW +C}loۗӖ5._ ٺ%>EȪ-S{)2'0D!O6zˎ {4#MȃbӊOvXSS 4[Z)! +RlJB.8tH'%Ƥ_Qm)r%ݺ5^goĖ2:Yoy E`EciiKmDpM&Ӯ6W,NX(V܂Cwy::UaM)L:S'jY$=Oھ5ۤKTVT;`RKJTWXvHe).) XQN-B˦oXy"ϢY^pG܅8kqRoܠ/͏'~Q52S⹖%K>P )Y?4CY]Ml68Z@ SuKR +P(ѻuSpHq6ĵoX +@x5)sR 6Wn*PO%$luV +2ϛy2WiMu%vM*F&+3{3ݨd I%.x@<+N6m" i?.JBM~GECmdXJèHOXA +ԝ +Txt 腮Fa»A`ʚ~lDk'8S4z.X kA:v {zT*Ps++ϨZap$7I5೓)R'uK!><}1T^I>uzq|֨tZ, fp~IK`M|bNf +9y)U=/}-1* 򧗄vMۦVNJ +`H66j^ЬtrvsbVm 4&)2? IZ R^'Q'RӒè)7W!~f*f((w j,Srue J#WlF@ IHIbis|QuBׁI<ZaC,@~kAM':{A69 ぎji%.c}ᣈ&BYr4Z%iZ?We:[h"f-!Ϡ(C5"3Iq\r{K*RJF[E!l*: 3%&j-=4ђ{jn2Ï3&lӛ7T!QОUxo#mD-,Lm*DL#6U]D 4 qnK*Qƒc1pTjSKiYLJJ|Hۜ=}iG+=J|송0)*c֧x+"{B ~cE{N8>Tkb3V'eڤ(9$>,YA Gű9%'K0Hޮ + c^p67T"y +=&P-#CbR`lAƗ(jٗ64VW)$3N˒Y$w]ZQX^zǓLԄ ;Uu[%~`M&J*oQMJu:`4I'ꝮYg1L :)J<V>.<2YI\l6h~4^#f)_P6 7LyH_ܩD<: `pf:'#7n\kr2)Im& +dxwrun,c%6SsF=8\$7W~]EMO4qTPS'/C|B@$|r8mohCGoHSr 7ff"4 !TZQ i6T /5Gag% ~񬒏UVoJ{]Y3-72Fn#!M%H\U o)sN>H'_@>~ 1t'NqV"> |.Wm!C,B^$M'N̊] E5ե BP Zɾ9+qt\V `;ᇪi/ό-Kzd$#:A)MIȔ/DO z'3% Pd)h ))<|SBQI &zc.^:kemyqhf! dž.\%^7Zܡ{Fxb$o8_qcvR![[ z߸96EU}F k 2Ol+]NQC)Pm5%\9[J@ 7:p9׏ZRBT,\)@uql bOm3YЍ}#V9 V`}jl$ejja}9Bk_[\{D)!JeM(& +3u*|%\~bAN2ġLu!Wv@W;oxԖZ̹ +VXβj`i]z :;{IY1BOǥqH5~䟄W!s!D̄B7;9Lb0V"{N%eBtoro':mMEg "͵[*|q{?l5zITf/]SA&ʠ$, 6Z]M`ZI[}jT•]Q+ k pG)k\g -%)RTԇc 6At}* 8Ұ ƢDG PmC%΄zQ˰>4BP@RlRN۶Cj\ݛJvGVJTm#Ъ4P63b90TMoa\WrʖLJP +!!J'1bATu ;(8 %;u9aT\t8l)%ZQ U}tu7h*h~mDkTo +q -mo gӧIJZiKQO94Sh@|nŽ6]58ZlUx뎀1Brַěs:l7N-0ApdF|˰8ע.wPH*`mIOBVN9yuZ׾#^92B˫m*[qR^HokH~ghHaʰܺE)+PC(?gfzlӪ;\EԲθi5'p!]pů7Tu@fHJ}TLޡ 6x!kt>:DbT/ݸx%A)'h b K }P6NSsqsT'Ir Sƛ@oveG9q$\ܛ}pu. gOr$zȇ"q>T7ߺI)"k6-F ~ՑB%7BRҁbuML%Ct?^FچGjq&|xJ;~HY>ئTs MNO./l&LИ҅s̐}ǣU< eW2F$s΂z0L湩Z\)omt[z-Pz]y 'c آi5[۟1eI#^>- |-lZ f w9O1W(M7oA:oʯCFqHK'\o_t, Kh"o/y.(ŗDUdTn)% $pS81ԢHPm#RR!߶ W%5;a |_D=yA avԕ'2W]fP<HQY ~RAJ>j>Zo@vmbqBoQ}#E[rmW KG6qD UJw)lpH JEa؊ڒT\13U_C xi0³\Ş ήxM-*Ki +TlG:iޖӨHڔKK\m [WY2~ Mtc@sHMVubɿΓXu~6l${.wGWD*o'oicQ;i? uOÄ=#|[ιVI?R?:ȿ[L(>p +Ic xnrB(YYk&д3u$(#M_Δm/M]]UL8?:{KOgMgVlx:k^Kx¦w|мwJ@9/o:"˭EiTضܰ+,6p0,=+H ~5u-ZDEL0=%\w_o.8u9lu,b. n(-AV sFRxu0/uT +Pvsw竘wGmtWCrKkzCFlnZs [NQ9mpH2B 蒑!RV}Fj|])%56ިGPW釧F; S改asݕ""S|?LW䏺Q#wkUsk-$a6>1֎TL"U]?^W Κ!_(eFAka_vp>`\]Xh]=6n#Ǭ59i~'!S#U5\Dˋ"qN !bg4ٍ*T̴/j\xu`K\}Q9YQJaf ˃I1ǂR$qr{ٴ#SsO0ٺG&O>" ;DžGiՄځ=ӅS#C:H:zʹ:plJU6vtno(Fvy+Fy a`x8SCmB]hN2ifBDnϰ?Koϥ e]%GJy*PBes8>}Qym74hwe%}8ݸd:RZJ^L#Y6mO{} ^4/Ê={~k`Esp\8ŸQYCʞOVcIE&jS-<ٱ +JȧFeK>X Ñv\Pq[XG5WQ&uNt[QksXyǺj(UFQZ; 6 ~ .LI&̥JԥΞuZ˕gp5_yM3--XB7e)DX]DyXl!ˮU29tf̷-Pˍ.Rn ؞QoJT+Q$A$6HAI Xṍzb^Yb@)*$m^\}E +HUdHK!$$Z)I6 2qJј KJyԉs%r)J;Ήq:-mN *:qڏG.DWcBeQꡈ5SV@?$&IĐ'^vF!h6U4tQJyJpEIC)s I:1z{ -1I2c-ezuj-rt}Eb7eh<|GZSتs"cr1, axnY!ɄiWG.ak4s?)oH)1,6&,(7~?.hZhH, 4/u: .Z(N#UzonS]Zg!;B\HD?ß[BlP7<̪ ۉQ̥{-RrPVk ' dV9%T B XI)E{8+0Q7-ΛN2ܥ-?wTԘ|lҠ;c"ݛPLW~RrPf^q]i+J(Lsm~+)!O-t<%0~@xiEv uSNm7WO.$&Y?X1H-Xk  -&T4E5b+`q-\܄xQOa1g)$EjSO66 +VSyHMTjRT kW>jcZY&$YPMHY҇Ħlj:L6*u,Gh5,@ XIw.2R +v.1S*~J&T r(6-5>G/d)N݄])G7$]HAV*=*YISTZK\7({46[h !7䟾fVe벸ԌekRd((:v[ 2ҳr4I2 +_+Qg87FiM%HrӶpCC3UyjJ@)B VUX0{Ce:.H rhrItYE$oc]HכҖˉoXnKse;Ee1R/6$(;%)b6OV G & +f]:^lPP (9GȕlftNJTnNԪK]ÊHfs,A^L=o::(,bp/+%܁QjO`% mz(q$ l\%۾}9N#O8e'Tp]d$gmRnBO^#Ft^jJ )n6GƠl߷|JuZe+lPG FЌBih]&Y)XH6~*'7@" WLkxmZ%bBq$QOTkJTm0lr&05JUIBÏet4Y*CI +NYuӔL,N!Fԣ l:žXf2ޙHp NTI>ČTD̻Hv])Qwnv-qZC̩9ʚ4ahqŽ8 I<#@pI%JWd dǬ*cqi,8j0یH|uuTr山XY)IZe@.ҁ*$X.lt!6H%gQ,Vm'dkmg(Ti@ϸrO+RoU*+mڴPuL7 OP[黁3nyI[npɒ_ ^*tJi-'*SM:g]m-Wh[4mFqcI +OIe M^?x8y Nlp = o*앁7MxR1mPl4R2 XQ>ܭyѧZy':zK3Єe"AHʭH@ZG f “6c#9 6X鉎^3#w=pf#V/%\ҭGxPt;ցxΜBnbc59%m/ص>$ joRS*1I+""T8ڋRƧ!eIΩ +O5uq4FבC(xGO*Q[ߥ~4[*edeIH?PM^MBRN 7&dZ̰3iJ!9q 꽢B{(z2zaAdJ]<-oZl$|V^qU:nŲ*$Y)=+ <3)X$N#ד2!{,RAT9lē=T)W`928̆oRQcl c+%j-JA,v#PRl-K9;);5SӞK쨥hPRT #QEq9,U4HĖʉ$(ΫUt_,bI,[tVq4sL-gIEZ$ 6Z֧ ̾ iK-@1+TTPL҃bFuZ @ێ\T #ʦ )-Ju#:E]NN-P]ZtQf%7RR~/)%1*RIs&u 6;c3LrP]į`Ov9NqL=00b皒bu5&Pd7)q{٦ҋ)ğ7Nb>ifeB/8Pܷ\]PX)j (ǺT -9ڪ&(E9GCs\VbçcДޙVHm0A(BINzqNsL4eZyN$uq*Ppa+yI _<"AcKktgk(\t r6_՗t) 3E S8x%< y=o Gqu dPU$as՚q Pʓb-r67c8LsZ.^u-/]Е+SjIR{*Mz7fm#idB #I/6ԭE]CEM/2fCJV&> n00@r236NeeUApt@9T +eYjOJ--е& ="U152iBP24 5IRP&ŕCND%:hO m/4kdC6n.}q3tH % x{uSBmi =ƝKK$|syԌ=@s +:]JQ%7J<ؕo„$jP؟tc^znRyոJkN'XsO‚ +Tٸ6M|'\x";h=.ړ Jkk5!wȵ9 Ǣ\fRˮh{PZQ_I=o +gKE :R xXJ6;x`x|1Xrm̝c>`I-IZ9=K ;$Ks2h'-A׸ Q(rR>FYZJzLa`qJhA&Q6N0ݸ,Un8=b[V䔥Q;?QYߐKF61TKXBUöI% HJ) v-!gqh b p$rNkHTEa-B*6'*u"|ĉ׵q|"ʛtd ˼@B}Zu+Yi29Bގ@?SʁgVc!Ä#jU8qP[QjpqNET gAME9cu1.,D,Sk1ݑIX0S+c_f!%s/[?\Qsi8碶ssS> h)j@ŗtV0Q_&6RfbZc$Gbb1yUV>Vl˿2ʯ mLP^U@RpQ+rE[qu5WQu 0]۷s#Rp(MwL)$<۝ĺU@~rs,6..HtێV,I3d>C\z5]֌mR(_I"lC1jF|).ХjƢP3ҍ9f}i̐ӊ4O> Դ؃tQ;kΨAZ=!/vF ;TgfUaP7|#g8-Hf>][kc/w^8(."4Q]˗iR1ՒLv˰.5:')8^m6!JM mJۃi!J2/bިД&ċOHLAˡ $}krB\ +ZTwH^Srb5ԕu߼Ɨ~NS R:H +C9Zt:"^sh/ liZmb CF%.$" >iJe.#\`NųdqlF$+Qw:ZvFh@/]e ÿ́RA6n0IK"!@-SڏP[PeĨ&";tk9)U¬DоfX2F{n$Wگ{#b0o*IiY=`ßˉJEա[iN%#VJσGXͰkȯ2 >Xn$sOV[=Z` +7~q%ݔ;7+5jZL%"3:REvMͼ ïN0ڔd(MPYaiL2}QsuMZ}nIKeo7c7+Q:o)J_b]D2UIJH7ƺe b5}# Ф-:4aAV6*!Q) @(HE@|$"))G U'U<:`-鈳W\s˚uEJU>@4BRUcFxCeGBE]+5)F !Mj]7 w߫Q%OcܡNQ s fP6 +JJEb\)ocsI- Ą߀EȩaS&*^`]ri gP^~QeKR1AgAp\HG}oə/:xI̱`O+Xċ$^@nJ,TͺӦ$jAJQ!ImX%@"i*nG'iFX +kS'5H>12M72qt_ʷcR@ĜoSKĻrh,7#)s>6B +V6FDzGw{_d1ADT/{zz2dRRW̼Ҷđ% nJ zaWM'8\Ï82Deu}jZgQ!iOZqb)Q˨AE?tKyv>"qcjԵ*< sՐwHefΎK5HES+bdui\tǸ8xq%$ʸwBPR D C +HR{B ncc +Rڥf@F8ȋ#-#,JVYZN#=gX -b)RYeZP%eDkOa zr]Ԅ"dOaǽ*S`BI$ TlLQyD Th)+7*@\I$HtͨRO3謽&j:NΠ䶔)- w-fѲYCIR+qOxg'D$F#Kug%['#K[( mromIR=f=RTjHJH l4ܜv˴,>@AZ@*)W7ܓsM,V t:xf]Ǫ@/*P-mdlqs+nUUj\d(i$z q&4$J$ 'xl7ThOF"Z&&[˭ԥ Of[Rn3>i"뷢AEXL+(s~s$Ȯcl][3섭wDv[?GzzhyV;zD5cڕ/Ę.VIBBUZ$:Snx6)J$$e=0I7FZ*yEK$nI7$'R|cSV\Q +hfC-;BNGZҷOsqKdòZ`$:} +d!?<5TNWq&ˎ”UGV|z8_} hwQez’̶|6|1Ҋj]*Vօz}[tGK@ڑu0'l[+% NԺhoS/ǗumMA02WTq:o1\N*4ׯ'Cc ѧi0hM%IUoͮF\T/RjvK)yTd䤑>8w g#2PӜR_l\@}?P/\<:Ga)lh,~B|e|D.~Rrx[`hVkp|DK]دn[Rmk-6;b evnP,{QXRlm&!PRת}N(r̀ {q H{MģxP >~X(~L~!YG=M (l=]͖SᲓoUahu>OV򣯨AG ba4 /j1Ne;]^%'Vd*b$4ݻ 7w+9R ,ó* l+eh3mzhUR#>ɕm?h;q|0jU-b^U%n+@̝!!A*`'a9D0!nBɜYBd']tMDA:ڭM *9BO]@A`)) +QQL7Q<$ry%>r\oN}Ȓ#wF*N%Yo>Mk ԭ;I~aKO:iaU-X i.BujG=14Nꐵ/*7@S* LT.9)m@[SrUgk>*H H zLM}TUjQ9H:oIq($XL8[DqXuS:Tr6X~kQ?38 vkKi6J|㦽ޮ0IA[8I٣}aPKD)HGynY$AEȸ so48NQTi{M2DQA‚~2kJ{^HKoɎHJ +q]\QHRtsJS.4kإX5P9Ĝ!< eBGRim+Ip;d[l̼uѩ:AٴT*Aڅδi~k.=PW.{覮hj؄[I$+}B^l-sKʔ-!-t-:U6m*vH/ l h{:l5h_2<*oR ʌڕ!m ޘm0nH&S -m[_ ZTۉoPlOg5kG$&v5QI%d9O8l+JE"%,.to1U&P0R7$whck<_XSaâRE'֥$4EtZ .6ʠz!{"{ zkGֈҫ.ܴ^ )c=UW+c.d !*=p +lh@JO1ڣ]ɰmG3cOlF7jxe,ƗZdJ[7Z +p,cJӓqhXNMWO2.̍| T6saqoeKrF[ese^⧀%RFR\%XsV[IK+PN<.y9A aQA힡9k5eRR@}N=P厶#V"3UG km{CQCChRG6瓎7S +x|X᷼N-ox]#c׵ dĭC G{q: -Þ|\j6'pEn}*Q ,dMM・"}惀:1/ (1p;).u"e@L:8*7&eLH0+DW}aKO64#-|>U=,W3a +dKR.#!Zdcldh] c56zT\YWQ' 7VQTδi>}-a m<ن!th8eq4bLƢ*X|a֙ VKuED'aB@?۔?W/u.af{#TtgtXm[K{ ^<`Ol6T2-vyY1D72Yl[s{|)'۶?j!R3> 'N#;dzEJ(}>Qo7ߛ_ǙoN nn?-H\a6y>WmUYgD: Bą+##K?{#L4٘MZ) +'#8?ƫ(:3W$TMXz#HT-a 7;`=黧qlhdAh@tɊvJaըX)@kX(*9НBs @  mJ/D#Ui2RýTt$yqo'ZtwQz!㋬ '77e\wHU@*o넧GO5;P4j#qGNԵhw o0 F?(7B|zt~,o4J +z:mwf,|l~ȓR*RA1j"@q22hc2y57Uimq9^6fl$5y7fح.j/! '<8}fQl(ܪ7ְU$#::\mIN"4wKlxƆV˨hVBBgCS$FO7LJ>3Ĥ&$uf:z#-h 5JeƝ''eKLLs)Cך-\ ʮ FPgK&vbGC=CR}թGJGeYK$GsPMN*x|S>u;ۯߤ UaԠ)eRI +Ff)_ +PkJnʧBG86[uBFSЖNJ+Oq(QshjNRVZS^+#.K~2RR.8?8Bnq2)O|,v.BI.t\ wIm( nnY'GwқhnN4 +7 ayɪcnejɨ7cۄ$.MZUny aGk¹P@,rMS%-)-v!R +6 vmH^,|uÇ>.p #в;׿HٶĸУA-ߞW3dxKWQ6'Q'd7lIcf/*Kv$փo"pvCbqe\:D44lqujy4nCo$㵀R.oXHk*ʌZ@JIнnIR/Td;Dz|ࣹ`Q4 Z&jAX:DZg=y65#HzAfD_iijO#8]"zqBl Ζm~\e4̥A  +CqSj&$G[=4iTct%N)I*J[y*O*ԃ7Ң̗EmmG&ZKh}bj"BS-&m0u ܳuq_yW7YiңnN >v$ *P${tsHɵ_Hxβ;Y?H3Sې vBa!r_2IIeBAӲnH- +)RN؏dGN `oHYQ,-28]TFt]+^i펩GtIR!I VE(XPy']Jj*TfbEJ@8y>X|W۝ӑV)ۅKRYH1AIGkRLJBQD|IX-%椂} DԲmjL-%x+`Eh]T -,Eri<7ˋAoqnI#l]8ʲGk,=ʩ7ۛl\hV)n; +J]4|Q%Oq+Z@!!,<ۭpO&&IZF)%:JY@lY( +2qaUfz,0mԺR mX'ٔ<²#0MR~RBٌHi(xS^q^RBII)V0\pMf"YMJUF4M ) %HJH{pA:ec2hby]R,/VTz@SS)>`= MCoEVIFo00í&IʛBW qXl'HkЪu ۖB9-mkXi>3vC5CJN!,Eܤn#-T]m$=O]5BI{q=LdRIo2}I/,%}1eNEw*O4 +AphD` [8ݻ7Tlm6"_iohKS~SW8 P3 +ci +ީ!eF16-?f1o`.GaW^4{t80pXnd~Pt Je0Q +2E8[Р9VŌUl7^{ O3<(JڿJzܽn]"gP ЕX~igS|caKRӁl]H\cS-XV%bw)&ޔ^j)%QEDMB%'7SS[+(s1֤+cB]SrM/7( =6D&?*\$w +H961Mqќn0=x>'9_xA<ʄl7X {ڟPBu$=0KTj5ͣ<ڽ@栶xxJʈHܫbYjc(i + +$3ޘ]@ww2nHJ$d& $ }M]o䎟[W OGpX 7> +W ``>ܞD.R YCOFe{6m=V!AIhUqXy[*r'e'b2=}{N >rժng6-F[d6<;@W('fe:T 9$Y# sBU(qJT^mf +BU$N) +jT(l >DY2-t)Jo t*5֩(OIX!Prou87Ro:TzԼ^9S]eA,7ʏd%#@CS)SraaԢl.T}Ql>|n>۔0tcGXVEVjfYrM4yӳ^f"\ȩ\Bsap!{,_-BrW)(*i&#(qq[NS֤p:0sRjnbNh˭J aY.H.ۜ/W$k~D KT|3 :UtrvЗA6Gᾚc6q :u?^L,0A~ә$ 6Ԧz~ҩz(9Jed"$6-lYIlBcmƗ֋ʎm=|mR(mG-;tf)Nb4%1!6$62%GT3 oΈguCxRFdR +fJ7[Ã#Pڗ#(!9_'T[I}m<.Pދ +"ǎdzB^l22KRڔӛ-V? ~q%AihYJSX+ W AIs +.d&IjbHA**Tڒ/\Ó|4MOaMEUI [D}Qi2Soק{c-e uX#u e +HX~ ʘ +;ǰ&šY7[(zPvyd_T2Q[2PH"Y7aWP5L~cj,L*ekl-* T (oHtf]ݎSm8қj|9{|b($!}f):tQ'TeGZEI .iUWn-pbDzܤfXS8PV3TBkNpXnԎ5%T3ZYO1[n~l3\øzY,J<a麍Q3s +*;t{>+O#9,!4㭍bayddO_o%N^}9q +O4 YK#LP=O I$$w-GG1]5YSG +Fj *$Hm '1l8bI id- U$~ ?8&he5Zk[LBZMԟ:ЊS 2[U8Em7[o{6]$Zb/hT5d=J +h@'(:PLuM=nqJXkm)ĒnQ).4S#'\[h$kk,kɚ;jH?+CL'ǔ qd}Qa]]T#hsGtQUMv=R}EZc~E‚9,'Dbp&zQT7qw)CmNVBtzUMcl@lC-"WHOUS?I^ipK8}.,JS&`O5NڜUyщ2Lّ6&gXu­u!)_)^zL7>aD"\[7_om~|oYc_XNҥ['a]lWEDCVj)V),fܡqϼKo#{L[0(Rİ}S(amJ?\FsASTR m$|tN}AQFutM5eKPxD3>1-$d$[/ՇNfOWFuS3 :S&cӨ1RPz" ~Dh-[HyPU>91bAqd83v%#nv0ZJ+yIRaܟ{qϰ‡(1sK(UeylaϿcfL0pF OИ^mvxMHl:xD)րw󬱼fKc,S;z$%W)Jٱ6<{vly7z$f_&Z`xyLǞŎؔȀXK#)"RGG*G{SGRqLx/4HJ*HRG{6L'Ϭ +F!5>ڂI'T:捿6,Y?ˋ)w!;Ӧiuۑ);C *p iw=>r3 p&=jYJ#*!iԶԦt 0KJ|huMyu릈 BP/aGrx%MJdd8 ||GK*XVGXa8d̪jQ]~Om聅96={㔡=7ju-ɤSl;FqfJgd "\5y롥^GO knZuWm{N*גj jw'ͰuQڛn9*fYrYzPaрvKӲ~oErfgy,ԥ~祳ra iu|[kRJhahQp(U $鷌h1Rz˦m}A-IRͅa̛F/6RA(](zro^$y)UW GR>T7pnn=qOb.ݎku +[.m*|&-e?9L34Ӊ}!hZV-.(urj-Mc~/RȻZ]iCpPw^HubCˢyyyRJIMP*hE.uˢD B nwRY&4N&6kx9+V̶of/a1u0@V" HRn} ~ȘBA-*PtQP%BFqMȋ)4IPĜXxiZe C^n'#2Vn7kj5 Ucm^H$JXaA%J+JO'Ku'Q.WtB#cҞF,T9sA_uzܬY!kn놲Jn7\|UD-e+TXn5"vheqcQMQQ0 Fo1kUE.nBRUt\ܐ?f-6TCnU:Z[a7lmB㜋ACzcA̹6%mᑌZ$Ԕy˲nk!?|,RHjFSNZwYJ,x*)ZUk?8oPt pەߺ^ZtT(1χPOz4\;n/~{beXMDDYaTJR]q-*=[BuXӲa*1xw[/0?fʓq 1*j!b<>tF!YiJ902x)#;-)PpW7c] Kj$U$MW^\Ҥeh{[O إ!K~}v^oE7hbOP$Q۠I#n%A. e`T*>k8. ]@۟X3p@ci 1måm'*l-V8kYO@/ `=WiC1 jcGĘZ Ыǜy-q-:4>X.;V!Q7j=֏!b4EY_<6?qwIe} P*U +" OFT&HR(#qQߣʹa&`{H>#Ӽ$N hU/{͓yFG\SiU}=: *3)FLgP/0B8lv!i)Sa9P킇#kqKiM'6`%E}2*T΢O@8ryq;q5'q[#hQGK&dYy1|^gTqKR";r@:XFgMTI4 ~7rluQ੫3N[#5 viJD#!eS/>N9~NTȄ ;2RK.܀5%ԯ6y¢*y(;>Wc tG/$伱bT䑧V8r2 5t#H-pRm[ 2`k9˛uRZmN΂ڔ[VZPDejO[ &r(Qֆ!%SdIJC3u[lK4zt&)m=;h4 J8EtwJbFx4>%i.JWV%!'A} [GAyySDC+J،θHO EgNcē&>~1X+3YS_iel +^'1 p!Q >R2qm+Bʬ|~314Rn,Tt<~'NBm8~tkg:(un~Mt-":v`zF5#dJtBR` ʭn#T(JGXTv=iiŀ=D!Io4lT)㧶?` % U߾;QN J G ![6o͸^w&(X{ƙ UwafGs 6UW(#[wĭ5> +AM6*YR8ܞB\/G>!T"SZ +ҀP)V@)$w e+t Iu*JKf7PV0vH:iҏNrwfgi/{c(G& *V64,cLR~P`=áDn*ׂ7!ЦAwA77c_ISιE6Y&!piA_;\ryf}jYQh%-|߳n1ĻDrW 4(/J RB0Qy]> JJOā;5%&(uiHvCyW9 1L5Iru +.C}ȭ:A"a)?Ǖb%m&M)؁ +:† BT@>6"==JlBaFidDZ,-k]H`z4k_#( iҞ~B*9(~0߸ze`(_$@+yj&-*Bm!gmRVү_IJyaүHr,K Ohn~<ͯ=Bmi \>[>uIf,ޘRRp64KJs@)Ę`:Jke̲6 LKT&4޹pyŵvbnl/V6$j]- _͙w\-+9M +qC]&PJi` K*<7 eTeS,~YMqE'KkLv<Ś:gD!#u|HtQUoP!O9a셳2^Dϑ O2\^JֲRJY#bbþN̪Sl kÊVMX@^t9&%z(@MŬ/mm-"O&DʪPD[_pK \^+.(*24 xR[C|ֲV|@ v;ƀV}J~艩jSm;n}1?R ʷx⊀\N?2${NZdI>18Ҧ<[Uy%&*rj?*jsS)iFJS +.}~[u~:aj|>2RrcU o(~QkxXK{!Z/RNaup fgld㡵Ф 5T +[RnUCk +Hq=֩/ 2î6P4'.Mv9 ^&:<$O2["ʹwOlH7ˏTbGhCw$:?B$̪t, U\xǺF ڳ6)9[Ȗ3"Bx܄<m0/C\̻M. "6(\10%֔J.wp/ S)>Z +VQKń{2J抣̅3 J8N),.֣FETx FWCi&2JlI{|?M3!o92t9%^CMsr}qR3KՎ]Tⵁ11M2%G-'&.DT^`Ԭ*'k+F*V\x ל d~."cD)ȶ N H8fEo0%M+3( Ry9v7Po!XnVMU$Ͼ,{(^VbL1]ekRICiAS5.7E+ +Vy+ԣ <{ܓm\ghcw-ǺHVp?|eI|ybrдU?]n.uN@Gxgy>ȍtX.l0uli9m)#8c̃VJoctĩy(8Hc'jQ 2 P&q|ZߜGi(ĐTjI7e ُFw>tK52>І=!S7>޷8ċ_9*&?f}*QwqTǴ?zu.U#DﺐWǎOyEaSD2bb#tvǻ[P!E@ݍ1Fi|܅Ǫ*\ދ'қǀXlbz;#%'|@bnx+&fB̸U! $ \ Hv> +#+.歁\%qu!h<]bNp~yͫ*{;KT'b *d@/eXt龏E}r;#}|,ܫe >wLB͓Fы؋VeKMidJJ$9j4y+@;ݻ,+d0$v&TN#*(VI!J7%J]&ˢЖu ˓ W;G&Z ̂Ocb`%π\ѝL>ƞcIR#;[r?2Om]!2`|?^% 8GXGO0}&eoU 'VTODE:@G\A5Y4"-ǖ| t*Vsйkq%̨v +")O4e"Q)H1rT֨yقM8bp~x_ +JIم8|_lMӡHP$t$hCrֵ)Ժ<EܨKFZP#@"᪫ +ԻGU.Zɿ=Ό2}|:[K5(rC6$hmwe*n|6WP# ]4b\?4eRx߱>e +]PB͉y5z%˪ $tR@NlMH%;jUmt 2”Vܕ-bfKڤYwWKBrٰǐ$3>&sBW~ո\a#O;9\wBRҤ.j _ &Ѳ:#ߤjM/0 k6jS_ oേft!*!)$9f, [ꮇ}M}55KidIVS Vӣ]Q#j{TVԣo'\JHDX:b@ןtO1TR9GZB@Hq$+MB0kB;+GiInw3%*牓MFIױ + M) QLl-`tv'I sT}kĠ#sJ"*Z#\Rɲ,8x MOX\}$بR /cm #AYI!iڕGJ Q|v&]q7Uu@tz5jK<(|S¬/vL*֐F':9ZҖdIlU]J.e%:cHiI[/2iE.sn%*IЂGᒤ()&q1Ô1 +:n"O~u#&X<JSk 5H.:|CoG E1ou!GhtfŞMـjX@ N|%*PvML{7;wq9&Gʬo%>-I?i$sl:8ne+:Tٷ; =0:n]%v UNƨO9J")m)v !*eDyr0hչtBGMHmO5h҉d҂nܓz_5ͬ +^]c{;TۭD,+YOuIfZFm=cA!$i2RR"YRA_\ㄤ7C2܌Pn>"G?5U*uG8Ï+(&>[Zf֪eZ(cOJI-KRlE<[ǭSmց̕;PoC ηAjfQN*l:);RH*GON6aꊡNu7$&R&C3u\3M_J[u TevAP 91.G RXKh{jHJH{MQ۟\J,`)1V| ,6y3|^u@9@U՝znpf׵[1A:bš4Йh|-x7eNXZ33ӏG*Ew߿8Q&]kuJVPx\kz ],vU:[eHW¤]!еgAM#F26TMpM9$Wd%<P,H!'Ip_.oBt(fpc \ΐŋrCʮu2qyj׬P}VTܭH+5 JNߧ*QH mH8䕢?Xq3WzՏ5gFYtZg?Вib]9$edؐvZn.}0׭թ.]fC-p':1夙 ]?ިo˗I;uv_5gfo*Yp@ nUCH<`;H7oVBXףc'SiYs67{|bI8ǭJBx"]c(- NЛYI2ߖIi|x#p/ ʅfC SS'!E^r4G-1 oLT16OSo3N$2,w'EQЯDKs1ߔIuչ.^TBŘK%:WVH8g-e.KhYQCM>B"à.)*u ߽'#NQZ=E\uSL@Hyn6t_|K=s=ު[L*ڭ(,xne ԏ=OOV=F+R_>DlX,q%Jy‡*D^9b<(U&lw>Z)tfB{/iE8H7ix~b]KeZK)*QE/ b~-vӣ+(Lr'mB.W_:7BlGvLLrرNndfmbw(( I?a]Q2bgAZm +u J7H^0FrdK9(<@\"ײtMВ@fOkWhӽpv]Rڔ75c}v|B(Πdes0ʙCQl}ScnYSN`0/*mlmT&+L* + *$LatS,=2f8RqU78c+/140uirFܭheiE-"q j*=cnZʕf%D FCaŨCAx w,*H곯8.òH菦PRp@{8;Gm^ZkAxENB{~z[1CzuVCt|w>RYAn-i,.H}aoJ ^ySq;24@\FAʹ:>|*iGlv@TU(KQf\h*>*$:E(R g$Rz{}P- Ƕj"GP9~LJ|:kgy @ByJ.H# C뚘H%%V.3:Rk=pISüqjSkT&`$7WrO At> O}S8L~>5)YhFTvQIMPu,ք҃)7gW2}92p ֍>\8_%>zܛ35btL +oYP)!o2na]*zY!Rvc*yl[0꠫T3>ɖ eYӵ|NODa݀Nے LY~Dۀa:OQT+m)?[a؊8Y$Ǣ,漕Losvk)1!>}oÚ*}P6}1t9ښk_Gq/ȣ *Wb`7f-/CQR~#HiEL=xXvGt>o;hb4]=KSl )_ݓ-%'bRoUtI9h]5G?Т!@qa utud >&.N\%Ziǵ{ӿ]^;Co“D=QOS,U3'+!8m:ߢ4]Nً<[Ѹѝ/$<++5ԗ; ?#06U#PW)vjN&r7!}|afUd Uc@w|K6 g12'WayTYmO%l6*} ڟmj#|zu

    4) +VgLpA*}ބnߐm}^\T8k9ەN&+%ZqY֎A:^hYn +3p6>p;RD|e&790&jŹD'$ %;ONuv; #Uz}@hf"4!pվ¯#jRHRr5㡇CMz.8z35G*y͢[ZlDn +Vsho̻FUK9?x0\Bi"6zn4ShlnFcÍofT&e&gn}5.q Τ6stIYvyr+UY[>ehF&߁<4rZ~Rl͍lXҋ꣺][^k ; '3b`$ Y*Ӊ1k:vM9Rι6nn)am!i I ׊u!+ 勦YnA(I %$Y$jIOL+R HݨH'ܸZ7  TLu[a਄g7Z~0hn@Gbzɟq[}j唨p4 C J%Ip.`rԷuDreZELTPvDإIۂ A3Sh (fӘh'JU |tG:HJz-luwE}B3.]ie!}VSL!ݥ.kjW%*ybhťb54 y-}#O ~LxSm3U]Au).BJB D6oRf(xS|Fvr_j!LE j~=0՚Fd=WAzfeI2}")t-nZ 'wz-BS},#0Kò*uױlLH\y,p|W(z0p֬K%BСbA9GW,:ĥ2T(M5f!H^)Ot+>_~2f]EL)a]F\/qFuE{i뱌I闣88^]W.߲M7Nrc30ߧӎ0y*Rl)R 7":Dige; msxqa6Qn;V$fO 0ߵU2n6Ln)l JI#q RT'I ԃvWw硇a4[+CqѣǪtSlE{#VS'%vw$<\9[n% À&ڍt$׈04t|p΃X1+҃SS$]-Pa!.Ğʖ,R*ִ6K> o"Rf]%@wk}MíOa'6ҡt:r'(Z[*xCMn]/Z5s\ea0B؎[J[J&ֹ')R)ɴYvI'a>~!$ثř)R($TI$MvX]ixHnZ"2Mkv +RA< KT)lٸ*lmӞ'Lr?offZ$V#-d258I(~q 7"ڶ r0e HU4>n;˚ <.svFF-a`xZh2c5MeORJP8J7QĞmIJBwqr<) + +&[OR_K8`λ75FRYG56ZcWg+Pr֤SeèZ2rya逪 >d@}ח!K&GۘI1􈚿'JX;f5%MR^MXYF]y Dhe*{HeǛe>"b;GoEpO yy>@ +섥iI0p}p6rQls-̷4O=)?Ľ(54i`$U(7uJ94*BK7P=~p&}/B4H6I܃a1+Ly:&ʵ~~1?U)MH%\23.-=hJuq[I3I}nKM{3ǟQQZ>eͥ})pxn+q&)|K6J\YY]jo 98 *^gi u]n)$蛄XWt:sd:RdH s ږl$CN&!4l Dh+Wr5uA|/v0߇ Ct+0 %Τ(qɻmus|*s&QĈ_M8`]Pqg}'ZZs)u'q h${6u:Nʲh)eHjY}Km~$Pqa|DkEc3O:. +JSۿpa'KUE ޛ,*Y>K˲nV@RB': 82Kg"'eImiاFs/ɵ0E]p4xr@uhKhF^*5|$2j&,͔YVZAVro!IbKLk;ZAtMCIJUh<ʂFabYr*ňKJb6$VX +J'Q,-"btf s(p +_~JqUv|YN-GS8}y=qqO;-MEJP [D 祥~smTJe_q6HY GE]UI%$꓎M/Q'"lN#B0-%4: 0vm$imw|7V5d4\9\vGnw;iʩvhGRi0qGē~2,;+e8kCFmI-d++p_DE|7u~0':'.\I~%}bG=huq{Dҿə§PPIpxrGw* rqaV@ 2ú^~^]%EF]@_-ݫ9#$0e + d\XmgZzZyumTLj|ba=QXIW TW7ړIj"Z :*ތ 80<+aKc~Qk\Rkis3z3D źlV!"@1[ /vG3>"V1LijeOy='Qr8Y[5[bJxUE(%*qQ{{nZxɑ 0jNnB4d!19V}> kf[A3 @Bi&/-. ]J \206#ԥͺ>5I=9FT{ab$͒RRa7xےFg$']ZU4A-O,krSjE7PcP2:܉^a\p@)Sgi@89,{xna"PrZi:\>XQ9n}T+xNs51Zz}Sr4S% *ZSb@|"}Nl\$K(+7Qk5ꃪj~f (܆r-NsU$Fm&)Zc? IP*h'w7*4!Xzn֛(JTBUx KiF]"Tw$_nWXQ)~U5*Z,FR +$%.c(f)ժf=*B\rCRֵI$O<>%@m% NeO3A)L-)Jd%%6xJ֪N2SSpJmn**JlE}9m]HթR&il/Qԯq_X.7OdҒD$\s2%P¾JMmя]5T|jRHӭ_)O?iQ!2Krn 8?<%.[+atD-OO.b ?Xx=5&]tZ[E@$ |'Yf{4v ޺eNDz ȞU&]~RBOP ۇg%Re4ܔ)9;@kqG=M"斔%AK9?8P)Vv +P_hV( 0a-G  +Cעd|z֣T }4ȊڧSex 'iVTuG(S }GgIx|*W2QUNǑW RskCS kgiJڔێA~}qazK:k"ڝ[I}NΖ-XT R `O8?|y''JLOLL=*RRS)D(x#?+tR$8Im))Bn$ryQ#6ݛ@({ uA n] eosnRL NSval Q\Ze?g|ّT4ą Бs#rl; ܌2*+%r[+R@O'k%lmms Tdpsk)C,[|QShhL\wMUNxG1BJi-ï6ӌBI+YJL۪e)ŕ-b$ewӜf0AIRn'FX'Pcr+!$RZICfVu:&nj/R,l\~ s[WhhmݾЅŪWħe6Gބ-pAWM䔢I::QbzanbTSd~S!~CɱKa#wHO& |P6Y?4{zdr #MO85G]k4 484HHS{@ܐ8[lgQJ 9G$6bAnMvs-7Q—P[JV{v{+R\(7%$>wEȒHnbmb]miaB۽&ypWjAf6k-! %Pp97>܄նBR/G}s'е}l[O[Y&:U&Wb__ؐ[j3MMe'>ibI!%(ou8+퉧 UA̤fO7~5Og-Y~.CHJ*; kHQwqWIb`-ɕ#AĝNθ !iT-ڋ'>RMNMWrޚ暐~&t!I(RԀ6q1*ľ % +b:k㹆E]L.e~L!4S{_AN:ue*Nem5kjPZ]2Mms}9*J#Px'Hk8B6V7Q֬I"#: +/``{ǴaY͐Z6SnepBu ƤuȲ~md>l֦ !YTBR+ɮkơK bk%$EQ"GdC- O7h) Y-!Fr,(v[qozT\"tJBB-| V$,]7%'̡͘xlG%t|Dl +77ZҀO +:1jCPMpeA-lmk4FZu;J~<9Ύ=|4vg7U^PF شUrI}!6dYCsir9f<ڧth1r.ʯR>e)ˣNaT7[?^&l/[AM3녌)8d=[zEj1 Fqț}Z>yD-)3j%}]Rj+Vy}q6hVʚV5\ Ffe=Ŕ{c@6{*#}TH5B|d{d}y7R9Q~ĠF6%݇̋w T~*8ꯨaՀH*Nx.ib/ĞAR64.q$^&#iοUs!8\ʷ_H>&1:۱ԭqpqV@H: +Wye6"! MOC/SZJ|GR aa7T9Fe |g %jNJP;dJvCq+Y*zayYʭ>3xW(w-`<>'; VF@KH`.[.M\8˟1L.Qah?,̺&P"9TR6ŧv{:7#A yUd'SQ}(f7dլG-ޱCK&RBTfXA*icǥ%Gp"#1iNeq3AuɈ5]y{X !gW-'REڜ(a-ጟ܇GZ@  N#I , /Іٴ^7w{z.9SGH{&uO$+\󵘠gX3&騍Hf)ǭhtI 8qL:9ؘr/,ӓ'?t.aj}E_2Jas%>\ u }cv|E{{Or0 f8UvfHt)RqNJ (RG#ot; g鳡rmL+Տ_e ~Lq-C䯰'a'(4EWe_L~$>ZßJMQ~jb̽hDмĴ5NKuHk?eo Ё늩~L7l9ի쟸Kڷ kE}y KqNIKYڎkM;XӐJƱ#xIJ;+Ju^yQeAE7Iok +zǓfʫmhN)e>\~|ZQr Rr(|s3VNYffH5(Ae[^-"Nh>fIVD)%JqǴJJөs8^ELI̬%GQyo_dc͍e:G*)ͨrI6n$!)#>UL',˙qk**TS)JBoz"S KZzy"Sm2T)Y~t:eZ&iWS・!JJAelٸN@.As7l.mx$K 6@p4']NNphNW]r\Q"4ˉl$IIu3k8 mdbu _P:-sẒ2oY] +3Hp;%B~bUЫtj&G5if"Pt5zV=-y8ZZhaRBU61k7u@̈́jЩª)+p<!`Z>xyY]}-J^&bܻ:ҮXp1m\AuL*B'_tMcT-P1-vCN#iS<)!+G>1sL ).t=$#&--Y +?aY$-MtS-):6s$5U m:TO$Hhf+ TG_ X.3! mk=b $ v#1 hKI&@ie _DuQ.>aY)J\[JX$jUT{VI$(Z-*ϜE1*!E) k;v;A/O8 +2܅34ȹU}{㏤k=N-俜`[:ACMC&H\f>2K+7 CFU^`HX}K*A6XI o o1lbU2-\}a +}@AMO&h"?{FNe6F]҇͂`M3` 6"jn}m!6: ) MU |"txU̴M H/Q:ѹbHnCu) Bލ=#+I7^M4 |%+=MQ5 ˛L2澧*- mlcaa`/:$kvHHH77><ɉ%40zμ[\ /*zZe %u"H'XAޫƔCWJ^z3 q ZE lmlxLIK!W'_n1p*enl<6CŘr&knMr^LV=&"i~AJZnrAmkJtj֜eRHPXB{Y[֮OW~.Ch-()#aqC5<9cSʔ +&%-{eCd۵%7#[eH&6Ru_+e]Pѩ&956]1KAņ}AJ +) py^\e/6MHq+;KaLJ14Ӎe$e \ a _U镝)yV%SF:mII`>vvP6s^'[mncUZ..S +'R(yW^ ,zmxRb^eW+Aϊq9j@Ȅs +lM)gY}!@G8E[M$eAG(JSbma뎩EG*.8e&ݪ(f$ =tVj.0YA[9a4[{jyֱ I. xX Ñ : z++aF)S榐ú4İ/B.us[)SߦI;d[̓JI6Xqm)M):)'ٗ~9E:mT)5|uK,YsE$lE"5=RCyrjn}@iia>go3 R$hʗc-v ʎxgfZ\]ny| OiwP$B:`;t߄7\U*P~@!l8pu%$0R^K%Jm!f$-s%FÔZsta $me2t~tpUe" έ SY_>R)m ~m*JG0'&YOV z6#Y,{i~q=Лiy dmr(Yx71gYR?6W Q;)-hc|!Ze +]$Xit[5YLa$I% I[ 8f]fF\%!)M! [E[rjvjKI[* @$@l;N +۪TҞ+_14Yժ[M}za LiT7Y|?],HN<'psnzᙁ Ql=2/fTSkᘳ̉~H!H-I<A#IYҮ q|3)]$ +B؃KN:kc2pTˑف=喝jZMew|CZv)]BG+"aڪ2H%*a҇FUC- zUFR즷%ar ׭yWKY,ɟTxol+J;x1 +T7 +^:{/E194Mz*6;%ė$]J>b5ZUI+*=z" v>,"MM4'UMt[X4)jQ!Z#O??]Le2KS) DdMt^&Y +U8R#k DZ ~ãZ#*E38 (FRIHnfTkr)< זdl};$.gj-8 o1PVQ#37Z4Aj؎a<:˶dUtgJp,㩇AVC5ޙaB@d⯄RTx&g-Ҁ*EzF=C1oǠiihn֬E&`@.Z'.$2RG6#'qMG$A8R76H\ee]{2okkXpN +sFV!=b!@^ ^z{*u.(qLC +z)T[r C<;]Tpߓnb4;ǥgZP`5~z;pPqTs6΃ŀJG u:Z7UKMfR`% xԧʯs _ҧ>\/V,$*{mnI=^Ms,y\ k^z' IƐnڢ*ޤGtYzJSMY+#aDmόuU]m%܁{&+RR$:enr.ױVYbPO%NG á)[g 'e.2mSm\hխn ++!@ #c~< s5-˻TSRQT"sJeK۝8m*,Gmx\*,8llrx_6ǕWè:GB +B8;i [)re]q|eo>l&fMCIH^aS ;'+Nq :HPRs%Sgz,5my%Vφ۞ZB ܯ%\¨JBkT@4ڶU +HM̺U+A$ 䁠C:r!gB}܎ IFV"RR.>-}WX%UR̟EjDg[GJ+>zc#0mf ~d|l,nM0@Z+>\Yƛ~J5Rfi-nvFR +S$| TRI:..=eIsBz Lxl4>u!@kq,))}SEm6r c{N Bo+p'V7sRۦi)o}Z{RP锚d!萹 +v)otoDQ`9&%Z$dytO5.\im7J aJ*R\[HNeZ^vctXXr]53+ąLqPᰶWaOU"*-Iuˤju\p̮W2@_}oh^ӒWgN؍0*P{k~6$ 6Lf\0y)Cm]_ޥqp,,)^⺩9 ۧ{ߗxlh#x.p+ quYyLJPSnv%$}mK£ܞoq.G 0JTʅ]"As^<=x|_-goyVwE qvmUiģu:Gq`{s.w_dLO*sroRN%U!(J>`I+t4,ymlzKL%Y-QmIq @;:& @'_l9e ȶFpE/&gIeL<ˀ5Yq[ +~Kg>nd۔fאIM K ʇ}h=.fV p+jnaCX1٧vY_c[H~a:vW6G+ߵ[M2d0 :GUEYlc?C-_ +WW pe**&ΝL;l"<# +nӽ䄚Gm_ rg9r}ēM6:el?L:~0 G"/.W+CwIN$j1P(#Yy{W],,u&IT#h&}A~}?'׼ġJŸDyt"J7C6*cފǃUq %ri/aĭ;_|i +C@{kr,l,s ]jmz;(Em9[Ktm*o)ltXlԬC5`s'a8s4Z ~\;07%~=~?ps7dK̏YZE[{ܘ轛>=d7\?pMitBҒ- +:@ieD̹|{~*Wg*!RRH,y,ps!5|#FpZm{k.HRД\J-a|@S:Dp#:gURL MR쵀y,z}򖺙xs-vPā&>{ ])ԩ@x){ɉ;)\pUat' veC=PP<ϙlʅyq`bU{WC"%j"f}SvFҳ?Qb9wO: "R#qO`ڄ 9dGD=C~rJ3֕VgR>EAʔ6RT5Nd%@>kMu<>>IiE@ʯ\h<5K PCsc6-t̸`AւR줎{dósj>p )7]hѩF4.n0:Տ+t(ZۥMzI2<쐢c=+\†) +eK~Ocۘ-X'coe\ZIBّ +[|' +rlx5W 1&JA1 ~#"5# dԏTkHRrRa}N4=NFQM=Mb/˰ w LOjO:#(Q%ηs33%5EB[`J*LNKI$$ԧM"}f$6]]m]Tm#N>"rPnsňkhYPP +RBFN97A4ӘИpyj)-LNvД:E&_8Ҳ"Ȓ3 d~rb+X 6“/DH6;'*,4Ck,4!@% Sxe6~TS +\as|NGNk.p]b4Dh)J7ŭ[(GYWM5N;)?}j)).FR Sغݬɻ/0pp%$b9_%P]Tq#C~ 'Aj~UK2%+ + _tDz6bJTmTOjΤ>ƃkDJP7c`=Iǝk8mbI71ʳ*LgUn+`=,ia3M +\h!#Cu mzk@&:LɳС<AWl[JMVn #8o=#."\pq-d2躍M2%c&UTDIl'}moRUqe{a7Ge Vz:8\&Э 9y흳p n X'H4(5EsRۑVnYAG~]q- %H\qS- *bR_7厶Rێ7DUy1SUb#'ZWi9ޞ8xIpxE y)'Fb1j'RSˑrcaƞ]*kFԢ\`/{'#>cRP y"U([q)MWFG n _q[H<u ~m‘FI86U 6\(=0q2xE4;|9]3u]z_1^I;C+me%iqb/T٭p25ȯ:}GcxSzIBm,$e^-_6K21OfT4YRci7nIIm߃+\2Yw$n?tIfe-n*7@I!)l1$ij7JBĤ$\i ff8YR5)K&PJBȽVHgP@ +4]7LN*7Tپm;_Vz:id%e[]BRS@"*.uO.fbȍQM-+j2&A( + r| `j<ɑ\Q@YJ=}cgCr;jEƱ;~O +U/Tum"g#l,IGKC?izXN)fjK~occtܒ0䷜vsҫHbo|V?%I)ລ _i +||uON=Ouw1egDCu*4:&swccp1&cV6P酻$(q?05[ +eVP (\U}9L1$"TUl%MUeod4X78I9NJBֵbL)>s{rB$UT82IPI:8j*kNYyԖ nM;#弫iFThɗ)JR#t6AّR.5|Ю%K +%KJTTnWQlKfԦ]B̮:$h)-IsaQYT^e5J.5=ռ˓l!J=Vtd7KHWm!I G6^'KeYJruRTK)%.Ϟ0T!!DԻ^|"/4(Ty#ģїHHdqeB$IQs,hꤴWKC~[:-C]ǰT)ٳb,"IWkv*윀ZTE}@w7:R!Gbl a + [؊T4fy@wqo΃6PjUAQUζ6#xU6i K ~ሩ&Y'}B<# (kΖ"G J!HS0m$֯TJ4Fjo𯘲[V +E€EBiKT[*ΤlPoZOC *t[}(^ |O+']qmLbH*,uz笻)0PNOGbiu҆ҢW&YLk"\*as{ ;~MfT/F%2Gy2^ +Vpr:RU1:]^d.mN G`:t[N,*u{Ё  фR 6K0k.׵Ǜ*fS[-2JBT8x^SZK'*.MI}0s,{ a +n4փM)a * )f={Cn8%?Ā%(s j&?-jZl4pO7aډt"_1Cm3nuu<@ޥ{Gfv);ẓTwv[Nuk{y%ɰ3Tre?|*]fb$Oʙf8Jv2t) @e 8RTK-ҒtV;j$ NaKazÝzB$eм5p@SIgdZPKңP]Ta}JxeiPq7qi m')P qV# xCٚoAMR3mOt^JZ*EZHyQj(R@y@PP؍ >=etc3+^|E]&Sui}g!%_c-6"?ݒq9%%9|idaN9XXz0EEIRPy(),'טa{_xDA8jl.I~2-2!0bRRC. |;kxPdzil)cfM}(NJ-E*x(؛"mxCҾ- +J$70T-:,\fKg7Qh.u *L7VsRiCA= +zZJNK x{1Ԝ f#/\D?s%*Ui L&U9\ ' +\լYsSs6NNxhER{Gw Y, UiJ@SO:7 +kswRBM;VNq Q$%- ̝Me0u;.4FMRlU’ػr k ʣ$kErÒSKjHQQ*%q bNe2ns1תRR%3OJ:}o,@ҧTWgQ[r'e4ϒ̏7Xo&Mu@-GTzu&0n=ЎejsY.6eӉT If e[ R]a4l7ZjEr9e cN?L2xKE>س^ڔh8m#$2);aɽ{bc[n8ā Ą1%:LҥZ* +'!ߌtn4 tlÄ}K1Aqn/$!DؒI<:[BwQQ`nI$D4׳(̢u/3C :Tr*BnR OО;&BJVMWƯՏi+³euuC>h~8 +Udϓ@fl謪 u Wth&LzJ7ڥuIIW7ZE2  #̣rI:¦$S؟"U͠l6`hwAOj]9ZRp{D_QC`xM"Q>岤xte8F#i˞[Eʲ +:l@K/9>;qSY4׌v +ZcAw.*1Je[+Y:iD)`vl/~5$SIt,sqBl;w#LFyeR|xZsqv+])Svu8C~Ko {rI#:=_LY/֑CKFʹ'_#gK=J6IQ %W:N^m)S qߞ4/tN RK!)xo6@d?w8ul@ϮfuZIm /}qcrny+i]?W46q6p*I *N8Fg-6e/*x{wDMMԩD?qRoC(4hKO|Oܤ RYakm$xS$).7|Mx_ u'{S +z7GUC$XiQd<VJ $N}m438qtrJMx.Ș +EՁl A]'*8iLzR| }K(LYJʵ*?|%=:k+[rs~ #SQi2@|T^ڃ@!6ɲ|x*NSaTs7CZjSNK t aS 9[Z(i .9VbdݪIar} T  HMчkR]fCt,\fGt6*aUgCQOd47G=U>nfY 63 +Q +k7.^)$Xۜ;k6t,ZM-2RABJ +[;%n |JGS:ǙVqsn)-u(yWU>J5?dE JKt(lr^ֶYړ[Ol֤*w#E]kIJH߄4j8R u6J[R|/E0Et]*B8̲)d%& o,N2S[HrZxT 72bBP.˹iN:ܐ>XUJd)6P)H"A 7gUjOy(n~oUJTqn#P,9@YǐشP5" C()WQ૽_iM)jQWQake9iRlM-5uNS: +JUkcma*4]?H)m-5* +R +>P6]( IIe}9za{,a!t8L)IJqCB".;%z-u奢W\5OGs[+nIXqڱ3f,CKcK1*T6'x)~`a;XYKs2řD'DggF +!;N %hq *'+A"XTG./)ZG)#MXsQ>iTe4~]ކ uԟ>!sKy%IdoaIx)j\}+*{a4C3q^ZuTsOaD5zfG?m'tr;lxzV>_ȑd4 1u7$Ʀ(m-jROkS'5o?!"{t}oĩ@I4yCw 6 Ro@- o2)19zo~ycuwtKuo޴ɧaUru.gc5`dWG<$sbXLz0\BMۀ?c~j]=Pyϯ~0[3F#0ꕸl\!4:$}QRG1 c\ld?b +3Xm",D{YA<|!v OU-I0pyy*dq[u0I &Lvh8 n{}s0q7$)GÅ[ 7w+~qU**qdD;%PZvt*] s?͊,h#]#H+2|,a?PI|PxAbM2 +P]M樓</=cH$-s_KXп)J\)!_q R| c눯H5EkN%ƛKSjQrW{>؀@mY^ٷ N:bԲ<±Ŭ6ēD+}%Α4T{]tLWmW =+6o}Ɏ0_*8+`$d@қZb4 +NԐ6I%hS.) ZxY"yb k)uANmW;*GV,^L.Kx^y>cn=%Mx*E;b$2XuwoT>=yG?Lp{IOnI%?t4]s o+G j8m֞L@s*{!O\Ŭ@w8 I,W:2nQ5Ԝ۔.q,?֏}зH%Q~t8szi՚9HtV=˒Ly)Xr{ys/>YOꃲ +؃MZ5QN۸4q[Y'If,%M86S6Y^ \.t2^լ=Y%9W%kmNQTM_%` Sj;r-kwk5<,r[Yσ ہ7ǦڜJtdR:[MH"=3W)ASu3Kvk˒R-‰ 3KT\dd)IMSmwo.B + V=d1CJÕ +yt* +t-(Ze UPY֍h F446o+q@su(ܒpĸEx 6aH;4I_5_L9gV+Q= h44O\rB}1ߡmԭ )L/+u"M]גoa+F^Yp}bׇ+2L)@nZıь'rcʪɝaEIQ3|{J'd10iƈMUZ&dA[P $ 9NM^y y;OibU$m6Po>teBO& և -20Q!J +R7>4ElRpc.)a$_f?TH5Q0 +qP.AMܙsy9s2Wx@Xi-{2~&䛃dlO;k ^vPt%)׌8]l<,t%)W&S@RWV x^jjbѝN'G] w<_ =t pn-ګXʈEI#bFU}C}bw .26snIPnby58s2IRA>&d%iy˶.efb@B!VоOވa3&kSZEW"PNARwnB G"ضUe*~zH$@#Urըu:"SaV(6ԛ\k#ZMVpғsHl|'IWWc놵M <Q2E{/ Q*ۛߛqjj<- DYf \kZ4`*: Y*Z<'n h󇓪uX1!xa1C>2PU>xAm +ށx_aF7uHin'^ll[ dǙQ"ee7#S} PEF.9ORi}\BBʴcQ􁶚F8jbUo%o! a?қJ{ jx›.>O~B/YaWVl3(Ge6jXe4Soy[PۖyfHI$Ml;%gSYP3)VQ .by^媾_řFE)҈< y,@ BÊ)q4nÍ䐠v@ @&:EZҢ{$iꌙ韤j0 +}BRZ.[uճ[THRu:WĦYȐۋD>i>&R>g'*h34PR +IQac6]Hl -`nNb4Kʎ ץenٗK./*2SmZϓ5>ꚽc: +b6;R96,>XNTNQxiNL7'r{͊-'Hy|NbTuYI/ C0j4fZrm/Lu +;c];gzJ5fW.L{~9ʺ[6dfPz"rK Le6g&T./nO}GHQf1OTS丳$(>xsrN)]܄%wES$R4-%[ZA҅e uI̕ *t2c4{+fGښ]HҟoƩ @Z܌O+{!=8 )+JBP:o=Q=JhS?ZX%E.0>],+]D'8Wso;L\C"E6Ԃ9`~4FܲTW +,W֧n"ڑaΫ3RI`c2\ +i~jŏY!0< p:>I:‚87+>7oߦcmMJ+\a_etO0NKoV?N$,%x؞&|CJ4D8^qloR j@5Ob132-Bax&/7‰b]X3cQ6)'u~z5L؃k*uE ~D~-H +uCBX,foM$؛pr-hZ߉GcTVLN_ &6 a%K\060z򺲕,;CVY%k4Lex&,Pu_:I,94 Bylpu[~ēʰܑ@..F`[+p$v5۲tQ\h͖8ȩy6,=" kY]MI%TJ ]@*e7]&eƄ]m* !hS&؎ gI)ԃxV9ymi9.THII uZgL)٨zU>㨜Gu+ڧS`K w*aw(#VNPhuܺ Yj׶G8ޏ'\eH4BTҜP$F\["W]BrsF+CRtFiI)yԞc<`R]F`9giNw6.,h<Ūc'kħVQL$)k w""w +֪U%V3NMF\;&[u(~XuVȗm-la70ڳO- TfeHm)M) &?aEM,Lä9o n"ҖphGh?bW%o2Rl;jLK/i7Dթ'\Yʚe R+.T) }9Taʓ4C! EPevb\*$ ƒ8zfdŵ),wk78BIkKR8QD@z!W_K|%V&[d ?s@F7B_=F̹x9'0AOu{Hx5It+b?+e#lO}t%fԞ3QZV*iq]) +=X|8+Mΐ|CЪjQ7Hr9boLY⏘~JUQ6$l7 +A$z* O8= e RG)$#AAÎzj]XIMao#/hmÕֶӺ~̰3&ZqR2cBkv* &n2n +pU_Lu=$I Ȅ-ThZա |W +.ۉ'+6X=qVul9EF>=(H78R6edHRAIJӯn8Z7Y:9OnSJɡ{{Fhq`n`wŻ9zGsoA(}8& IHDIO% @]-b;BZF2 r ;nB{;3R-*e@)6xoHJkk#i7*y6&f +kOeOe#˪50zܷ? rې{ Gk!fZME=ܱ"9xfԦ p?B iUJt8Y,2↗'Bu F3ڭJ5ɓ ҧɹqkQ=:+Ea%7Ԟd )t: 7hȘ`Ҕ.Պ%6O,0bT-(/rU qy$hA7-XRo"pNH)$)9ΖEfHeCR)0j +땙][nՅie%7쨕BΨԜ3)iUJTʔv]RaLuǓ6xfyH&bp!+'Ϡ$В~Sa/c !Fn̤BT-E,%Yn,o.*FGf;K]밑`_e#^KI˩,ͨ0n&0Ur1@DŒu,cr9<‘"k}hmxc+(iV8 YqٗMnR5&GQ4|:k2%sV򂗹 iK0U'*3 o߮PfS*zbΫpT]Lqnf%.6BTlNk}ĪxZKKlDMň^ $_>xvgsiw$DOX~h4HyLdMɆ깫4 .mf&STq*=A'+6Mvrv譛lsGt5t)j</ ִ{BT)9UIp_&BoԭEdwtpŸJu6J#Ѯ#䁺H& G;10>ۈj8JJ@6NdzOtŢ[kKDd#Ǿ2u%[~1Ū~ez+SkM*Dkl\! u1l: ~u|RICjZ۹FR^UB[ ޹r9 +C׊Js5&~lʭ ÉH(ۙYiTY +(( +c`Hۜt 3OiK+LJ .ΎBqb[`pF1fθӊPR ^܂R2H5Ou=*nO#")# o70f_eV`,|O O`,oZԑ؀DŽlQ˕q]EŴ8ɧ\ɽ9(9< B N6⳿.J!:$!$SpA`!s4f71جTP[ !GxkvQM;0FU-ӛ0[a4eNQ{<={pǸ&/!lTT( '[% h9ƧDaKb@ J[UZ6gx$#)h.Iƒ 2`4TUDO.fWƲtq02˰R+p%vF:GM[%DNe#iFZWߐWGڀFH6+ f0}o&PBkI/"MM=TdOD7/YBò}1;NTQ*C.-m8o;h0P@S'Of/?vy^mSJLq9 +H=MJHhGzM{FZYSrpY_Rf4:bVu;K2PUI{sdIF\m: :m{Z& 1:nħ@<"yMpIT])[Xd upqT)߯8ʔ6o)%(I ؝S܎Re +Qej|-d۔WZ{( %^O5rMoZQVR)G ukÜ@^1(:[{Bݹ .V7U&{m%Fj-`mkqn}yn: jm6Y)k9[]6} j6lcEJ$AǔTHhr:\ĝ憆$e-uBV'} Y:TC>gܥiMb}8/Ԋ%NCWK"FE%Zs G'WEdM^aB>`Wϵ7rm-'Oꇸ UhVaDԴW驻銡j+9>e,9Q`-@jq%Otpڀ!u*ąGԴFe6.:aqch `_|goFu_O\N:6̟|UiuI%U064uH|Cڕw(E<QAn2O|?~$:٨׋OB)5q{=&iHPmFPs6^9ՃwKG_9I_qXLLsp#=l雀^@|4p=>u?A> tN= +(/lT\*)P74W0f=BQl+KD%N^[񑿩Hk.؉OXm]-G'FgYٹoOKڼ%ʢJewˤvM:I;\XčZ:"?^{Q5U}t~zy:;cG_ Ա:.5_|8@ژN9S;'".HԀIR, +HbԲoXyH_|A#W';M<==bRk{l2. ;~0Z□zbG% + +ʫƎ482fUqu jSk|cC4uI3Njuif2]@P(^˩I\w´Zx lsAN+Խa- N9H(Z%?/!d(_Hɽ9,mx˧< X|c GVɎ A.sA4Ɨ_Y_ZCJoabaY)c'T<+Ia0\4>^NKc}cWDFJjcv +Sqt-3]~1)i! LxDUVe|^\437*?qʇ԰+pS啥k8ִiwD۲IupoC5L(})se=fZbm9' +',a&n]^?$xD9]M:y똈ʳ:z}+c / ܥ~K:#.(^1bQR$xMgx|2hxAKWP"%D>Q91ZQIJu*Vܴqd%%"VpDdjtw:앳%`b6JnKbHH$},U<1 "\YX MY[⢇\jZJ$M1vJtń|H# EL7:F`UBVe&.?m˭ҫ6 +tXmH^W (mNJ*ʾ%eݤ6]Lu v-UfKnEm)ΚóIdhT*N>LTaKr )S\8lDq?H\w?#?3$З믁0 ǯCU-BAE@6FUXWm`whbi5[B[mjNX"IfeY\ Q\msu \CܷZ)%!Z(cR yכ*}kByƒmU-am?dqJU1c)rBQr@EЏMz I&3BI-6,C(hU/D TwRKҴRoǃlpAXǶb‡ 꽘Qt[aD9F;&# .%5[RǎI~N&,fյ^'P 8!C1?8kl4>3#<a2瓺BZ[6/Oh۴U6JD'"fC>#nF{G|\"T4}SGHB{8#lSP hXmBaDa~Y@= j,J9~N^JRj$G iRVO(H$X-a( I:G@%au?P+ol[{0U:nN %5 +ԥ'~C(u CL-*M=MKYN@dIw:CٖlXq g"B^C>=:\+' kzT+3)m@w#e\Tx3PXN^:/NI-*)m6.#2вn2hdɰ"KARyݰ)1Ы5G"Nucthr'{_Ӧ jͧj;6nL g)U%33!Sf2hB9Fxuj"YL|ZkydYa7<b:b׶MY !'˜;SVCutVԺ@*'"}"']se 3⥖ݥTrAEi*1 ` +ܻɔRVT;+v1WQhAH$ o3 +Ifļ)*(m,moBO_Cj딪M6Fۈ,]^*I>Dm%] /:({ӈ zÂ:ԒhmJq$j4 qPYhb?lkK)*WM T~Bu~)w8іp[J>^& +&F  kCjiݩXJWڠ6”\om;cKbJ'MM~1c]MvM3+M7FLFRd]?!ۣaN&Α=S͢\u'.,4,JTY27(_B{Ɛ^5<Ph2|\6R;\2c҅cKZGMfqhxzb^K)S/&z$#Mĥ݀ +x}<鍊j}*QEV m(=?%Y&aڪɿXi4S7Z/6 ԈNp jNB/ +7%eiko}6HJѦHbJ~CߘݴC[ ]"p +L9CrԊ3Zjta2L7M1SM4fmvN1 BGSm:FizZy -yR,K \oGrxi*J`:o+Czk?P7i[2ᯮ)GzuUHlj x(#3**Ch=I*˘ 34$ R[q+7))˜z&]JdY)R8LU}4#פc*j)J !4ԣM&>0:MAZ*'l'u<_銻Rڂ'R0ا&A"\:GKPp,\ %l_ۙKcieZ +{l4K/* +o8Z,O<9'DI5dy^qfe=K(at/9ĔLՙ[:ep[1#bH +@ɝ7HUjY{8i6kGmI6?#bN&Xu9=a0vrlHc3!UihK.K%BVo[BrWI]+eƣZ oƸAO MඪiA^tp\>\{̶0ƴD1J=bvWI-'@ RL(X +N$WL]Uu6Qkr>%!Ӫ)>5UM7t>6bXfNjfQ*m ޝSj͗*͛[( +RӁ!V >`w%Qm,$yJ%JK+ Tx!9/>$Yl=AL֪,^-"]B\ 4][Az4jrhdZ.hRtWG;$!]Z`u(qβY-8I[Mݵ"3|FP24¦4b9%]1*$c@Km4֥a%/6AʖГbrR*JFU \lwCe"um!! Z^uR8 ٦{_$B&;*Ž.q_%#Ccn&Q~L')3vx}teJH <%=re D u1;mHn<_\O=-WڀSj{ňêqCVI(kU{HRWrbGjc?pzUBR޸>zoݨ8|dDE(َznZ5qa1t-׸T-Y(x."| HO5z}֋˄pi4ÃNd GS6bHW$+לNePDA)ShX)&#[겞u5 +Pr:otl@4m9UՎ +ۤA]8,\}7ʄ_",OX% +E=YM؂j^P.lakD9hKi]_הm>!Rf\{1󏸂 dt[Pb?>锧̊ixTe_ qKL@iԪ)_ ] +銨{ $^HKFz. ΐOz*Z:..;!0 +˻`JIxhYւ_XGoM_J9.I4&o# +s.pNjHwJS,jon=/3剺%\̙Tx)vX@IqZ{n*.ŝN|4XWTUS24m[> - ;"B%)ϐ]Íukyܫ}C2VFep,JX◅dgZ0;NGBu>:y5L,St$7讷^Qu)턟E4HZJTPQ1_p3!L.wuR24Q" +*CJW\߈OutPUe BQEB$Hzaf$^me[;>\Ð+HONu{l0g-2dvJ-qvFej=cOttbUGm,&bVy(zR4H 6mА~6kYӽa)U>Q$U3%H$dro/1V<%WJQMgؙA,ˏcmzcM(!e<&KQ"uXv9laRj%NS!(@6 [OJsw**IQh1j6Vi߹K)XI);Op +H#ӃW1 *QIּU7 d܄n٦A@q{=%!IB@* qR%[[U79kaHNtuh6E/.?:R7"]OEm;G2Z馉?hwV +]v;FaEH#rH&qĪBlf>ˤT|7{HGQC&~Ebj +(vPQNI7 $4SRĪJ:I_W*L2J۔lMlA雩ԺI)Rnmhim6n?;%1Ye45+*rĤ59ͮm_PO73zn_WbFbB74꒰`O,s}ZPPKIRԲ-ʦu6ڂO@^1b*2"_nԋyZ|uա6BPl%J.4]t9JiëYNŠFqjiYv t&aό1g2ZTR)$rl4TۿFT7],t9һaJS2aA B H@ЅSsoZzPŨT\\.oH2]?(C)Gu)Z]1ݙl$i?BaGX23IfR-&}LsVZT +K8~:eo<ٺn4>>sXAfˉR˪J"Z,pԔG|.;9'/n}pa^W8TonE&t(^gRn55.%0Ғr8\#l >h"'|DSi5]?lgN8՝blNo閭O2V3u=@.]}j%'AN$-:.m=xĊJu":Vnbed˶U9m.FY\ G,/fX#5[ 娩za#!L)r%cHV~oˈX"a~sCirX^"k +R)r1],$ Q z 1o%+m,4㯮'f]JI$)g%mc@?%+Z!.&L$(*ѱ"CvatNFDkֳV=O]*Jn&-泋gcNdd(ވA o~s,bqu灻MA7WW>J="朻98,̊.+ipt i\Lژi=n {M-8JOsKMINQE)Ys+(j~6onTiVK[06Gpi }OwCXmX*eK2sfG$zh'GGӢJB^TMȺv樂tʚox߇|j5L7Y5? SZ6138ep)l ΙB{BV4O@>?n0ee>QcqǧKsUJSIUscb%@N]=i9#8+oR-߈߄} $Zt?Y:Dns\[{roDzϋAcM|tmHjHTs8;G,}n{87.csk$Ovn~-V;wK䶩QOi[)I~i:]f]t IOW'N-2;.@?v}ө.DiYv;1 zHاoIWZ,VZm+]{H@6a7Mժ[m*2eĝi"،*?J2kZthJiyEZ~DwfQ%7JUb|AKUKuEN(r~v)H"-,s(u*|XV):olc' vz:7ZVxڴI;QQ<8ǣtٙYոl +IpѪ|bRAC߻mxEۦ,):b XV%PyN }bPS H8[ra"NJyQGae7|KRP{2 +k#l;J_`ә(pF$4{_=FLCN=U>"Tcڱ ʶ_{vu[i${fY!3htАOG/pVt$=C__C Vϵq n=zshHH¡LS+0,(1]%ڔ"hB\\{TÀS+/n$DS~Mer\wH0R#$jFNRTFX孽=^ aJU0M:a)FN7Ląq7 W$Ζ?R }g64~T}-AUj}?$ec\>׳6vR\hJ@ QQxR ^i]Ę:RJ׵0VLHmT _ ++RG׶xkQ;!9!dF>: +J,,AØ"03 XӜj3V-nG`p[\a*'=j)6am@ب?LV%Od[/q_ i#~q'@z,qxͦ둘Mx \[+%ji!_dm~~$-9$z 3q a@{ >gP._b-,fgvY+RSϕqädRQEs2Q #vITV׺&&AT>JeY y s&%purGOJL_>zOʖ9S%돌~WrNq][~zthX qCcf>!<~&xDY$9".2zCCA {G^,^\0V -(к#dtdm51BԔnx DH(< e {s\NR)|hU߬yՋ<itڃ6yʏai7[BMﵲ{|.a0Q+2MR}襼ÖȂn~LKH,Foq "+@hcAyngj#h ZVq`)ioYGII#s$w@I,# +%fmeqiqMFr9{ +kMWiGE>=N'mŁ;$쿗44-EIb 6*OG݋E*"pLCXN=o'XeA +LG'A|}?:kVH3!QŠTɖ,HIMRIMa>ҟ,8sƄEf5WžV) L*~P<ʱnjZAbfXPG*|sUI*y(#늧g5pai^|6T,m{wc|$}c0G&QHKrN$L&!e&_"I IJW*Eq'iJ(; 󇒱/%]Z:ēAFGPѩuIK) ̀|IڀA*W:VGQeoq^`tآSǻ$i uND-%X*e5yT,[,$'ϾQɎ10a [%I{W$74yO } +TOH䛟,y94T@rM,t94ZSQ]ޛDة5<Ķ9@(9;Ė㏳ǚȷ!ZIt\rKR| (U_2y R{ŇtNtj˴{m!6ڄ֫ʻ86trnW&B;)0R[a ꔛ\yoLFjQ +Au,꣢ +~Y[ +Ƶzh#n!'ITMS+;'OdYNlMN9UR K@ԭwh*_D +vVCnը_jA3KB%[wh4i&3܃{1eITcx))  G;bơ<D N䭥RG$IEv1"s$1}$)*ƣt[pHچمEtt;65n{MB\Xc6d$u]JC/MO+MvFH9M}r mjBRH#"j]8jj2䵦#oGjUU%ŲS~)Jn;hNF0*S$j='UUH?lE&$0B$:ӠJAI$oT.\G钄6G*Mp0!(U{_0Q*m9ӸT JYV=x+-Tki֑}?O- +DxRдɯ8—Hm{O3V[4ԊT<.BMl^Ʒ䪌>ڒ)%V7qثA~8:FDu%-t7I! E1VF>|d;>,mJIMp6 m- @5QRY +%V${•Ok*J! JPK:.]R@F}*òϕX |]V|^JTخ76YXnLH8vY$J~[[@B6GCKjCfT*\|SA7&AwyBmjGOgl9^3%CԄWx%?e$aД>߫6%o +Vp`? ~S-Q*G^;婬Kע$7ÁLLҫ؀VkXڽACP/_ډSR^Zl{!P4FH&o'@gWs9Td]BnsGIm\mS2Y /M2?iJ!ĐGc'jz<ըmbJ{,<#(gx6il)DܠQJBoW8^snϋ5Zފ]iDIk;q#aZyma[%hw()\Jz.eG^<9C,en) GD H + @>~GJ wM s/4[]H U v2{+izlҨ]k'LrWFI#Ĉ\%l/{X|1yzKҫ)Xԣ;\&%+IDžrjhRBԾ8B 06  ?jR2QM-) !_h wAM5P|xlmWʭm̈́Rmú5ˣޛ+TCR.COc+-Bw=`ӶkO:C̭*I.Le{VVk@p$ۋa:*j)IqCpx6 *g2:h'%AmC`TLS( %9 پܔ\#zU/0GOxħ2nH?D.N$ 6ġJlJ \I7Q(d&@iK.%6Q:թJ]=n@B'Os0R P> .nPT=]Q6؋ $]$u+KNw)aebc'OoWQ:ym4.Nž)xQ<$EЗ.]oLs@\qPЩi +t 8i' SRQׄFzhtKn];\n,ǧܔѹ\RД 4(5Ts!qn-O zajMLXl764ץ\R6;W'_:">0쏅H*QG{8{7)Ԏ:ՕrNDvoR7.6Fen,{I :씣 $$-xYhP9Œ㒪"I"TKQ^)==CL H^:^}I:Tø@6,ێTyRPRmӖԢa- V{0bv2'YJNoյp9P$@_N.Ĥ)9#kUNjt\mbB0] %l ocBīc)߁"#4R&e֗+RPI"jh_j$r9-ĄlSe;o{ᐵ cma–B2{Kw)cR}9_*g5?'fs\lm:3G>TXmJomͬ<%0VIQ.nX}yr̀37H4yV+P..vYBSq0%[MbG(u1F}tyLYn[(+D맷fViΑ1dxX%fai{JYHuRRV9у/t 8C@!z"j +J&Ƣ0P"5nyfэ  >XX*"n;* f^FTy%CIW +TJ36RWVGK2uve7xJ|DJ}ݢ tPQ! Mկ$C'r(X7rk`oI$I1*(vFPOUoY3u%qo ۫?bt)(f)m$+*3YM Rl5tF=od"ωtyHWu+&%MhH"Cf?Լ1fL-I1$=9]oYuH6b1R{)5tѫln@+0*ur p|$-CcʦO//q@dzA"1}!=EΥN:Zd&SOmR)7|&2cFA);wKϴh^UyƤeb,Jsb+ `L׀'IWMWI"x_[u$0u$}vZ rKeT| LJXl֛!k_ŞFMJvԯ6!u IH6Ugz[,Pp8 _d{CXr]zc#$RZ:*MPcgخ[랤_U|N՜khBNsu)Q=[dX~\{yfQviFW)oV,\y?nf|XNO\S2q`86\V6'1T>PrX@CJ23d: 5tK0죫Sub@Bod^XGjCZ*c•GYyHJFLuS. 25ԨTIO az#q\[vj5**Js͔*dZֆN8I?0/:mnmH<~rRԢ&:Nn(%26ⓡ]bIzӴ0%)U>앵fN@$} +Ar2\4bm lWV-G]#w(6VDTwW-$Xqe9JuU2j^E=CrmV5Be.*\m~4b&^|b)vt$n֛M/{y gRaObBCn0 GTE۾=j3*[s?xqN彯nlLP x@Cg/gV_Ϲ|~/+ TOH3&бbR9OAu)ʧ;W!SS!LjڍE迤Yjȩoe쭷Dj."(-=5ZjJ!N f2I$,|aq\TڝJۊ%)7t Rm'9UH'i\YZ ;0f %8 +%RTVU &X%kDˀ؝Bv4c Lʇ&enu1% Y >u-KβR:$ s)Dߙ" _\:0ꔗnR߉:GxO!N+iQJI'!gKb M;PvᴓkmweRNnjH/a{a6nm/JstCʖy$Ԏ6|/>;ל.Bˉ5X h +QG"Gc +Bfy%Q,`b}>\ZUنvSp 6_Wr[+2 HNboz [j{avAnc]bkpm-fAAj;MO=Iyr6eN\$5s}RVTUu}8P +tڇZyנ (R +67]3MV ɜ~cXm A*1TRxR 8nզUKB֤hpj@#7o 22\R.A;xEt%oy+ig˚gʓݸXn Eo~ta<ؕ剳,5oUIRPP*_G{scYtJu ](DfjYvRT R?0v%#u4Q`Uc,m/n v\ZdNJȴځȕ('[keHqjKL߀Z05TM$|xZStLڛW)N Xr.?tI"ԡDGb>A#Ǖ8r ]G*G  ZRڗ+acm&B6} +`=brCr#|]Q7CVB9h,O4NyIjkI.E oXʔ!@&P%:VNn'F](p_WdXF+hnY(D˕)Ccq8s۲q"=Wκ!%t"+-90A+Hh0{ +gXsL.H vɸKmrQK:Z䀼dxn(gAUIT +DrHJ jvAMa%YH$z18Qiʷ2N.=HAdʺDH3 J +;Z-)[v+H7-a!1l~puԶo0n/`q2{>1D㆏.-@|ۜq6Hӌze5z@1Л[[TL&ˌ0[] +Zee6%˥\teN/ +}}&c% 뎔9$Z9SR5vIG7.?#.&G$mi?*ܣSul($y,psVr͡) |L)iپF`r~lI» +%`³&*3>a.ɸT]6^:[xXhF7y'elNC̥ͤĩү@ 8ibt^Pxa펹0nGOTe+ rH* 8AKs`4ےa?E,[&6Q}hڱʼn+d `ebVA:baς3Usgj5V7:U!R\UM2N lx6= ù7(0Bs}q8tiYU1g&6tZ醯5YyptM&afWu}3SRIK@܏ۺ_hdД87On|U4 ɺZ`i0仮J#RM0@3g10ɞ:賝 +H!}ѷSl2 +[zC2d5f|*˵Œ"Vb[۱(Zea:I2Ohzm$qjRGHٛȟaL~"6#Rҟ @aԞQ/uqGK~y9U_|*P%k(kT*Tq1 ڔ\[PCmQx:M(Dkb2bOĠ}J*! ܓkgf~[UnQ]1#4&"VP}%BAG(XT<ʄ-GuqqHFѪXS2V8LDZH:0,#[9Nm>J~|/S]I>utSTXACTI#h&?(}8#n]>Ro]e5_,0e-8Nck +2N)Y# P0ql3Or=F?6O>fyK#+#dO~{Ul- l(Ql0רW>DXj3#DMX7So=Y:Y+1׭@=׍7=8zbz$> YExJIM7C8J@Ɏvdq`QT:TiR|Ӧ֋nn9[ih{7yv9$(Uk, Aꮴ ri\CꅥYjn%Ae]8II8lK}'yhCf~Gh6M&p*^jPd{6>$_%G-G4hB[a}:A?H+R |djBI?( nPCMΣK(y醮tRB=1h7kTF"ܚdBJ,TFG8~$yzc)jԤ͘}H[Cp)@I pcrC, +'_Tp0-P̽'UX .)ة6%>8hT L- UϫxPfI!!X n L ƴ56*Ի=$,۱]},5EG/DdwɥHE_Ny 4Hf84́hdž.npp>dmWHӏTY(7CRa/*LKZO ɈCI-nqXG`˓pPV<7kYӶ>DayS,+ʳ&fQ֐xgӔDMonWJ":H7 ֡wn>'ɨ:ʌ놓Me s:(`Is#L̥ tnJSu7Otp* )7#T(1.RtTRtI moPC y#8JKβww}G+ [$5G)h&$^`S38Z)["Ⱥ(+#o5ZƐvYXuiIkFLE==sE +F/\8oKY;nw?Ӫ&k +ubÇdj#ץ,7/J".pxp"%4eK[ߕ.rUMQengEhHԞEC^ K3>ZO}N6TލIRTr߶=pEAaMq~6jlu7Kh4FdBڐ.msja%Zs6S&u2ZC8ڀ)R{}GĹ\=(K.TE 7=QPٲr҅ySi"43fZN>שa6l[P!C$>4*/2:d I "=N% #@GĸT +S(9ēq~}b} &yw'&w<?;6GwFROI5aa̎Ƀ)7P$! D"F\*ǣu6!)_,+Kˤ,#+1VóIJ Q$E4}}f>ZvDq^}NdдSYE6OiL(FcJYI\wiJBڕ~$ bc.XӍͩh#tؐ}a*̃{e!W j1FPny\J9V2(O"?Y#*FDwT[ #!p.{[/yr>1D N*jY%6;mm,DQ!aJ]9T +RQqD![E*^eZ\K1 Jbۍ6V\&$h鳦 +ȚrxUl0P-Rxo{?9+ΝZO3ˬVx &0uL!GꋄICV>jMAfo&[k$z=t,KeR9Di%Oı6`>z]*xUMСc~c +K02<0Ү8N~Őr,b+%eCZ) @%~ Aqw짓nϪ%I\`}|hkcX*Rөxe.9e +{=`pp6;TFD/i>cO9e +_ pOi*;8TLT&}I.2Re)=t4$x9Zzbk|Ji>6T\mKMim4<#UL?F*?1UQv"Wn~͓~.I1MM6Xe*k; -ﰉ”^U W15qU>LYS,K+UsyīRA]edLOj{;lx( S\S[GYZqrcvaI]#aTq0R<JpB֖HoX:+F !*Uȷt9%: +EŰ 7#S^yt5V_OcZ8ǸR~0P/n1*'J.  67)y8/kۈH(^RiAHiJCA2 TbRHIۼ]XzəE% V6JؘA[!It7"Bg*Js~)eZ9T`4E{M4Gx.n=P^[t99@2 \zԑ9J^54MLԣe + .=sEO?#Z^ʱGjsj]rB^s]pFf®M)!.)'+H7}e'N%XȔ̙YFr="3*H(-!)dnIrZĽ22歇г.\ +.iź^$** ɽ}Wz܄Z%`D@PiKxi&jJE'3;Hul֩M.^詐)[dn%5}L0]EZ 1l"5/ٳ~d͋.BHzE ^GZTsb\^ +M_jV,^D̦Yk,^RWXJZN\*K:SJB,oa@TRҴk0> oB IT|,YNCiSp ]j![m~1&5f龌A>]䪤3{)a$t|X,Ŧ=*<*fZVm'Cn5M82C(*B& $[|Og*5]]Aq)=! + t$[Q $Ԕm~ĦiqleARr,QQ9hy_ExW|Mmo)QkSH`] ۅ|Ksm 2OőjR+)M͔?,AnrYg*Ej;BJcuUz?paNꒆg$e{I6( m3h֥2V\ "37Jy=o6 ŴZnn3}B'(ƈI>醇ҳ;;/q{%#ʌF&Fj=)_ʅ59#=ס7U1<5m#eFi[]]-MQARS<ߔi.m;@ќ^95)iI-wB,ttq9jc0k-P7+2wZW#kL-zm6n +̈u:2Yjz{.Čv2F=շlZ<7&h"Uj+ I;zCӥАf/L!8>y)iK[Dv-Q;czTZQKr Ixtˈ:t\9ZM\Aԩ_/ Њ^huZZiVd H${!,fv-aqrR5SJ HI6Yi>{3~GTXI".WJdH=MHv{+h]sZJد{ęwtһUS.0ltG^CYFf[ּ?"թ̦&(v ~eL @)k[ss}*9myM"+Ѧ6Ѻҫڅ%W(\w#nXKGP*In.UTV㹢LG\l'kQ$n&XtȊr@?& r~w] m-TpsUY%%.]RΒP V}|N`J5bU?X25ZA庋,)f&;̃]Gqا!v\o):לr +Q7!`}Oof癵#8F_hl.+; $ &N_8}1{_3N(E!LQ&ֲo@o8iյn,@iF'>rQqĪCsHؓe>\W6qIB@l4̃d$?k~kD(_CuzҢ>w-" =b\"Ku#P:h!]ƪJO ?to=0G$9r9B7;~ Z+,ȃg:y)b8Q;+4yYH\CY  U  cE'zbyj@-$4ar[Zq9NkP(qdGis9$T5),KLI2BIBc%{4tG-iKtƂ%3QLWe X RG:`UYT2O3kwׄ䥖9oixnq^q z4Rڟ/mZЀ6y75_R|7H:꣧;flRwW6QT20'P +[OJ[H~nbiW}=DdhC1y'-%ǝ"TF/ކœPT҇m}yj34Ch\O2=.`v.?6㭂gEE9sM*;ޓFK˫F,MTw- `yRQD+6䥖֌{fPw:1'N͊]Xn9="7gT\S&PT>IZA'ͽgm-=4wYʒaIJPJ&6 Uܵ܎Ҋ9NJtlZm㓪T`O =V)V7*Y&]rF=FfNKUzLHYC:J/zS`,981*% +SNjiS=sd8 PwRFsN>Cwd:;Ÿ+p^ZAIRE'I=!NO~oʇe=j}$n0gfURjTA$yJ-8&IMeIq~q؊tSl7Wdzsƌtt|TW}nM:#e +A%e"9 y-$XFj jprS jArJnaqtoɏZ +tCjy j< qKq nK,$cW7[z H Lt eU1'\.0=D:I9.lk}hzql +ݿx$vlK'hQ[?f>NǮGuh 34kx@زo+wq<;hᙔDG'!;&Vm=t: h!U+ENuW>}8E{DzK R688obAf|[]ΙrWR.9kR5ka:'N(H\wI+.}nʕ}/8+ g&%t&s!l!%R5W +XRɿ40ƷJҀUTw\9+6y0XB%IE!qp}2`.}0}ӄ+qxTT!Bdg1} 6m~z ă9Dcʆ_},EBKx3!)#K.W]PԱ˶c<^ÑL?a.zw1i.:io;%dxD +_/I@7­勛J!"ɋM8:tS',l +DMȒĴmWI<6h2hpO;tt" .TRohH?PIWϹxqD~AMG-hW>c엔v/b9?s'H~[z@sz ͏oS mj{h4D]ҌbmrpyF}'y) +N!CP-Pk9/%#4: 6g^wM3 (hI8{?IW; $lu +ި{}Ti:a\ 6J'N8ФJb)Ժ*V}M(7Sj?I9 ^һq3[ָ5IJa"\k ,}c(',̒9S䇭[/G#Z.@^"?V;7I2OA!kdBEjOjO;=T;N$b%fT:Y_`.,6 pCLEn3*KLc~q g=reN\fcM]'c<8>)>0 6M.[@&,>:hm#a2Q mlCȲA[8 At1,UE+N^sЈŞ JLne"-dw6T}B#JEH6j)Z +M t)`ʔ[^͙,9r}dLܟ-3i%HJV6┟ي, s-kDI@q䔕} >T>k* P1Ce ma'1['*Waiͬ.:MI<'-P]>v7=昍: +ɵ y#ٜZeͮaͤ~D9,gvOhu0G:aTM)9GI +G*x %[n9W

    6OZ*KQ-*:Ր7LRvᶄRnv->lMnĞz"=Iۥ$!'4҇i$)L-ǯ3j-b7:'(E[}Jov*Z{$qf%RBP@s(N>[[obI I;#FiB7?JxۄxgL?/2Ye,^Vmn1="3W`ȯy1Yܰn!&jO#+J +qM5rk%cQB]:s&Ex = R̴ZEС1}u+krZWmj갱 gӷm5T~%MSJIZlP~SgnGwSjj8/LY_L^QRdy( KB|76n3iTcc^2NK&<ϔ͔lHM p~:d59əbhR4AƤ>ca +v`$Bʬx|N?ԉi{eAK pRTԊBiH"䃑G[;ZWkֿBՎfW0ĜvԦ$_J֝ג;*vł蟤JU+6&rKe;xll8iY\h|]&95$78^a6-%$Bk"5IR)$dzU,DxҲnYK}W*|p,B#4m臼uMe˦_ho !5MIs!VS +R $"N+/8f֥QC PmI祡Lz2au(NJJ[l2ZSyR J*T%;%jGԇT9]jR*OL\}Iq@,N&tun$:׵=jԕw M+2͆IVT IHA;5M C>]җdՇ%l0_# 0=ٯVQ=zꆍa,m%k9ߪ*e4-IҝztGIpĎgHImZKyf) + }miJ97:\+[{O4;-bENrPl&9õZ%F|u%Pβc'4JU(<Dc8Ut)ԮIJIDd+ *<%FŶJW!naΜk52JR%Uv&m}S[ŕ,:eCK-kuqQ cfipZzeqaHv}FEMho- C 뚓zSəhMqD%cHRR8]S+i# +8aGq2z*ŒWZq5 !@qǡF]Ռ)3: H E#!T{xae 97 ^K)MsE.mbI=R<g5xd([ t1^b^u`sω?Q..>xGq7n Ӽ3"Hi=lp.#Iɉr#mĎ T4TZ̩]O0q!Ad+\ Jtbµ|ܛ4=44_m#d'( vӮX=1#N]CKJOaW) Z\Ӊ(p%/;i0{-F@*'ΑzFmC)L&ِcbP}Qє n)Jr^q# ΀YVd.|~:|BP7 統kk(j4TtVH$d˄(t50$RG^f_!$GN% ی)tE`Mǐ,3楊צԝ"B 7֍.mGq- +֢}$(cuM~h#ڡQS+Cmr9'?'2-W[+O +Wj/*eqLA#Kiv#3vZQ=cB[[@ >aVJ:f(@yN{uYt12 ,Rʄ݊%RtKE̹("laȕUG)LCMDy\j]JM"%Sg*Qe^@bZ\ZkK<aS|;TQ*%` +ʂ.U+uFt1+:7v)uOV2|Jr8(y@r}g̋btSiqJ%'E=mb7m4ӹx 7ԺI%=jR )6:U?MD䊔Pv\x)K ) XWlbNN]1 $e:]JQ<.f?5g)B0zjW@":XdP#J2v^W4Nau /.ˀ$ %bڒ(\kٽ^9jgQIkt_ c fWM6!$f{ vu t]4Qt͔)SpU$~cieǒ.Ĭ?aRŤ0BXrlĝ8ÖVVCyu%Yw,3 4JSyڧLHQ꼊 p,b /hfDs=#/j8H8eƐn\ +>UiM%jJ@8ssIʊekxM>ij&Y!(C% Xȇtc^zQ鶔XR;]%\\9ؐ &kxMn$7a_l~˧ڼg6LKmwCTQ%ilϢ$Dd{Feث8 +óZp6Q2R[u2κ_8&g%EƊRf:m=aJ̭NeɤK +(Rn{vOh euh}4QԠj_I?aI31ο!M?Y_껉3jb]$m}Nb=YsY!Z )ڡ;VʱYm&>#9eŭv"LaɩZ:o͝_l9izB46jaf-”<ܔjiU_~8ֶuߘ=㇄qTC$n"bzAq nB<;ch'Tzƈҫx[UYe<~تZE $pXNF{"aĘ.GG3fYa6mI;K6a{Fz"0 C)~NX(,hॱt~ re1T볕BhO/d#PE]x/Jwk=N+fd:Fo>h \L$(*;, :ƉiթnaHI.qMR4,-ӪIM.(oT/mc +r׿{e[}JTM#9RkCIЉƔ{[n4"KT"S_e>ZSpSnQBJ{-2}-;`xUIlt+HӈOv52H&s/.;a + +N_7Z(u,(RR{l=P[-rؐH!8ZHPP)΄(;6  +5E=zǢ=n9+AiȵG%$g=F55],pFEBzrY@ +*#J-8kH Wm ֣{ZQMЌJ' 9OʂŔg9 ! Ʉ +|⺙$4 +qkpcoP^=[Tʥ.6 >`'pT.x1\U&n8L_% dZ]b?kǛd29-io)Ú0m'QKGsl_FXq(=cVyGT)` }1/Ky3A`!zkgf0Ĭ +9xESͮ4̋_jn`zz(ױpoG l-&v= Oq*'LUQam]!]Zn7@dˌTMRUB!W#$vD՝U$- UNUALӲ+2!CP=" V~ l̬iEC=TW &R>nCjQ9O}.V^ٶX4;IdXjIj#@b]I e=*>5U 6m*ECXX' ׆ҫcNchcJ=,%iH=za#U)p ةOr: $۷Ce{G乐\ +%/~mnTŏ: %ǘzC-tgf9F)Wm=?̕#-Vp; =V_i%`=MÁsyzX\m!R=R988zo>|~Ť4TCuԺıoJJmOMpV_Imܝbk򅮭rA?"O>Jo⯑ CI<Z^ٞNd :a{{a`@_n0LÙ~buB+JTGiҿ9෧H H%~#'HWO{S^iyӔ{V[MV@KM^"n|*Ue9fu06t bGJy=oz Nzu]#~:w޿7Nj%cܟ oq@)ʒtyWL|ϧJDz?tk }q07vY>cO +|.Wfnhsh5Xh'~OCmnw!H¿8l,/|6p^52Peg&BEPmfU4 YBjGF02} 61"+ָЎ ^nĀUm{{D?2^?l0$ 'Ѕb_σ?"NSC 5L3pW'AÍ_~rcBW bRq~SP{:t^QҳRwA 7(.</V+pLRH,r15Y@RuТEdmk*Bdvފ#e/ f%ҽ| ,TicE=CY#O3Q}m|WIl>,:f%XMC(;;RCRvOGar-QI +vxGa9ot80H;_ufw)=dHX%IdXm=pUnޟ\W)Q|*g/ +ioLα)(΀ +sdQ!ys=#;TNL"o:һHW[O@*kRԜ%3֐OlKG/K'I)ҋ'Q U7+t)ŭ=1s$i^TaCɑNe#7T@nyN^GigAYQhFO-XmI$(VsT%7ho5y DlWJIWlddSfzN~IݐՇMҢOGg4aq*%?ӖʈagyɄlLuI~:ERG'PMK=$r-DTu1 bFyiCqJ$$w$cVd*;Z׼@.Vkxb:ZÀ p5;GIiK5TJ*éZ +hG=>xϜ][u67n|I%I9H4AsW=2 C +,vؕS> mOyBQ;UPX/TtBQ\/Iqa#"0Vl)D%)l&+n<Ǥ˺nf*=Z[pG7UӶ0BW㹺(o?$(>CVܶUwkLTGTomh8w ѩg,Z?ӈٖS%#Qaq-4:,f(% +RkΡOc"E\nvT,U~蠞$TIq$nn- jy16XM@I*u`"L(N(]1v̋@Q ӓ xPߤ|ªK[JCMPHO#`/c¿<()ME)bMtB| UFO8d)U,OfCPRfʄtCG},T(2gT!IȾ[`},:PYhfI`sƳ(4<4KPătoubnL-PڣNHDWݖ($=:2 +D{+ϡG(ɾ az:m3Y)C,p-a4!=H*ZykhZ6أ[ +lJO8P[|,- Uq~#Q{{almW=6Iʴ;[j;SF`.Rى*u:8+u1R[Sb zb,=+L +z])'.P 9q?>7HwMVTքIJ\RlRJґ[&Ж +l)Ňb^lS'"S1U֒wi*n(rmڔFc [nkTSJDP0d"X+!J\/|hBҔ-c s̹TR!Zb[t*:%6D٩rU(1cJ}+ +J%)xd+ԯqQ 4AC~ r⯽ nqJGu|`\ec-˔Iq˃rl5&奕g  +ˆ'aᩎq]{.*US D e/vܔ #ǴPr>oε4#OCUZ&[SW&^GEڝ>Q-*A 7R}E|51<ԫmaU-NRZe2*}ٙK(ShSGs4jSa[^(BҞyn< YRuye"uc9IGrI)<|qbilG*RZm2Hux8wЧVMu;KST"6jDjlQ)R֔.#|ĔKskBXVa}6tL2k3!M?f?H`Y6nM8ڒ7JBsF徐r]Pmc"DXщ`hUb51HH$J l8\Dg!)N$p?a[4y4)V~JAЩGܡl*M*Q\#<$]ź]!dm+?OrI'>n5#>Ҋ+*:ۂTH sC.w^ORJ-- ĦSr0m3%YE('I')Ro,OL\ʳR+}ڏTO ]YGu˰@ԃDEX9ԋYZf?|$TE$%SlMԴKvծ֬:f6̊\xԚ)ylRRyI˄T,d^y#sٱU<c@92SyLʱdˆڭI鱆!r6>@۾֦8һŀLؘSo_ opޘOql~]鿢7O+ڝ9~]MIZP&}|@' smI'3JE%D ce` :+fbqm"N,$XxOpYdڳ"P +w[x @b9ZQBcn{J?8v[.V x^ [-7sTd2nM_O.>G$_;-#. Ʀ4$4UĠ)CB܀cfJU%RJτZ躆Xc2SQ"VUE!mvI펙piIT/j9D\N$[i&䏊{aV;Ѭm(PyG#x#2Αk?;ҵCnA3Hp$ԀJ  UڵV{g~{rFg˓%}ķ\)e(-*nEF$ NXSɭXBl,n@N8CBbefxj!׌z&ý:ɢ&o v,4Sn~҅7O@(TZ^ʝl.:kLULUkVA!m; ICfIW#XT+ $:R޹sNTwDc^sS3s50c~l*q,)R|s12fq TBsrhhJQ7^X̉i"TM< +ZPNLP$,幰1!|La0%!%^4z3e2XdЕ*~o8۔ĖA)(ehr8fIwӺ ٔ?FC* +إ&U inAQU3*2[[m(nA@$HpGZ<''BjRHJiml?mr:3 m{T\i9@$5-%:aǪWR,L>ZSHHp%n8nqaQafJHPYn-6&GͽNm|]U*>C0 }45->Ԧ(醣JT*H  "qԷeHpd%P"(I5d8{Em~zB\#+B֚} SlѱKCOKUv)L`)H$q;PPy}dč:iRe\xʗ32%%c+ + /b- \t+i[aS>3MJVXs&Vtahc?Yt4YIv]=\ҬÖ3TYÒB n2aA\---7qYLJ]WԎJT +qq+T*OI93* k[Puکjӭ9;Ňbn4Rs";._m-lGNu`)%D) M!Vaǜ.@1t!-KC3LE*X+֡n&׸( k2רL #rӣ@>fE huCo\s/\uI)Kg^$S%/Rc"?ΈZa)NFk +b 9<`j6,Gq^] "j01TpeIĚz;;_s%*Xxt*M/冕rD)o@nEa <~WtVN:P])ΩO VshJuNR2GȨYSZPNCik~LvO\vn,P̠ JA ZqS+&TzɇMEGH6=LnkH5% +BI_eԱ)HS^[-krF53.=ZST@J d,̐ S'520!$Pyq\Jy<\\!x(%k7IRsX=V) (Jo;{bQUr]OBS**X%i#B{4V q~H$ ہ`9ı+ eYȵgQ7R h+3kl 8'q4M2ee DHQY%z-K%JVWmV^;mkX,3-Tu׽#Tb.=apJunNȝ.b^ϱ%OMU8:e>j>=j)UԾ՜>ҡu$Z䤎؇\]5ǔ˅%0)=ֆ"(C3;Ŀ;jMd+,iBNP2N{JeTW)LDM9.:].)R$- UpAž]i'Jv KsCVe!HX(ekN5Ei^*$.; ҄8i[e_Tmì Ϝ=)J +N뷪"٪R%QAWwFOm\ky:.F,H[hR#"b[;es˦L+S>"F)A?tLQת0mCaBNCv}jF)MܳnlOƯ*I$`94 ʳƘ^ +Y*Qk啕 yӨYry2ER<%;EFL$3ɘOC望%򋫺,M!Kaċd|؁k{= :}2SrgJmK? EjbBXYaaj8Dpl=:TVM}cŒJMnw+*}jM8fZ^dYD[B*sͼt+5vB+!F*k :Rgl<|yΖP),P*SNBMNiWŅI[Y@=iM,>NlĝIEFvd:Bvht6#oj*^A.0!CAy[򘁲iq'>P+Wvnڈ=^,l>\MZBKR'R/=PGE4D b]j7Z|_akr,OH +M/jvH| W"&Pr %_M hnPU5NFu?Y>'ljCQ J7IKWA i:D%s.W4)TZaNZzۛb`9KWWPGZ:l +fM +rfP YE}#eG)1_оh-Au$Xt+ko1RXp:RH#Ū]UcO!&ʳ]5Oye$ݬ9MW!aZ+#%e*GwJioSkGT/0bsKi%mESܕ,qO5 Ës0& ۄwMs.`}wХJvNRhIR2j!IH@bol/ JR&,xi** \\IAИ}ӆFR<})^$ +N)p+.Oğt6]x2t.xn#Lثێe|tW'l|'/L֗pG>_ 8@&eO9gf'uC׺5?MMCSX=&_[@I9(#Зx*1ZF[ujyHT`1\o5,$aؘs'A VG*|r| մ>6/TyZI@Bb@9${}qGbQ@*NkB7Sg~̛|O?\#OnQUteV<}VوS[MqSՙ*Zjf9RGt7K9k'hn,>i]c5࿾9i X +OfkrFV +JUeAIq7Гc.]$mݡXүF+ !vm7S22qG{\\bT :aH>j ?f|p"6;@)/0XT>͍H| ~ElcÌ(ă3aE)SN<UKW"MOoӸHR3\ǚ$GZEBAWb}+ d",S<FdKR`H:P#a'dyzUO?ij=XP)WWQBa$k#P#i]1$9=ۭ&OJS¾\?eW8^d]g;A3"#RN:CBWŗWW{gc*{=H! RR\̃X(i ~&57 c_s@{'-`<|[1R7&9ƮG`'=MceNjKJ@;aRG6'ړ0{ۼ!Mͣ!ķdTD;1n>a UjMoq9ce,; ^Zz!9ey}߶7zR/e|H +NzJcXp'8QITf&*K +/hL>dT\?f՘~C$ g B ;)rge'$8i(}D9%7 c tR*hO-&W +趥QG)aK_VU䲱d"7<@T D*? v<[Ψcs}z0x LJ=1[kz[4e穹tUN(ɴYTv2x-uY)FGǭ HGiLȿ|+;FTŭ|b{O~Yo"~bHZݺzT9o8ծ@*:|~9J+mjh(mqV+pS=42HEC5+A-3#a  Hb zfĸw*QíJGDp˙Q[GRI0֭~`?:%oE1@R9AS5t626+'-E O[4; +`:4seJMS촋R΃S98H04*([ +!>\O% ;?_>U[&JVݦ]-L4kJF)K ̆cj[oUUu7+4l4Jy*Xˎ0.%*$G8ЙDcPRnQ} aWMֵӰN_iRMɃ0 +kVT$m,OQL4F7 +JPOګ>0tlxGzfVIknF gL,hfA'̛xhk[4)n<6T[SA(I%E{kJHYSJʀBT$Г)Hmˡpp!fKn+[DvVmo{!əi]qKD'lۅgiWݑ)$j6'ex&& _Os.֘hZFhEws\BOJhyDuLHlm[wW6@*#^q(pاڈg<.4LWUd&EڈNP#X`rl-Pgt9 2u'tIJСteXqnJZJ*YeyN {kLYۦHBet䔻 LPc5mo+қy.ަ:f8bpO:?iӹ(CnD)-PR^ʿb0H5zG$M 9@;0S,>_0xӜ8,8j4L_پgV^-pXQKRP ؈1Kudra&BJEM"28}ڪJN  |)f]^U%+MJRMl3׍ +_lE1;2-k LF8GۄPVIQ558Ti,yt H vT6BrH̠8Nÿ*fa -T۝S ) Z1 +ekhR}OY(f +›qM-s~Vq:R1&)u7\ +sYH䒻vJ$߬qG[+NZVg>⿤V(1{P#,YYA;a/#FmD +&RCb\wBA)oCH^-o=)KjU:$@mFW,6od6;8+m[OM"ohpL-?Rȵ=iM:(x@BܛeiPP[(P]c{aG/# 2,ǜv+u%HҒMnC<ű%*rPrkBBT ګdxGf/}%Pױm4 +LH-fCfHZJz8LW-*KrZYII +&ݱ.0k[Xkh8,abzAMIP=-))Iq{\hy+l' #K)XJ.  f:S+e=RITy7]:'/42ҝS!JbJ`2I7ȣ%'?,20alBIRsbM=MfPT'.mĘ0IJpiZRE+0ͭ ;OFӳ fOF{ +q0u_S}v¬lrʷ1Af'մ Bذ.6X$ +BzO,)>>9gMݍi?/5@epS?x"GxQdg|tfw y7TĚ-ԁu @l]!24J*'Thv Zc2uL7%%ZJ0y|8uywH jGֵ <Rr)HicVN%lhC`r + ؋FB#{ZSB.RTT1]SVYjI-grM~8O$ <.m+ߟZjU%>mhBHέf:>C˺e) uIo3A߅KN۵xmMVqeCj$d;ۅyj+i q*V'OdG*%~jj=0~%Yw ufg&h̵(,TQ +)mX 9RHd˺9L9nK5we<;>6<"vP5Z")S3cYKr g5@RTYVhlDHS,&#牙;KkqXJmRlu2HDkz*mI-c`6ߟL(N8FZ[ $qR%R'0JlAt̟$m{Tn%(K(\]16Otܤ}m),B[ߜ&\IHpNxġ315?5$*y5B5#[i V:)42YF$ATYhBYD4oKTy +6'NƵ\%axHO$l{:=F/M$+SV&+NI&h0Nu'.ܔʠFڟư>mf deeXP۞$1E3fMZ e+N +$o~pʓUiӤʎ2;AP;OsI%YI$sPWq)O^P5$ӟ1s `)@jy)uʧ;/aj;o$2I$8Gȏ(uEnUwqV%3Y촓{~0Cɥ~2i ­\rBNz ҆+mc&S]'sm}qU%[:f{dSE1f)Ka 4^#rʟ= F^U:rfley2vGHiJ%^w^DjNj4ejB +Q7jb}{,S\Jz$)e! ('r7?Mg-LbͧF]QOQfexi=X 89_PTku8: qJt5(O}tP'B ӗuXZ:s.mBZLYf 94@HE”Jn1]TZS-=;e!Nm&('G{ں%s;ݥiz?KzWLըrR^5$qN (%Ŭ05]aREtbԫU$[$ h5qm"ciT]n]ʶQHH6&K'uI6gпhmy~$jRBQ-88-~.R1Z<*BB6#  VhH>:>38euJ-jG;{ k2SˮW(S%%L\a4I\mE*k1Nt-?G,̥(EXb߄@ᷥV35}Owab^̸lla +Ծ+)A)$4$C/:tMv|*VhGuv(`;N遼A8\H-JϠ.5 4e\},3 [s'z] cdISI{*~1f_ώdR6a'R!K +*.=$ڥr6s'.+[6F̼HRxy8Q5$պ*0)At'̈́>^͞k#1}9bk gJcqV2| |8E+]FyUsO#qd̚cőfR^a_I6/ %:AyF\LF#S4#nx_N JH<8ùޑQPmrUIt /2BmF8Dۛ\?n'jP[t'=J(Hܰq*Iz8|"*C\V?C{^'Igē H<"K\Q~D)V +RR;刖^w[-87 +ǔ*MSX G1Zɪ,9'eD(%ϝKWJ@P\;/ڮ! Qy%]IdlۑV %#{ 0Fi.44[="? 9lR}0_'ڙÚOecrDٴM_r3W.4r5NˡҴ%B-\ gÅٵ ͩWA*7IE:VIGPmS[-|-O#$آ=+by8P}Vt>$,Ӝ N#za4{e +N[t=0T ՛ut٦I9I?- 6]?~= +aV?[tvSl߻BtHJ7(9v*}o'\ wI@Us]@M8q*yLU|{t/j'Ф̋-̱ԫnTO*VI]m;L/.RΙ,i$Fɑ"-NJly2$}F-dj'mV0@WIn~|1}()jݢ>>;aS2J2ഛ"/B:|tiKfu$nmWjzҫ)PP׈ߺNbiWe9#pF]yGnTQ.q P gk[ MS)ZIaI(KSch5 +4 A)V fqBi>ߌdݥL83 :4&?(OukaITx4$]E&ݽOaɩ |ڋM-siS*ɗ*T{ s L%g~($))᫕f; Wܧ(%oӜuUJ &GNhT 3aHqXqvi~pY&J犎S+JSҊQR=,}Jtڻzf)7i 0?!(.-%۵/OO| 0iA\X7\z#9BUC(-@~)= Y%ͧ ~N\:|cZSYC5'$l|%PU6տG>90  I Q>ΗPQ^J˪?\ǫ o gqMh?/Q GM`v# ՟y;U$n-A!ԨBSFD*V2."di}q; /<E滑{j2u/GYsu:"reOi&') 0!G8cCw+V3>KTSr\VWI(U(R6*5ꪻZ)X) %eiRTJ&񔀤5c}^d$ o\G䊓w|/+Dc2^|IPNӤ6L4w6Dc2a',BZJTFC>viVk _eHʐNE);"7W8Ei'l,珳s>v pKm!} Ab\6-n6'hJ2c1n 7ySdMq".ATd*K8Yw?e@-Z +t2hTU;r@l~1rr*bzEeHZR :mDI3+eƟ%^M,YwT ҡ{*h*Pr .2ck`\w Bpb>DbHˡ"!u45Н6E]3cu d92_9 ԓ’}/=Oc_S:*wvoD8U$S]T6n!Ba :d%G~=mMe*Fsz3r;TJP"Eʐ!-)J +@J6 ]f:{m&NGK-}cN͸ځmmlfJX$%BछZa:⿔3R͗  Sa2A%V&LOq)mqJX *׈R=eVYʤ.8HHr^ IVJkJdpu(od֊9dD[a-*Ÿ#AnFLA<}1`ߊ5DSK 2jTt9s%#uqC,+QR#c,)Xiϩ+qd.-ŨkY*Q'{JVݹVcmdw5NViL.J849֒训$*3xiV4B}LMi!* +G62Xlit +;%TbNhtgXcfu }$گ$u ;#k(*c2Js q-Ep:%9.TҜ$/}OqPq+B~cpw ;U! ;a΄hIV,e M:o +}(Β,(*8$$!\dZ(ʭƃqI3,#!''Fd4milBn&6@<;,g:n|A _n S|TJO +"`)~ $I#'x;*a*̆H֡ʛ)I>i7 )&Jփ`a;LN74ލCqi36^iZ|lv|n2 +>5Q8R6V J!'J)*PHUۅ6jM(Z V 9 e6ʕ߱~ҍ"3u7n溾eɳ]Lz%5܇غHpO"ؙ0y:Sk[u>)j_ J:AĆVjʒ,Zq.Z*j5CYQ4aTA>#?a+<)<8_/P8w>0D0šO˵χU>B!*/W̥-է@ +Y( ِI$'Jn=Ǥi) k$bSgߐTowLr=^ e)i-HBwO~b% ڂn^M&5@19r#/E LDR=RP6_1Ϧ4W Z^X9#U:xfU*U LMԶAW61?Cv/=1*À:͈Vl|?]<̴@PWM8C]"8tse]HI9yI*u*.ۏIkRj@:%VT._Q!J"һ9ӖN7OHQ1,%aL4 9omZfntf\Sk"ƫZ I(V[(UFmYf]%TJQ@A AR ߎ"J~_JؚfIYPT)Ω: EƆXQZZ4LFjԫ/RJ/Z +BRRR23ueR)~XTr@ZSΪ[Kq@o޽;;cCz?kv3}.thS~DՅ&qg&ֵq=~$LIZTqRT|Vz[Hv?k[Zu>R=/#/RلMM^]T@o<<!\ʔÊ͡[pH7Wahاb4YyYINiqխ +Ȯ@+(>'W4gLeRgӂzCAR_}B abpB9H۾8Wn_hCPOU^C!Ҥjk 𳏣S2>qaܑWFR)pyNu+(< m9q!8%iԥ*HH/ nie2Iʣwi7lP~7f6zHHho>+t27SZCe؞1L%$K쫁^?HqҐBz!]*aΖlJ6V`Kbk_x֊NV + dpr5Y=c}KmR"8Dt0:ATR:qf]㵼MCS !䨶r0 5/ZzT4-T%+a%jeYM w yZV[2m@IJhivƼ,bu+"a6XYf Ѽ$wfgV4*7$_V#9R9GІ"q~1Tz?IHNMG3O d0%)- VlHojٮUBLTjOԹ55*%1S\mY> +Rnk|<[qJҥeΠÔ~z畖 ޸LjHE9y2m)h+{]9HaOuYS3Dېbr YB_lT7&qD<ĉy 6f V>`((eIFn^iԕbAM.kh63fޞu'@J˙` >^DB)Z63dڹl66FٺP+ T=kigCJR(&R`,@ohesZY3I뎗Riyc4TިQa9hbC- r=:..&۝/ zëJRt NL3+Ҷ.2 Z!7BRI NЉ|RHŜeE/ +ӣrycb>˪ꐫ_tS&;HHSKΪPM!,yF6# 0RL-eldH2rL纔zU%c$dk8y䲌(%#rIhqN(`7'nP.T~Iu(HŃi&}PNL6\r?W)A)Ϧ*N"3]鬧:t.$PMCd Г/a^:~RrIYFwgep#i%JyG-wG6u=볓xqⲐL6m6?w'NhFb3-ZgrOAb* eypiRqjbj D\ǎ9K[YFU:f 9ri}"Bp8me* +8-ڋaCB'Ut|˟S> "BYqJKhNO76<:gY!jRK ejRH']rהԈ$r+IiPA))QpиŸp" p16zc%Hy3τ\'Z i\wX7ڛ;:t^m3e;mbwRRW/~(9{%VQsq fV dtT84WaiY&? 6e[Dܶ.S%% H  񽇄li8 0/qY iCprj KfM9#\gi˖1W"]rZ9`m5[12ZR@J$p00u9VrXR>"GK5K=XxaڜquRS u@*q +RUʉ el"ͬ@OO6\s{|Z S_ tď ~P2L&Ue Zз*  F]/HfժPpq2Dx첕-ǝyA-)* UGeK~ <Ӛ?KG1ᩁ >Tt?ig7NFJhvk/ʩClɘC2JW'h*&؎R$@7D M߼V4MJLu%@iIJFcp3l({::&􅔚!r%AOTEEa1Kl)ɇ|vН6$=9oeBoG;>缾2%!)JvJR$d_{Q:gVwe<;sd{hBm&Gzl%!RoRZ2+rͿViSN! +VDX +ro؞Ou6e u0Mfٟy P f .vx>HZ#qUJ+j1'b`c._!YqYHBt')IFƥ@YScR48$?UV#t\^۞M8B&9 +lgob)^7A}R-SJT="4D@OlB8JYXSi* UC5E"Qp>3+ʹK6Ȼi9IAPA&-]oͥ,j)e\jbZR +TosZ=SLP&OJy'TH񉭙QRO\J8pܽe]9f-meM[q!hRIun*uYhQ>#l +q`}q I`\a\=ٖIu"ݙH +=TɉFQtyei*3o᯵\QM]yգ< +Rw Y |_?.*6ImM@FUU*U5DGiVs! MDNIhVNnJZj=6.67_?g69w-CG?\KHNHa&9[Td~ub ğH1=MT +I1קu*g% L9q f &}⿛В6Y'QvZ#v|DH*M_MWSf?_%yZQ R+yUmR~ƣyH>Yi x B]4uƘNn~X3[ןh ! +'j}f)JY{Xt3:GU(7\7[IQ'_I5#PVT㷇8X੦YwIYY$F(Ϻo솟.V{?%^jGde0NF&V&1Ci;~f6}C99;Iz2-rԑO*GrIf&}M= :Eh3t9WǎR`4ޠ1jd~%AGѣxܖ7'u_tKXcSx}oآI^Y嚿P|A=ޮ$cKwϾ}L 6 SPn ~F|bpXWI +rBQo"U@7Uٚh\Vy )XWRKPֆGǏ{'f~q'Lt:xG6h5&?ATnlrZů젛;E*13myk`(V0-0xM=_|~Z7hxxR u'R:qiDݮ aCdl*11O`|6:?ALifm6: J(wHS +#MD9ýl~a/DV&KY/0<}q:` +_O+jBq('zEB؟EU%f)E`/%C":%C~oE!uHV}Bezv_K:d9{%LHgɮBd$۹ࠃ˗Z en[!HPǺ2% TVU.])%j.8k.EYєܺtb +O6BVhmMZ筵 b TIUJ:t CWSzY&}5 +2 =+B"وʁDi?2{pLERT6wfP)Oij2Zm Cc!? g˪*&O-bL$biRTzeBJ/87Cq x$0D0fd_[C唄$ +3FW,޺kgU0R*8ˉqՎ y=SWSofTX\4MRMƢȳ)`(Yvm>ڒdA$p7gIL*S^)JpÞ-ר92 +$m/2âgz5`(ɾJVum]};Zy,fz U* -5"NaInRGu)6$ ħMLu6P%o<C(l@ oGUmJm$8T(د($<3Xh b{_aԨu{.m5$@5*3xS HźX % +QŭeBkn 9'JKmjթNҒJ@Nwy&^dΉJQ k9sʔ@^Y:rzmn.y'}\Yz9!1 U/8yJH!|l?DHg)o!nQ>[xycAB}>z"+S{a\jLp~mړkL+\X`9E]/j-*#.y>xCUi%+Gm omA;PWK(b>cJ<ӄ#u]Rs^*YH6H'cmc7{!gr<\DnS\&[@RչHR.'o PIDJlbmA]^e{ c8!նUlmkCsSݖw1R҂JA(HNp&Oj !Oȵ949?%T8–ǡߤV2f\lT ܠ EsːYCw4i(JHA +IP +B*JomՙMHHJ5&priַ +k r,/-*:zdzAE!{{c<sBլ~9QZZBG?d6.csRU;E +(A@G I!&E* +>8pt3LIO7>LGX +2v'nB՜$YP&6T#9ڲԄ%>u3E*j%A%IMv݊:/A0q$B- +NI᝾?'j +RKRR"*@rv t=RN:iwIqU}ثd3">j#DDNSsuZ7bUd&0H +mHYȤ+T]+EhDAμ}4FdԹ\J GiQSgԎ<ōu%"oM9: USC'/G.eDN/e2u%%3 .(ǣ7WRIOûz\MHp/Sb[VT +/»mt$ (m)Iu`GԹ!вO\ DMa03ݮh^P˧jjNcp%>iuqO7=wJI{1SNϞn&Lai[}6Uk#*㕡ՍjtMdmDS Ny#'q+,x1^GuluI}Q:JIbdݒ&ҙ]tH+m8v"+Ί5 yΊYRlbHE6AqyPL*o3*`jٰ#1(#eLhG=#ѱ]LpգN<*'BFa34."D^!v +M* FibaCveηL<ϗ}|j u؈'B +By U@K 0#R4X4=RBl,b9b8T-ٙ &W.*&p'#(I UvekB&M)>\_<=QK@o6{s<#tK/I+ +誱_;a!l{Ay!Jx&d R4lg5*R#̊ ̚{!o6t A +RZ&$Zc+`+4+XFҘie%i +wB(Z^3cT-4a%2CJi%Ky*PRPfm!EH$vHe7EV׆):kl 8ǵL]=8h!Ɠtzy % D[TEm3z=6ScNyҡnQ^;OTor3kss9W +NT?)-. TWp.V{$eP /ëMdG;ŸSj5[Pi"QPigGą[*H9xea,i[+#1#. ĊM++oS_Ej.{-ze9 薤&Ekm ʒk{z_%(I*ZPh<{&y'&MiL- `)E .ɺXup;^ˡ(:AOj^ +e溃dX~B !I*xaNfj\[8~)Pp$j5ONsM[DsQ%72 J(WQ*2kLˎ-d& 6@^ddW?TpI6`2NLSMOe s'u|Ďۄ(-1!Q1Zgj5={yq%8F`9H*,&)@٩D{܋t1RrԄ?/~Has)R}N˩)w+_IJ٨Jե#ݮAleK8+{_PbOfz*ʌA""tc) k'N+5bpVQ]5uD;wiOz#TZBsqN-^PQjrZ^B,ԗv͡@wWoJv|ACn OhiHK]I*H$#1#>p-P5:M2U[M""*ZSwRW*R);BÒ|'i]2E*]Gmz\^MݴB>Rn - r5ְ묨2-@8BfxjOFXQ{I=}At(I<.rGc<2όN3rK J̳3Ibg˘njn(KYObF߰A?8fffeo0AR D\L~' bIU8MRnվҔ sPQ;.7Ps#k~laa“ l$6@ QMPEA-7p;Eƃ$|s1ԝBeS*rqZ-^6 lzh ]4U\*K@a@ZAw\Oʡв5xx` 4쐗lw_N!XhEԫ!MxI7 +y*^ϜmK7*P,XikxE.JU8$3CFRXMȶԑ}ۄh +v'?LAm)u_sIHjÆrP.R4 Uj̓N=zgՖW#j-F#~ Cm !a6>j&T)SNIarRvVHiƐQ9ǔc&8Rn>vX(:)!H'Kb6"ĽbOzLYӢϯh!ojOГ楏gK`f5>*tiX%\߼X"t[ӽHw5JU8ۧ,ۆ~w* +T׮ ߼'b47(NbT$IK6:HB\Kت!G]R/E)tGaoO,YTM K|v{8u- Nhsz;INJHYlo*/3z(^lg)q=-l;q7ODIU(]jT@mG",lkqzk)RD<\ķϒ&A*ha="$jppmg+F%pLfoy[",,L o`6t[loڟGuۨf*)VB{RH?u!_vRr7mc*cG=C1JbYEJ)**!:wĹ/f)b6|qE2=J8R/Oi'tDr_=p3gtqm}II+;an~fT2:[e7dϦ-fV{+SWp.}'×1s-_ܡ8t3EB.4(4#l֥9§qȉAO-'8E>% Kh=$aNC Y),|uh8mɩ˩lmgk@HqT:3en6~vHE9Ow3w`FYUMĒܒBvrr˷0"$>^u \'}V9aj㷀9G|kF|Ϳ͝ +V+>aHHHi5Z+\M;e6?;c:q%U@j̸7K)Q pc"q GH r@l l_nxtUP)$.n8GēTHS?TT) $}:[i\5F@!N~$Ze2J?U0ʗ6nI^WW9qa/F'K%W[Uh1_RvqW4+N雖ZP4(ᔃ \~ܩ(h7SKXe)5xQ$ѿes7 XB~_:MSn$<.&$ 0$pRw/U[[U ÄxfhvpӆV]r&<T"{A2J;WZz4=O`]P[u7?W-"1j*;N7LUŅ:}IZ#~┱rM6F`{l?M>?%NLT|J7O=1 :"%0MRnkel,Wx=Tp-%i_,~z3rUh ni>0d:Y!tU5@q6bZaՄ|*'ΙMA% m+)^u*lHd?}ei{C-hr=Q6e1\_UWimp;7\m +Zercdԧ_D61aj2%l]s7O~ ōH,P+ +բSii=!5eM,Dܠ/qMSrsyDi /ar$)J>Hmꔥ}(ʧ\YI&*TVĩk%DdFz>w +$+f0*59;ř-='*AYXᆗ@Q$_ޘ+̏mN=!P99$?lFgQqK#' l/*n^UGk;|Jf LOneLz+"Qڄo`̋tŰ|_ KGިiHӖ{>SgpĢKosrDgӺsjC{~?{Ksi~U~ǒE|IvݓW9ّmh3onbT W?G? k7:M㷞#IvXUПʮט[ +]. iu_Q!zAKsLGƯQa~>ƾsMj< +*9=?zdmX畾=0_eՅ.1{ڌ2\CvQ0M(%|M;5pN<}IpoQqiAVV )?V?չ?ڠ}d㟣'-:ꍮ%&TV !}$A~G Ni-1/W(]lG#¦'йcBV 0WѸMBƾ|DWȵ4/mf3usC^k'ܽ}W2GL2 +'/kk 3crzuoCЈ*a>SfÇӖzu:۶;So A}15s S5"iR+n +)U<Yojݚ#.\w_t8/UqHzXY~G ([هN"V2EBUjhJ4H))H7Ur~[ bj]-l{q$h0=0TNŸmu:>^5a+rklX0.TNI$$h":jD:y,i*{WOv,T yVɩ)5M@DsK8}}GXOXAaA%ԝ5mVQȔ M>=7i}ji* wڔg@bV37Xu9-6H[1ho`vZ8, +UcX" S)JT5*R۲/@ +M2_kn $45 q`[paZ3ةժ\m{؞<9F6bUGQ*LQhIuš Ċ< `I176ܲsBR&=`xsa:%S-ZHnNHjrWTFТ8%/F"IjA!6f_&HvwîRH! \+*XdKSSJT@ܟ ޶9[{/dDQSi,K},w-64O|O/.u30,hFbSZd{Z(7--ԧQS(к~R?F!e/2TfSiQ:8{m(J@$CYS*$Ly+j(KK}9pl4ԥ6 ->4. 72NϬ.v\`Ik?i} +䈺jl{qYds]teV0t׺$qԜP;4zLTMRw ayN$8Mf*QS2o,  s(UjnV[LlZ&O_9 +Ȯw=glgo"K~)eR*?^Za[8>^Z\:H6!DjψHAqŔ]|4j# .U V|[/o h2BKr2j@QmE#i"赩z(uHVPH~jE5ckR+:k EƾK.Cu&Eo\+l_Cӣ+hd|&!w?AW7mgTq#N6SN[ƃ0+2p`?>RJa* lN97z:]NI\-EKU~*]S +i+!,RY0Q1"&) +I};ҧSU1<[q3{!AB;VB{*AF YeD|U$;ܲ NÖ<X\2ÊR-F7$$ѮB:o{^ޟ<~l*VFu̡W؋kjzY"(j,2`T> +-*3$)(&m}|Q.X®5.FRoI&m+1Z,|j (fKym-&YX!%&#GSLќH˕ y0$9b˅>WW'bt}C *属*ṭ)9̡iasþ%deve=smUIpS7LI֖MTEę+ o:cQT[a]zƇ)G+T )J9һT!Ti:zT{>ěs$Rmul"GqlyX ,~tX!tܘg +Ӏx L̲![`!կbiLUUc%aP\ọ̈D+lꟸ+Yjڒ}ZBA*c1JW!"laR5+_VR݇A~x~Q[r\Rn- 'v̟.74t~)RڒP(Ud&&*fH:MMե&sq&õ5 HmcckO|90- [fHQU!ҌU4!4ZAJ 5ɽκbz"EΡh3^~CC}i{h'&犞2zas.R| ,{svPU}EyFN\3'.n XPࠤ$6f 'QbLziѹM/`ybVia=aajmC :J~nܤ2.l3V"Hsms>Odj%4v((ZJ{6[J3*Eeq%$ssCԕi 6=Q>^f(1]C,!N-G䔂q@Nu 1ĖʀI;ɶ%J N䄍t].[JjPjMԄ(} T,.:3['ǒsD6H=0rrlcR{~A嚟IJTP뒎 )'M;*B̕#P 5-T!5jq7옄|dv +C{|(yFst)* +P˨NcqH' +6<oìH>03( 8}=+Tl)]^Oat$I53|IiY3& h+uxar4v (q^[9}mDxڙFGD;g0Wۥttj,Eǜ #qM#v{;S) +'Եu%*MQ>1a#9'K?0h.!PTJ[x Mo1CC+4>:Bq%*)m)(J(BTVUإI-()n"P5:!)Nry`$^??,.df)2+CSnڂhJ{-kR;skCxתVJ2tRoC|;h i +󒄃y8\43auҨRo_;R6s%4iRr; JK@(p` L 'Rl;Bk9gMq?Zl{e%*z9ǓR&p; /).xᦚH52DL-̹RZV;cGO @؊Q&#nKO kj!Pf#s֕B]\Xp{;pHne~ \F8ho!@n#_t|`ˮIK;*+-y2r*s ]>i +w7u#55RRRe1&;K7QjHu􏌋Ѧqi4d*s5+mKM_l9l*>̊$ om O~e:tHWW>V}:[E&QJyz(ؕ,}'xjyM;vbF6P Ar'd-hC(RԣH*7N? +s& f68e$Ol;:"WbB͚!ҕDnxWcHW9mqLp{z^ IQFTR>H䣩Z$Q9d/Mr̉e869SM9iRV/m7n?3 7YE)-\.HNbaJq5I\_mu&k֌2#U11uV $ }bp#(([(wÄ@XVM ʁqr>q}ѯR0:-Oq_)!Kj4(GiT?]rxO4CKLl,8~!č1<aS3d%)DH$͙#>dv6*U$/Il2.nxټsʦ}ǝ!zP37,|[ w)\ +m bHq)wvŨ<'o;a9n/(u1.A4:[Su13^ )g{HN'Y?>rVDTh6& 0AYEB&|lAh{"Mk9(LLwj6òY`vݴ뫜SġJ n.4۾$)PHZ.BNRm<$}\i XmcHJh +)C%'1!2'[i ^p ;[bK̴'$$̛y4G+ ?Ȭ)YJ/` +VXq~U,'i{=p)@d5Wn%u [*XfTg|Y[i +6:>dI俒]3(% ޘLS%/gTATXN7*D|l + % a^t[w$xʥxL B_Ö:G V+kfCP[PaT}z@wj*W䧕!!GF0dV׊S:In|!UT.|ѫc_Ռ͕)b QS+}hPŠ,h)$c>1"he~H:>-J$hGLgu]X"ڛqU#[Veʕi6=ɕD`n參w +!KԛJ\x_0D0EjOLHJJd:9-FG؞-q4 7&W=\Rbw11! EN$(RZJtދA:u^tEBaiPVVd +Q>gPYbă,ܱ:*׼N#`Df} +L(Rsʧ=GFFZQI@YiUċ4yu>=¼ỈDک.ҊQTA?tdtL߉0ª"ȇęj?TCBQ7AI^S\ux+a^6a,ލ}Gh>HGcu[|u:?GX&'&5h zy%Yg'ZHX;E.ZaהN>R7@1g.?OT45kVAtw|?|"UEП"N UTT/G㇢HSxa+-*WIG hr1XilӘRAb8 ?T`,SPeyuSUxK2;)LKXh:G*BR))6MwG d ttju+ai?LCy^T;+أ3:nF{º<ج&t"(9~?Rhw)'gG=<9'PC9Ե(~1ǬVC}FϹ6aqH4@^LHP 9 ,CAEey>g1o%\PnO\s_L4l)1+@*@ypu)s}&ٻ.x jdR R{e./K2n*e}q&V¦l{/ [RacFڹ?n$LҬ8oɗEER"mN\ԡnʖxQMz K2NTT2ZUzPSdl,p0a!}@ؑ{^N[xGMXh6޿t*)EZV^u%ŭkJ 7W\p^G_VU&L眼G3%]7y$'4 >MmsfP7q6vǚĩ@`{q+T-4T6h6.:ouC],/LFo@ y?XL/LGSfԝqhImHݏUYoxoZ=i.(y͉2$% _Qbө>)r_J?|4<2_*Sq㎊ѽPU0ƍO:\NzW؆c}#7ʙe.^H+|ㆆ*}f) ]jT?; +b"[4maYe6n7:=~Wī% =@sHN]H_-˓ m\މ䛃> [oM_UM>/w#5^Mϱ1C +(r3'ԆeJQqZ1@ r`5Y l>J@+xO p@.7/{N+.[u%.|yc+A`6kBGX ,>XLHi#uLU.ۚ|6ڲ8EG{#' 8|sZv\ڋi̸B{_ Pm)%qDw9fQc0SH472⓮tX=1}ƙgFsMwWf]#D䫅b?XU:d,NoVbzoFſ莨Z׺1O%hHHkW,PO4FthƠel91OTU-p XdDW+Cy5Q<4!#Jrta+&AԲT J$$#ODfe$a*n yMA];a蓅5хoujRǪI!jK{\GlVJŝsS=$RzpyuEfjNNR+Y&)J uR`4W}LluR-%i{ w'!Z~fn⍸vRɧSDj +*IrE.8_QR$u$[.h5@~l&2 XW^3A]UΪǢ;5@1 0fU蹓44lʀ} Vl^@#u&qBqH8fmH]"S*Ȣa̮8$*ٔ]k9{q.|;ůQӷ+VDk ]/><^vXj^}%lU-n!/δM7;O66ůfY3%YUck(k@ly^"εTl,cn"D!^$X4褝E66"+Qn@4HzPOˍ!;$,X#r12tK3m8ْ퐣ȋ\CW<ʁIO+YWA}vB^Y.8Ff5ԠXbj[ MxC|EF2sz ̹#^:4ʛ蔆ݏ8aõīo{OJRuJ[L(E{ߴ:o9/26 =e!ÕB9+^ ۾'oٱPV|\ѕb3槫JҤ _MOעR9˩njRx؍UuU[<łƊЖCI-8'"/}u4"3fFs)Vܨ/gt+M iNn, "T⩙ UH9SwŷwL]($%mL˄.Nl#קxOjf +J-I]}ՄV ;I>XT8NAKeGMRrH974ԕp5׻~jZl vZR4'u hm-&ۥP^!G9"BvDqQByM8 +O$1{)ddp+Vi+m4'B.7LUjxyޥNrI +CCqkKN䡪f<DzhqGy/e'R@~NRek)͐@}KҕˉK5hmGQ&fZiZ@ˆ!`R.#c&&`6CB9Ub :^Wu +U*h%ZP̦GBzWz:YVf4Ќt1\5>[ p7xXsOa7em_"+gY:XԮ55&[$.;|adk ULՒM?tVDt.NQ.?Sl3|gWh ]P(y4r=ekZmC')?PG'FEGnv|95TVQԐIpŵ,?O>Fi6>N JTA=$ߩ^:~0+P̵69TFn ;!.|!bBpiHe9xBjnIDƒ&VuVIny²%*>b] +ˬb9*lґ"OB//ol@5KgdO>A1 WV5̄nK'hSJP~S2"MOa>C8O321G^vSp>";i(14&eժxgA|?7\Q5.Se-TWP@/D@|GᙊbK`6DKΠ^\ mJ6%AIq'ʄ."{ϴ'Nki]h8#ۗYC(tö T! IP7ʰ4(JG ħMzVbQhR ؤ6Ų_}M&Afȡ~k3@6'3 {mAǘmCRxǛGҖ\W.#O"ZCu>Jcܿ:z?R~x=/$'ǺY[h&!_u 켽JpJnꉭC: eCn+ÛO h7q[1e~MI8RtQNHFwTө̋h9F5CP+VphMM6m)o89۲$[WߥweDO˔H:lKLQ qd&os5l7ҥ6Mm!&+Tt>+z4%*r˶J}HJAAd9*`6K#pd193&mŁ#Yw:莾-d(gq=x/e޻';FK)XnKuU$Y@|Ot8-67xapa }=auR_b&6Ҕnq$e'3ѦrYnC[S(0G!ծֶN}0)^mtV͖q/yIe 6|"AV7[J]Fn +IpPo{'[œ/Baц]j\i +`"tk H +(e@ub{W'=>Pp% ]djr)E +$N]6*;ZNc_:fi+f=:>/ljr9QJmqؘ]҂ Аv6]e}H_S #Zaū3m0Kk7*)`lv#'L=lV`7 +FGSe! (Pq/%Y!yTumt&NWK=΀qAuVUu研Y |w.Nۮw wčJT&\RNl"?tpi:AxzaѾ3Z—6)Q)Pʠ=X54GԆ[u+Nն{Xchp*R|fĪ{Y*RǘJ4/)ng1&9?K*[]Y5THU)]UU2j4Tp|Ǟ*M55OQ-ZR +Фj Xq#H:YI*HEw\K8ua T{#2V{n?/P96OW-آ|ҢN=dfT>|55}KhJA$qcq1֕>6ND'jti)7$XD1)ȅ% % ]Uk:wziyFSSYܭǞ|K6 .:T-zR0Bu 8w˶9AxF5nfmp +؎1LJ572Oy&R((SUJN smDZtdIPnaKDKlCauc*\ _wsYڽFGeJqF߀7 +7/F(ixHXÎY Mj/JBPإ=f.% (xDHt\놿TbU=ִRO30{^u0] ZUP~*6;9Q\ᕈ1 Sp J!8{1(fdP GKpT:dYoMjT$U:'fr@BSbk`q@k)-VJr&\bSSi @CNe]S")%-`ְNZ>򜙒=+$<*S 'JB1rgE8)n8Sq{zN:(k_9PI'a.RQuB5:@q')ޥ3Sy+-FoHb9)n,N+|VƶCFҩpKBzgrbdЧ)@jOBJE9)zF1 XKE +<] "!%ܘ.LnR(Ќ {#d 8AiJ$y׭Ir!JzCO&2X]O $GH1QfqE&Y%feX8t@1)E$_Ϩ#=GRtH}d) B I8}=')y滋tY)ۍѳM=;xCzJ?IҶޙ|'(ȂST}v2{V1V`9{E.] 0C-Kivۋm8g{--"jS*]Th~&&/|%N^еHY&OJۺn&R!GbC-7RJl79OxcVJvKTҵPmmzܥx<kF +յ22y :G\8Z9(%|Io1Y>:АAJP) IbYZ|)h| pR7:~9$u*BJTuz(ްap*>IJ&3nFq?W1&+3qyrl5Dǧ=0ê Ej,'[T*/e^%4]'szThI? +d6]zZ1$"~%(Vxo IzI񋍇qe)2V>]̔秿~i;.29s YeY(k8/{n0ԘrB' +%I̠Bҵ'[s- +e2-PJMR?Lq4{׏'^d|A9/+'Pk9Xc>Ӵ6U_LO_em'TEmlQnzJ܎ L+:lh1I< 5[)υ8c.򨏉z}$&~T(Ԕ8;Rm Epl^){>$e+|7)H/ ~ѳ2-޿ 42OOӃIe<,*b2:ҀDkǤCUM|-Q`$RfI>!$) +c))ag4|Y$Oʨ.f>AW +)RqN\NSk#(H;h;3 <?Dn=~ SCzl ʕm1gG* &`QzQ֓Y:Vnb-~ ~; qese*"@Kuj^]EЧAM疣Q2|v6䲘TFUVBm,2t$7HI>J^ik7Q՚tgA +]FDԟWQ]FN$Js +G2@nQYQ?j%2[A'ύ͟+O84Kxr"'캚G_F:ܼ1:Z[Q.l W#o<1Ǵa>%\j06z4#SӮv>I3 +i#K^CY jtHJ)DƓ`J|퉃|F(廬P_L41 n +q: }3ԫ3 3ujQ"*M"3YaźrQi<᎙/COj]Ejݛ,~|1$twХ3|s:{F}5bgTa>'Fb#`~ gT,BTP~-ȓ mYP\>jJ s7<0Iœe b6q96j=ҕN +V&d׊Yo)R6EKwA띐j^^zaA)88ę%" rJОryZA˼ғ3i V3' +G)C[c@Խj縫*LDQ,ZW̖i]=wP-ڒm.*s"ܓz l‚y$ :VFk6\c"%5: +~X)qT; MܞK^qK+'8B̦wgtdUk2MK&6 M竴SRwNu7971wĜzuIREOPF\cײ@n;9LxP969)8/6%hyc@sKb +Sr퀇%Ҕ-V(w|WO$Y8BP><=fA^P@V +  pVjRHb92Ɛ#SQMt-IWt@svKG^a2RY@Ho,QUgH ?P5/29l!=(Yt}B<]j}ޘӮZM5S%Qff2wI$ɍ~7$ >z2gK%l"W$ G9UiK\ZoXy;]DkU|TGmjiyK4)MB鬺eUI*%.BU$]X|AMGʑwHZw~7 +`]BvaY\Gw Yu|=EKzVo3T:F:_ ei:Kj߻p\̣S,(WOgQ2ѐ ö؝ IW&6TM,Z-,wSkJBP>cmQLGx:P6rUrN 9cVL%CK +|[g܎qTJ)i6T~8AWX67?ֶo`Vd46QI* [7I&g:R^vӸ>Ȗ ;"[f>p{ƽ R5 k%*<Ϳ1tYL}`e ]EY%MC$K T9.R2uIN`-ț]YZOx{e* '0>ˍn_0!Iꯦ|fX>ReX޴֚ +$X-ġNP[en%7m {Dm[>*{[ixX[ Ԅ U+[j"uO>i˲h_R6\Jv V"T(s4\I\^F#aIԭ{˗N\B:em!u^iss`9J.!9[PS[{[ *<@7‡P#^Q$Guee*-k.C8{s +e@ۼD#)(KJ bB1ɺtк&dDeDb;a9Il:XITq?Lr_k'0UKEQn7${Mu-4՘k-{Dqcb/8 |I$0m4"9{#VQrNnrIZ:R[J4yʚ=cԀ .Ce?X!W?Qz y1sjlۖIAD^:0k}^n9JHuagZV?%!4.˭vqKjvI)[xLE{$w7ָ $)(},];sj:gr_I!iBcQ P-kJ_z^[]8};Gҥ(~k<,\.K R8]/“ffbʥ>];: +PdWGCJqJGپۀp@ +LzIqm +SGB*M+0d!hg IBxyvyރ@p-kwn0WK{%D򸄟͹63vl{B/rGc܏)gX).ھ-G}cm`]G=ΝSc,FT늿 {oVeB~6`VI|#?҄v7ͫl!9rrg@+5V#!jX͠RZwhiVIXX(ضňЕHY_&  +)lDe!&,ly`wf,$'<5$v϶;QIv718k$uRVC?6Jܥ%!א p,>e(S_vZuYQ* bYaލә .m~L2#VOoL?"e}nI*+7@u}wxq%+!=I%GtrjRRTn[aꖢi.*c +U|#l0a3uW:Hi# <^JSB t눣fV>:vBY*X%7t@M8jz7;<'.)Q)d7Ӊ!^iܣqe\Sʗy9AHO <;N]S4mOL鐤΢iDuA(QFjOA,{FO fYΪG5Qԕ$Z lSj#zVUEJ _]Q d& -Y颭ZJy +n8S6^W]:PZ2&mNa$o 𕨛"7k4%A\u x%fA]x{a39D76הVQ-dRbƒYBR T[% |M~6uZW{d R ⇸~1X/<5<} ʑxt:f*̉)n,ܩJřnY!kD듮QRŹ2ŵfБlRсGL^uh59B7yiG͸}irqR!KH}Q*ҦTb27Ib.tb!N>(Q#*EԐ^^cNhߨ;_ӪܖzA s +J-f/,pޣ䜖.$g[ltDMrn;F![ +6 :ϺKb'DrAP3tJNe 7j2^c"Zml]IX6$0kN708d[9㾵JDJRtq1_$ܤ>IаJBmp^+B랦G)=zzvKi?;J|[W҅ʥ_0Rp3k۾ ZT,N<"mcTa6TizhZeGH:A#K^:M[D>i}”I&\3yNTTШX s{$i!);EmT\D & a ZeinR6̺T)?O#63ySNqҡs á@-ʛz&:N"<:Y~Y`%IpIEi +^pʔ~HRÎ!"s7'a e >"+$ԉ|br|:Z/JqGA]IFWDʬS_a@6?ozy+ʜZd&l?a-' H;*Tʃhp@$ +͵yԎ(oVUΙ8rL;]ޠ,7()H|ŸoYQa&5DAuR.I6BM`p#TU!A4?% JR--> j۩Ru)WE82X(G8s:îZK2BBCۤw_R}">Vi6* yp5! %(ե\@nIj+yOSJR!aoV]]聿|H2l $#v`F(*zm7xvRmIV:"cuܽf(3VJmF@JTx9nNHOTrV$ [D3+oO2GșV|HQÁe1T Ȓtf\6}PtE%2e}jCo9I\Ih ԏ1 +rNRDԽOI'd8 V Na M!h]l:]')SgHk)XuSĝ)ۑ8z$c;JR~RNrv0›2j뤱+3Gkj*ߢ8R¥&*Km~sI\p0ŕt,|) sIWIмSo=$a-)'qZqD6O CMƠZ=+9#rG}Q4f庋e$əm!O@oM]Fn}'馝eZTGyIzaT7'Z0䲊V,b!I$ ؈[{%t_ 2t–'K_<8عh2o%5l,;ߛ54ZVmIDڅ 3s/BZҦ@UE)$I߱aʼn>Xn~w<ऄq +Q$ &k*7 NR[a!rZ\%ϋ̲RE'ﵴ +-azkj}庥)QR7'|Jj$V,9Ib5ϡ ` v@Xh-CNu)4:,jelƔ.ChPiXp41xWe L:v">~&Ma!U *Э\'uX'Eeӡq,i`n5ҒthB߰,I!tjOؕB6N8c F[E4;gQu(O]ԤfjzyzSR ӤTJRER^!+6')3A w"D?P{DbK}(N鴎2oz-$Op8|*1"U砂8L%7jʇn~¦m.}z-NjR{}{9MQŹ8HlEjlXBKhP~Ə}.?mA/&tjQz~&TND)dqK3F^痵%ɨ/o:{~8o-dNJɿ1ޔvO[S/`Fac@mxaɎer^X&k m8 >/OhAAmUt/;Me+#_ܦ! -]jBF܉Hy[28_ǰJ({MrIOQj^M5Tڋ!-S%HU)Uɂpcp>4PZI[b!tYj=Ѫ +)JFNciniE^!2H Kvnf=s*<eT4{zΫu{q@XwF֛Pa?j\[9vX۝h *ДTCjJܡDl8sE=-%#Xh/(ero.4O$S}9Ć3Lk2~'U 7hǞ"_[:G *$Ҧ*4T@J@Р#h.*3X~avګ(isC]v7z魏Q@kգ4ldPaž&^S +S {ᗂFjq6 &Ͼ"HsXf &!D#^u]ŀTRþ-MnVhk'TU$褷CF%4YI@u&QAQLRP!zx>d֯i?čWMk}D}3ϵ_lK݄҆c껐=bp+7:jN^˵ʇo>=qήC"Xk3LeɛRnφMާ}D%j1}]OTumBrtܭL'/q|~pmT>|%E2u.5=mkxGMO|=0[qypÛurZ6HVF`߰al!1^HVS2K|nq.XnS#D].4}d/$pdD~rT[+Z PV}0R> բ[m} ǎ2 Py̤n"XoU2:Mm\9KI O:2|ǻh<㷦`,㲨V%/N::doE 4 ?@>7荆*1@ z@^@>G_L+R^Fv;?iZ֤vU"#뿬İBVRd91HƹxB]SJwQ|-qjlt :-nݔ=,ph J;&ԀZ馩=Bm.lK88+ҖoQRB1g"mA(Q:yܿv)qȧGSiӉ# +IS*[S+)>_H]vVd&=!aEPtOei?w"xVGiNdzK-p%mREż4uY4NKotԩetX1%D6FQej@b:'Ӧm%Y$S3m1Ї~Jt r7& {ESh[Ёc᷌%ձKT$vspm?>Q9QN@ :/}"2$u[a7pWTT9"ɵ,, D, R$ܛ4ʕ~~b ؞\ÔYG.~Èaˆ%A +KVPOWgu-wodH2yågeH+2r +J"E"oХ6یPA +qβ&R>rH[mY#E#u&tӬYm!>1*Jyŭ辪%E8ZvX +4|[MJS) q^KX$jtUX>*-,hG2XR7Xr9i:u (qB16Ka +RT>^1XFMP#]n6NFsFD}`UM鮆^ ,Kj۴;['`{R'Owș#ӟi i߲e<&JnGNn!,4~㱉VFar8B`{(nѼqD(r6]?ewT,dD&?MaFRozaW GMܫ*НOrR(pGb0uaj.o{m!t%b<ۖdtdF..JO<\^QpMO䛧TE3I% +XhsT)XmiCZ*̒'mf4_22dc̈%t8VHP_Of*eZ)6p{Df,2&_m5H=A2E4Hr56 k^R,Ct*oԾ+}ŐTbAÎ~ d\vxmI>VT-t۲T ʓb2 B4*[k6Q/Is.~W:r (h;{ŷ% t Ff%^0{bP~RMMwSz.|)TԈo-9›RPAƞO>h+HRO0EAy Jt m/)FI{:kM'&dH{LA!ѱ[`)I1npƫ*[$P9IK/.}Q'/9,ԴЖ&Iʼjڀ|:GJtѤKbS:k!=t<!1ŕd̺ZX}7Vn@BG34SR{jpHg t2ɗ4 +Y([>@HMK4ˬޮZ,-Y_,)E(.>pЮVSqX{̚E- {R G|r̎GÙIdJq$u'{1:of㭡;OjE'ELT_qi$ BKMSқ4)+I 77bt}0Ҋ؂!)OފMrhߔzd5P`\_ +:gԒ n |?}+^-O 0ZV#90 t0g:~$NIc9ǝ$PߞVP[q;_V*m[qFQ YM;Z-]5Y@m򖜶nDyo#JNh_aгFe*ʿ-mN̟ƕp51y7jRxnU2qܥd,n:y7]oA#xHi}"WOZv'>g*Te4̇~ J,+rnqr; ;-2ҮND6c&%ITwhĵG+F$KwU)(9El5Ep8ĞR/,;'R}"fvP KhI$q ly9s r/%lhJU$)'3@<Ks[Ҕ~ͯs n1R~CP.䐢=PTM]G2̼5|m h\"a!Ze+%VcʧWȭ*9K,_"}@Ǫ+Sh:&eA JVKdZHl2CE#) 9OiHHT~CPWe:{}ЫXRzQ,8p.7N&HTtN 8d+F$OkI*LmGv.qFmEԭEx<ҥ+Jn:iJE4VPa}Etm.Z8JA[LbhsesPd:8KhRR/ar@m)6bDs儓i$j|6Nb)gsA*fP o&?@zU|Օv2,!/Le7Bro@Z(첛I`4#ۤktC-8SNI ) aDM(Q_D6. _vSnfxS٥i2J mJ]d1\* F$2$~ZT(u<b> >N`!SN%"$Xz[fqV^hs"@37M>Ni.U72Q8V[ ~Q +iIv[KnLx춵uIo9J#^(Zi<"ld6yn*xms-UtԞaz~ Z)\nA޴~辩\a3J=RyxaWXk0HA뱋k]eןmL';Lӷ:2t_5?'(P/Mr)RBd1 +PvtX߀;q1J`f6=bȺoD?*kGÉgy7q&ЂiE8n8භl-GJfV*qo-(@BJnHxbXTE=5=4$ҟH]-$:ǙRf - Xw$K-F233]~'GLJRTؼ. +.[mM=X*4YNF~Za'T4H+(:p=$- &~Q+ZRno9,˩>mƹ'e%i\ +Y>H=%ǃsriH.M}2YubTNe,P@^5XbE Nu`固ԥt * ^^g֒]"\3]7laMRlSrSߵ߉DF15*!1Ip릦iuӆNw7ԙNnngP+ xxă7v!@t:@-ERچlNߌcn#/ x! Z;N9=jyr^GeF~TYL$r^Iw.-Fyo><~;,9rc?VhX9OXj 5,Ն +|ƒ.I>!FN8QJyA(DH~h,s̺*JR4|'RN^;5YTiCV;8$#`Z<>RXC 9iᰐg~A  7h[adڬjĚr*&)Ym:P\ʐ%7|[z-UE!}^qJ + }DŽ0xK)Ik9:9vUۍ{oc֕֞urޞz:\IqOb$&e:ⶤHO ' :ɥ/+v-+RHܛ Dp4'I@ "׿+^_ +8fwBr86}R-J7nmh:.|xU ZMF,_b-sk8-UO.F#==0%"Fm +ϰ)3\; ¢DjRs>q.Tc`3uI6R󄶄t5L(\4$IU朳Icd\Y^u*.9><){f>;sŒ:j0jyU,aN({[4#+y$)KrؼSe[\FQ HX(-𠴐yL'() hFV*qvYu\0q#;MtLK(cCAƂU F9(ҋZX");ˈbkgN\SenQ`trI%oqiHLQLٷ:%V4f*loQOS|+fY +/1&ĹiEb_m!јBh~Uj nc*`A I QQEZ}Gu:M |S1Rha)ZHIlzO9*s yhOt䛾FlP$Z{d3<)uJ:P*:V#Uz]&t5unr7B'?7:u XǦ(恏;I)8u4amls:\d;Y+Zxʷ Ai&ӾI>BOq +T'dA"bRO* (> +_{k +2EHjЗ717әY/09- 6Td *aD17+'D~VI#薺9"BtafteЫE󻴕q7RTwGQ2{hHN Y$b=]r|RVH>*Q(IK!ViU>@Ȕ'5I^Tল[fh$('d7^ݎRA\R^splHbtuӋjx|K$+Dh7r4hҙG[aj-ԡ j㲷d<"t9TxrJ[iBHTvlhܺPнͭ`9[}8\m<#Akb$I2=k 89@ܶٹ$2u ?GҦ?[}bJZRnmB]"V(~%Ȟ>1;Xΰ4lez +*-C+wnIOGמ>f6JwccZȗIT4dBi}xR;Q OeI;qYRbEuz&`aya"j#+e.ċL FG8MwNljDuSQ2 4ٷy>(MS`~"$K.ֿ֔Ьvt?+H+HjDJ*jtR8XEYiե\<[ƌ+cے=+# (Ѷc|\Ozg>SEDyY_XW#m Ѳ۷7ó54*\ٯ?zɺT+p?gc pE`"ɿɇBbM'a5.!5ZjGfSv¾EGPxc+ g!+PӌBH'*Uh@VaeII^_t R @R`J5#Lr)4NZ 6*]Cѭ5]4IVlbuB4'10WiyOǺ&N>IGW:cCNcy4Fre^׿8jLc(xTlh00nf#E]mt̥H& iR<W>VkK:^_SnJOclM4Pn/HĘc4 =0')*7ɥTmŪ*!&p xfʙ #‘q[IVBmqJ{xEZVx@c )uCN0$˯|-ǎ!vpLҒ$YMH Ęl;52JVhsĒu&9+ ͝X*N梲/%))&3& Jiiy% 8™I=L_uNknRtn[4)m a Tà[A'.iţW6L!Nb +UE (8VU'aWzeYT*=˿q +m#aՏt*͉}q>I +Dwb+ YhDP6XW1jXu=_z觿px}4J~}ʝ'64Jmk~V}~WDO o+"Z$YNO{>-e]$Pe=Vۑ}/.7ׇ9kl+1^'E(W=,z3E!  8TA2L8Ufc5Lh~ $(g1U0qT)AJ:=~PTSz^xF8fՖZty*'UmbRysNˠ}'SG4ڶjuԔ^ť$)'CrB(If+f7)5<DbJlF,2S=U/b + hSTś(R"3}bB/:7I}-d'VG6T"r<%gA|ի+ًƦfT.ܙr1~BO9k~!\WF j~'b9y# (a!s$n[b@bzwMӺd ą4tY)JErOsM/)O>I*'$&)+T*ZԢnIoPDHs^^)# ?HO!8r2dhLOf+"yq&`҉ #}4QSuQXՎ4t^T)[KKn\2MSj6Sg=btIAPfmјd(h 41SL0ToL]E ,~]yՙ 2)*J/ DJaSOh݉^/}C7<Oak_^ڠaS$ &A䤨#}FUKufoO# ,:9ŤzFg+ +̂+ f, R BEOt<È6ROk)6%$~#bC#6E׈< H}hKFf4~p\K R@b%Űt]03̤-LOy}wz;Y&|ˆ8XBwMV#0ǘ؈$ffW>tzYv{BTGҒAA&7(nI3Rk5)ɵCm2j) *RHӺ\Ky"T%EMNlG(dըNN^+k/:Օ%*&ɹᮦuN2o-~y9w=e]}M)ncm~mn%xR خ~Cs<{j5V;OL)#*8)뢩)tp%j5mȈ]MU0Lق'Ax!EI$rźOSd>ѸP#ŴI +Cu^iNCT^TOZXn?>xzHMy l!_aJUU)1Z(}"<)eR:(%cCP麗\r=y.MYJVv&Dri]|[d9{V(܉ҡڷG2\iehG09s:b;Fii:}ijS*Kn8줼PPc= "e+ɇOh6HHԓbOzaeGŶNjko.sKR琹y&uɧ_ȄTP)Dhx LI^Z4F7-4^{I+54HR]6|\2<_?{!98R.0NB E+G8t.COV% /ÒXbM.N9B8+"a_5Q\$K@2[ٞ_\oe8S-,pU{F+Lr=-,eI)py^SC +QXl*H6aD'bji%5[!j|BodV:h-GQe4m (ry'DT1[/8I2O=mE;1[øeFA"\ݞ R}JnNz T,D4!6ObE<-Lwt@Pj+>1Sdq̨ * öV-BRm{WRUɹ,'&fˏ2\-tr=~qq*r= J AJRt̕r?w1 ɔP?D KK+nbQےli6 +'Qc#t H֝'tϖ %(M.89gVGqDX8LH[Q褭6j'c NJ"]* Q6Uu/4:mneeoK.[pnJ| @S  +ON+i tA5(\VaI)H:o2PLH+)i.0lnW5qhuI+k'q UM>'TF(5W +eyǾ ={J!֟Ϙu%$UO8 ?k[!ӡnڗ6R|oW8e;Xd 6YuUlc|QXWF3I +:9t:}-:-"127 ms~"DՕ!%)O <#bTMQ*:\{"=-_ͲZP߰"UH(JMϨ舩Ο{+?qKk|wP<:=O Ds8y6Dd!HR}8Õ8H +"6:e*b3;4e'*/`):/C\䔩K2rTխwpʨ=:{,v8UpiΏ:3,(YOaNz.:д%IRH¢^Jb,v~0ԃb$n miBF'fTu*χEJG9ZM8Oep; $)TPmέ' ]Gk:J.Ë9'C)HZL^Ti#6)mKt +%mJ " +\>OnbO6rS +za]kRq%]] Օ$&-yVBJUgfFdNIF䋆 +R-3S&1NBqv.N[8}"@ë w_)i4u#A tjU'Q2.HyI\BbA6I L ^CN"ڬ(mt>*=(rny}RUkrK8nKv!un +!ihm@=vܛj* +s6tB0M2b$IqeZbt +TjFtRXe-J~[Q~~UrRHZJciYU9rMfwR!Ê~K7 [;JAӓ df>re#)7RS9~L:14%V2͒:XBO){@zԦcj57@a^1ׇ›R ) ~I>d)n6ʆ`HFִ6*K1k (~rGCr!!9 R_V4BT˭"R|\$m 1׎{.o8@J [Ϩ*L(o vx~-><ʮjbƘRq=_:,ϭ?/iqd抈J$'.P)K إ(n#j&)ņhxopIh +*]Uyb Xr *6]F%WdUk,mA&)_e8פeKM%=bŐC̞1)p&]Ii<s$1n.FfhԘ*!RBV,(|[R.) (ÛN5<.K l >qs:V/fEk n0䔾"bsW(jG5h 7SC_Ei6eY{MϿPqQ~F[d%)ʊv.n& +!՗ &<@:m) @tWy0$%MʰR.@im j򔒥9)nIQőēbY8Ni4;".?п (3蕔s}9|Ї Ii G8C̰*^W~^}V ,t D ;ܝaT$&wTv~5;Ǻ秛G-mR,m}66c9Yibj(u q*B q=&,qI'S +I O Jn]t/:HIO5(Ď %%1jVՋ-ja2vfH;^ LLna30JJ*䛐nc#ޥL|Qq}:x!D%I8F8,hm:iupu, "gd#Η-\k-/_i6N7BٛnyN'{(KT=m0IOr%c< r-SAbc31~W thS?U;lj.2Vۈ(ui+ ’pij [!@0[jaV },JA +I 51.I(qbW=\a髫 v:Śm& s{(Go+6V+) )W7';)$k p]*@4*JIN.cZ-RvDlLHZT䋑߱(uj)!.\nZʀF%l)=s% V_[1Ewd%Ԡڈ[![Y>MFy>kP!BV)j"T-ԆujYh1"O-drA)+MT%z%)DȚHkZ}FHLy5 +o,8!HSm@e,",\: + T&2'-Gd"2LJ?>2҃3 >-Tq`vNUahlyƲz^ѩiDT7%@Sc=qCHܩ۷57 Ff ՚vaU Z%"뎲W=9V)e^7$ܓsp>ؼ8? ~iZRVVꢧ0]ʑdwA]̪*ހ sֲRtJ;HbuA\vQLi 6yu _ì)pi' 'S銉\$&j}gXXiJZW0$-Ca`Vs4%ΉGTZj,;oCn>A#\J7HU:d+$iT+Pԩj:"ױ*<"Vs4dPBR dᓗDa(P=*ʦ.,ܓxqWؓᄐ'@0Ύ:rOF-%eL>}oҤ當<ЫQ$DKTj y@h/Nkr) G6^bc#DYi:z ɘo^Њ+W(udx~?:/ofԗW9gL ~UgeSH.eWnf=EY;lsY5Lw!6mG}Ko..'SCGNiK "9sMk $cPEAzʣ#[9w|PrқGÿoJXr"J32Dz +Le:;m3/BZ)O+Vkh-$tKxQgۿc>.>;5SYvӂZ˴$SO/T?_BEoίEވXdEnnM Sc+W¤GWc1m(nN]-)m,:o4pzШԇGD(<[g!6c|q&9537YocKPyB/ ~?tM2O,lT9م"C@? K8ZP =#X{wY$nޱ n߰Es]ҟ0*27N9G4bqLjJp4J\ {bL f1_A-,5RVb!̨(QN%rip\s+ӀA3o%GM!KnE:w)nhwkzmhͬ*ay}EIXR>i#abMܸ5$XG%3@Dc:ϭn S.YB<=v]) hCSKIGT>Zv@ B.8xpR4<|*ŰEs %~ʴ>RMFG6Gp/^j~jWu&NqcHB eK+;J1t9L6Lz}28­uY!G>xZsGS6=>̻UbXx5UT@?Z>O昛WH{֋D +ѪCOޱipv;6lxtr9r=,BǭiLEs~} =: +nޔcΑXjHϧCŲ8uDTh{VfR6 komس:<5ݵ5M .^1$UV{w@~X^y +?S.z)#.^KJQ޿<{TY>HT簈OOe:{dV216 }eT~_<Ų F;Hjֿ!^uc+T *uH^6 y!g&(W\PQG֖q) +xbyq$yry/҄b>1^t;97SGS'0c[_\|);y@&ZGUc|z~z4}R5rߗ* +&}T`\ + Ӓ&?5=Y}K.f6H:ð>v^:n&?'{D=YW1H|mمLs*Cp_l&aS`.~lh Mr j-l yF@l|] {!Jeq?=hcHfcem.[mlF.A**b̓b5R`K͖d˹R̕*2c;+Ԕ}qtH#W(t + þʈa9e#FdrC:Уo}n.ȒH5uJ~=䤑OzeIp4T$_#P;eb6HuLӍ7qj\)Q(X.k,g ;L" LȎRp*P\x8Kf% +I>F%IH(̎/13GuBP Uޕ$Az钽ѦVr]UGx'p|r1|&`5ԃn<8gDt^T7RPmyRvB;Hۘ ^e)2Bb(66x8zusK38 SNy-؍'Jd[KV8;@%Ki?w)WJSPKD/hm1p71%Za; +%GhP)jox d7 u4\qJJFQҚ_Ch&写gZ&S.v |0CI (6yΔp'a PξӪJi&eRKrR5A +^PN5;VjZf1JQ. +kl,;C0Ԟ'z +=Ul˽ nتp/+ nu +{0I#;rOf$i5O"%Zzшʊ\NlxG1X^eV ȥ -ϻ͖2mB؋:dnJmTDVU0RY.l6@l^5*;U֒V#(('R"f\<*>vɵ ˊoqMԍD܃e$-pMƤVWCm'R7mG&J1F3"`82lxCyBsK}'Bn }1Wڿ맺C,ը)jDgKmjnR/Ҿr9ߜX*V3U\ZQGdM)VvnPn RReP]![4ƪP%Vq +mW&8 +mJKhx+0 Y +>qtzS.QNيn,~WůeAz\\@7Nl+vJMƇKB.q~:dp*u*NK&8w%%(KidrJVUasЩu~ \OW0Sr'^vm;ߑ4ӕmHarVsǙ.C*KyխFߓZiJ'+Ml=?|ONr\Z;tyּBXSu)HiaJ{l1$AnV*YUsKM`fo+,C%kN{Wpiy// +B+;y{z9< ]J 7ļ<5H{UW),r%ks䶋umu*,B{I=tNWaD!(#aQ;)0d%6oMͬ\=_a)t^B)\Rq_}Hl)\{ Z4H[;,۪x媏SA ,Zs7M,!V`Cۊl.v^繋UȔVV:vRU&G$$ SU&gTV{1qDEd!%)MxQkum=ǨQ&ƕ#(& +F^a q*~fΓ'2kvm-mF>h1jojHq3˛Nu(-|$)`'xPRv_@2z3al(Pg%Z*"Mm;ϬD7@2ٓ)'xe0ug% Y46ԋ6exZ.QT|KYHP.RrH˴N-i޽te CVLy1AmR!7xnJx&[#=@%/)p 2WM%e؛(r|HkrRSq.2\s_@א:#jkV N۱I#&G[}9\HUba˫;j)< "t<6 0Ɯt`;^@))27*RapnߧШjmJ*Ѻ\Cno d۽͸ +X%*$xi  !:5ٖJ]ZP $/hH>L)4M%CK;ƈ.F3%IO~wJVͺEc >zv>M!F[-eh q{ +;qfQ~v7ڤO *(:ShsPZGȌsX[+e +xIQ'/q!jREP /|gR{(nGE?=L 8 tfFI{5{XbAr!)ڀ;x£= SaM )'E_5p% hE' +LxEΒGhTA9}ʌŨH`*X*)m!7 1udA+Wdk:Co71e>[@ s%zRn5^I;n LVAnT$c@TMb%]*؄m *U-d*UB/m x$l6qvZE1Nhuhm'hWv6pxU -5$D\R@@1Q+92I}Ֆ]E4m2o?nhn9ZO'XrmJ2~W+2QD/Zg(I\\yc6SkG{/jģTXID_Qlj{HS,[r$Cz‰q%%E$@o-MiM#44ZxI\kp%_bd.l/p9!Shs*$HR%mN ;qO?HBE]&AۥQڋ`%\%ZE!C! !*h8bHA~7NeWn9-$: HuV!ӹ#jv:^bDwK̖q`$,*#E))%Z\BnVR@9~4\%[X[8jlQbQqh2N%_FB-8ȥm>Ot(g%JT쑱 DU2ihvFWe*cb, +Sm[Vz:fTYmm JA{ tGD-vB|Yy~{=*MBSٿG*Z[$mʇ S J%F=.ks<*D)1d<.LzI'TqoD!Jr*ԋq۾2aI,ɲ\oi!<*6CIkW0ĺ͐(+:PZyZMWS QC@SlW¤r~_f^!a-mۉ xfyJV ؂-c4Z&i%$ Fnj*uB]VP?h\pMdKPЌTEԅza&vrv܁{\< TX%ƚj.#;KNUfH܀ s4#Kw>B)[hW(v'gpzÔ +T$FpICw~=X֞eZ[n%HB*tP8 Do's\S۪(QJ>˻$*>d0[lёev`{OmLI?("v[9}t\hV 79,"ܹҝ#nmdqW>&s8rkSk4vyazVQ+-?S~v`?8 +9Utr,tN2EyuVdL=ⷞyJZZآ&t6STyOǜKs vܓ ɥT\HPLW'EP +dPYwv[G|7@Ǿ-A=?[R+؅$_*"Jaq~6E!J@CҒ7<{!-TM7^nw|,)Z\YY_ƵTTyeSiFDETqṈٕL/:7$Q3B|2 ?\GU%շl`8B:SNuZ.'Df N2Lp2fx nu2+qMo b=Ʉ]tYøC6dأ+즋IGʶ +|iK67T/@ +glRA ƮdDQjiYV3P/δnH1RG'rPv *X` ?Kh-AWJ%I]̀]o +26hq /~ʈi! yYU᷶0fPf"|9N6VE*J|; N*J$>1.؈Ghk Z(>[, $\01kI}>2\QadZh s9*N9Q+HW$59Vso\WLaX +y)9/9 Nm8xUȑv{U +{KK%8iXKjNiZ)'oOtNSW$nuO ޥy)JV7e i-U)(_%5#Mbo ;JU>@}L ,_ c)Iu0橹I;] UoT^VRsŤ])қS[Ho-%y*l +:zt7hp#xzӡCKks=sDBZў_RiTRAeRq*7$Åk fBËyY@Ni{[B4JSs}!9ҳ2WtjRt ~as0˖VOz; 9QKbTٴ$q+y`fQ<};UY=h4MXjxJmu)[d!-z(릝Z{Rg/NcR:@ v'lXRq*b(ukm@$Oȸ:lJKay[dPuhClVu7D%f V[R<;E6\O7U$ W+.ȊTg*3enSPrGy1gZ! tceQdMS-( 3|?MbT +3ʛ:$MQOd#G_?~U;,2K/ + ىx G5Quӝ){Q~?-V b +_*|NCkI3ArIM;8t} +F),BPLd.J߸GMդᅦ툽^#_W˙{!<=~I1ϯC:)|\*t%5v*?89ML)d>4r'ֆ~1N\I $qkr}~ytIO"ǓJ9L=Fiyu/ߗIl=-*_'#*.9WiUVA6chAO WM{}qJ(o([` } ]*-6=royj? 7Ry&|B=sIR;Ǿ%əV9ʾ?P«,𣴻pYO@l|+ˎ| PjkmfQe7:z=#RJ}\I+XH('YPB̹5vj'cxQk-EwHcz}B_pERLVOE{tXN\dyqu%؏{t 7نCW%-GzNDGKFܲ!8үS^2YORl +RBy<|?ɋUB[fG? +چ&}WХ#4NWy2"T`ݕ/Oe^?\4:qV*.KɈOMS%AI╀6mHVˠ77mڇ "j|}ӱ@CNpb ::Z$$$G&2RV%Zv)+RO)W8eYrDY~pZF˔nJKjpA鮢}!vr_;(-#flɚPrbނ$8JlIQ<_|HKc\X-#K nt1>j`ՀCȊ&1SmYG6$\pu2lu5*Vtd66%(=pROⶴ>apXӜضБ:#͸snjh6Pi7)Uz~k$Л+)c }6pn='*쏋x1^3xSuypU"D@I/a9_?ɻ05HIrnߡ~c=岟~8Gϔ{koxs!O\UYhJ|XO~X8=mH#PգҞ'7oQMN7$Sєzh)?HP=qj5Z>WOeg-߸aPXLO50yz=&w>9fN rfg"صJ$1!M[09谎& DtsL/͍>LC/B1U|֏+$f6QrSGcJ6Z= J92aakH: +Gr}鳏L1ؿ'|HoG#tVpΫzޥÎ|SSoP@̨C&?MZX{ЫVZZo~UI"f\cȲ^i~|D'Oh$Vr9P9*#xe™yQCbm{|uRlJm&IgJ=I?7wr IΫNa +yPuk[RʀJZW,%FRYK_yxF|.9#wĠq!_:+THl~Q"= +/lHW.,%raY!?h[A1phϢwJx|گ(f ~Tz(HL.4~"k z 쯸)G*dƻA>O!#˾4:vIǮ KyW,oaӟ+2~^ȰʏMkQTwaq$nY'|fn øʽ6ؒe!J%!n@ D&2]B,GS)I^i~ANmh&VSZ\:U$d֦ KNӖ4lbE&!LI+y<ԫaSGl08_S˭Y>jSTl|ǹ#uxn=yGYfR! +$}Wu7U1>4]<{%LDQY16,H%ճss`m&2nːX*% \JᖺjFQwI< $$q+׿v#N>HP[3+EH!^<ϖG?XgI"z 27-{r+q)YÉ۲w=޸870nl.Av/m&;GXiyW̲3L2[_qN8㫹%DM|STv)JP$ZD#?>ՕnI_VUs,{$#Sy<[)I +Xͽ$)*¡d:E[z&!i"lD}4܅J㱹70 Z=Bncaٚ$if76vDN<:n@B}d֎PET J3 H'C3 5,b* W% X_.G#\Nq.t6b|xޟѝy٘BPQoؐ8m~i&F|3"-A,8_y婹:DgAn ZO4C%L̲k$j9EwLzU t,<$!Ia}!E1K;e pTCJy HuM1΍Y,۠knW(q1S*)u#t|wi3n]D(Z(--*%O^>q`8q/2qt⵺7˹vQ E Qt:uI'^ ن䑝^Q/)G"718T4ddJr.Sē^<3uBEi4GEETӁza"[|Ow42Q ;;'d[(I: d߀pAub4)N^F^KB\jI!hiJJ [4ʵ$DJ)3Ĭfn:iqx=(f?1A}۔1Vz +."Ɲ' !0ʗUÙHΕn;DwMD*Z܌FA)RZxs&pEůXis/M9M3eS&U2+0֯yJG! +lRix֛;(J曝t%MJ8dG Z>GK͕$Gh8AӄLa\3P(S[ˌ[ˁ)Px=8[KmN$@"c;ӆNoi{FzH+qZ-$-%RT 蛝hcK \ٟ˔eQ*h56cLQqvݔ/kw +%钇;k fhX{n E)RQ~:M;DT!}Յ𴹔DQK(Ai +o@ڹIfZ?耐ۊ'|)_\ҋ>0\APi |⵭I[N@GOԟ 4gj5H(ƪeIW/ O =6S7Mj`t>B 40{A^~TҦR Qi`+5 @ Egi(Q/o1<5Y<=ZԦeT%.I$ fBꓛ٘gSȰ +PIR䕔u)E$^&gJX~<@wfO7R9nȣUeBq">=ءʩiZZu̠,shPyr3j)=>OIy2q-<mԐUmB 96&Sy)V帲J''pC$)J@XZ?s>AY$I1-Hi>nu̶g6f8#im,ꄞ}~D۬x($o+M?7'buzNV( 1Py-_n[wa?$*2C*4iZCx@HV]~]GR.G>踭h@W\z5}Ԁ;^'TP2(qa5tL=% Rl8so ¡f|9GM\y)IB6V}p yy ؤ6U{8āL= B ɸEƃ3nfGbK`k=rkT>Cʣ.)r *Q$O=Fm!.j:#YBvq Y)0>Lg 0Rn!"۞H~Q/Ԕ\RI8e` +~58ҳЏ0!!eI7 T \l FTFr~H>`6 Mx6YO&e'OD:4{FsKU񺮗XuHTq m$spŬ%1X$)Gjh'%3~D'U'_v6wbW4Bp@V +ӬN܏LQdڛ! qMiEСs~ayͤ2B<'#Ya+l6)Rb:$Pv8қ] + !i.G0n/T:$t=Y/LUICǎl[AbIxڵ"{Zm@-,˨s[MVvS)Uu\$m:DS5UJJXEԀ)@r oH ED>*tRd%]? >ⅾJM@̋iol MŮm(n3Usl渉Ss%-)<qY);.uy1=+JeBT, \K^^juST:-!EEZJUs;i ] + +YB5Rc7(tJԒSb9b< IW{C QeWd>6P8{ɰUI6>PA8oĉ-3נh $ADŽgۭymbO%f)Tz^׽iAкbө#MHsl[ĐAX*@=sMUIRѽ.p"2Th7[OqIIVE)C&!eL +eܫ>m)[F]Ofɵ9 >!E-|4k |-d%Je7DYꄜ\΋6A)HVP{u;B .j2]E"a1)´R$c.>1.zIM74ܒ,,d'ha)%UjrRM%S`jtt vGex):IMzP>M#/uzD!@~&"uQH.bMY;8ԫvNɼ mR{c&XoI ;>l7$^~“mcnG3VJBrb-kmĄ*_kl(܃x}A- 6Rnwnq*,玑 ~Oj)J\u"Nnbc ~&a#2]oBH(N'r:uEZ LE%.A{~D[JX(@_[ 2ΐ*$s؞Tb{!V $"GR.\0̅G ЭGx4KKR.léƃoDBwt/1p-,Ñcvşx8sa%$l~^$yA nPb~h=9H-fJM 5k r~} 1˵s~0<|8\$I#}n6k?b.ufRhQ`ɨ(\)WE#ץ Jiy +4ʁMscҮ7v.i]> q[M`yŁ{YI)-xLfJqqD䦭?}Tۚ>ŚN6*c'ɲrPHs׏XԡA> ֆW\t.b:cЛS-%U8T2Ϸ~M`FJ뒫 :Bd ;9R?Ѽ'GfDw@=+8nB9%NT~ğ%UG?,G m$p+iW8kH$֎)0:G'~?z" z!az=1Sofri7S]P&YMO#AUYyTT&k(3tlyOáJU,%P~PVP4MHGPn)<8RTN_VX3[GCiFp[:ĦHTJe/֧CXcZM>`Wܤ% X$'RMŎjf]6f8s0# RJna{i`;4 S+[e{S!ϐ1.Dg?X( *moxfi~]Oe%@ MTM8~Q?vghCwyZl$NKm{"J2nA1w1Kccn1*nueت5] BQU9wdKtU]Ai4[09)MTU]Ifg1;SN*HWU3>}Ы8/k`SڜLdQa]䂔܋ymf#WCׇZ\Of2cnlQg=|iw4]'J>>+b9c9ӗk7Pu$) icV_˃_c=*8 >%kg- +y$ss&&)\a ,Þ&t ؛OÈ1~ {`Jk"?X ~V6T񪛴WBS!ɉi809-~ BocNAlzA#?P2|8z96t9p}i!ȑVLW)l?Th}aC+f<g[AJLOjBxyP n$Op|b'ŽƃcxQl$؃pG5@r˙`HRD@C}Ub{d> bcZ$6e9,F*yn;S<&Ǘ(].mi9[0䴞pw3PWoƛѵ%?.XV72e7eá/xëRQ| F&oëK5 fWbx +/J_["Dt$ܠCI6B@SKHK*qLI7IyzcWWNEV@f*sbT,I?%ѵ 8_dS32Z}lFE.qU6a0S,.퓙 VO.DpL-T2X좝0{ !SR%R%MRNBIm,C/U^cAOL_<ɷ;_f^=>6>,ꤍƼG+tďoctIN1\7OZ#e IW81*s*^׌[|DpxiδtF&-Im) +@p8H-#N:G];^՗Uӵ{ E{7 ެNZtYMdƔSm9%ЕXv-*53ZtԄN^2M+:pYcmGmeQN ˥+tB)NSQ8ggWX̛ *[8:w#… 8'w~O{}[ WS'*C)!OwU(hR8^{ηO6]ydhRQ*dYqNYl-TP)qi{}{oߢ-UY wt UJ4y49t}+]J,qqmCAZ)i|na#~^8!F۹@jZ숅k ]Zzj)rෝ=\;Tb3H@G/w=A<# +.L.fqb)6vnh~׽R`DNAXjeDy.i$UnI߈cFbҎmD7s- qCU;^ů2 &eN(q!IGI +-1efm-:bJuI.uϽ;~)SK-~*oeQnIWR˸27{zY`E쇶*.K(ePZ#܁i&[SG"Jn)^ +O) {<)M- bMƢu80>$M$*5,R8rtͺr|&rW,*|-/Ѹ(Ga~8o)ìP,%$1 @%rpmT#&1rnL",8p {5]8;|)Nu +p@zIujt]GSe$QTqbQ6OuZ%#rI6q:ZvjnNU0"1*"mj2qD)Ҏ@Eɾ+3˭!۔MJ 5J{S9G9|9վmN3l%„.kel#[EG%Sr=y:U0 L4Ӫ--l$nJPlITTLT,JAO 䄫\$$uRxyqϔ8Vˀ1پd6x-^9WYz{򜊾 +l5sUQ^ju5mG j&'TY+Vd(%` +Z#ǡH Mm=Y!\,Ib0JWTҖXu#P|@vԗN]А 6t:k=ZU'8klWԆ.&r'0͎Hˊi!]yąUʤ^S~P )>,<<Π,6_PDW5MR5r9d) +;$G&R*4XHҢT+Eɇ#L*iI +JM͒H_4meBǀ6"(YGWYA$&E22 LX$2#m1chnL׭RͰ܊IlXPu(JrlyXd @bm gPK+[h^?x Ԭ%:"51E|;.HxR7וRH- E̤DR:EtS%ULSZC)u #zU <7JҌz-ffnVoa<^\ ZÍ Rx~`Ia拍%5 \xʳ֪ǍﰈƗS3f*=lƙnK9^,qY'Jy._JJa뒲Oh|H)D=aqôZPi +Lq«mE{vkDbuzjV +^bK-8n +R8$Db +Pՠ s$"ARmA'1M9e!nwR +׈ƇYO{Ő')+F"ɓJ)YG R|o9}AG{ГQU)f%#J@'uBX +LD1eGGu6[UU0:Es|ETd40jױӾ*GQ1`=NCq4ɤi-jQA] +ŝBNby3u +zJq"pSdQ!bJlBߘ1v"N/4S2JBJq -CV:IbkPhZmqTU-7}1$+ jfE$SZ1=G~.N=TЖ[}6wl G{pB =KgC/ 6'O=[l-&l7rDjhoﭷf+o8J/ )$j4Z lG}僱8Fb:PZ*9 !'TP6 E]~$iJ.*nTBw+{/j:ꌴ{:ntt--j.G_5Z.Uג 6lm)I=U=>kf\BuFdf* TT~&J~H#.4#*һ#)mrtBob&wAX L8c23,]VZtҕW@*%˚KlCiVS#1"#.(eG6qK-]Na85G*k9Iu/O%{M6ډ~qe~Kw ]Y~h@isj/Yi'%W#O7Je,6Tb*9mr<4漵<ԛlY&7샧FZд8;eZrq4a*g\bQ&Wi1 t$W"gâl0e*>!9G)7>:D?Ńš(aQ-PO6?a0V|~ Q?~d,Wo@*jxt*􄾲BD'*,d>BVEsqüw}16Ilȟ4>[)r2X*Wh?@X†;Tݷ18dUy7N-DZcK+lJP+C _1vO$oɒº?O-j->w8^6ZL9YS=_s/cO]t۳?vPFi>'U:(NzRcm݄vʐ 2 W8R^|hWҟ|Jq?&?܅  V7,~4W>_dY{Ta_]_a7d֢1p}87v` N2Q6 >u>IDQPATGukMwUQ<J%jk!;85iޘPƑ +6w~wm,)_qkq(Q1w]=|jMH IJ`lPU}@~18oGtdmV*+y#W DH2eE3Rޭj m)>{k\f`qN +,WCN^$W*Fn fJWa|tei#9HV@ga}5Ml$`$-~H)1=𭀾-م\ Hoф\Nmm.a{~X0 +Iqg~}dI}I+6Jce*"K.qI}8qn^?ɟxRTQ7obFT[KٻNRI}wV׎: +BhL~U +[OZțMQUX4 L=ib? +6]De<şK*aYu᪤Mqqv)6*ȥ{/TWV@N"Dr bUr"՚7K{ެ;.9d Qa_#q`{{a@23)#bl}1 aWҧW&2wڽ xi$xdMT %A Yv%:|ItŌے\pIRLCirKtÂQģC, \̓`=qH^џhVf#7OoTz)Ǧh-%-~JZÌX>(cK.;^f(15}K>Jehm3F%z!6S宠&vdظIH*iŶmmFcntr8ˎطH@LF)%P:^w(ĩǢ[(͡yzZk + vO TTyi% 0T; +Yqb.Fd\xvWz9_Le ʒT:\mJ˪mĴ]jJEQ}Qs7;Dz WQoQThQ!!B5s gϨ3aT\au $b40{Vz4TҊ{TE딭+jm!MUJ,u 9h=s+CdI^g\e˲%VU3*)C4ۉomeD[[eyR,MmзhƾMVv&d c`obͲd?N}%:LZUu*lH1 ç$9~#33cXKm$T z1dm:IyY rxuХ-=< +W.ʝp\q6J|Vph6h5W7ejtwɎcC $v_ [Stc[vոq6E>+@'A!5)24YYUХ*6: c/)ƥ2 6 bOo,t W4Siź +l277Es{u|w{gAZd,^'r-rswo]=.nt11D˭ɔU\FSG +O&A󹷖G) ZJmR.I +E쫧k~pڪQZ-) b Oqd2()`16wl'xzE*-7yl6qAo|$$ę迥zfA33PÏg^G*i wX֎:F؛2~HTŒy@Y@Kf*S:&R{*6ٔ)(իPU.HQr*&iE R\6e>Uĭl]Vmt9tX\qi^.aYB8پ*xn"CBjJF"ڼ 5MPRH6|zd<器 @-)ԩ*[IYԠyĔ&TZz.Tѷd~谨DZ):\I,[wy|tdLީ)Q\t)nokslU,M͚.(]O Zq߾~,K~r ]ni MZ BnW t6ņfN 2bZVl6>|PԅfyHSW6i7А +I8"vTê2niɧV喑qo #KP]\t|pIC,Np8ʽ3S*?5!>針n#0P[I`')/7BxwckU8F]S+R74I>caNmז-ZpLX{S!3)j;i!-y}I<m":+"Vnc-XB{cܴ@txYLy+exUa4i #;8n:^eE!ABlv1Y[^"$'[:A#CIj~A٧B1a.2MдZ׷x_zMbQiH*mK !\FDC=Hv] $$N6RraH +@PkF ˳ԦVJZ<6 yATʼn)7: 5uI6rMU9DLSۂihG+ +^uT-/SԟIKЄ;u* o^qE32hZ h24ǛqO;hEyڈ +t(BBRpma%6\bGZvXU֓,>~XucЯ.'=hdٯj2Lq2h Y/k_P.:5+DěMk+$dp "\S +P +&Eer +m=ZB$eH]{7~t/W"9uo +#o2$IR#? l7 ZđsjM~*i9I7ms)S(;WՔcU &re! |'Z!nJ<,46z5nUE\T؊7cԔRT}&v6s#HSDHZClq/ZsǗ8鍞jɠnIUn''T-])zEhf!S2htsm"k]2>s,-z<"zbO +/,q?O ++_L]U*<|T՝Q3Gf Nĸ*qj?'ه BJFe pVH)HGMʨ7ZY=[Aymz_JF`F5%ŕ +>6`)CA67>ŭbPi: mc;TJ:nā^ĝMO65.1RlOG^yF(8~ꑤ:t4ͦml,omAPF+j!,6R R%^3YPZVNмaGxg4m$,X}ψ rt|uI<5$Q]qrege-`91g=ZR?\t) '0tyAJ~a*[ZڅD8˞?̀Ms-Qb9 aNj9Vԃme;G[dl=qDJzY +HV`.@U>0 Iͬ{E[.Qq9Nt)iHM\okkYm4W.}bv*ǩ("ٿƱ*`fR"QB)%{T`%6;؛~x%K3,.aް4\&ݥi[Ҕ-~z IeWNaIw3 2ߺÉJPSj3.1 ZХ!I H !J\ıjMGI/Pt"*Wԅ%IWd| +.HSUY_2WQ5&3jI4,G~5ƒ4&_X$BU6J؅N&]a{fJFڭ!Dz 0xJMr<]jV ||!6F$ ֦򺒞;S!ߒ@¤d3#R~ҤQ;CA̱raNK$8ĂcqcC:XהSmAJԱ`BA>V3EUZ:o:Rԫ7$Iﹷf=2sEF;Eý0Nɡ %6%eJBn2Ec-HĊIm+ز򖭩Jp̣` 7Z׾0ZJBn.IƝtM9U7ӐPQ`OPfX(cTT\jRRE[[;RR`vE㊺*3]D6V9ZBb2{c{S+deIp*]%xRp$$}q9^̢HdlIc>Jօ@<(R.P⚈ʥlT hRz8ExS+&\t w8wg2\HјX߇xE(էA$$l⻂vg0/NWތU0Tf/m% ^W]~rؒ +m' +lhFKtÏ6'jȦʬ66RsqSG{4.\T%(!]Gw+U1ty"&gVsH0ڙξZ sA9RU"`Iwd@Oiz)Ԡ& KI)as&Y4*s-#NLeN6>q=ĵΔT!.nßو&q,y)=>f GWp4UQz i4ki]7WՇ7}iq=!6eEUjZ8E*u<}'@!ܕgjxcҖUGFDBWup!>®;EnGDpH?0[Ni&XWբڡn5+-/5->)eV\@#kKp#[ch4%j0k ycnZ.ey@+|kv?ot^m> EGJbCD{N.&J̘NP>Ї[O$Ʉf=]]֮#D~{ 3i=pmP%VZSr=¶?#cxB H1)d{_D SJ*O<_kf>'m_edr'^U*CXsIQìl{O5ayT$&zf +jvd=:H(?Iw>y|]O> k}A"h~-7*܇"1: #/$~N/ۊP(\#ߋS$;ء?|SlB_7"!}ĩ[XqB~q*ōMǬ7̴x\(Y@J76M)hB7M,{a%bĤ#h ؓYꈺ +d=4KbY`©-=`ĸƈB0:j#f/˯=eb~JQ _ 8la]ٟ\!6Ǵ#ޒ +]l3Gf#/pκYn^F-5e2O'5(JGAEDK: ҘJG߱݊ o6734EJ q{xi\yU<~m^t8+3#olG1:plN%B Z>t<۽9G*6Ɣ%Y;px4sqY?WJr>0 ʟƋX(XO>N:0,$#|aU+ScP1a9;"C#kVKrÁ؈q4N$(Kq nKe&?NSW$[{ U2mqh K9Kl8ݏ={ Ryiٕt +&odRn@D&3dҫ뛯AI79*^*&|Fl+~$_}QϻMy3e#8Oqe8ӳ=&EA , 1YyUҚiT"97D. pG8ZXP:ʬm0lƢ %])#O5W5VHr]7_"p=gg-Qp6cG{O߈ja7q? >p"fqG ~Q  @nHmliډ;}:y[~JTBǍֵ`J(I'!:۟GZƣ'fD8UEa`iAe9{!t3¨CYq  rsɬuҋJqr4yB`EZ `$f6iÙ0(Vb\zE,تP`@e8S Are}9+f[TB[ ~7'kB:irE3uYTVouCD7pjn:G~ߌL qj ICiQ +>+} 5@ PM |AKQ+h:j5QM:\ lII +m3jZ}p+% +RGbScEp;$ИNWi O>؄j #Rn.lyķptT^C.:0@6͠6zpMHMoø&8[Y:Ziem],|LST +}ޮB|EtOO^:qZbY2s'"TA6TZoGa겦.,m6+k&~2;cw'\[ɲomhtUJxqutgCaUmZmryF.tU컜J8)Ű +{2% +_a{6JHAYsLBK)~k@Q%\,l48m(u-\JUIi=fxQ:~˞muq(DSZh2͵Z\`_=x7gA|§ 53l)J' a yc`HTcIa@V!q]b]b&[sy:[Pm K φ0R'>q&.\㖃NVܶEea]#"~4jHe A#B;jtySם!J)39f^,FѺ{^e^L̅}GuuT;kqܼE:䘧Ֆ{9#.]]U&h|W@q̽2Lt$a I.8qSo nRr]= UTj +nt +IE-K#*W$ݧ:ڬSp e<< A}ӇV)4}":E*Eňi6:[aMܒ<%C9O"}iVi4RlO88" 8kqˀ޸SnP@$fe8LHMimLH ,\!En)IIPq.%hmwRKн'_%셔i&Uz3e۞fbX[mvV!%W+MG +Ӿs}Q_n1S|)z1É$%$ ь9*˝kh)Ae:_=uQ΢4^w-JN,A<*RYAԓq恼xʸMGPn8EZK,t]:'%s`8]s®e>H<UKIR˭vC+UooYd^ML kty|D40׬4m`QQp;69jP&hDbOK~iV0-WJr,'H͌$iBJu8\麔MGDE?k\Hށs:qMYeH@9煮QFi?OT/ZVVHqaswEoV1\A_RR,{WDIزĬD\ЩlGKchUմf:jrp/Uy%7PoD4Tqg]*I7Z]a.6P@"ZַueaԒ`}b=@H̚q\ _BwS b |=4Y)KM:Y$PjF3 +*RQ~VGV#rMAqĐR lhyW! 'G&_Ƣ3%2UeYmu@G8La:̺$Z ;xxŖSURJ֬U:~"%wo*"LgZjRPSf^%ŕ&KXNoδYl" 6_aׅfة!Mr7m %L'6mqUʺ\Tuyded]NV[j&;-~ɶ$ "E_SzaNp6mjT|AJR!)Ż\H1χ1OL?NΕqjRjHEZ]<-{7ҿan#Eq͎xSv$% l;ӥVxQ~Fk-VGyZF<8aQΆ .]R7ƒyJ@<,JJ}si )gD (,%: KAx$uiI^k\aܗRχ"1$xl~Z ZqzR9):wGd''GQ'R]q)Qr:E“{O_îZTن׽!%Ɣɱ6W{㼛;~x;1ԯ<=1˘A){帴q{(Qx :L~b# U(/h!3)*=•~Zmİ9Vhj+0֤,6ܥn(|;bH< 44`DB_T?YY)jns KKj;z:HSJOkP"ay 4ո CG @ӕ n #&t@nu j-M[}R2Nfʤ[MWEyr,ԆR瓉G]$\ʠ <;5qNB9~)fjL$>)Cܓ&8F£3z +qJ=R!9" .H6"ѭq:Pqĵ@ID+r+7l88Yh)E!$Q_fm.d~R71jN5w1%TԔ)DN +ʍu UJ!rtӭCݸa̐j辟uySt5m[ Q;D՜ԼWK +3)ǖ G}WJڒAuLR-AeR΃1G}v7{>i@8XYD H*TI_}x}#G/8lMV.eR5ֈG Hڵ@ŬJ50]J2l,06 +UhzRzŢOa&.ae*O=8Ggycù7?^~Pk aWK΋ c$]&ܛ.:[0lݨ,s*7~u%9GICXaЅ̋'yE}3pi(1&Izj{B>w>}-*ɲ%)~CG @rz +7vq)=tЌ#ewBgIRxq (~l,\y=qC9;BQ%J8?HQ/*f@gfm{~S])j_ +P ,hrԞ!Z&fB1 wai)Sۑ@8H2kN}$QhYYӇ_i:C2RB?8|yuWZi-NREN2%J*)>I<x88W_%ܝ +F}Gj선hb=X:w Ly AЛ*u!BGE +,|ځ wB֤Jq1Z.UĬ ]VbUh34:8 Rijːӄ=aHIP/M!͙@E\H&KZʼJF܄m +2:%ְExZ *y %)DQGURm6!N؄J +P`ADI 2 +RA<|;At:[^V+@ #[LkSӫP-ө6K_)=B[Jn$ybQLU&ٺmS.0k/%rJ|e9J)o0ũYucvCV v&piϻ)e*C-FM +6։LZtғ,A7hgRueD>U控p*;"Y?`/Dh + L9q8? nμ1 M7n=QD7Zn i{q˹*i?x } 1OΔOޔ#DoF?3-^'|" 9PcYl8x1x+,|t٣!bטPjNicaXQ7B%gYRĉ2:z +,fi43bp9y]^ R>D%W^?ʻη8Tuabζ9SS߸/ęт9QϭW@_&}v^UF|s  H0x54s +B򎏤'Q~tH/BOgӸ)%Sb(o&:?I_pLG$dXp^Ǥ99{ᐒw_80H,ߞw뮓O&}6avj"riʋw) 3,_a7/yiz}$1fSh;o Nnād>01L#-<9vX`M4LyVxGRH16~Al8y80-u5M\Zt4䄥,w ZA6`q#J5Nk|Iȱۺ1w óhQPSfYnt:m{o gS`iE:%M6h\kM+ăKa.X6sP3?!'"kl5(ئZYvS* ART#<lH#sXN%I$mipm4՛s-(NP_I'aƺ{oQs7)~ظͿl~E̫oc8CbQ'ЖA7FhR" GZp@e_\ǽpFJOj:ߐ0 +?̻ :a nO3f2 +r + 3N\F-:Zrѱ}vŶK&Kբ L;8Ɯt\M{X˶A~TǀI~Xo1g6RL=D?r -5:%\3C!'/K܆IF"rbKD5/#<Z uT^fX `'W2CBtt3Ldƾ;>՘LX&(fB׽-fco>OZ ߨa=`xv XW{k#5߮xi +hT?$9y&'5Do`UX'֠MO?xG0×o9Xzjw|m!Cm\~rPBh$}?O-BFs%:dCm]&u5%:>x }.{'ؒ*IigZі[%qap33eai&獡7Kz@H ^q*KӉeaĤ)Wǎo VKD+*RVUb +x:&awih&[lI4u, X*eRR8SJf[oC)JC ӥ/;qD";ѕE)U&겼^@c)Ey7^P9m[qM +SNېm،]e)["!):}DFIe})nlRI"6-؛] 6љٕcfnxlzSm/I&آPAHit + %\RG yD'Pz͉ +Z +Ip#-µ%TK$ۄ\"+b !3v9#+WFV$)ۓاF.^ |C[!~<$&љ"Nb'iB*R-\y+N1QjaH-qPJI!I i<_'Xވ暴N|nNf`s\ڳ5Dȏ餚b1cTkaXH QM[2^ɜ\3m ++ +&$b"~ba + +,; X۝z3J o(WdAb6p9. \ASqVVwr)EYK@-Pʃh~"76sktì +|Y2~1i۴*(@c-r PIUP '`l :ÐHQ=C!\u,X Je66Z1Glo52+)%K6 !9o{ѩ&Z4**~[S/'P~A<ƺtFmkYJʠn2qc%kk8̐Hwr̲8X h 7hbdUQ*)Py+QPGo>x]]Źj!p2|̩Cq$RN3!Y*I“2m:G!ΙDTn:d95:_TbfTŖJֆw*o{K|KI%)$wIpP1l8ʜ'({sٓ7ҡ!NB ཻ %6]&ZaC WMajU֠;iYrd̶۪$x*0dNsto>"Ih*gܪ :KJVl.;JsZ]I$Q n~+Yq%VRul6&+jfҊlBЫ8/U[u]~)"sI +- C0T,.<<%ÎBnKZƤ(j| %4p$Tqm?Ժ9+z7 n6TEhʙ4*`GN}ۮ ê4ܐ<~ mc^81. 9q#>p΍%bC(I*=1@ dXhO;:)&g|5l֪^%CcOЦnG<O8caޔ.SKj˿xTN8b]͟w$85=VZ aOiP߂W%ZBt)$- y*-MGt* 1O:km +M^ +S!Iu;J paՇF]6k1sWz-j~OK4RJA{IU'j=j" RԄꤐVz!5NYײOc/0HI^=!SjdjNI.NULoӧi,I)- JJ VB3b;xCv'$!Zp:R2'-*$ (>di:F5b""T6iOu&T))*s{i:g1]=. MӰ6+D-̡d'D-*Un/!ZȚhL-}OBئ㓆uV0sdix1!UQS JBUXj}Vi=PxK&&akaʽsePM*vdd-,Gu {XߑacIVpyt) {4T|Q{o Tdֿ,iii!Ѭ +Dڗ0ڜJ +SݷaڜD(u,JRnnl5LT @JM@U{?GQs1fJkfBCmLy-ކ[ -*KPH7T4AX $ X_)C4"VvTB,-:1U1Nvix6DYm BPR.GssьX̧RSyRJ\wZ#R`91%t +|-R$FUԫ hXΪYe#V6$ƍ);bɎKVڒ,ۜzc|v8al2Ol+B#Fj>p[+>ERșRB:@ْ@ 'qc?ӺOHa*6 +$PfFЕ8{'q1ݥ(\\6ډLnM!_la晜}&X%#[jt}1sFQ ^844܈Un{`7 67>ħO,@/a}wUB~ǻ!yMNeco%ײ#WGV=1ClJGĭ*QNqQ?(A}%2vQEVmt]Z{^T2o>v`5̯_˚YgJ ;J-~]n,U#1AR#1]F`=1<6M[KC4DOm9Xv*'RO5e3^c̆ۀ]+ISN$(]+I'%,fS +`#! +UK,-m +tkV7Ѝlx,A-k_h-dϞ(TT6ګQ^r tة$Y'i;0%S NVPNUЭ,,-M +ː\Paq T Qp4!/X;C[ƛR$e!zm1W 8]OvA +4+c+6)ӍGMh[u|d|9h S&HLAKʕs.$W9X) +,$ĮIrBDs#ɬ+043tvT0ݘEH !ҏFttX[Pvs|NCjiͻ1e; +iH(GǗORm9BC\}Xi.zuI1N0"hN)6O%t:0ӽ>Q)1⤸`Tx @TH LJ&[iUN;p-4uvMZ|(Z\6):ߺ'avT]mc*-8{̄lv|? )$.=q[U$x$6]RjBO -}iXM{v j"Zo,oQdhU{省XFdgOTu $AIa)hU֢OZ< pލl:)B{|(qG`KˤЩdv@02Os'%r2ڹR{wA9?3>-܏ +ê꨼4|-nFR]{2'R!\WZu{xúBLI!"]tKχVNxTryn- z}UD [^rc9݆ =Q i[&Ox:Ea'녊|,6/6lA[vIr9<":&!@.R))WbG3>4M6Tw\Ͼ'Tt˺ϻNQ]:7ҭY2풧_XQJe)G[l7Q Euimc\LTt!V w„yƇtiRiBԨ8~B" G[UYh9}6J+M@d8lT:ʌ:ey]Գczb$ob4 +4ͬ_ak¶#JtAC5ՙe,#bvSm>->r$ qf9<])4 +Kà!{Rɘ{wDӂ]129T*xJ* hho]s"oڲJnxP]R Ԃs\mGPؾm57ӈq+V|ͨ7X +RoaTH>T%GAu?孒۠[8ej.ʋ$=R "  ;A+Fr)7>缫2vxfF}jNQyźPTU`xlOjeL]\j!WL +m\mnS,.hJnVA JBA*m"q"51IzfR12-H|_'lKPQ_< GI/TT$[ore)m1PI]C?Y:uzu,@h 2 ؂Dhtt{&nܶ#FyY P'ML qX}G?eBoЧ%+Uq(]aI dfT֓ODѨMmEKGa7'%نVb%>=!U,8q0f0Rp((lXYN.Ď`A=X7p@d} }ȏGtkCRxV֘mܤ/+~:&NHшŒ>A,9uW)gSuz%Bq?fb|ijϩy5٥' m> O4zA\>,}Ё > R~Vx64#D&Sr%ď>7aG&Y)LяҨ_TS*{uND~s 2?ɏWܟiQNs-Q엘$ 0]A'Z>+0Yq⇭~wB{-UW>G<W ƖσF*Tp]9cnj`Q& |&/GW{ s,v/X{3I>!N!3kY1/!цd$| |Brvpz%*e7< Cf>|`w߿n1},hNNYye$ʯ̜&FYH$6P%`Ĥ(T`BטirEFY BZ c(2߄qc>LLpL$c'ip M8C^ g&PbSE.!.Gt뎚5A5v)'PD9JfF@u; (EL Vo0C8.6G8 +CΘ: ԝ" +:j)$)hBQ s"Pc2@iLipKY$-㮱="nHܞ[%VPS"6 mp/%~Gah=| U?G1[YO#=Q]v.~lFN8#i% 6 s忍Wv[#Yfx~1+V{g#SA<ڲd"9=0( <=khFʊd<᦭ۚf +G=QrvBŶ(&O4S(:rl_DQÑ  W3&q_9j"JmWsܯ׎vm_9rKSß݆3Gꦢ-h |Ky%őǎ`Fdy"'7 T6:l+1n$Sb"+\cr?a5z_XԗkFS">xjtz =\)̏l䎶B*MHH$O7ģxX ?XDۀ77mĜͣp*S w ¿">0Ц5>dz89r.+V9c4ݿ?#RRQ1j{;3[}qr}+\+Hi&ep R~Ruqd-)h;mA%SLӪdn]9PNװ*#oOG%zHS %JysTgSmq9}O"mXҲjY+JI#JxuYUtƸru=iӥ|WZ+ba +8˂+4m$K""S&Є6.h%.62 $PwKQ՝'joǣlmk۾㆞4ImZrQS!Q2&ڭ/k/B5YE*C7DJ5VNul)]6U:$,[Yۼ <7_LS(:0)wS9hJ@ c:9|"4o+L1Y.{)HLÿM|6ޅhC:ҦNXzcj38ִh߰>~D^yegsmBJmb@<LFm$ԺD@LBsh#`M#n#1UaƞHSn*ۥ\O\0)ӫq+A!IۑR~5:{8MT~ I&\97G?f/Y{L:!z<'zU!qIZy Vpʨ.gI"761#]iV}n-^nÇMVxØAtAv. xqQ 6ԟ,u!6ԵB% ++!p\M y۬ Zy&4G j\]i*<e1#`vϯ|NK&ëHJ)+Rz޸K/2 :(@K4Z[r2Qu(>}btZEly4Yι +jbV(q2cҥ4LrO8*+3+9p.&:8r#(\ko UH*:mmrw:ٱ(ycn uBa7MyÓS^?).%G +b@L)qS˪I׽}csJ20.n4_?$:t"Xl0RM +$P0"s^xg0fJ$ΖV󮸢TI,$JK% )wWASܪ%f]/Hʧ$ +Sm d6 ÎI7^ߎ +}ƓsulO)E,-ցK'¤rrͦ[_ x[-~£P|K Y%[~qiMۛ | 8Ŷ7n UTobAʺvPrOIG2yԵ慯/ch[E ӽO/'mvʎgl)M 4pªK~cZUX"x2q4)} +ӘrQy+pAH 1*AC_JO4#E]Wi#MǮ75֒l%6TO{[XjM5uRR*ر}tکyY=k(Mks۝`Df 7Cmm> M<,Gæ%LED_x䞢(kd{/kxMsU>-|Hh߀Ds7t=M=dze,oXm!kI_Bx}pwt$I/Rq*M 5'0Ǐ3&Y֘[o"RP?829kmӏ/m'vK[*Em$ {c81JT jItpi[k/86}$V]-ن.Quk Y$$s7'Rbm ZY;*t$/TTmGf,ܫVi Bnx$[g 73 S:}17&Q$H &F}'hޯg@&t?Y4Nv[JT09 VF$CM$r./m-hrҹܙ=PP*\,z| ) I mkD-*!D&Ŕ`n#dM2ڐ @0f}%$OfD4R6G"\|M~گ=lOMyf0u 8;@X)a).}[RIl47ĭJ5%!Fقr{s be˷)0[PTRB +xIhvLڼJ-FAJcf's!Ognrv~VU:*T*IqbFT&iTf^BfKܦ;߿8='oȺTʤPG2g0lqcr"r'% +$|H#Pо4\gkLmu$׹Kt~qo-Ũ)Ne w )}F` q% aT;_RYmd-63Qt7J{Tr,_˙}R[ ;K%\ہ^rl[$\oC{T*7{v:0S-54V2wq~iRqeKZոDV<^nZm)JRR E"pVI$NS8듎)ŨI7& +{@ >%Qez5Xҥ22WL!hJb;Kuś J' +KjE$$\J\A7ugôbzXp1sTsTE +pݔJy r;G﷌>lL6%!+U-!έ*Bst([l6kDN:ɂJg9J>ގ\s&#_s 9%'QIhEin0I^0ժ,XppZ +J./e[eVZ5j5 +=JZWU:DWO{Zܭξ#<$?lr13ڶ^w+Uۥ2\Z@J7y#XtSDz6]j AgQJ;l(R>{OQ.z.n: ^z!-i=,mk~ULNO)H%)+CW{SٰUh +bJypv6è߿|FX{0Js`8Zc 7.Xi*QB J0/$k"DK]QS Č$x xH!g1b8\)N#ұ*U[}=PuEJE )WUkvjCJb]=mC1XJklZ Whb4mFx`gRь6TuFCn+x8HS~D鶖ܺ0K!\FFkWWٖe+$THpeXq@![)hª!OD%W+ai&f("#OWJRInVKiP#ԵPdjtC ŋMʩڥ}1Phtv[SKvaFPy\VN12[KhGLҕBuI+ K#"8 k42_fVNJ&a+JT%Y>xc34kV_ +b#D4􌤳WV\%^ةN @Rl5Dɥ!i!oO/qyc͔HzˁmHhS%$mMsY:'=NsPfE*AW#@om>,헛K9MCr_C5&RF?PqtļAt7Mb}'HXKI myDļYJy i˛ Gf k k(5깦Lp8ӒTd7amuFb*LSN=])ight`91%HL,bOXoYzE"E$iu[y,I$v2fB$X =ՙF'SzɅjMOQ>}8ia~[3&k&eP}R٨8VA\FDZGs=qnEO s?X} + +v__y#}+Ҫ4~L~ZV䗶 NHJT` '&RZqӅ^9ʖs +7C![uXlpoch6M4lvqiJmIe ׌vD~hoUse792ޡl"[JSGDNv}˕XM_ԉMKy+H{z^u%"ǐBOrG 얒O}ѡRbw_/uki +"7ODrEF-U?'6܏Ē<|ecl6(~b](\r +9NnjmOOTfIKϿ/JP[bKmOaɾ3ۥyyi˨BbrHX()q®omMۦ ]TL,K*K@R؝m4I]Wn#<שOF>QBDsS3THk%}RT?tW+LMMKly|ZB[۾=4;Ed"m24hmd +6H$^AS +ԵxH;qdRiCsy%9aLFsU09FScd)!m+q%+#^L0BM Eǟa +RM͎KֿRifYл4Δ,%J EåME#u^ybB&,.i2S/`1kn h&܄BӕhlrI[uF&u7S *:a_. +.ݨCu,ǤDwS5 +sS.$Uayj#taTQ><ݗMfR¸8Cm9k<ޘ-_l~[RcJK^Ԕ =zLiM86:^'iJ~ <]rٗ9gBd1is> +W-*۟jbfb# nq]Իxa1,\{Ee@xCJ :%=O[FqB=2Pi&Y)H=jONo,Ku. Y7Z:;.\;2һJ8%= s;5( +Oe*RH%!)IhDOMV1nm6!O,ߔGr{kYRA"6Ii@["`۞)D Y ^{5Z8:o&l%N8Hvf%ZM(THΦ3㦮6_P(a˵}ym[:l(f_[% _)[ Rn+@..RYM*#Kf: gQJ%>T P6% !=mlT^31SD -JhېUGqa;);:PBoxwZBd%)H< +;#h}SRKn(yܥ[l<?Xi +ؤ,FFa|BV{>r1Zfd=-+R~ K"|QhjE̠6 +mf +<̺IRKzE%Nlׁ<4̽t)NZԅ첂v]ͻ~͇~< Ԥq_Bo8epzwjrͅ%Ptya\'^B} >Dahn=5Eĭ,lRADD!5ZJ]UGJIC@.<7QIos o~"y]/ Ն䂕)$-Aeq`@91oV"Xiݽ\?Mީ̷[.pU)'crab YCJl$}}*ѵg=6裪дx;f\p{)ݏOv.y? &0vk~Zm_ώI7R)KUG⮰uɭy^|/ xImxg+ONuGGb@*O*!X_7W?5#fb6fGQs pV,BlxQIiŃ+Ky菫f]K8ܭf~lc@7OTǼxBFܿ.AJ NERlWOcyF ["U*M N?Pޝ//҈#2$a*˖abGQYs>L̢Z)ӎ>εWO=dOUDfNLv'ۈjcU}ꡣbXƒCy(nP* a~tlGaH<%Oׇ:X~ I_r?KY \tskh\f<*Oa~!*g[TO͚˘kqIvCⴶ? no>Xُ1o*2$NOp.'m"νD"#eWB/؞l2&j#Sf'U)mud!DRA)$M2 I.lJ;$xU#.8s8$)EW)6#f(SL7-q7_%O!zeM!et3/gXEб]n7ڌNj_\l%'j]ATX<'כּg ̟4XxR8Q-f.P|"7ꃱeɕФ2p\;.ZH*0;\eHS',Suj'c^' +gOQ +)[ }^s)Cs)N~tԺųO<|E0oTq_ʫNIKT uS X}Zi!ZcxDh/RtY-Dm*7ˆxǢA/.8|/&JpquHA &ƮQ@&HH6=L"1rDB&|lk˙񑑠׳U/Do[c1֋_C Yeݿec'S5z};U|JU "[g>?;7AoQb8HW&Ef34cJqWzo|sVAc n+tt5%@GcQdN?N:iuZ# +(?$- +0)ij^iՏWGz?=:Oљ%E0Ro/1?ڭHKI4ݘyߧWUUQBp"}M(L[jb uo6MBK ġ^wxl "UL$:ځ*[k1eI\Z&)HJd-i:Z}im'BRlD=" )B2'HCmhx<B@JQ q!7*;$s656Td+sfqg+mIBxU*t)˥JqR6B?hX +KA 6:[qGl_=@v*zL8KHHC`f RNSqhm..V*k~Ql19;JڬRn6WLN 4"Õ[sW"XaA.6JS|c7'+iWi2NJʸR 6dahE mđǜ?We͂J:_rS W0p%@Tb+Q̇O4tKb^|-]3 2s67qo.%Ѫ#-v'%rj|\Z",1a%~&T/ߏYRŕv6Hq&{:)'`S8l)x;˾/7E#|xe@hVP"*'1 +xۄ_1MLM23- R?i(ht~$G] BEYJk1-BK*P& +jkc:D?vNRBVIWAS F!hx{hPIOmz9<~I((zOyʉVx B=w6JuLlrГ5cM1ktY~3Tyl)Cpv+vWJfJq=ۜrVڵ +zwG ]+͸t>1Ž]th:Qsv&](Znܺ`p|1E!'lk ;j4yEgWj8tYeo([ŷ)f }O)=JmSnL: \頉1.I+E^;\QњDeCJKsqP |>Uҩ%YWiZI+H]$6Knq'ڭ)EkRmpNPwH:g4=ף<ęe+eV4RQr77+x@7 h %(:=vRR>6$xU)a[p!PC1HY+bxkxz҆DEfT?}>aNH+S7h9G,Rj@gc*TJoMU[9Ym.IKі)`Aܐ8#e v̇J5l|}%hKhqDn3 ;t1*uɢNDCfRcɜKRV3$B;<-6gy9&CmF-o(n|6sMI]DХUbqޱFmr'X4@zޯ9,; 3"9N<=ޏ%)ؙ5gʤ +@l + +Iѯ8hLJ겸pVY 8ڮ;\-m{DΫR]zmuj՛uv7$ ?X'W)a6þ#LqPAeun,>z (KSⅩ*өTeS\ik &J{Tx3VE hZд`Eh:kH-PWaxy89M.$.$2e +kna/Bv{-U2>W0ށ:nj&C0٩J9F{%Jê*7RtnIauo/*.Hs=^%`ZedX?].LuhqY +ʯ4Iu_lq9uL2S-ilEG趍!FI!N8QXZu#%nmם)pY) +aYl%$yA=RVR J5&܀$kckwņKk *+T +Z D?\*dZRQ)㥺lFru- 6s|T .}.6$.ĸcʉWno'dщ-ImuŠ*[YNVһ! RH>9kv)R S FaE))dD[mqѝ)\@Ӂ$/ an k{s/|A%嘡ԈBܜe +d̵6QU7m#U>Ede8RH&ާ +xkV<Z6l9:$>K!(?(f"ְdҤáJ=!7B\B7=uabq庿ҢmF^Rʫ9fvvЁPT,rHeD2k8r \nGm9i. ,[Z9?%Mp-!DXJM@so<2kRy="ʞ1֙sO qJӯuh4N2SQPԩH9t%%^{G2X.h@P4>^sn‘&F+rBfS)i ,O$Anq1)' !!jH!FȽ$6DU)4Tuj MkX뾐ўbk2e!cf|dHmƯ}p܃ALae񬨗}KN]R*-rX EKZfJI);ANfJ65Je)cu)}i!LSyT$%6ܫ08nxB+]@$ޔ観5<9"P=kKZwۉKz$opH/0RfWmR9{N* +$6z"iY*$ꔁcUrۋPR2^5({p&ҧO)G:I*@}' Ϩi0%6P*s )FP~RHׅ znd:)feR|@krזT~ `j6>H O(S5j}&pLeKP-宀z /~Vf\tEuiPLJ yWbb~اTst7dpNׄJ7tbn=;e7Yy;E2e}Kl,4\H J8T8{ z}FlN-z%Po};1Hlե(rH^Ȅmgd%D$ןk) >%Cx6aņ ڷIP_q؜X:8 kuL"OMj$=$ZgŤAEV#) *$QTΙzn<eQ""Kq|-߰ƙaޏi=J)Bu]_}`xټN:DW{t՜]eRPoIANE*uG4FۧS~4nvxc\q1(ݗat2Lf,*>2uI +R~N#gr#Sl\m'}qL93Z%KVTw^R Eƃ!K7(XOfZ! c)I;pH +Ww=+1E[t6:Kcug HB>kS{mT +(.*KO;Ň/ABZ8-FWj0!9Mې}j^YG.\m U<ꌼ&]aA ($m}Gͳ\\_Ei~RTTԀFUby^ǾjM1LR_܋(NI1@wu77aRT qo$RɭuE= MIo}Σ)W0ĭD7M#8ě+9$owܨD2NT]&mxZG +y{@JSRM)%ED;/YgM匧X'-+Mt1,J n)!S~"!tu5+L)3Aڝ7haFPQ#}>pΦ7ATSznQRh}ڕں+*nC:wtgZ2aJbm777>4ĤzAIm*䍽$cZI{DZX'O(Gz ') :BR pSq д biLMAg4ώѲHieop;p#:EjK̩Yf[n ʩPB{۾Xgڪ3Mqc-άfX +#-&7D~=Yr]*bJfF|7' :Th@Ci7>GяCh2)(o ev'b6Ҙg\] +x=-,G:LەZzXinU +.>-)rU^H \(\IJ *&D뷡"̷D{K+ !6XPk~\zS_u?ҟ/@:pum6z fO˕%N$o%I(pNV J_/.ޘ2n~Mr/*\6CN@ Bئ$t]95tݜz eJ\VuJG|_iGy5.fUjLWfRwg^́[l>>\64R=s$P#c-R uw_peBwȟڞ0/76S]E:U.RCRܝ͸?jRF՞$pIG݇_C}ny|%j]rG#W*&`G8ǙcV: +CVRi%sA.ڀ̵+XAƓdi\eEiin9@*Yl,>xʄ8nP>" }vTCTga MHaGN(fAl~ZҠnt$꿫M:Gbrߺ8ƚtbnCYHda9w;:C*KπYJ ge ؅8*UJBٹtKDONJ + u#)Te )t:B-`ND '0Xi)ƘZLcG(RqI85\\_&gà)&oL81)4\Gs*9BKA)TڅhRPTj#Rj﹩X>7 \&[BK -~\~j(*@#|^r.&L)+e_ZNU$'S#)8m!(]JyG:\ &y*"J7*p?KBDqț7W3P%.}Zmz1p"ׂTǕG}&Z6pDM=i7Vm0´̄{Qμ=Te`rzqqɇiOTٳJ1ђ}֕2 >M]Z`m*}5xxsz١G?)gZa4G +'{' Icz֝C19~o}?sO*JRPl˔CSI꾱KlG;WՙL}F$~unj=h"P-}?1ޡkT>&I~MϺ9QVVM]$3 -2wvpMn wp0m*QcؘWI#b7vQ_d6i$rAm4PEa, 76緭vJS(?5#"AiOx(Kzbf妇Rwu IuISCէv%)K;,; r)VG(e֖/ð7P&8? +V1Jm? )9oX ll],=& XzÊ[òas"H--:Se(Z ߇&p:lmku<$ꍵj~#jQ()*=Н}|Ù3>.zZP-(8H&Y8aIQ**PRŽ4 #RvRRJ j ؛DzR?fPfOC[V2Ȭ6SI5.Mʫ1elXs&< Ud?Ku~o" ov0ExgGBGGf#yHaKC + + ,c᱈k&j$&Vy~Żɽ*R5?f wqO\ +6a0rqK!Dy+,ȹfʮ `z=361YKx+q~1~#WΛÿpaޤj?7G=݉N2%byC>r5V wC +61SV,cN`Z xVK CslbAnCtQ!HoqEc ۬sV<^|>.&mXlzxUz \lq(`nT(C~}ʟ>ч0D#FO jn'X䡼٧%ʼn= 4'#ł+U(1@IڄE@%d 3)s +v[@AOaM] &Sj&$ j?PI\ :ω̞,%) +7CYJT%Ľe8By$Mo 夨v H- &[KphqKkm55Pjl֘BmS{q+K6V +RI6wp0er*@aLRI \3+Q'}m"sTbi-Ce+=_ _+[+Q7Jfx>V;ЖZQIѸ6ĸ8[Z\~8Tʟgh+ͼukOםfs`r9Rӫ1O!,HBE_yUcKM %vm\-(˖JF]@zo/O\Zq6]EMܰm|*[3LRw$~{Hxifs`gR# ÙRDK5^giV}p'lUGTQO]"p}lX,(she"V7N;$ZX C6| 1i(:(wsNKn0iWСF< DntNUZsi?N:I&j|Vv\Ex 5IzѮ1$o"`)}5JO,5#1tcU%iB$Z|X RvC +kB +zfո<;z)#Ӿ! yڎ[D\-<2%xsb)C܂j CMt:k}첦&]H$Ѓ_SU#ZRy`nT5ċ  +t:D-̡qd|D@CO]BtD@VP81o6gyHrMSVR'GQ!jd{ed%#U-:q#.8-RO~Mlt(Ԧ8V>k!݉l)w 6wHyq +"{l m0f`/ h/E]kfUJu+'U(~jNdX|q:Ұ#i겁=RdN]eD5{GlqG@<"Iʬ;9C΀Vzy{-P*~Cא x+>A)MufLa`x\y6¦V[OML̇@) +ܐI>h֐RtG-2^Ii;GqvqE'TQ'ûD.a E\}@p 6>Ntsy)NcP*k7O}1 (Wq#XSl+_x}S弡_*"t-q,ʪS +)#G\)osqDTܭO.Kn7*&j"I6҄Zl"\ʊMΧ4^i)MR-'JT{0窒Ti™#]. )'AҊX` + [xY\6 L,;R 'ygvrM=[_V_ _A+hܫ=s j WJw)O|=0zVNW.7 +:G~Q%tغOEv1^i޹6U~elJ\PWJ*'o,^QoJumqk~EE&Si$#bI )_X);Bs\E]-K&PHL!S/L)*m4Z|Mj@<ڏûo+1 !ULoh~A6,UfrS[{y!%̪I$M@@{=T5 )r#AI>M8q$> a`pڊBVQ骊-Y_O~VyrF$qJsCV}Zˡ;}WyK%>`6`n$mS^p#GLjJhSHk*C;6)HRlGG4<@Bٺntf61 `lqՄK#O!o\%SYSNM~n`BRIT9*!;rpTE@hDVl$#r5j4B ;Bݶ?M*fX_ST'GXPR$o`aE.gЎ1i5ivܗj Gi.IIQ6RSsɰsO +M/]ʅg(J9V:p5Of&OphbrMRnlBX)R +$), a` 0{I:uUC[))w^SINѴ@YіLcRJT<&㞐*Ȫހf$q`:p̚5JE9my'决P[l7S|a1:RF"pJI\fynnh|r>x˚Π'՜'jeQJx*O¢ڧaT6Ĥ']}&0D:TWy9,`Fm +wh͒Y.Fn:|4_EDXlcI2 {uI[OGak[^wѕ449*J̖B{ܒ8+5o_+ RlI;`8&$ (t7x!(O#F{X2Mu/nBI>;[i !&]9CH!YFtaAfBeRʷtHJC~'Q')e%JAmp}a9YZM;$xUR)&Sd'Ԁ/V?VyrYmޅqBm-M b4&y7C?;<2 z7AD#7eN{[2%CA*SISq2ԅ/8$\ytBM0Ȋ) x78)$> ʖ`-tD–P ~ Z;t7qheE<Fm5%,ό8G+fWVUAPF"{B̰$`v >dw ʹqԒ\ei)'ץ®%R="2m6pdXzaHS(ļjc%H)Iڟ\}&l%;=w/VYKR6Hr#"ޖ@Md H^mI;me,$%Q3[CznNԺ|Olr;ZE (d;@$Cځ +")0Ω&Űƅ~l\ɔxixJE' :‚R9O 8% ?b[j. Sīb.{) Yylƍ1/Fd.lxUrz&-UGDSN$P)-3fV3h)IMm.0@m:nw W*Yv^qlf+`iJM :"VhgĬϣn*c!me'zV`n~ms.pGdtJem=q%aD\h>$nAME=YS[t8 Ke'nR~VlJiV)6>)!HGOLFخ\4SCg*U(H;C>"NhC[+|~0lt*7@2)D"RqA-TP]B{V|Bo/0'IX+>[PI^|4-o?@Eei| +m~F,좧ikCXUm7-օ*'w]66Sb +vKvc$ی@b3]ƚ[/.4J'W@<ݏis0+ۋ~IJO=|z"?m $ܓLѴ')T=gS;`GS5P}IPۖ@V:Iް ut]'2@xtvUV R?OӮc%纐Uܛ;-Y͙K'G:hfIG+G1J#PZώl09>ʒm"Ʊ}R\ώAqw<}Z{?|)T]JA3-˘¬1jKi6zYQQCIs/)K&tseaCw%Ir3(Z,5TM_< T.'Ne_:^U^R>iUp(SG#D|Bv~N-c;Etb2G xVe{wHI"萺c#]j+9;&wkz|JnPqz}(~P1\`Dge2m|_ə_*DTRAFRJx!Mxa6{GR5F[܆&Oyr7Ii1_'ƒE6p?|1QSĻ2R5ӔeuV}j m|~}ΐ4xrn^4ky_3^qS=k2qYȈ'g8ێ,mx*әi&LCmIPAzJyeVJ D0$\ 5鏩4yÔѤ}B)/"J:1qcۏ =>ӻ wM ֯4lx=N-<#f, Po LpaMJfUlX{'|\Nf4G4|$ c"!7Fxq![]&LGP(QZ="% +",.q0;Q toS7MgMgÒUc9_<1eĽ>ʷ|LԂɂr3Reog ̻tXnТ_Їޚ+YaQQO]1A^uW?4-lxRyPwHHj!U1B$R;wV<^/&wA-oxXUn,mۏ$_UJ ~k(<Ț?ڏ'M0|g躓B $ڙQvat9OUZsapU'8_=x0FB{u"jP- ti+"+I]iIPIJ0wBMGpmDf *imb61bHW*cnX6Wnذ.k"}H2<@ z=jM)Z+&U֥*jT}6J"cMW)dG"+jjJybTemqb8#x3d +s*J[Blm}qJ#hc,Z'MU6BP UpVFȇ,9֑4$kbK a҆@B`X (ܒI>1%! DW]S+Q$IԒu&mbQtL/&I~tGo ~_V6ESK u*shLC||g-?亥$HcL\BJ~;ғȿ׋bRR?J2v~ +;HPQsTmm<˖)ZH5$hyyxf΅+<^%ƢU4<S:>2_RE{pO wE=K &̻N$)Rku'I:q.{hòȰOv4!\?w=R~;:8B&[mZd4IIԝ{"񣗘\JRmP?>g4n-bÂEާFò8@ԭnG#!pn/aBαQ(Iʮy(D>@,B*i. z$[m*u*c{BÓɫM~&7=~$Z/d|+ v T֊O)6? f,I̠#% mVńFW#lO.|X14RNg%:|Qh)RPSh 8; cJtAY| j 71A}N#Y>Tei-r[nCL܄6S 35K#UO#ZaUG$rx)Y<#K HQj +̵qQ׻AALԙ} n8H̓a7U8'6|0\pl6VIptѧ, +|Vb!S +L-lrqB_@Of1Hʏ5'Asꂁ6F~~) +b +#r&ߪ3N}m<=8y~6ߙ*ԓfjgNÙ!wGORWVc|Sޣ S{FO_ER=c2E:[us(;jMzGB) Ε6ĝmޱ^P 8xLX]ZZ0VZI6{`!ohKHU -^ʔۥHڥ$ac**y^<؉zAyrp:)?:<\lR +WoS 9mR|*/ *ZRC ~iEUc셶:`j]dR(V $,H'WRl2P.I3N!RlYIJs,MόqWehJJWsh<=K/ mB_)qn1)_^ȗ +\ʊV ߑ⯶ԲB{ 7t$0y2vv.* +kT4fI9n!)R~JqJ)1/T%JJ~ [f c"VCH#Pì:cv!4.jpV*=//t3B.3-6rPFsNtX=`" PP $nH +>H̪u81}iJ??88Z*~!/>&$OoX>S%m86m"miWGq:!.ʩ7ҡܨ6g{W:/@!ekOI jE5xeIw}d]f9H"Ҟ@"0JQMHG dʻH)᭵B{ ~6翯s\<>b3|j1׊JzbRн%X=-HViTWRUni an?%VWh.s\a3-׉Q>eʝ)ʮ8RuȀ3%-UY@{!3BUG:B>7" m2\w%@{"Lt!a ©s[iYVe\;{a>ylPZ< Ӻ00g){P=.@]%@x@|*Axe+f ~4vW\?2)>0gi9nkw ..7siFI&.* +( Ct&X)R +JJBIxqj I7ӟK HJBQՓ[mxcNhn{Ò,{!c«u %FP9nNR8u΄ l:w4 Rejz:S"S$sM+0E>}`%bWEAؓI +E? +[mo,I:dJ lTQz-O"PYRM"`d7'`7[Z}LRڵdcT&W } )rʒ[hiv%)ils}  3H32]If1-C#i$rIdxC7P߻HBT}Oy$l4*5G*i28u9ԥvԩFma`4޹i!Al]oΪז#ҫ(b7)B>067BD\!DV3er*;!#A 6TPR\[$8+Cj @)nG*x$'I>J7OB}8E3 h}$.74*} ugp%VO"BEˌ:E2Vڕ(|?X&XP 帨A)6P7A_9,kfU](6QVH6hKXY7 iF캋L +R ̸MxFSb +qd |Ϧjm{5كI^%,-aF)@5kG+WcrDfZ7>V5=f+-Ƞ\\<3 .#P@8sD'mB]U|$ +#VLd12V >P䟥-ULu&8vE=QRҙ t xQFA#\IKHl.[̒?RE#EEPy$O-/[DmO 9iIњd-K,)zPtExqQUWbcLZ+Yܛ&q=pT1Uq.i2,\>oG]*UdJS{q^)#0vp=_UȳL[mBm YG1DÏqp *۬MJfBƌ┖mCQԙ4dqgOIMe 1⤔֎GNPԲ>A \bpy%M(_鉧OL <O+5)o.gO9#ÌK8>md6 9'`Rt֊);!(bh;+I8STSrSy#òRc 4Rm +qvIJtvL5R3 +CiRRaF :bRW7PQsCT[̟)6Zܘ] ܗO?Mm8&8V(XcT Z44Lr7k}ƾ=6 =^9M-' PZͭј @ +vj+;Bʻ,{52rx9,~fpL-NU]@<犋HIQsD +-Սbp,܁nQtU7LHIKLN_$HJS~I}F)L'urq&:BH׈ͪLQޮuRdZa!I˞ʛIp#"ɅRj5U%slYn^\N3_~]>o|eI**W?tf7Ɠk]tiG>'4=>xd쳗]8)E׹s1LI+=v=v[5ԠԍxƊt0JRši~qN)A6uJŠO${_G/,vsÔW^\㙔o~ױC&T6Jl6`V(]a7R8ܔ8N/܏d2-kăHe%j?'tDdK*l ivE+|ׅD>2n4ڙoyPZml>CjM406»73z\YBTIȔf%eEGaőlT>[$)`jp}*}QЙ~\DVM vDhzUSӪQ"qeiPV:; HA~IU{%J7ʐn^q.U!EC>$ZhT( X#!Ң/"KgjoK0jː""yӹثsPXSs * +Bȿ,G4뀴8~"$L$촔畚)$Z˺.9/(e0FolE!Ry^}|aO< +JiULu -6~ M˫X);g})sD>Qʓ60U w;~&]^zqVPE:4#sת +Hc ?̞1Q~O핷'خR +`i4jU<|R<wt uIXRL\^n"ey(M_W0Z1L#|&4q%@|~7CFkŧ£ky|質a!dEKI_fsL_EQa?UGtq"4=ɿC;4uMJt1.v)|HS + 6xGnA0.A#6Y1Ƥfʎx>hڰ/z}鋰fY?͏ՉAqc##%#JiqSM_9k|y~CuŁjlްVk;@Gtqaq4W01>HUAzo +;3U~C/D2Y>B-'$R$4ӣfKlwÔcɔLJ4{_v+ƆhI TN}\XEٖ1ǜTsNev#>MKC-ؘK'ʋL9tY,|O <3Pt6XPLz +l;^p|kUh~F÷#:Hjjuyj/}}yvNw:.ppY D;!XRG$T +I'n{?XDгy7}?D F=Vfi?v[J[S= *R|O3JwԄ~t'~aV ܄?ŁPekt~-x;/ä됥f)\i\)J7o[\ztU&Fa1Tl4NJ +yE^wO"ʨb[ۯ8 Ów~Ph2ve-4 2|jis.8I&aFssnO]uEJV 46_2o8c.ИC -{SJ3N$h.}ӳe)Z% lBGQw-ɪuHPے?? *^p& y Kʹu>O'?R)'nPS{",([l:Ïɛ,L*tiT>')eQ3P' 5 kT4 mNy¥rnqGpGU/ǔ>pmbѼjRC@-Zxԫw(RuA]ָmEGvR}}Gpqt(61mr?״BsJ,8qx ,k$zdI"mcUAa6iթk!1ܖA<)$r-۵"lu-!PIKn\n4mF9nm=¶iA@T*U*ck4y¡&㈺hU,R)X[,.5$(F(_ ՝HpSmiBI[~a`q,i%ҝQWキOSL*)'~]ѥ8QqT RgTRfYZ5,5hAϦ&rQd%1&e.pKk@M>CLȇNel ]|,70F^m.aԃ씝{#)KqY_ [+*FǒBS 7/MWrq%7Rs.{r9b~8>\p 9oz)(^'R%+9B[Qk6"0MSSSMI,-˰ETtF)6̷h!u(Ӡ)])'y"U ԍHM})RxG|*I&UjlP>oZ ꩲAL*6( "贤6cb#[^QBR{}ا8nP%A;Nr[6T&31TK1`4Եؒ\Gmm4smT7*:lJ4:HB* %R֠nT`y&)ST޴3J"ع)-?Hiju!f:Lj EFGjɰ';8%IqA*ZT$jR +ɰC̝{+?q{JuM2mu+ƶ䌷P +xRO!C:YmβpͩeVC DgꔒYtBF'?>1ڎw5iٶSRgCT/NTβ+ ++~R% в.[kOq1HK5$AB5ar궠CLPVqVڈ +Me m">!bUϩ.;$& 6=Y.T56zga >}Uz]eBS7I_ rM2<,-o_ +RXra0赳q i7CꎚDX#[J $;\аO0Ю3L-^"_C 3"嘔mY UHEmf5-8B# ᨸ$2;@EQĿuw 7/ed(˝$AuaՎt̶gd*^1SO%+GJI!_i5ETI[RӜv)Q;?5y6-e7Ѓk{";5R +qe"͹qb=))#N5;U&6¬QI6ͼ} +aP3LJ/2+-kQ#毶?xl_P3nb@Z^C N= + +y&8wIqWOuȹZPeI_mVi +>ۈr[϶[rQE3/)F%2 +\84q7`#Ymŏe~gR9b:RKlKEɻJē+()´*9FķGO(q!CZMDiCxHmyfa Q68*b:z32vR|u t3ͼ'`Un=?s R-I^YȩBKsr@rJHilRyQ:sJ 08"agӕ^m +,լmQψ,Gt޻_ +R UXp"aJJB<eʌz=%1,Tqq t֕ +stdzR":\pJBlMs%-öoAj-]OVn@KnF״oj6CL5)%`ƪ?$xbA8\t8<[nʴeVc 4s)\ Ls0Y*OH<#>D {ܷBEQtIoSWTrt + =kc + 7"&4K1%B +̆Ss|SYʁ* m1 /vJV[bo{ᴬ0(nlM/G]w i"jIh5P+c݊RI?|h|JꃥfHԨ/AJG;hfr<:qTܑKՊg(լA)~R;8J8J])Y;R|y76Jx=Y[ A*YA)RI.SBak(T=>6u,> +TU~qHf/ki{['6IHYe6]ĕ ˯ lc!S+*'8N%+iuCi6IMN+S+[J[@k%)vcD*/ ;*\Q$*X_kazyRI9UUP|$ e +e\xH %!dpI=?ӄOVmZs${#yFq_tuL![{I=$5ٱj.V*b`-≲I +A +H4X\al:&JB͎k^ܬ& u#/)6}}W/ȚVK?>}9;A6>gCVT|Tn4HuJ4\qj#CybԚdyJq(eЇ^RnHUj ssm|/Kaf.B4IR66!s"ir"~/Ow)Ga|~iu6rrԸR1{z#dJ_X(*ZY“JG#nl{.plq#+y]ZT P%N){owq-&H܄_y))S˗jG;$(!se>\YM*S0Ⲓ@N:p%?ɒqo|je,Esu|! )Ϧm\%"[TJAARJ-y@Z7'ڨT*-l⸄-V@Л Z=(3h.^\ = +fB Mzz#a7 +t P`ٵ&ϪT*\:Tw~ujY'JfDYЁkvRDoLu$|!O)$)+]@&ޡo4U +\Q̾ T@J.)IJJ0jX *)[ZG*E[ vh(R(]ĸEE ;HHZ/s"e(ӢqcJC@H/eͩ! 9r$Xo + X4ahx~0'3u6($WBDLɞ[i-]Yijm)şFe2gtԥJ5"_QZ=]M3%YU>Qf+*F M4M˶cs +C~t$MR;IzhlUW5_{`Qic +&_DyK6Bib6Fus]e .|8)"Py54GqjQQQBG ~QDyQwܥA%\_¦[YCi;*ӡ "s&߳7ۧUYRecH2aR8)I:mɸ>Go#S4X(8v *av_A"?NVeP.bWu!N-GhxhE畵f +'EZ4Al\$vGGVR!i$- +_aAv#[UzDarm[%+B#9!i_3\][ϢYIr8.E$dl:̴Q.BHUЫVǚyQmbWyK83ctKT`R=sZXt:ɱ6qpu1%KmD\ۇ1qwsY3N*i$b`sAXS%CH5D=9*ۏ{zbc|74'Pà%ԧ@UaO}SN'r81<XaU`ͧeJ¢Gy*fK C + y~w8wJ 8AFRﴷ]&bP\+IHiIgwm͞ G)վG^ȱ}H/=Iy2vn;ud0ݳgHx[@;C8C@v[W'?&幕aUTyh!0[yCI Oq +@ 1.̹,n8^ehIr؋qP9؆M JepoZɒ8‹ LZ<EjN ` ;ǓhQF iz cVafKiAJ6܃HȍNq)m6cbEhZ_B̬ e^PR~Y/ol~F_90-Bsk5tϿlsthSB{Ǭ85ǪS}ch1}J3(\N46kme {>BVy<IZ\~d̔(jЧdvq eS3ɛ( աB$: NtG} 4)L^ZR| /\f6;sOO*O4HtO3ql4QmH:}eB_i'2VvT&jPXR?6PS_|!.鞨ܧ5-|<굦p]KV.|>NyÒMLZP%O} #u$\vqssІ`~3?i2[Ke&+mە +rok-$ǕPZNT0:&.[PӠJt5inqv}Ty m{JLV>1!s~F~0,BKW6P3Nf6Aqԏ;DVƆtJ2 eBr m(~r@WTUʏ¦҅FKOb]V&ewZgQ;@ HQ.qTfvXίQb>x꧲! ʴR5>oPJReԴ6H@!W3p<ԶRͲ[:9>^"JN(lMl~pSޥ"o$k+̫sBW|ʁ!2ʒD}+@Yd7BD롆;H?5*V)y(FyKH'g1Mg !˜zL<Nep$+_9B(Tj!=n]JN܀mֽkK0ړN̸E#O˹($"<.q :bBq&BRm61cxwen\0}J"}^@ݚf>jX(d}TncIa𠪫!9DyuI?8]s?2{-Eyr@-E?*:6~a152Cc$%j>x LFΩ- yܐ1Ė0$xL~zyy[J֣)*&i5X0a-$:qe8%z[|lH* |.,$0wIqŀ}H"^qW.߹bA푥NVFʵf&-fJҼEFpܞ| +bR BP٥_XxU%VZe&k( ZLO!ݫ2WTGݲwV? R8{ds^A*°GUa!,-VdwrI{u7,KgB$?SUSq2=2w\#1R?W?$8¹˷LqSf%ΝԕUXREN>*zzY[]q8n`ue?y6,Wpz\6zoHDé{WkQ!=>%,6x+LW>atya^'!JH"MRFi?.ޣhoOv?p5˱WJ]O=kX+ +(8jgw\~=$Gq +(9!FlJGtpe٥@CIb,uY^j=Un&u1aV7(]R|oQlwS[&:/oX= vj[ ׬ +8Pp@6KҖU +?Kp7Q2A;¦Ѭ}>#ۆ|ɼGt"yOB+)針)RMU:amnqoIr,~x6?N~11ᥔ*'70X b v?e(%KOmb.M~8`fe*Pq<9^M0dn7JF>q-&c]CemJ$.*_ +PkRUDnEaӠ7agTJ8ۋ6QJ M`SdW}ᲜI7X8; EN2ju46 h-B B>٤HE\]]f**bM iʔ)#Unl|lY6>}Rm"ױbť6MNNhsᲊɵrB)D:CR&gS'4e93\,"ARR{w"-_8ќ-/t+J-v f*lۡ*fJ|7j"!FHu+HPu1ЩpC+k~몔H~N׹NވLcHܞ#Ơ`̦^iIDЧ<׈BaYRd.=qѶ {:jө"MKWg7 .*(ÒŴ[XךAtAYJuaC1R>MV ֪\'&4TQPe\icm+㎗us%jMX=1RYǺ}6ig34m %uBVM7uQDTúa=ٖ5$|LC.eqLؐ|4w΄S4e9L:|t0-E?mş5(S Z.mNL62ūLv]۬y{nNgڧ.,].VI71Z6Dfw{p@tLq}a{t^ H4Oƿu{`#"߲\!xmD-5TR[6 m"Gd*.LNFMëU+/ʐ58k$H",+z%Tz٠5P#sReY6v`:2*#KOfvu(}](7 7*&Dz?SYU=ͳ8]>C)'` "xl+:>L$X\!#'qIX`X?)L=g~հ^ly$/HQ+(oCd%I)t 

    1:ZFLȷ[TAu]6+?K9t>J0'xYԏ b֓/$ IgbmZCjR|)6$|dzrf 1&^k61 U&<s| >t_t6^ߔ:v +V6;L, ٌ4uEUMbP$z&m|c4j-*w$G[+Y\[v*2v-_"*b_R*wS*nFa N+Hz3̎:BJ[ d+=A^̭:-.L)Au (J9 IG_:&ٔW>WveVCJ_p +#4AZ\XJEJ̀<&\5e Tl[u+Xs߶ Ǩ+fDe $W+t1oX J7$(ѵw߇O|&BSf0LYD[wcyc7ʋe)mą|(}Ue*B>GJifr8]$9 +{D5*l9םpr}Mb*)._y +Kå&SMv +yq=JRl5?1v~ûPdK%FsCSbXV]!K;IA'[穯J{9́6 ?RM@I'- .?#Lq2@,yĭ Sڳ2"ꌩY}C- 1oQ3)}7ʭ5|R22̽2\(Jqr}B=f{l3=ĥP xy ukU"l~j 6IzQ(-OtLSۚt=*u,^r̶='ߒ=VU&؀:tMtX"5A]2׵Bv9 8Pʼ'V4J"WsBQ[Rh*1r[ {#-!)9~ m4ٷ_ǦP 'ЭW' 2s +3G9euKrcNDHM()=>2TG5▢1uJqiy@>XH\Nfs@:f7@>OJ  \:a҂8)^$IVڏnL'4x*BT,H'v鲩K-j) ,W7j]*Q,$٠y|;YeM:2ռ5{ y oe@5LSJn#Wc%q2aQ 7OI%l[LrY-蒕 [=Ϝ%i٫TuRнlV4A +6ܭ\:ZH<]m5ʝIV/9M\Ra v<jTV2i!JSPĩFXunp̣J,P8ft+^*!R=zV, +B\p5N08xq$ՌpTju!(&׿폶%4ss(}R3,)ŏ *ݬ?uGh$Pۉ: sVKM6#wݏ7*@ G|1gp'ʝVoȨqi]5ЪPf\Ex m!GAVl|nLT] +/A'z["VܳMOcΣa:X^4u_K"*ZEq:Bc!MܣW$y YQ@y$peko^PJ[AO X 3lw*=as=4&uܕ\~dLyʀvd^ @xh5)hr._qo,mFMT_t T{yɵ1kLfx*Ɯh\) DVFNQZʮ]t%'> yK79|Bd!i7b;~R{Q(%BjC5FH*OQ8S H\s^iÁDTKD]mL(9I:zFǼud.t֣UuLrpqo\hO"G4[~Y3mmv<#js~CIzGBH$HvHyCk%0A +B S$%f +;VHOpG0F5SrŲH6=m9} xKωN=pyT oևY{rH&F4RUs>Gm,,X.DjC3)@#PScp|g$)Z) ^ 'Rˎј~J/-֙Im֥) DA $Is 6~qZ3 "aN,dʜ \?g<<qaӄy¬y2L[J}hǦlI 8/eL̖ ej7׿Szz$3ubezb;()v=Iq*>69'3%X^rmeYG I3+@T”{\\W+G}+Ӟ=YJA]B{t)S@1Ǥys7XJP<Ԏ(h `u5vbkZMHmŒ;rbzU֡TRftul ͒T$VT|W˪αܝ/U Tvo;QѮ^}t%ѴxS38뇴.:QH2k萩M-嶇J~Wd=siM{jF=a;\⮣5 T8|983e (]`v]t{ 'w[n%u"BФJ?ڿ˹=19 m_QdyE ә> Sƙ06<) P]p n114ҹq$L8ۏĤ@w>DL4( (P̵keۼǺZ|ZtK NV8韏peqi%Ru]RYDv)--JlN#90ϬV&&Pt$_ GtVtR^of%+s$f`HoLFsnc6UmCi7$bH<.5.l<|k&%j' U&۞%syL~cw5?FrNRp\%DwX씝vIaƔRҤZ M?fԃemq#CoXѪ^[N^fKؤ% 3~np\ =/Rq!,yO#WOKB/o+/s3FZl)*5 )[&͛I\4>V D+C 7;jJo!i4VS((Yu-OR8us 2gVw"j;~8Js{x>ZEʏ*=ʏۥٸ;T/sلy,?8?V;[%+jZPǓӾL4Ej6^!7 Os= [R{?LęR:dQё-¸i' c9Ck5bB47-erm};s',X);ڳ9s22~p' ZY>Vi!C*jZ\A]iGMqd%X֓ C:f{)יK4z0Z˪<ޜ ci(z&g1IFaMwE8}hQ?cцGvol>HG8Ϲv"ݗe`xtAUk5W;'Mq6~tȨ=o⏽1~v>?}2aMua{?\>}5?͟|X\]K"-P8Iׇ C?"ZrkÃOAmE^k ne~P$$~g狇.T)rX6?)T??܉:HIDUDOk5c,I'ЮpJE{4Ï )bߎ}|̥"[*~3n1Ȩe<[SSԣpr4q̴J$"?5 +K$(ʳ1_+8pVt85\u:TxbʰSaL}h^Vm9'3yb6r Z΍-4&EOcۤ$36bw׌IM'v%rCz]^ Or|#sfƷqǤ!rSBm*dTxZ244DJYL{>O?w6{#{F6tw&,HF=Y>x [T&Xvx<շ\rտ'GtYњ +̹EvD5FYWe')5\#]-)UkM8X9%0OtU< uP?sTP2K@mlK!m^A`F8*ʣ*NRI* FXܕt6qJh +(MĂ@*$/7$HSa4ځLG@[אe+0RcushvE.8sVY'$d)I%(uZUպ-kL\-Qv#M;<%NmZBU D B#M;/-+Sn V:āAQW.ќ7.ӷUV۲dO>l6/@>C8TˊܘXXJJ6⚫ɠ$6'w6<|_Nk|*;IvYI'cF$1d4 *A 6k} O~-թNjِҡt)"1Lz&wa j$Ԥ"H<.WCBa +K`lFidx LiȜin:ΔJhaΒB;E+nB%*e[qR&J+M/-'DB\e+Iufu*tJj -EkVҢ;_j4֐:wR^1s6h4&Xִ,TߖeHIMӼ`.4dH{:ʝwN{#q£hKH6m&< $am+̳j 9JJO^a =e{BM &L%α- F沈铪1"KtDZPQB$onؤ7Prxp91,+u!ΒP""E7ǩ5rjsj3L/p.@ )e$葵BXf#&%nNF 2t0^dSe%VqAh;*M*Ǜ1,Rݨေ`qM/ 9t܍Y@tJT]h8Ԥ +NeY*YIMېNC3'NյíwT_ʈ IF.E-e™( lbrI[:øW +ⲾBUrPivB4t-w%Gc> )ZoǽJbu{&tlH9G ,o3V +fg[.i[h]o"UjYvĨne06ZRPRO] +g]uSjJִHl2hQn,A8ŸZѭLaKK$v:-*N$X">ƚNJ RKBGt0.6xf +28LMds@- sW  sB"J\q)XrPaW ~c8lC KBʈ8D PRTd +Oc^<)Jy:Đu 4:m ꖪdVRkHۀ 7-~ Q)m<(4am$U[]ijzfӛิ1|qVI<ʹe/<-LS *#olKabԴt^Ci+X)I99PV-rd>[JV((ҨHJRAI'S7*7[ސjS3][Ke Jl4~u@ pBnt!) ̈́E+Tʃ)*7m`.n"=}+FKډcڽP"T:}B.p RqQ Fŵ{t*DE5;xD.y#cf7Sv-=SmDI*% O!!0!;6٦ѝuXs1v+Oo nzkoL{O=VjSNLk|]>A:҆PH)%#{cQ8Hf3КqSp˃zm +BtZn[!ْ5SO MÉ˪i_dĝz"~vVZν}AcBCj+uDD$Y$K "#@" 3 +Q$}k O7kcn5iB5=RvP}:LJQή6GlW3T$P}9'DM'엦PCl$F +)&&,ka$^;%%fxj^N3 r)m +2cY``:ɩ&>308VSXU,9NZކ gBb.LFn}:G>*iT x(yǒDB;U\ajAN"iLHTuwܡ+oca4mVE[Vd +Ғv2/.RT[e)k˹j䀿y{'SJ Zm|9;>?2brڕ*9u*Pl{o12f`HH}rL lKI>P&\g/Sk*?jpykQF,-7RSwA:kݹjl:TR B tJ"4%)*k`tJOM:GVgU&ǺПZ􀻽+:ܴq̑?5}5ZͮEJ\H[.|6ie{cH05m“# +߂mBJX,C`vͨ۫Ld#}O'䐣n<mIh)s;6s&d#=cf\)t!J9.|9O}iIPbYS]7[X$%mɂO;Sˀ1deq =Ii}<TU$]W,M)q$o>c}HjFC~oq3}"]bi_k1%0wigDrջHpIcJUG:U*m k$F|H pXܑqo5$Gwy&2Io\éj{!YQif}ğ +絕߆Òu8{TQR$Aخ&Jf2w-e]V:ܤma[Ff0eݔ IQvm,E[~֤ϼL%<&IiVwR G2 kIeYVu._6~7*լӦ95TFvb|ç$)L= u6|5aZ;6ϥJ14]PJAҠvKIQƯxn~qd IG@C)3-4JςIyڇ%XMREGBdsCSW*6-JL+6izvu4b0)pr8N[q> +R_sKTL4O|FvPԌ>:JKзlBT +!tBօR +Rr$ :b*SVfE-LEi 8Hx~?$d'ty-HOa+oA>&ӝ0`6&VHs%$\'9ӈeKb5%q0-4 ,d| ~\{Q#uE+JR<.}c/6y)Rr ?4[Ӗ5ę A!l( r~Xx5"d#񄮹OI+?c_tg.=ZBUNR[wHrVK) +\$-uN Tj^uHXIqJ#p)a+tAEl3E MBo'|̐mv0G*S쀥 Ƈ-GRTA cвSa;xNH4g[P:4*k)U3`wYoS!9&zbR^ZP 5kpƛ5 +*H`iNf:%W~p;ك^Q!#9bJ凩 c@R LRyCsk$^0y/͌J#:V)!M,R\t%,! nEᩅ}Uj8Sep˿x% Tf$uIR9RR-bTX,5:,Ғ-eWO>gpѭ7SeRRAǼXRt#XPJoV)%+I ([暴 +.k)!6ۍ zݭ蝥*8䓟"oDۢaf-9<}ry(+TVI{U^ZJ{?^mSb[̆}yp +X2TJlӄ!㲽Ӳ\G8zaoՄדn&dd+SbymYM@%AzG.j5<5*QRATTׂBw;'gs4r6glT+3l|˥,*DևhȾga!eXY]ZAu*?)z{|[qyjmOG+z Mt>OVZ+Sg1ӑyb"&U Vi6KH]6~~Wš0tyqO!$:BE% mKJ'a7o_9rG8}tj`@P7)ዙ{DXAy}_hl#MPFEr犥 pŹS::wZ[!ct$T{lQ8te_1I)|(OԝQ\6޸hLt)[C^m,=l8ƔS4N'UXi]=OqqW\nqiPխ}mm#iDzޑbd4(mr]〩ob K*wq[1l,Sa86: R89DIs(UiTD}hťOw6% u^TyO!rK)6WG uzʕ^~mpUm=KZpnDlWA +ҰUY}L>ģNu) Ѵu`ajA;Ssa~ރ9}tyL9"R-*D([B~BԓQ'S"Ϡ=m׈ћB@QHn/QlWz-*RfZmNĉKjԞQc2pej\R/̥t_=lB'(!Ũj` IaPH>\sa uܛ~vVS@BlH )f0fZ(1qblqm{6-u [w#TSn)/,)x.& j59ʋizp>IZKg2d]Cm&azئ.sBZ'"4ex1A! XOڗ"XڀvGr^,z(Fz=DghvtZ2Zzr)NB¼=ޒGcr1pLh7{\q~T}c +9xgWp"ehf~]rgdAMR/ո +"4UGTm.<72 :ϨIڮm~̊$ꕍyfƄn U,w e%rf6<.3$/X{Ndz&oj"٨8dJG~x둩;: p߫A;xR`oMW4+7ld!dx彇t)F`j[rqp ^wJOw<߹BNVl-2?,m,~iSل( 1՚%38=i0t✣.q0ODMLGq(zd9O09?I){N }iy1M腰JdDǗY m‚7!)( zZezk(G=^9lsh+j[O1jǯbKW#E'~oN쓙8~ji|K>m?@yGRBM_ǥOGǘ>T1+#Fޤj )3Ұ-#VRɶdX19JM&cp'[K6ePi xBj~DO %P:Ud?LVjiKi2m=ҊSV^'57^A$yȷzG2 ӪLGi&7eZ=Ө$˘vۋV{dsOa?~Hl{ckˬ6?t?~;<2?_$'qH Zx"} 8mKIѷ~$=1ͻX72@<֧u 0@J{mL; +-Jeߛ_ar&OȜ @ZUH[6Vm'Ҽ~v:i\Fm1?S{څ{+^JߚKeŅǮ'CQVQ֕S}"Rp[('~_!.6O30SG%;&>2iM zbU?QԢn=_+ 2,VV@ H},[&GmD !'[m%PĻYC5JQG"Ĉ˴ǃiOaFB8R %rꐿeRGдVc H8)P"eʯ+m 8.!3*Edtwב؎`"<') H%)B +lߜ#o(%[_>QWQO/u֒:dwRJc.-o#w*b qӌZeuIj2LY-$RW#iW&Y Ec1Zh:|hhTu*A#Xp(yFXT$h-ct#=YZynzHi!3(s 6<7ӂٛGfS˓Ո +i+(V;&-X%3 *iwiz#TuG?H-Sh]DS Q>h$ ПWzӳ/YBd['2K>':$XvCW!${ +{+T"|8O\D49dH,{yK92|eo>`bjؚH2IR#&)/#IZ߹SXY7y>xչ9p"mq*:K-d*L lu7Ӽk)TzXd9BlEMAn7oGT !k>oKf:EAz"?Mfh'nٽ c;!Iv6$v7t[]֌JΣ0$zm ^RjM*QTt8+8 By$Yވ,/6Fi,<^R[K$6ߚ9 A=A{-fd՛(8 ʭx%?NjvV JPn6,-tĸXkQJId)S^Jӊmh73XS#Lפ&#LF [yiܔ緝\yIHmڐ m' 39Ih#Sj2$*6 pkk;h-&.TDG Y,a+!>#3|9%mˁ x BrQܓ]GNLzniTBJ-d:9DqC֔fS=N;ϲ6R *@$c {wd<LH=ZH PBqRzZs|CHZUbkI±Q\ױ;,hi :)$JIRr1- Y?#elmaM2r,C*/lbS~OVW~qG$}A\&=I08 G$BBn e1ՋBRP?j籷s8 Ye-Y x +ƲhLB'v|z\C?mhpq8ۥR7.qWO7c-e6#G8@+#*Dd*Ikh܇Pݵ˫(2u DReD2 J-yQ)bp [psELT +\ ڔ '. dURQp6o;{ \uV,\[V ) +@>$=8StS툙WBg%;{o T~EE'C&vt,TՆW}@҉&ݦA:5F(ʋ-$(UX(TIߎm]YVmP%5F vV-iCX*z]΋qASbͪe^"8I;b|Q2ʇ8t( X'w{2L-o 9!M%K]{hxgOT#M8J\YqD\TDH*Ĵ_ڒ:J۶;dN"lmH Em;+CNĎղm'Vs&(eR2(+ OIau/JV9cyXWOu/6lGFrx꿠E0IN QU qB1UzKerI"jݸt'= 8(G&lU{_A+t$^GQ.J5J9[^k7Qeƒ$T!!`mҾCRM TcܕyGnAsJG==X0'G~'hq囕,]F:XVL%16'h;BEs'A:4LvmBy3KC7tkJKl3g +E`(jHr iߔ𰐥,܀,lSO ZZWyĩF54CSϸne nnbWK2Lu@mE@?.v*"/לT9FG`6^FL8$.LRps7P6(hC'^j_%q=U +#m!-ģÁ!.ʱ琄,A󶾖1J]&̰qnw:*VM[VsӗNV-*nq8NNPgKhNިS3 +uDrMb5U_R%Dp,;Le"hioDX|Y)*:oR\"$ h~R3I7jUDiN6o- +ZP~{lU cQmɇV +Poq˩tM-]KRjS-LdK\J%--{i"Q/Z3#ɐψ֥ %v7fRJ+Jsd;0qDž᥆V6Kh,faB=ZBTe6 (7OU3&_YS-xNޱ@$۰ R+Z6&'‹iT8^% F350C*KqyCvԀ<˘RRs2FVjA)>X)v2`RZi*?@=qM}Q5GA9Vr6S14Piƞ[; UVï~hjJW0ʥ5.BpPHR z@BmŔ]_&[yA9*,6[iD$7*WoRq~G1ASOiek%GArI6SFuUhU)mq*}@oWPA!("gA!GP ڼْin|ѷ|\hJ4 Û_"ow Dsн*u6(I%r?X?1z @ CTÅ $[QKAy҉mr@10h}Gj +k7J;Oa v7a.D|sD + ]1:-k/6rM5ȃ#|-IaFd] QJlz wJjݖ '.pWDM5$";ϭtC _=j*ٙl}4kVڦ0:;YTJQb~IJ{}1ۄ?0ޘ?+Du>ylǽhRnݽ9R"ӏ8|~iCQ#tz҅(]0:bp_>ߜ2Io.QBM" ܘN#*a*_V= V]Pmn)|t<˃=շ{{kM|籼t4Or*=EnC8O'Mه`9n?l0(4Aj,,8fMqD,xg(p"8eu'?RHD2 Bs6,ҥ<vmߦvqޭYNѮ;+Gmj7cm}9ËOg:Cp8b7],ewUP%S " WDZld _2~6NlH8b9OLTӔ'TN7$a)5f-ԶY.gqv$ .m4L ma*;xgL8˄}֖҄C6rʘQԬÐ:&ҩC~BVBZa ޝ-GI\v7VQtfmP*̈́"VI6JHY/@ؚn_`ۅk芯[?pjS3wV EbIe}Hy8fe2,w +ګ3 qIØbT76T}i:Wxn!rjJaͩN'[6KRb+R_p=,KkwxōUY5ڲbIfxiӤKԶR<sjr@qrN*i*7X-nf&G1XB=BOkT|#@-驜d&S%.˨, PlGo/Ԛ0ov>0Wf 7USKJV|7&Z I,CAi1 ydlJ F#͵:S;bNJm8VEbRJu#N~VgFxcɆmĮOI4* ,u8DN=DR +co_n!/,Zo͍ŰKP:s!p$kCIέ + l)vײ~l|b:9:3TV"K3"wFtRPnv+ +q;Soų'kw) +om, B'hTi:uy'u1kffG)HrGO@o jy,$o|aAꎙq8BBoEN3 OC>)z=n3R u)oDJ[S~#m*Mϙ~܌ mZsOK&@Cn;k*7n[h\t+uFc*tjMk^l%dᩏN$PMHTY`ŔRa\I +˘ub/p-Z.LdHChHKm6)1HIԘEVRΦiUjZV5Rsa$b=F[9Yq5JMN5 + 4pMƜbrDyu)NLPV\ury>NLA-h'^TM$LI(3e(:r8m 7ʹ_=&P$T&,tൺ:UU$m$ov IC2#M-\My>jz/KvYrh 7%#{[ZJU;KӧU(.p>+r;S +ҕy-etQpC (Ϟ9mz ٵIS/c],)J+nTT>/SQm뙉7YO՘hJ^p +e@op#>u +X4nz#~vê*Tm3֓D F&uw4xsVd(-B({\ Q6\'DIq:E(I~.SԾN}&'A Jh_oacO]IzٵgpVHųZeP{-mG5+P]J@b6FYGQPCf/#IȖE"W{("JY4CImmS~]~m'd;yH1| iisX-D )gИU.L arOa{3hc(H}T2Pw˥ɹv 7#^=A\Ah KC&s+n3Y6*a؁ a'|W(I:ti. ?rIbm!@,[.txIZl% v/P߄%T Y[uVkk%(m/!~aܰ/WT1,(ͨ2Ԯ%JG't]gHJE ~ )MĶT"T/ +,n{'اӋ9j->cGVF_yDPH)aקHLuŕD3-i,-pP Lw2qϚwez8G<#05pvb/0OB(q*GKgQMfNXC~Rfeu*P z d- +'Nq:UeĠ_ZTJ[p6̛XmcSHjYӠ[/EE`HmHZt ={PE,]Avt]"&L4kYyK̐ ,\ +F$hBwѳV4jUMRWܠoऋ6,mdn/^oI\1l|%Y4wQ:O.boBmIX AJX S"¢f )YAЍԧLuBkJ H~ +c-k&%8(XʣD_njΠG%MS؛SiD2} y׵pHQ)^5㲂@Fl٩ע6wR˻{){L~ d̛T!^ȑg1M:#6O7Du ls(/ć&+}]+Z7$cbyD7Zo^iRJn6˒_V8xV\\. rA"$X ;mϜ:IKQ{^J&MNTo4G-COµ$iXS@!7< ;ߙKm5$[3 + +ft_\BNa~Qr|C`ge{D7측I[6St 8j,?7Qm6Un̰ӏ:CM)W HՐ*QJBպ 16vÉ zDz(g1TUA-[JTME`}Gxdf}΀_K!xM!Lm50ӄ,nGIׅL{9}:Y+fTq#[*$M1Ax#Xv^Ы%NFzt]kX]$+|RFb7&6U sFٹZMiS늖7$,(hŬqcfniIf: ,, >wD5#ң gS ٳ,Q=y"O %I +@ +!cᣛ 9F*/,M(7X%jj%E{'- d3%.E®@NbKIۮ;|\zu֣ +RZ)MћCKO?݀\f7:@ * Q0h/$<|0 +JMg9€;oxrTeu)K%$|8pČ>H~AJ`A~Q~ +6-kѼ7uDչ ''˓WkNp:ŗ˅)*: xqM :`OubV[o8AUeLTG;YaIЃq ,@$E +NQT؃jwT'-j 5H&FCuVkǨ2_A@>9&$FyxDMA̡.eQAS;m+R}Za-镾4o]s/u*ep4{Q'[VaGCnrʣ}7tpmQ2s%|uk'dB&)jT^V Jtfpy_I4Rn#"!L0E qz=teGG7,xrIb|Hr4]F^D\b8y5)1'd"(c1!)MLʽJI#R"!9ObIuY~1NTbGPbB%TUUqg%4R +$O7N,ڜX^:?(s9@a HLXOK1Pk<="rjoP=bٴ'@=bUdJnD W#E(הF|=uGK|܀<{CZQ9D,aT7.-:( zC5Ne{&x1wR$w$T BE?w3 ԞQ4Tq:N_IlM<k/dF|f=_0k "bYry2ۅR/&WQ"pt(\R68zܽkacVhz#+* .VX% ԩfSadjIzPzR.K +k6aق$l&I .#7G !I!33H$@ɦmı "▝O:Z$9=a*SϾԽZ&NRѶMsc DEcq*xs/,Jq mdz}}.\o!lYPy;yHUSmMUp2HʹYFYQndpܻa7V)7GX߬) b}(:*q̑i\ *HP.7 h7*2Xl뮩O;!זO*qf?SJVeXXX6VvXJB@J@ʄ$lxI$xՙJ،OPbi*j{HN)(km%AY)M!uDmEkcs L&nb;FN֚>jRJ>)$sŤ•4Q_4S0Ѫkn[}i+ï=0hXdS}ZRn9rNie^KVL|-LAꬍv}qgkrHs6rvLaNbL)c$BENeι`0^eoEqKuօ+%=%HQ? Y..q0yA`{KIPnU8< m +HX)bBWk66$>f~^ʆ7*ǞbKa9ܩr[7;w?{&$)Kl$&[BlKuT* ^U +dhBYmH* n$B~Tk5 3 HR{*Z-n6[Q7RO|QKʵsj=й2:T9_ ]% f.L˖%)ۄxd +îisS"!Ѽz cK%V(]5GN=ߊ䒌`IJDڥBQ`,Vy먼9yNӪ@9eXdZFd߱fpءT-璼^ *ʍ;:)YoMUAaYN6  .os퉏N8;tfMקr\*>MJ"忮|8_=}aU^(KS޲RFi,*žNZa6C?R%~'f7v4}>왖aOӞMQ|! u$9Uַ='ڜ|&PiG +z}sߤ)FHGrL*<YAڠʋΐ4 ^0 zuw띿XLcXiY .N~yFwma0Fe~rP{OkGq1_DS*2DWrn>5'UZ~Z}12&$ϱi25cT`6WO`-UuѤ˹ e6놋iYw-^3iDqymC@']!䍖3 ؚi~u7ukuqYOlUϪ1r F8`!`-oޗ_~1XC]SHVȋ9ZM^qcËKXn}~]|<nZ۸=fz$>SmS+={˞_Xydt#vf#@G'9i\lTR7UTtTGR_`lLSCGŮhU(uʣbiZoR&Ϋ@XLu ϪV~yVz5!^륓P=@E~#j)Β2rh@l%匇.ζr/7hvFS>ZcF;BmC$CYO{ +2Oш/7kJl Ґ">kL!XGu )A@r880g‚V;#:`TF$*B aa %y.e +S{ u! )ϘJu qqԱ JIH Z$ m̢i t!: `]O=j[.,86 4\š"#m">AQG)9 ALw!{ZTT!fGTN궾:xh}1,-()7Rg >tV\0a#_lv2,B6)*yegU.m_ L51GT i*PU{Ý6dۜGh/57;ۈa8Kq^TPXikZ)-#P` kXt"UN!L9ֺC~Wd\&TLcŠ]4ZqdS. W 2/*-Pj,P[U*; xbfqjĥ #Ca) +W#SvX-IX2H셄ɷM6&F~ӱܙʫP RJ7_r犓+SS)~jMXؿ%QG'nRRmT*ܴtH'I ŀ垨Lr+lKd I-7 +ᄁ4Fg̅$񸷤p"dIr)'.dmcI9{RӘ.TA zV]~2%F:@~ƈsӠeb +n@K%?h"^jǸR%kjt%@\VBOyMҒ*ZB.6+w"ͼ .k"7f"*T0 }/LW-TrRܦͯJE|<7gZ=eLj~a @RNb2|uk&G*]*3Hjv+1P RTm?p;Tdvam$cmh'HqVJm{!N/du\6I 5$;o'TRmMԄ,ͬ؀8f'狍 ZitT;j +$ɐ(d}1CM`֧= Iu^J[ɛ ;LUsF%8 ղ D=|vתIQ6t +>iH*?LAFYV4.O&no>es* 6An0]a8>%pgc9CrZܜ▥8I$Yi2m %  - *ydrI]⫳kS%j'k @Ӏ8 #'J%\RWT\~:%E9RC*2:M`y ,/IQ*o[R?NN wSS6SR[@p@ْ@rc*"c̡},?DŽ;56cJ3IJ|O9ܢY +,>WE5)YkFm@#Mv;|Mۇ+3Pm%Es~{ͨ +i4Gp҅;t HAEd>=Km:dtL25in|ѦnJΡMPP{ڹsMr ZUQy hq}B@'$1qMAv[m"rqS^KG[Xj59'aV$67*UyU{}2.@!:_}π$=aR]ec!Iar,)VjQ)m>mRmwJYk!![P\7I]H6[XRD#ly YՖҀ)do+IA*Q J{X|v1ٹhS ,pkUíT8M"F\vS.ZXZ +)#BJA 3/3j)7c]bqr%mU`-%v7JŻSt*f*!uEFVԻZHBr16 IJy3^t'η1HYvKg+I(X͖lnZ=Vר}3hSS6/wO6,iXp#ѹC<$!#IoTb*.k`JQ<H&)Zz̚{~&5]bTK[qR72rb-DKOX *xٹ[hi8b)E;L@m`,DJ +vxggR~􂃘+ӗ.|i弿iCj$N+j H!Љ>芽};Xuqqrp7!ht:ׄg!njyE)p!7$ ~yq JΥ P㎜bJ:JR@1o֥nԡ,)*׺=:I.fr.&A*|$cE8fqi4,_uPčLY|\N8sR-)K+-(ӎ\%D 0AfxPE +IM + +A) ߎqE"M +V7azIR*ʿ"P)RI$A'ڞF +T)mWZP("BJMCnxi'zBgCV+R^h]:[[`GRnD\|ZQYTVj%^'[K(Kh 4 Ewp*ԓrL-)LԦJJRE6Ӵyd[uHSTkZAۛyaMg*lUӘ \EJ RG?!,{~o .(es{۳c|av~c%hUօcdGXP6=צ[070,ҐxLNߪf1ԣXg&:ʁ*ԙvu +"t }kO>hNK9~\F`r~TRR-qWw;P ))낳{7MV[i bYd9' !*9bAE1{5PSІV#!e65?en)%=7FT {z$'ӓ<=u#nM v1ƧT#!\7Ǣ]ΡdGr|}O9 +, 'k" 7H~%MP >IȪCkI%_pm +%-|)ur# $FjaCUBNIsFН6XC4˨R'{{谯aRځ;NR<(PsX.>/Prd65oqJK +xxcJ"4J>@7ҏ43Z)Z'֕:RB */b:^k:ClbE}`["F#~y֜+l DJ-bZ{+-:3#[zj^j-(;bNi^V.TEfJCekq*,B괂ĬV+PNtԋvfr]`C4z.8*u .4dċw?l&rd8QvBU7RI8JcbU!) EqsQIˉ)Ș;t+l~P =z՛.2NZ]eAMFIkg4Dze MwnavF7^Y:GasFݔOqs%{;cGTt`z g1:np|8id\?/:&j"T'hJ<7Q#6G38i*ˢ7ңUbRg4Ǣbpyَb >|MZAJG0za_$[vC528\_Π9h ()z9Wu͑k~ +Z\8iN uhQeEP\"]k^}~)L̕y0&Cs|.}O*WИ\dzÇTzG*+KR"}FR<@s +d }Йqn' J%o*O\Ǫzۓ/Β?'.0C/uU?@ޔ2>f8>MJ7R?FQ* jJ+Q}bFkJDؒcb+-e=DyI3j>^|o0}hZgNjL8e.xwop7b3e`?:jÕ5ӓrd^J&[nePΚ7)=FS)v%4O)|aVC77/~zcq6f3բ'Z\#d.f k31Oe҈ؐ F}#-!ij]RnmŭlIK\Ե҈6{iq -żVRTt>ݝ+iļChqĪB;=j$riM(iowRϧ ڦJYI) G=-RAIXeD8m;- +&مe_0.-+W[m.$W`/26UTIuCCR Уr?TD҂()ɿ]|JdLcK7#JβGT+tF2 +<&q IFX|\"9OE,MX9f#toQMMnlACDȡVGz|54OC1^=]RP,LjQ#,F6 +x]cAy!Rgz:㴏=z7M;2҉{'[ +xIT(}'kӀiiI-'Y ?䦽{NR}؀(^#~qUY1zH;D=S2?ڪ4z[_&[Rc^iG>^Vpe]]گ!FPHV<gVU^iG5yuyP_CS,$FPw*pP'I't$X:>cUUVW w [#/ S٬M8F7'UA +)O|QǯNJ`l#4bW ^a?s#4,~Z}9&aFKX[(Q+hz6]9qSYVm3^5hf,ыT\o2.W8˷sI'Xu5Z'%ٷLlzKmVC$I>DDLgz!Uwt&eTwDIXn;DR}ez$r s_4?膕 oGzpI:%[D шD @/vџ&z}hgbAs-޹4?YQ+}Ǩ?׵ǡ5KP0LLuA- R|Xd.ϮfXj"){WB]IxW#ʄoaώTdG*|&NMي16JK>1KU@置5 ZR&VP'["E8z?W?VaӁ|t2{/1௺#O;'R+!pKۏ:RQ hpVOh TUԧ)j-G zK- >-!9Rn>B=@ qV[eo<έYRlCHA"BR 'jo~|GriǑ1dGo,)I7PP^$(۟~x[u>ۍ)Ag(FR\Uh: evؔΐ"Y `N$1@g1KiVwܛ!f̠2J뺧J-.N8%ns%^ݕQ2~p#6é%-:G_&1Z5I$ ߌ0go\^"CU'˺]e6╭ +BʾHTd+O)inPISeBnoW/*٬P`ċ_zBdF̥),MIJqk%:-ԤEқ +|k8nWo*=& ͼ<4v{XK7-ܢܪlCR,"OI߄>YNa#Sh2/ +lBJIU.&[wJ~/Sr ܪfIwb"CUUrL7, [JAl>lU,y )@J^a0iI6b}\"bĤ7.kJ)2vJAK6 +*Uρ.j{7QS E6Q];] W R9DJM|]e8 +I洐9 +|!M#yJ e;5ƘJ*_2g(,8GSOEx,uR5/6{1GbZ}`9%[s ]!Vo-6-Rϲ>eQ+rے+ +mBZyS([>%F(G$Pɷ~PX}++}T7m'J`-[@i]*ד\cҺA])«55oԵG'coD/Jh}>ПO*L 2N;\hkc1XY!- l %H|0Ɗjj\l)UDMϑ +[݅kRҢ;~JZko8&2F36Ru 4$]mUb&ڮx#Ȗc53uJL +f[uB&f'-KJěe<ܶVGu85v7b&IM2IiŊ3/:fW\m.k@؃_.u"iZ<,Y'C茸ߓENҪ4u~D+otp|7T~%GK˕w]niI=įfQljh+op}Ȭfs TJ)aR-nʁ6wE>uO^w5*^zM#jk#Ɠa[%Ҭڍ4D';Nr(_`$&ڟk\H):IiZ'YV_uAN +M8c0$h&O?54yj< wDIe +x),B ;a=5xeWP#' A?C؋&{:pohRRzd;7TM҉Q%+lk\)aI9.J{5ImaR8m04TIylү51z,vC5xxi,(sP}c=hKQK]iL(Z4}EQ蘺CP ;|k;uS3-)wbUC|$ V3nL4U}k߅xS=2]j9SY,{sjҒXteD,xJrZyPEӸQK$GMNNaGrEBA_)zX#b/-$cH>!D+1kq?E-O]2:n>m^X%,؎.l:`LJ$v*A?Gݲ̄$Dieǖ,ꊯ zVwX?U< %']9?ᕑrI6%ga)2eI* _u\HQ_P݉_v2jHKanC=-(\X߶:S&aR1H l.xquC a3M\++pm֎r5S,) QmnJ;RG5RڒuI($wSerMȼHI%D:Be$:d&(bvʪ + tC^ Ʊt!j<^SX_Wu:C&CbIl RJp:<²fBPm~ >fQIEd@pxSNXvő"9noIʈ߽UTP- 7|2PD8ѺM*jh5,[1'\6Kze=WwI'_RgNjUXm!7B S%i0sr5ӔuLS[k+=p;=C*r|]OM(`ZT!a;ͪ:wĒ_O"4Z앭g2Z ; f":neڄnޱEWѲ>VOd$p>aQX:vingP0e&(" o䔛>?cJ>Pq)m[u[sPM+0IKQQˉT-$&jc Ya9oRX(*UJcb={!XOs@F4B?j?8*Dz"NeA4§Vl,EjI`SN QjWcK[M$N4 mѹjD-xO[( @&XGU5Ełu=㧕,SSYϔGVOܓcC˘6 +"ӇeJ[77I&NJl8 +TR5,4EffYRk1J K`r{_qR4cߧ8MgRmѲbhD͙_&ӤIsd/lE” sZk3l ϣXYZqQuj >:QwS'MzLVJSZƬQ)ȳ,`h@\B5)*S:EŨU $lR=,U4$/m8.Eq:j?69(qInU**Ru%W`m:wQr%y077YkҤ Ee[Kk=u[$_yѦMY'Xŋt=a4Z~dCPFXPkx`g/ti۬>q.1#R0ɘ: </(IeRʩaJ%PQe$G1 DHȊ#غR=qIj[1JU^箺DM5"%#p.? -V[upMVV殤-2&*n:MM}@ zg77ʞ:iraV}UۖQ6@5?Q~ADVVN$%)66[`|d8G>y'e &Q#D\-%fV\O[+Pp\K[M)dDmmBBD;=:t_]٨t#w!N_ls툓cV-0s.0Q2s/Dk?ѓj[sUmͶFjLcN9GKɧ"B _xu?W`M$FiJי1tۈA**CJ7vImXHRCųf+)@_KˮaC(*L"w|r7{w)W|Vqݴd$('s\o$&+qGHw!Ia96K\WQs; 49e͒WR!YLکZ򰎗> Omgμ)O-m%/61YUacR:>FF[q^Lkj16VM\\y«r2cr[)RFYZ;! Ԭ xLO-V7>2]ǧioR Դ2dzMKSf},ڞHQ1k(ڔ?f0:<#\0qSI)}W!5U>a/ +(_8je2UV +IN>a5*Ay*i^O 96+[uV'3T99G?}zU1ajzZPG2~n#QS.j,91*?clnvH>B1MPRj#Rц:Aa9%Z7J]bu"4  3izAԖBKt)Ci^ӴJ"UJ}P齭Fc~֎9,Ijk$[͓)JGX{jNa\_}!G)y{-5m&s"Aq!iR Pħ+M͖ֆТWzņr*`Uٵ,B} TbPwBz̧*lIB'A=Hk0V>[B8R[$6!^9` 6r{_Ѭzҕ%W$l/ io1",70Qҕ(3eJsOkST` i1Csey~?\v`: 83{ULjqz;fxel>N0^Gm  +7H +URS{xӚuFjjM!O|qv#6J>%۟<[Y|(iVP<믪+۸an)HaD*eהɖCͶ8-Kp[ +Qʝ6ZwԆ`f!rྴSoʈ +)\sK.KHlw"踹 +I6-#2Իږ,(fP .,{& ?+9F3;[R Q؍{H>+*HIxvsb,cMǨ 5XDW2<ۨ@] p,H+1 HqnA :ۿ0. w?9nr%o{3d +'#6cg!>|KSZ@W&AJ dZ4X=! ^o NQNald*@T"?cLxQI6PƜoOX\p7RwұQiGq7I>pCܚM11:'/HW<6or{:n}>}92%i6$ǝQ+w#%b9o!|+.9*HgcYisE" @|-:p^!/YC%1?ňN̡֚aNJ*7 ҂HN_Þ|qœ&P'Yq>Wѕ}S.`ZLc@@#:ӷ1a&X|Z|!K MUmEN~K?k(^iGj ͙坆ߩ֕UlTv bU 5?>0a:y;&BBVZ6?SKh\:;?څr>q4ZO&SDq_]JuMUˆMԭnQS1?˷Q?:=g,ㇹ1t*z3!Y@KD6JuRHiuޛTk[+ +a_#r䤶Il)Esb) +Tʥ>iJcJJEv`f8߼\W-+H \sUj-$Wij>nÉG"Qx[A-c)&q;2Ki=Jf?fE!&Īִcl +7eçʑ=Al2kiiYS co<+m_B.W;@J7z?vFi'zaL3+.!rMmX +BKᶢ.Px&[Ҥ "?mE9mʭOcKJʆ򔨏I_vaZM"Uɢ߱c#:1HR@MGѕ?{?VɉNITǎYs~%u*a c]]rV[{ۀ/酚wPb&G֢ ۜ8h&,3Dٶ`A9kؓnvUo'R{+/3oЋcCHcoa[qӑ_M>jn:%U[Ts|Dsa`[T;*gVQ/&pX? yW1t6J(uq(ѱ8 +}tGL "'t T,BcX_Tqo4"E<f$(Z@}xh~$i2]GVeT7[19c{VSR$~FRaӀs?2NNU nb` y^.(sLXD`+d7BmAXb* ߝzUP^T.-E:rQ-O~:zRwC%%)'ˀӸ@!zc{q|?GL?ڵ XGZvǿG +ʽXXD@ԏ4!~S+&˖SmKԠ;  th=s:3K6M \(Ddܕ+@'QJE!n!y\Y k>'i&]N)*P)ʬٕk_rm݊BeR:,ztt*Sq 7.bUe˨Si͙ +R,!V:5HK<̡Og"; `N_ϙVSbm?! +ձN8ix|&FgqIJTRR.N : ^I”[OAuƖilA)RIB;7$ +ՓQf^UN)ɶJCؠH(H8ǙJ^$d(4qxUi^фj5uUjU"ߜh+Yu+94&C\5Ƌ% چ=/kRBZ\:{o̓g(DD?7xM$H跴b@bLsl6IcάΣbݴ9[MMRUhT̺i +𶻧⮥%fݰTKa`NU&jJ归<,1^}%N44B:#DhjU {Pל@]vlޘDպTPzzZ> {3gXKcN]Mh QU肶ͷ.]CFU석oigl6}f\~>R}O)3Ivȷe2ʽ5&Eʘp }?>VٿZ`kUFigI@&=Szmv\kq%0O5;:z&ba_!> U54G{(|x R!bmDR}Pǒ}=[<@cL Пa@tmARlfy ?&Tܬݔ,K3=s ϥ&:0AWMۨ(w.[0:ݤAYjHC co1u9q~IACBsoSRi|wQy[_2x-kqqgjRNk~69qMb. +Sr!#PI[~!h̟lxV[gv~KEq {ﯾ?BD!#BO5iʴyQӈPToh@Ȩ*YbXR)n4Tr""PTN4k;*=% P0tQ\RK.KN'lo1cs + +kqT$aDm7F=#ӱ۰JԤjK-e%\3!D ,Ֆ!=ISiPԗPa9,Ru7+ԙtU74VHqtwʱPs_:iQOW 6mP^Ĵ;mpsT]њRYQ7 {7IH۠763qs:W\]H*$" +JJ&ZQ?ׄ%PIW o L%S+͐mpo9&hcg7ڹ\[\Yăl)=[`,5Q̚*%ENXr;EW@`^&eYv A +ZxkE B|0ڎf )^5Qj} J,joh`kјQ̕W5^FgºV-uz#q/+ٗf㚍êW4\y l%ޑK4ejڑe3˜oQB#kDŽ ! ?#l[`b$:ޥ9T]$(vPUy+7FIK5$)}l%itJ lX'>HPnx‹oH~T3c!z<1lK[fǼ#"eW1nCl/ά?SeZ0#kS&@ٱ0tYMwCp̩V[.iw:ƘZ[*R`]$vҪGE"yKC+<8hG"HZ9eze6^}af))H7r1x -@-xEfnI8ݐPz' ?eS(K^Nj>+3sP +qRP,E|A5PxlNan0c}!d!7b.H;ZXܗYjbvt%VڋlH;~*#$*(M /},j y/\\䛒u;CIz n7"\(^ֶS6śDʡ %LBTh4MRi,lhuĦJ'Ɉ s%;Wr|LNz;2%q-M6R8bpAnǓwLր,{/լ0=,נX"ju?+kSM) SeG[9)]ZQ.)War9.ꈕ:#⛚PI N>v[A_(PcÑ.( *O1#9?1ox}xq.k%O•Emb+J[#,eԩR& cM60TG3 C/$J-ّFnyɆoΩBV`$w}BB} WC/MhY+\*矗wn\ ;!b8=1i?' +NJ&يT4nOp +q8!21w9ZtYM5 7[xIB=˪bJ|~m❝d~r&k#>$ҍ_C߈ $Ư.x7: +N9U4:U(LQo\m";Vxkr:>a\IZK9Bܯ S/V;*s Q3RiRpG$_YUu~uR W"Р}2f&2|:eә AE3[I(^ҤwTIi,xۍUR-_FavOW":]Pv5pq+#: P>}=_DqPcOGM?5;J@]7RownJajirmUamR^Y cBM##t;Jd@fҔRڔrsvD4EBI{/ L/Z/=9NQYiJ EMڂḕ,۱Ǵ54_Jr,Nʴ:P7oOH3$жHJ_ fvq)ZI.=PCIQI6FqnnYB%'A7QcEMCR!+^A պ2ԑb`.rn=bhu+ CZR`l;I[olO8i^wӼU)2ʋJ6ۉU+>-1JeU4P!Zt<\jS̤H"4#ALbh$ҵ;QЧSm7-2J@TT>!ߋ4*.luC^b`>lQN׿ n}$:U+ Q.Pr]N\u%nDd āɿlDϤy<< .:p}ÎBip9jr +q uZ%r_S ۥ]eޢQi.F_]r{!>}337XqKZ!I9!iXd&I 9GR͐`ؒv NA꬏ձ3J[S֞h 7 ^OnH9:K~r/;`^nzXQ+pNpk_rTa3Xuʫ>֗Ibl)-ZJ< "9r[v85S054*%$.$)ib8W` ZK5Jj""-u_m Ho>OR3$DT<~nW9Tw"Vl(:p9uvP51-{ΏMN Vvҭ{=o~TYg1<=(hJ';w<#)H*5fUN'*nQ֑2^ڄjokֺ6 +fο'fb?LTf:ꣷmG5fi=YʋnvQ Ce'.nː)`)A>+=bh#0MdmsKrxZKP.[#D$SMeD.)_$ 60ЖNTem;Y:{w> !ZSh!vmYoYW(өMڂ +\!*/a_$"C6B9C 32dKP>mYzXMJThȣ򑧬la-,:r:l6F,unz,:qOjI.j:5:l).Dth.YB"1 Vh+2BcٗC61:pl/:\i/6 Y9nj D^U;SPIm͖Ӊ+Ix=?Cmb8x_IB8FlMX BҴ+Icm 5?t+Ӷ0I HmTP.|> dMeNe%p|br +ku-3.UuZBh {^^;A,8(oCx +N& VLuZeZBvLͰ|H~ș؛y~b2n,2kw _F.Q/!m:t]N+狍SR.T׻TyFg%^m*{FވG}3XrRTv~,)6 + +@X/Xlw^ED7jsabn .N[iKI%M\A1TGy*:0UT G&1d@r&`HMPiQZPZbB0GhϏ,X{=A.~anQN9J6L*hnjI5\=hxu:.UM|XyڱSגe88wXa'K,&>b3xbPQ.؞q@WO(@#dZuD-}P7&nQX0H Xi}>T#ihu +2MI$&e!5.ZT?E?PZ('[TWggL?=~8jrN9S5+> mW9tq>_MX'8M5M?R B [φQ# +-O'{"4KUMul \'dl{{S EGBC6CQ݆ת'A>uG&jEŹ1q&azT35}-t +`PT)2O)&rs|z*Fo*JO-~b;Nz]DWa#yNʺџX̌N7IS ^ԛ ?.n.Y +UXh:XYp +Fo䚙,a$^ !AJP`4xHl+Д@0~Fab4i7tM5JPYD BGgc#)H*rFE9k<ʀ}j\erվ!`9 v4ԴڥRԼ3\oTu9ny?S|yCi .T%-~A ,M}DuDiDc!E;R$o2SZ0KjAdz .]@ +xfWPW0RΰeTZ-Ց,)eVHI$ݫ5iMAVQ?R0 Տ:І |m:Y\$.~HV%[teR|xj6UM +-]L4%zcJ|~J:*4e6ZY&$й68cG%LMo'.[B,=eU_ќ2Gll?;jc;2ǔy~Ǖ=e49?hք(#3QGjJ]yӶ܋0D'.7ˏ='a2Km[3u},:PZgjU ɒKTs &Z'i9O;Ux(H *&WGa(܅)'Џ3&Z3eVBsAӿ{E8Ԣ;FКk^Vej|Ť65,K`s-Nx/Ԫd&|O,}O'h&',UW2; Jx{ާ~&3s3XI6C-0:!$'1a#G-TVqv(2/bWoQp>T| qY[<{O=< sijpRBY!<3o +/R<6s"[ [2be⣍i7mۜUp8|:kD!(bu:cb`1m '`"]x-;%ZRR"ER38a]Kʩ{ĥ-'q8JQԁm-ʹ0 z(RT9D̮߻N8/21h] +J +ĵ~r£RfO$i͍QxFc9JꑷTP;*7ѶҠF +ӹQ %X{"2htZ$3'*jm6ؤ<{ x#Zpb[ZJ-sRi)ۈMw eٖ?F9K^?W섗)VU0=[YIOiG)IlxM?zm4Re^S*}cVR6j<2yt~8KT L+DVP]eP«iE*)iy_L +He{ꓮ˶}m>5zhIִ䨉$I*} +rE$|Z?U =?|J#dCDeeᘲ Bi5 @6%KvgpEcr _m$CE(Dx)NJ)VыK|K}aN6ǗFU~.r?n3P9ڕUVv1Йg5ֺ"z[p[U|<›Og؁Ė&yIKRHq{ۆB-,7 +&Snቋ|c BѦ#_P]PU*~'\9 +Mj>o>*҉,B`Fb6Mm͉I䘈Y&WtY-XuE +RmI>V7;b*]:Aj]M4#qZodTl$p@ w8~>S&Lp *˜ρ`?<31(JJ>GU:9wIn[|"aTW-0Tޗ -}meBQg ~q6Iq/Du*}1j7 Q_crJ,ū8gn k3kCO#T-D%9n"b4\NRf7 + 6]3<.ujPא?MM!I 8`}"փBSu8ёURd:iGuII |W-LC*%@6 +INM'<51f՛(y9U!ce ~̙@C bEUZe7 MԻ~?VQI΄6[ ǗOȄu>aBB--_L4ԼrNL(Y@$x)QOgtV)TIN\CRTv@RpqRSh@n,ǘ=&O/P癜)CKXCBlnAJ"qg,\) +SO3=Ĵ'n+z@$roa&vMa񝲄VAim%HRt }Q(tU+80/IY`im{]R5IBHQЁ{B/lOVy,Pr*=t\h-iRڊ% %d~к-hm+mutXsS]CD)Dܔ9iԹy@]̩/!I$IIM ƥ*%,hQ-{cC,I,2K<4`T0n "n#*|4ʟah3A"0q\ĭJI 6R8?hy4s^HАZPr36ٵLHR #-Di<: \ iS T d(x飯 X9)Zs.w\kO^Mݹ<6@lfqraȉU[@SBr0O8G1 +]YOpj#R{|"^p>'mr'}-oBJ8Ji hm[~t̘n݆ +T{K/[ßRBJ `58]tm 첛*Jn7mZeVϏ yPN6 &".3 W%7T8<ϫ~I9RS1[ 2Q'p)p cDV"&1rckX_-'DYm}Rno70w&O-l 7O1At$Py|Яд( %Rl{k^߆.,`UN*>a!̱5:AJT +%DXz xLft01'`w(UrFOgZ9BEzl7MJb©AH[!/7)=rleLT1AS|Mq}|U+,m@mp1Dr]5ZdN#p^ڭYZ( XQ[UD\F + ةo,;%L2J5ZJ|BVc;˾gE4ae+BV3 Ԫ{5 VO=6-ҖӗR$#h'6ѳF[&IU){ |.%;nAY,sCyzYNZ<1Tj̲HJMGusZa*ܼV)u!a%p$]y;?9-QKl5uiv[nqAWDE5I\FArmr)-6ѼBm5Q]Omnnu)H8؁"*cG#,AΑRDS+bU1ujO|vgܣ7m#8H>Ge0DZs_Kkps ..Y$s&&̣p@B7sSň~XYdJM./NI[Kz=g}<ķbrK^K?_v$_c>)}S{)_J +PPE;q6@Om$ZٸD-ZY 0N娀7NwC33 +p*Xz%PRcq:cMO:Q|Gz57ݣdeVZ9M#yywaAqu"50%Nb +ܸ)b G`k̍?tT:gTNJ{Dd m=Q'SĘ\ݔ,FT eH,e~ Qa.sr(7 +o@'F.>a]pH8<הOv|`V +YJy3"Ǥ$9XY{EئO@b-YOhq”,b7~b%+ok 9G19,onV tnQȟ'9 eж" GdJB\ 2#ó#Mu{5:tQ&ARR]%e!)g&ċ}lՐ8gV.cź%GVs.ˌ|5p%wQM5n"p?2J.!Y$[halso} ھPri@f%p2a&-y#_GuI'ܿ&U =0?UO+j:;_BԪM_ W39ޥz?#$!)mǍ]ܔ?-)ɻ!WyB/'jS:Q>#^/܇@UoPjTIC{{/e5I7ީ#·grIo2}q4 Y%POqcہH-6,}{ǹfxc0ht#*UisM[Q.8UQa'TjhZ+o)l*K0.ܞ_C[Q9Ul3. Jw/i!IW`eU`,`X৒RH&,78VrS ˙A"׹ nI}4_&[ F-K&*Q;A8Oftj oFF->:@?5yW-H%#HmTSr&.dʥ P@䟍AyR~1!Ru*g(:W7ᮀliןLna550{KJPױQVol**yJ#'WB +^N+ļʬ͸;`C]4FNP]MÔE~hu69b| DrZ&-ZWP)m0 <ؗͤ4k:^BS֜Au p?j~-ʁJs]|1F25zG'wڪ)8ãVM|eGHDJRuU5x=myw^K\ W6Y_Tq~w +̇PTWt) )Gb*)sPBI2ܘ 0(R|}?񢟈G]*6]Hۮ?Qk!ݕs:Ac[_' UOvk_vI˙yk*CJz9Gຒ ߏ֩\cWѲyHnyqǮcZwS_8:K ?rªkV/!ꄤ~sP2OfcǭT%;K_PLL'. ((ٮr3R*$}UǠ5rcR +Ϣ;H4~4i0ӛc]U2R79Vxl-A;^aJZˎ% I;DU!< c{cAڐ{_2q#nZJB^j(Jx^eE]X,^EC ?X70:*[.2eo/<=Y* loolxWTzo +Ͼ*fX[)NV>|)`^VL=4sRǶgY% +*6͌yJ Qf|[hr%Ac䩋Ta鵮%Yk&~ZыWe?qվ)`fln{])wW*ͮ5 +SRjܐu3NpҁqIܴ'2#GTj,YSY@3:D[}*"EL]}2!j3ҩqk~<Em0TʮkuDo?Xi'X9N=jkuFB9daZ]U;jwoPV!y$-i,HťKJ!HOo '0em9&MuUXQQRלXaw톬rOW[ZGx;u'2o,o^ѵV\J]x'pr(g^= +F eàMd +(`/C / TMaItg>:\" o%aC̮ Ls ʡ{"!5[EJfTt(fC[deX5XsFp @K>Gba9IfRf[$l᠅&:u!IG, X )E~l-J7<떚ajkJ|5:^¯Tp+ QJ~oX'쨑:@džKd(\1 dTTl%]}b?%mxo .@,4S9K%CBZe l z:'簟؝md)?1ͽcc:q/2Mf&lKzH 9*mr)/[(?pϚV}n0fpyr>~%s)YY|*J" &y)s(rpr7Gtb/^ATB|wT5$RgO?\4*Q]Ʀpx6*`.vU߱;K5HBidh(_M7O;GtLնLiVSOJ{6Mq\7\6Ў#_cU:Z'dzk5Su /E MolDEKTF.ǚ +E㶐^e]r{(ySq+rTe{b j)Pʡ'dqHp6搑.p~ݕ2(ؤl/ʘ.krKdm-ؔ_;Rn-PF&zvܖ:w;bM\XmEVϩ]ѤocE{>"^KRc\hON&ZVD <=bG %#DM:jh28:'l]Eӯs( 6C+~7Ra7Nt:()3[oܕrJ2(}GQK2knMᩯ)(BxI vMFuŔ^Ӗm'd# $@R->4'Bu6>cΧCCEyhn*s +̩:˨%.!`5I>o>y(?*ȵ:aAu&/kߝV[p3x@Db62qK_gć'&RS+7̴vyvwMDOOITf6I _",/Ifusz7vUYbN`qjr;H=5l6*Т@Zi$^P#*.EsWrfz`P!I +Y (/x|Hbi dmn&F6PvfcuVe#Mb~tE]{j{#"BܻcvOWe=gQTc7]R#,q%-^ChS;yq'*nam!Tшq>)ŝ@RԢ@y{x>-^G7+:Õ2r"òreWM2}Ýo9DW%DJ"A6+a})ʁxmM`q8cJR\<(yt+}eGc6H1Zwey,lJoݯ6/PGlBnH8FS!ЮFFнˁCִ8Z;ܯVԸj+jGďE]N= j󊚙IFkܼLnF_@I ߏ\CXa"6ASU$"!w{FIssfka֛n_zSR۶IҼ6J\܍OU72Uپ \KNCDum)ȒȺI*I!J Z,J0P5I!R=_t)NĤ؝mPs:'#8R\C)Jخ׷c\z4a4ή^{EeA384{"xr+Jg,6T;Q-I :V)<oeb~m6 D]:嫚}d%/6k=6vR.&Xs>q e?@Ys êtnP-ZУFve/uJr,kD bZ& K8& l܍<}bY5HPX} <+iBqOz]oW6+;jt>0|JXYp xEz=)JT\i(y 8R^.pqD-jI&D} 0 `UǢR4`@B)?4'7-*!)hNP6ط6(]q vft>=4YuW)Vd~tvX\+&X =w;!nQ@$<\WK7I 5)LFժ^hgӇ33&PeRbA$n_VKgT Kە߄,K@RnRMq6q}ZFiD4[Rz7`:)ԝbS׽{EtZ-O5fnf%AT7ą) +Xl;TM#)ԧFJa ;a+uRFmMVUMVD $Ij 97$I{֦JQ2J.Hl%{%)Eh"}d:B#ԛvCQ 8J}8yΥV*PHmW!*2 $X؋,e\5iVHKem-7X@ EҠFlٷ6ǫs7Z#uȴ  7ZG +W5W))ZY G@G!08U2"A6i L(V|fr-r'KGY0G+J~ѹ - -*ٿxl)=mIacR 0PBWq䫿* :B||nQE6*v4ʫ(ymRb8ob>c{GS!\Aʂ/eo`ܔФX ,Kݑ`<)s|?HqIYW +ctyBlwVBkPQ=yI +O8s)LfKu27gK))JlYd6w2}$zy}QiḣTCe$[Imح s|501l*y?qtfEZ(i* +Jj˘+UȼH鲏 +CigXy7K~A?^C lv}D+GfKuPc*z[*&$rڬ[V-@wrTznPrhUo)Ҵže~\zN*LRF%PTN :hs~VuGېhͫ=GasB-QYVQ %;qyq='F(IwϞ Fp.L(yi;mkuF\PciGϰ6,is*GKR)d\m<]ڙʋU((s^lw0>lئp}Sd{ڑ!?SjMNr|5XL"Lg^U&6\CP̦,F i;Akb3RVD7 !Qu\ZQ*$$Ǖg dv<$r#8oNiL0BUT.=GXӼB6Cy%E7`ӧt!u.xbfGYu~uhJ6ĭLyGCq8ty'7" SJ֡k%ehN/fJKMԢN㉎>z~}_s>jIQ~i %CaL/3EB0e uaU)iQU),K}f5;)qg/Go,ѐ +s(\_gNU/U"z8ICsS9Emwƞ0޺iTn o/I$bDSZlNL> p'wh/xʓ)TPVBxN9zÜ @[To%qA 7* \aQ٘"ƘT~S2ۭ8l=V,aJBI$n":NqԅF9e[jCB\$) +)UIQpmEg1e +چ[0,qI/ TI܁) +]Eɹ6lS+O-ǻI_݇\?L=!Tր' `SQC$A6M*6_ww7ZXEm¹_h)?o# btd:Qyżh}{u1_Ny!YSV.rRsOP ׹iXë4Rz179sUҶ6eot\_rڙÒuUiA|<8U.768() ͅ-,K!N 8/[)'^sr$']KIJzL*@ ]AKZPޢ-3MFMKI2gTyI$iV>oel"PH'xlRⸯ,#H h٦$KCZ3Z7NYKT}3)̘:d, +Bc0d5z)3m>3#-_R :Ozj?i? UDyb<'qk^tKZS[*B7ad=J*_t£h&>bxۜ xΒw%IEr<[STlM~p+Á'Y +@p1ke'ۼs. x (xt,T^.MJ NWp>XxXIBx:DyDxZ)/?{%-}fyI-Bd1֓QbzŻ?3̣'D?bYc0<6p~4oܨ}ɋvW2z$pf焿MVA"I]02L;>g~AzM $Pi[qԔPH&#+\ZLu}'$rn_)6׽Pgt+Ex o*fR NoR?Lf')|JCk$"?\CJrYPY^D#r{"b?'ǿ_B?"5ƿ51Qʲi[ZN?r&tz(:̯CR#g+XPprѸvq;s?G<՛|WxK20nʭ3P0Cܡ ORE* jFQt 32>,źJQ4T*[@G;;[p8hBdMБɕpm iIviU(y(YjE\״bYfF_?uJh kROݒ@Ëka:ZxwJQlY>o2bu?Uɯ_2dz-$zgcZ)>"|^jB>$}.6ҥ@|G_tzHct~?Oix)p@=f:E)Y1@FݩZxN,/M͏L4;ƕPk"E"3~=x|hIsގ-jqi8鮤'ި_XGtg!s*ZϠ%3x8%i'(nƜc[@"?C+Ëh=vceZwXoM 殣Њu|:4%()^v^Xrs>r㺄;̟Lx9>0yUOo{0udznQ<Er?sXKLO9jVgI6HaeOƝ)rhaQE{@ǁu6?9/̭H&b1*r&|[hWQ @& Au9=>aY~t| sT#ajɢ%ؐRH@)8e*gd 5&R5N\UW+-6w 25ԣHbzqrCBw0T"r3)iD8 i("3% +6 L7g*OŲ.IxwŧR (nYR7B|igy&= 53B_%I+X$gJ4e@JsZĞ[CW,O2a"BAJnI" $zwhTc`ίĺo͐$#NEnT^[ۼ*4eis!;\?PARyfM>>N>#yS!5)+C?E1%MRSt(!aߘ zSB 6NB k1츭*SpA qr݀JN(\IiXͥC* $hG#:99{4s*k6۩(x: p -(T:`snOx@i)bH24Q|m ӦO!RK-CAUwl^5 iP#).h @܋^Ꜭ5KGZʀ@BXSʲu0+\f+ZZNQtDKN[hMZSPSpao+6YFck&: -mU QHI5]KHieJĐ/ AjF pGď3*S  {bA"()?'McK_g ybcbCP-/wro1 &w&fa)Pp(!]wxƝ2TGS-dQexsDc- pa6 J*H. w(k|֭uiQ&\RMb0^A9o1u~SɣBM)d;ېJNJHN4t'0eZxm=_Cj)JTlm, ]vf^}J'ѨYkR9^2rGFP9!%ƞDWr8yw*'+sAO|rԺ9egud{ | +Jkx Ҝ^SeG?6G%L+I-5"=AJ*i.qR,P}rvΥsN56K^32V<)`eE?01&Q0ܦ)RQi)$\(;Z;(!SLԲ'4un~]*ҕ UbOYTm=ԖKG;Ϙ#:w '3g|̾i_QαIt{4VWqP@wRN9a ᪃Ck+'j''c_Ւyո<}RonpJ)JYG2tEJ5hC3pM(؎@UNh暗 bY!VR@kzL1r.Wͮ{naf뎮nAOWc3[ +5[Ccޟ8\<#{-P)n`]OJ$Y.[U-\J8xL"[qLȤ.lT&_5BЫh7Ân]3I߁cY%Hs8JӺT5I4ƳMHM:OILb+nK.\&D} H<.*zfS5(S rSȎce N'y#0e,::)>'$f u34AK=Aeի~LR Ibztd.N=Σ8)Җ瀦̟8+@>;1iL[v- +AR :,H7ǼDu5*䢶"ĝp|[;8ٲu\k{SƝJeM^Ldp7?ksD$cc،q/Eru$(t.R\;NdbkrէJ1$!]( $jgYWn7P%L~zZĕIqi_䴶JPPRG#"zԯ`9hi)p%m d˞XTkX"i@dRЀO'Dz衽HqpBKjJHW>F88Sp]~T0zPnAQxmݽPoGdVV_-6KUBs)݉kR@baniآiyӰہ}5FrKU$ۘ;R'i5T pܩ .x^1G 4Pv[q-8c]; rjQ+ 0>:4V\֥r$h% + +NUnRuT@=J=Qdz)oAq{6AGFd7%YTIR2|i ff*KjA#\yUBIP!BKuٰ,Km$_}1BL4 +)ae\_nDǐJRB3tVZk1rVzР)e7s䀜AM=21R J\҇ +[cqC6 +TqIamVOMŇBMJuj&t¬K2`x&:gz=%W4 +H%$l+aWUisR916oP6<XJVhI"㠄,yܩ*$r3B8yd99 1 0$C'x5Ci HG2m#aݮ^M}J -5Xda- R{>qҋ߄(Mp8ďvK$ ~##37WrTWIW?.8ذ 30ԫS{Z=ܭaxu zRv'M!m^k'~V)N\5cB@/sϧ+Ûecnjp$i i40mJAN=]e썸>I=׼-Ք+%ULLE69ŐuYpȳI#wGy[#׹ +4SHI)eq`.13+)#aAU}|m)`*R%EG~-@MG.^a>1_!1%H+rw&tԮ3l&U<֭6Y5!CnȖtr/4,G.Է4H(Q>EhS$gh~.DmxP;C[qBZֹԋnnDZ;u"wSi%L!>"nqMpU./&*J'.lNZX},]iHdkd%߷}Ȥ5T";;M,[W@8fcdQ$(UNOARy8^im>"'#-6uoo+S=l Cl<(%< Hs|Zt +Ac (|Ԗ撮!*uU')}[Zi[X'pq@#[d p*Bj[ ;@Ar~~^#;eE"N(޷P Q;O*}(|\:54T\m&NۍcU m +U?\%yH=ĽeBi- s`<21 S'OͰoTz!LH,6\ynWQQQ6Q&Ѵʎ{R2$E\ +47zh樷 ~R/JiiQ#0nE#5i<. +Xc +EGy9DL<<vP-豇sIg.Q@qp,Ub +!!(d#Mqk'|uTԈP'(A'5յ$Jm/T爊ۛq@tt<{)JS=d*&03Pu@؛?z="[M {=&e +2-QSJyTl pSb 8GjqJ˩3dB;_8rs71(:_jKFYj5iT=ZGbiteZvoM-C"k\k,`)04nj^,G==;@\)a juCۓܥ| 9xqCLsb򀽒d8JIME!Ƶ::4dkNZk>|y1c!'cf9 \nDGm(bb9wLHmS%Ԕ\_"^b|xf%e\ȷ2RZ,RIՏ?u&ƔD*k:Q+Dd| Oxk po=AjQ$ ;GJk]RyR`J#PV$ok0Skrk4uAN(.)nH?c<󳚸{볆 ĪW$ʳ̡) +񎜪 d]i_O5Xp ^$-7Gry.e.k}$QS}IZ1LXw$g4ߪ`UγHcCc(ic+UԇCv+>z׸w{[TVv_ #9\<@̓Vd̒).&]R0T=mr~CG5:aֺ'²[ .a?>yDŠٖPi[' !&1^J}k.lBG3x%7f{J幆Ԗ &)8ijClaPc*bj`R{q⅄MJP +DkAjWyD<35l?+NK4 BXhu6AIbbz.OfXn(6MT{ŹT̵mkD=qԥrܣTvCڒ:%4"1ޣ\8bVU #tgbl.K{9~QB}"t_dp̋b] $CWTI$2:ILTɮ=pFA[c 20At2,@#ڢr>&z9fYO&I  +Ym U\ a,eDC Й>n%Ԃ6q&e犳*[*6ɶ6ÈlXk,n5w=YKO1v rV +*$ q5Nra!pH 7? +!ʄFPB)mG`/&GXBr 'X'0?2˪Zi/G7#q>ZsU| ʯGTݖ Ge:B-\w"Ů*):-!U@qf,nVT`_k)[bfȺ=$$G=I\Y5~-=NfG f @gH9&HA QPm`ɴYTvu$r'",<|ہLpĉZ։'d~LNJ6iC57A.Rq6;c{g]"(ZmD!ȓT,v6p_\SUdHQ85V'ڱHϣ!>*=Yg'hk.GI=8[ho@J6mI_U D҄́n=@\P$|rJXAWrrG NrelC}-g3jD4!5%"qOlG}_DդqJ+S?Q3=)WxMXƐfL\v(]'ܠ<_@ WW CG'UU(` ]_pd#D̼otzub&nT)U9X;ko͇vTbҟXJ@G9G|I&_t˴KmV %#CmTN"7i2˱c3Y-%" ǹo,-[U]+C})g&;kaڵ[C\+r +5CI.AfODe Y z8z}s.-n(cYB+&f]Yqҥ(L~P9IXp *q< +"iu?SH+<Ka eH3Cd!%*.U).8Puk̅+:H,),$(͚$jݬ[Kj~? ~B㺀O3B\*RnGhocn0N.Ohë'qm[b[uJr#JI\~8ut欟EilΦ5׏cg= ˰׎i;gm|~>0Ԡ/jdq~@xmx\Kl1BI=勉=ʏj*O|ԧ1@p0x;D`tz:W51{,UT'Ťũ!&?gҕtƙ~PmexJ'1(2uN!7i~ +'8nO{aQջ$KYp)rRJԐBBlJմH#k1 Iw1,wmG~qG|!l`F YIVsV揖{]64HǴhݧ!VXqxW,(y]Ne]'$,a<E-xf?&]}.U'()Z]BҵJ& M"#VڛTFIqk +!<8GcuuA<-I PP: +Mв5tn䬽G˵WR*@TY*DY)HX^S/͡-hn@/8$ AQ <{ L%` 7X +r&d#?B';U:I[nK@iY #tU} RQ 2bO2é#̧u 5))'IAP>l4Ox,ylF?8j[aA6Kp"ٛ6C(J](_[bI*s'5:<󊩌iԦ\B02fh!4 R}cAemBTvة7o57~H1%>*%]@;=cI,kC8֐J[bl +âZ:d $: +U’RyquvIJ?N4%[6#b6<B@uLQ()kXnr;=AGǝj*/7U8[q}q̚+T.ktS]iu)dNi,H ¤i}H9$Z,UjЖx|Hz،FڈRxfm`Co +ou̟8l~nj%7uJLY/R?,J4Joh nipOg6kL2᱘i%r6 +J#`g-&Cn6v)Jp_ˑ!1vVR;"qCg%,חR&4 +eAbYJ|սw(Ԡ j63h! ?pH` +}m6 +T66"Ǘ쎩 +-@I#S3ˣTT%$Txn-&<8LδTXUQsعIȠNS9%eV6Kؽ-6E.}ITUKNIc[eD%YEJvF̔(F,8 IA8M[ v-/ƙ zn_TDXwŘ)eU-SZ +z.mq9qGVq^VK2v%KѼVCecp#m7F$<;=]$6l7اvmmHZ +T@C1 C3dӴ&SL3^ +(WhmArZ7:D#+S-%8TG/(.H-'cg7.p-Hƴ'擔V;MwQ; /yRx^,=\MMyjOOT +H,p~{bqG?<@$ē#(Jo;R:zԲJ R Xq0uCEE<9R|[gSm)}0)jl쁩6Lt*X:݁#sXdWh4<A%b;cIYS~cMǤæJ("JaJ*HQ-*Hॎp% Rtd} m@nÒxG׿KNVՑ7JIV/%#+LD-.TJ:ݢ~j]zn?6E*>e.(_wga]X序xTkav;^!tc=[[k8drfQu*&7Պt*cB_CC8-#z7pZfE-)e3uRۺ$zuQ7ƓKS*JU6|p+2+M*=VЕ8 |FSy$}"fܞs'@7KAjaڳـQ B/aR9haιjE*VҸpzC2PQupI9{2*T[Xԧ,8uN.ǃ)\DҠm?mOJA +Iq{hnK72̒Zc~|֑]DmuƤGnK P**}r-_2~8 D3Yq8 2*nT]/d, 'SrI GPu[e~+}}1KhIU +9ǔbde7t,PqOb qEwBu*﭅&mLLJvVrwPW֔L(t RʒP)! oĀC):#R(_8BB1̱=4nZ+̭G9s៊( ^~jHu!ʭ턌YEA4O?Sn˪2( R)cWvR2rKMƣ*+)].@n,nJIGFiR(YiB%&9?iZIe2>m~']IUP6!C"+٨JK>T}Dh|",fuLi}>ֺGH +_$ 7?PKa%xxTϵ E!L,sV$Lrs\ t! 0)p'P +`WKfq%Ն6d(x+tG 9R 10tw%HS\a[3U~%> e=?u +s*#o}D[POa|)('HJgڰ!ݻMѹ5(Ww AHA)~k s2?M>z1eZi^|7;/.\ϐX4iG6WYy^or#<89}"\>{i؟ŜZEjwJ޾ Bq$|~~Tز[ 0\s6p웄8#KV|hEhykamLt-E\Zz[Mj:ToG[g3d6,]:)$mObio2 3.j7QaϽ_I"2C7RW M,~=m+7 J!GpR\)`iY'= 4&+9)l c |jS:d.KܣbXEmRca !dhU*>OU-+7ZOsU&RJR[ lW$'xquJÕQI+t8S}1]ua mZ=U2ծT-+mV0b]tOVi`;ɴGjmYQrz GrZvn˨D)jڂmx94d jcdw\7 u#pmo?Q@ÏPPJ&fڂ%fhp"! +[rxClEJJv8\@EJB({pR+2^B 'IHRII>XlUM̻s#ӡFݧH=p o EӇ=򽔓 69A$>kP՚}Z)an9 +{ [x}L<߬1틩T-ѓl/6Ga +U~CyƠ_[DXW,¼Z#qgq2R?Cf\s~1$e@TYxFq̨Z<4^ +@8߄c_9/1,uW0ǩ?͕fnG"ǞlyĿYEs K%Ő 4TO'd*o,B&٢(hPA+5Lc 0! >qca}EtF+3iA)Q>%&9͂BILT$zEB)y/.ĽfOGUo=Dѐ*r(!cݛ O Jd(?Tj 򤌴%cRk NR!TI6I?,va)%m(oX}9j"篓H}Wr30Z%5'Q\ʵ!=Ujvπo+݇ϟ,:N]0-jxs\#^}`.~xZRZ_-w]qk!edՙ+ƕ$\[K$|剪;GJEm)Q*nxf$LKW8Llo)$ X$qdD)0a%$Z.wT9RYWHT6jEAʶK/qifڜ(K+@*] n5Qbh OCiJ>' ?$Z$#Q v<=%*H>na:ԵY9RuQ̭}Op1j!5 +)Jordih0(u+JM'14fSfnv +t'-(6B*tDFZ3_q^ I/)q*CR|$@&Ʌ%fFPZo:4|IMumąFg @*Ii:ZT`rFfCeNKjy$p6Eۜ?_jjq QI=/'b)ya) +RMԌWBӔ-sm2m6v狕$}`cF̃HcGD 8pպLv+*KOXvJidɕÍ&EJ~FHzuUl~SbH'mVYb根"&IS+#IϠr0bpHIVHHXk,U^R˲~1\E#dJ)hᑙsdT;ߔCd*ݚ;@RN"9;_W &ޓBVԧmVOOIJW3jY y>-m˭]23k3uz Y-[Xq9_N6e}YWk7Ӕ2O +|)+Lf?+z:9)KlDaTN75.vfQ*Ub7KDz<faT͛cj(@mm_5V}%Rjieݗ522ggF}xPeaVwO1NH?MY!HP-`]H:YiƖ IIӈ"WUd +.Q$֭PQI?dp=>GJ|(hy7ՅY]x8؂D?'jTgh:Qd;W +,Gb(՗8%6KR3 fn/Ǧ)n$b>9V>R~ `:*6Wc:1yvA+~\u-dsɢ8v OV= *DzKH5VpmeɹC&IԔA[9D!ay<6\jRjz# :Q:Gbe]уu8JcMI P%K|]Cf(5O=9qKX1ULRJg7`u4{9L:GӞ)H-,6f $SxZv5L,3Qjhep[} +HHbnfan㝂s[eCuhq"FXqm%wJV{'I)cH2ޝŜyޣɠa)lr2(|Ȳ)]mXD.x0Ҧ8n +>:mSiMK){h*w5j :ΧӔ}p$oI*鸴4Z0"ll!T/]4HKDGÏM.-BTO)"Bǐ@1YqAr'9I'm{zCW/+#uK\lYXvJaJYqs!Fwv{ +"~ڜ߄e4򅟉v~Ew +qTz&f29W\K!9n9O"#Cz eiywXjDL3iV~%DJ^bJ7>W z3g˨ߔhttVzEEOE]L,2MRe@&:闩Dbuͪz1un*؜(9OP%r[cN2s)6iJMϜX>)('p+OHzaH6MB !a([FPt3Aq~Wӈu#ėm 'w7p$zuvFBtBa9g"#L2唕(RB®m:knFّdƊyv,_wRoa{DbR2mJ@RΒH?B1ོ-5w/:N׸ַBOͪU/b98RrЯ0c^b%A:$+ISmo %K֥v+J 1洟lsIUa/escnY?N\qːhqE|;@dzc.[+xM)͔'oxf\e}bJ"7*, UmAk'[8ɷ *[-t+󅶑͹~w0MFw# @U,-Y,d1іLt)ʠldfD[OAҌ֫ +er+{:E,.-#ͻ[Õ (x%Z!쯭^Z}:swOLW&04ڃҫ6C*өBL?ٳ;4ΕQק +?.Lm76P{HHIZBPܩJ;XG]F"9zXI[9RƤHhTm^{T=iPjͯT\YqlqO4 \1VɨQF7 7pD[e]XDA)'3XwwŁ.y +Q4j8Y#Lf'"=7N3}"\@Cd1PfZOtwUL9PenM0]īW7DJδ 4zVo$d9.pX\(Ohp?*wj)qĨ‡8ܘK,yBE%YNZ ')Pe9PY%MrcҮHHZT9nò|ĩœplɤRJT٢@-MOy+.j)-Bᘑb_ bQ2ssOWIۏKcEpk(b\7S 3J*6ZڕRDeˌ8凡Ypey# E)aCQ5GV"uvN,BX)ͥS+*@SQ$y'm I0+PU긄Ia1hqUTR+mhƎH)Dy㝖@Q'XQ$Dq;TҋZy@%!IK|_‚/936ԢAkC:hejwB +j!FǁĨ ޢ\*=鏸_i +b1tLy|Ϊۨui!j_ Ϋ*H bb)iխv{kV/d+*t_JnNfMU&L";/e%DVy> +uH@Vῲ1TFW,_!ӷK?s9wD&J)ѐ셶Y?2q^f@0R +Rɹ}4QJ^Kץ>ӋJ:.R)( $s2}@{lF[/:'Զ|no5L+zi_4I;Dm`,=Z|$uPIMnme 'sR=a7O{82nV**mq{sE(XbrЙ1\vPwыy&;GWZiͬ κ%comNE{~BT[._ėPqRT6oN- 씀=CUg Q7[#Ky7L9%:j Juwb8LVc Ւat|z9kPH^Us&‹MPbLh&0e&yEj 'K=bp@oh_՜yC|(?,Cn[@(3j8úNTn"fѨ,֌㺎I@w;wFӝ-Dx\5H )GAp ȏB@ʈ +^vdԖefzGSjPA)r*2 Չcy`A҆83f[W"l_e)e͎}olL8#;-%[PgXhNYlR+섛4ԃ ɡ N|`H>rW zQz:[~*"lZ <P