+ + Coding Period Week 13: Aug 21 ~ Aug 26 + + +
+ + + + + +This is the final evaluation week, where ongoing and new errors were resolved, a demo video was created, and the summary report for the final evaluation of G...
+From 912d2137cee070ca423b173d670b0d84d69b2a9f Mon Sep 17 00:00:00 2001
From: BkPankaj
+**Project Summary:** [Explore Summary](https://theroboticsclub.github.io/gsoc2024-Pankaj_Borade/summary/)
+**About:** [Explore About](https://theroboticsclub.github.io/gsoc2024-Pankaj_Borade/About/)
+**Github Issues**: [View Issues](https://github.com/JdeRobot/VisualCircuit/issues?q=author%3ABkPankaj+)
+**Pull Requests:** [See Pull Requests](https://github.com/JdeRobot/VisualCircuit/pulls?q=author%3ABkPankaj+)
Thank you for your interest, and feel free to reach out via email if you have any questions, comments, or suggestions. I hope you find my work engaging!
diff --git a/docs/_config.yml b/docs/_config.yml
index 2cecb78..964a0ea 100644
--- a/docs/_config.yml
+++ b/docs/_config.yml
@@ -99,7 +99,6 @@ defaults:
author_profile: true
read_time: true
comments: true
- share: true
related: true
# _pages
- scope:
diff --git a/docs/_data/navigation.yml b/docs/_data/navigation.yml
index 9dc4fd3..a6a04b9 100644
--- a/docs/_data/navigation.yml
+++ b/docs/_data/navigation.yml
@@ -39,6 +39,8 @@ docs:
url: /coding-week10/
- title: "Coding Period - Week 11 & 12"
url: /coding-week11-12/
+ - title: "Coding Period - Week 13"
+ url: /coding-week13/
- title: "Project Summary"
url: /summary/
\ No newline at end of file
diff --git a/docs/_posts/2024-06-03-code-w1.md b/docs/_posts/2024-06-03-code-w1.md
index 11ba717..11781f4 100644
--- a/docs/_posts/2024-06-03-code-w1.md
+++ b/docs/_posts/2024-06-03-code-w1.md
@@ -17,14 +17,14 @@ From here onwards Coding period begins, During the Monday meeting, mentors discu
## Accomplishment and Challenges
-* #### First yaml file for Github Actions
+* ### First yaml file for Github Actions
First of all, it was my first time writing a YAML file for GitHub Actions. I used resources such as YouTube videos [1] and GitHub Actions documentation [2] to help me write the initial script. From the discussions, it was clear that testing should trigger when there is a pull request to the master branch, so I started with that and followed the VisualCircuit documentation for the frontend installation.
First failure of coding period:
![one](../assets/images/one.png)
-* #### Creating workflow for installation process
+* ### Creating workflow for installation process
The initial idea was to create a separate workflow for the installation process. This installation workflow would be reused for every test and other workflows. I worked on this and resolved the above issue by including '--legacy-peer-deps' at the end of the 'npm install' command.
```shell
@@ -73,12 +73,12 @@ jobs:
- name: Generate static files
run: python backend/manage.py collectstatic
```
-* #### Research and modifying the workflow
+* ### Research and modifying the workflow
I reviewed some open source projects such as RocketChat and Volto by the Plone Foundation to understand the CI pipeline workflow. I realized that creating a separate workflow for installation is uncommon and not a best practice. Instead, I created a setup job and stored the results in artifacts for use in different tests (jobs).
Initially, I encountered a "MODULE NOT FOUND" frontend error because I stored node modules in artifacts. Storing node modules in artifacts is not ideal since artifacts are typically used for build files. Stack Overflow and GitHub Actions documentation [3] suggested using Action Cache instead. After switching to Action Cache, the issue was resolved, and I proceeded to the next step of basic frontend testing.
-* #### CI Workflow with basic frontend test
+* ### CI Workflow with basic frontend test
For basic frontend testing, I researched Jest and React testing frameworks commonly used for unit tests on the React side. I used prebuilt React tests and initially printed the rendered HTML in the terminal. Based on this, I identified the menubar elements and added a basic test to find and verify that the "File" text is present in the rendered App.
CI Workflow tested in forked repo:
diff --git a/docs/_posts/2024-06-10-code-w2.md b/docs/_posts/2024-06-10-code-w2.md
index 75378a7..997529e 100644
--- a/docs/_posts/2024-06-10-code-w2.md
+++ b/docs/_posts/2024-06-10-code-w2.md
@@ -17,23 +17,23 @@ Welcome to the second week of Coding Week progress. In the Monday meeting, we di
## Accomplishment and Challenges
-* #### Learning tools for Automation - Selenium
+* ### Learning tools for Automation - Selenium
To create a global test, I needed a tool that could automatically click respective options in the VisualCircuit application. I explored several technologies such as Puppeteer, Playwright, and Selenium. I chose Selenium as it is widely used for automation. I learned how Selenium works and how to use it.
-* #### Integreation of Selenium with Github Action
+* ### Integreation of Selenium with Github Action
From my research, I observed that there are two ways to use Selenium with GitHub Actions: one involves the standard installation of Chrome and ChromeDriver, and the other uses the selenium/standalone-chrome Docker image. I chose the second method as it includes the latest Chrome and ChromeDriver, eliminating the need for a separate ChromeDriver. Additionally, it contains all the functionalities of the Chrome browser. Initially, the browser was not displaying correctly on the Selenium Grid, only showing the logo. To view the live action of the process, I opted for noVNC.
-* #### Automating clicking File and Open buttons in the Menubar
+* ### Automating clicking File and Open buttons in the Menubar
After successfully running selenium/standalone-chrome on my local machine, I automated the process of clicking the menubar buttons. I needed the XPATH to locate and perform the respective actions. I found the XPATH for the File and Open buttons from the Developer Console. Below is a GIF showing the automation process of opening the browser, launching VC, and clicking the respective buttons.
Automating clicking File and Open buttons in the Menubar:
![](../assets/images/five.gif)
-* #### Research about Block Composition
+* ### Research about Block Composition
The first step was to understand the issue created by David Tapiador. I researched the data flow of opening prebuilt VC projects, adding as a block, and the build options. When the project is built, the dependency section includes package and design key-value pairs. The dependencies were not included, which may be the reason for this nested issue.
-* #### Adding interdependencies
+* ### Adding interdependencies
For nested blocks, I modified the Dependency interface to include the interdependencies element. I also modified the package-model and converter for dependencies. Successfully, interdependencies appeared inside dependencies, but they were blank. This blank state is a great checkpoint as modifying internal structures introduced many errors. I am happy with the progress of this blank interdependencies issue.
diff --git a/docs/_posts/2024-06-10-code-w3.md b/docs/_posts/2024-06-17-code-w3.md
similarity index 93%
rename from docs/_posts/2024-06-10-code-w3.md
rename to docs/_posts/2024-06-17-code-w3.md
index 111ebee..e8b4fe7 100644
--- a/docs/_posts/2024-06-10-code-w3.md
+++ b/docs/_posts/2024-06-17-code-w3.md
@@ -17,20 +17,20 @@ On the 10th of June, during Monday's meeting, Dr. JoseMaria explained the Global
## Accomplishment and Challenges
-* #### Understanding the VC Block Composition
+* ### Understanding the VC Block Composition
I went through some frontend files such as `menu/index.tsx`, `project-info-dialog.tsx`, and `editor.ts`. These files are responsible for editing the project information on the frontend side. Initially, I thought of adding Global Input Output functionality within the existing project editing interface. However, as I began implementing it, I realized that it was more difficult than anticipated since it required changing the Project Info interface in every file. Therefore, I decided to build a new dialog box that can be opened from the "Save Block" option in the menu bar.
-* #### Implementation of Global Input Output on frontend
+* ### Implementation of Global Input Output on frontend
For choosing the Global Input Output, all inputs and outputs can be shown, and from there, the Global Input Output can be assigned. I created a new script for the dialog box and modified `editor.ts` and `menu/index.tsx`. Currently, all inputs and outputs are displayed. Next week, I will work on assigning the inputs and outputs as Global for the block.
Checkbox for global input output - dialog box:
![](../assets/images/five.png)
-* #### Solving the nested block with different approach
+* ### Solving the nested block with different approach
In this approach, I didn't use `node.dependencies` but instead created blocks and wires for internal dependencies. This solution was suggested by ChatGPT, so I tried it. It involved creating internal wires for dependencies and making the linkages. I spent around two days on this, but it didn't yield the desired results. Additionally, it was suggesting editing many internal components, so I dropped this idea and returned to my nested block solution.
-* #### Solving the nested block with last week approach
+* ### Solving the nested block with last week approach
In the previous week, I encountered blank dependencies. I noticed that the interface dependencies contained a single dependency, so I modified it to include an array and used recursive calls to add internal dependencies. Additionally, `factory.tsx` had not been changed, so I modified that as well. However, the issue of blank dependencies still persists. I need to consult the mentors regarding this issue, as I feel it can be resolved with some more effort.
## Previous PR Updates
diff --git a/docs/_posts/2024-06-10-code-w4.md b/docs/_posts/2024-06-24-code-w4.md
similarity index 92%
rename from docs/_posts/2024-06-10-code-w4.md
rename to docs/_posts/2024-06-24-code-w4.md
index bb5be3d..0fe3628 100644
--- a/docs/_posts/2024-06-10-code-w4.md
+++ b/docs/_posts/2024-06-24-code-w4.md
@@ -16,26 +16,26 @@ In the fourth week's Monday meeting, I showed a working demo and discussed the p
## Accomplishment and Challenges
-* #### Pasting .vc3 file and opening the file in VC
+* ### Pasting .vc3 file and opening the file in VC
I first tried putting the circuit file in the Selenium Docker container through a Python script, but it wasn't a great solution, so I decided to put the circuit file through YAML using Docker commands. After solving this, I needed to open the file from a particular directory in the file manager dialog box. For this, OS-level control was needed, so I used the pyautogui library for opening the file in Visual Circuit.
-* #### Building and solving inseure download issue
+* ### Building and solving inseure download issue
There were many errors when building the project as the backend was running on localhost on the local machine and had to be accessed from the Docker container, resulting in fetch errors. These were resolved after modifying setting.py and .env. After that, the browser wasn't allowing downloads as Chrome considered the HTTP frontend insecure. After some Googling and searching on StackOverflow, I found a solution. Finally, the whole process was completed automatically by Selenium. The complete process is shown in the GIF below.
Selenium based first automated global test:
![](../assets/images/six.gif)
-* #### Improving fetch Global Input and Output function
+* ### Improving fetch Global Input and Output function
In the previous week, I was able to fetch the port data from all blocks, but it was using more iterations and not proper internal functions for fetching the data. So I improved the global input/output function and also added the submit and checklist handlers to pass data to other scripts.
-* #### Creating input output blocks automatically from checkbox data
+* ### Creating input output blocks automatically from checkbox data
Depending on the port chosen by the user, the particular global input/output block is generated automatically. It checks the port type, and according to that, the input or output block is generated with the same name. Initially, the global input/output block position is the same as the initial position, and the links are null.
-* #### Modification of Links and creating respective input output block
+* ### Modification of Links and creating respective input output block
I researched the internal structure of the model and tried to access the links and respective link IDs of each block. After this, I wrote down all possible cases for creating a circuit by the user. One case is where the global input/output has zero links, so one link has to be created, and the source and target assigned. Another case is that there is already a link connected with the block, so according to the port type, the particular source or target has to be removed and a new one assigned. Apart from that, there are other cases that need to be tested in the future, such as if there are two links at the same port, which one to choose. I want to ask the mentors about these cases.
-* #### Saving and retriving old blocks function
+* ### Saving and retriving old blocks function
Before generating the .vc3 composed block file, the old model has to be saved so the user can continue working on the circuit without worrying about the blocks global input/output. The model and project info are saved in the stack, and whenever the build is completed, the old model is loaded. There were constant errors, such as storing the data in the stack but it was changing with changes, as I was storing this.activModel directly in the stack, causing changes in the stack. For that, I tried several methods using deepCopy, custom functions, and cloneDeep. Both deepCopy and custom functions didn't work, so I used the cloneDeep library, which worked without any errors. Similar to the "Save as" functionality, I used that part of the code for generating .vc3 file.
diff --git a/docs/_posts/2024-06-10-code-w5.md b/docs/_posts/2024-07-01-code-w5.md
similarity index 93%
rename from docs/_posts/2024-06-10-code-w5.md
rename to docs/_posts/2024-07-01-code-w5.md
index 9849aa1..bf37bdf 100644
--- a/docs/_posts/2024-06-10-code-w5.md
+++ b/docs/_posts/2024-07-01-code-w5.md
@@ -17,10 +17,10 @@ On Monday's meeting, we discussed possible cases for a composed block. Last week
## Accomplishment and Challenges
-* #### Solving the global block input links issue and extending block composition for every block
+* ### Solving the global block input links issue and extending block composition for every block
As discussed above, we should not have more than one link at the input port, and we need to hide input ports with internal wiring from the block composition dialog box. I modified the globalInputOutput function to segregate ports based on links and port types. In last week's code, only code blocks were supported, so I made changes to support every block. I also observed an issue with the text being fetched from the package, which was taking a 40-character name. I modified it to take the name port from the labels of the blocks.
-* #### Solving the global block output links issue and refining existing code
+* ### Solving the global block output links issue and refining existing code
For blocks with multiple wiring at the output side, a new link needs to be added with the respective global input/output attached. Unlike the global input block issue, this requires the parent global output block ID and the respective link ID so that the existing link is not modified. These changes were extensive and altered last week's code, so I refined the overall code. After refinement, the entire global input/output block was tested with all cases and is working as expected.
diff --git a/docs/_posts/2024-06-10-code-w6-7.md b/docs/_posts/2024-07-15-code-w6-7.md
similarity index 100%
rename from docs/_posts/2024-06-10-code-w6-7.md
rename to docs/_posts/2024-07-15-code-w6-7.md
diff --git a/docs/_posts/2024-06-10-code-w8.md b/docs/_posts/2024-07-22-code-w8.md
similarity index 95%
rename from docs/_posts/2024-06-10-code-w8.md
rename to docs/_posts/2024-07-22-code-w8.md
index 1769704..170c53c 100644
--- a/docs/_posts/2024-06-10-code-w8.md
+++ b/docs/_posts/2024-07-22-code-w8.md
@@ -27,13 +27,13 @@ Modules directory with all nested python files:
## Accomplishment and Challenges
-* #### Analyzing the Week 3 Code for the Nested Issue
+* ### Analyzing the Week 3 Code for the Nested Issue
Dr. Jose Maria suggested in the meeting to revisit the basics and look for solutions in the internal architecture. Therefore, I recreated the issue from week 3. I wrote two codes: one where a new node is created according to dependencies and new wiring was made. However, this approach was not sustainable due to the potential complexity from multiple dependencies. I dropped that idea. The second approach was recursion-based on frontend side, aimed at getting all dependencies, but it resulted in blank dependencies. After analyzing this solution, I changed the recursion solution from the package level.
-* #### Blank dependicies issue
+* ### Blank dependicies issue
Upon deeper analyzing into PackageBlockModel and factory.tsx, I observed that I had created nested dependencies that were not present in the interface of PackageBlockModel. I modified the dependency array for every script and added internal dependencies to the respective interface and methods. The solution was close to being resolve, but I took a different approach in week 3.
-* #### Python script in modules directory issue
+* ### Python script in modules directory issue
Initially, the circuit was not building, but the Save as function was working. Due to nested dependencies, the synthesis file could not be processed. I added a recursive solution to get the nested dependencies from the frontend, which was very challenging. The files were being created but not at all levels. After debugging, I found that the issue was the missing internal dependencies at each level and the improper assignment of keys. The above images attached show the progress made this week.
## PR Created
diff --git a/docs/_posts/2024-06-10-code-w9.md b/docs/_posts/2024-07-29-code-w9.md
similarity index 95%
rename from docs/_posts/2024-06-10-code-w9.md
rename to docs/_posts/2024-07-29-code-w9.md
index 83dfe34..bb54afe 100644
--- a/docs/_posts/2024-06-10-code-w9.md
+++ b/docs/_posts/2024-07-29-code-w9.md
@@ -54,17 +54,17 @@ Output including printing at every level and code block:
## Accomplishment and Challenges
-* #### Modifying the Current Version to Support Multi Code Block Dependency
+* ### Modifying the Current Version to Support Multi Code Block Dependency
When I completed writing the entire logic, I found that multiple codes were not supported, and extra wires were created that couldn't connect. Additionally, other code blocks of inter-dependency were not included in data.json, leading to improper linkage. I modified synthesize_modules and changed the logic for adding internal blocks, so they were not treated as whole dependencies. This way, the blocks were added at one level.
-* #### Understanding Backend Processing by Creating Sample Tests
+* ### Understanding Backend Processing by Creating Sample Tests
To understand the process, I created a sample test and added blocks and wires in data.json. This helped me see how the internal file structure of the zip file works after building. I drew the whole connection and tried to replicate it by modifying synthesis.py using recursive and iterative techniques until level 1 was achieved.
-* #### Fixing the Issue of Missing Nested Blocks After Backend Processing
+* ### Fixing the Issue of Missing Nested Blocks After Backend Processing
I created the process_dependency function, which is called inside synthesize_modules. This function iterates over all blocks of a dependency and creates module Python scripts depending on the block type. Only code block type modules and block values are included in data.json. If there is a dependency inside a dependency, process_dependency is called recursively until no nested dependencies are left. This method ensures that only code blocks are included in the modules directory, while other blocks such as global input/output, dependencies, and constants are filtered out.
-* #### Writing code for filtering and mapping the wires in backend
+* ### Writing code for filtering and mapping the wires in backend
After obtaining the proper blocks in data.json, I focused on the wires. In the current version, level 1 blocks were being added to data.json, so I modified process_dependency to include every wire. There were wires for packages and global input/output, which required proper filtering and the creation of new links between the required blocks. I iterated over all wires selected from process_dependency and segregated them based on the wire's source and target block ID. After that, in another iteration, I checked each wire with the filtered blocks in data.json to determine if the block was present, adding the key pair of ob:absent. Then, I created process_wire, where all wire mappings were handled. This function contains nested iterations:
1. The first internal iteration iterates over all valid wires, checks for global input and output, and either saves the wire in a dictionary or removes the entire source-target link based on the presence of the absent value.
diff --git a/docs/_posts/2024-07-05-code-w10.md b/docs/_posts/2024-08-05-code-w10.md
similarity index 96%
rename from docs/_posts/2024-07-05-code-w10.md
rename to docs/_posts/2024-08-05-code-w10.md
index 9bc0e0b..2f4cb50 100644
--- a/docs/_posts/2024-07-05-code-w10.md
+++ b/docs/_posts/2024-08-05-code-w10.md
@@ -49,16 +49,16 @@ Single port - Multiple IN and Multiple OUT issue:
## Accomplishment and Challenges
-* #### Replicating David's FSM Circuit
+* ### Replicating David's FSM Circuit
The nested issue was opened by David around a year ago when he faced this problem while creating the FSM circuit with VC. My first goal was to recreate the nested FSM circuit. You may wonder why recreate it? The circuit was made with an earlier version, and the internal blocks will not have interdependency if I build with the older .vc3. So, I had to recreate every block and circuit. There was an issue when I ran the parameters; they were missing, so I checked with data.json and found missing parameters.
-* #### Parameter Issue in Nested Code
+* ### Parameter Issue in Nested Code
The earlier code was developed for one code block dependency, similar to nested blocks. The parameter IDs depended on the "type ID" of the dependency, but if multiple blocks are inside the dependency, this method will have the same type ID, and the parameters cannot map to the correct block. This type_ID needed to be changed in nested code. All blocks in data.json are at a single level, so the types are basic blocks. Initially, I thought to create a random alphanumeric string of 30 characters as the parameter ID. After implementing it, many issues were found, such as if parameters are used in input and output, leading to more confusion in wire mapping. Then, I implemented a new ID not dependent on type_ID, and particular wires will map with blocks, so the issue of mapping extra wires also won't occur.
-* #### Single level FSM Circuit
+* ### Single level FSM Circuit
After solving the parameters issue, I proceeded with the single-level FSM circuit. The blocks such as laser_ROS2, motor_ROS2, and screen used by David were not from the block library. Initially, it didn't work, and finding the issue took more time. After analyzing the internal code of the above blocks, they were customized. After modifying and recreating, the whole logic ran without any issue. I ran turtlebot3 in an empty world inside my local machine and ran the FSM logic with VC.
-* #### Issue in multi level FSM Circuit (Major issue)
+* ### Issue in multi level FSM Circuit (Major issue)
After running the single level, I was confident it would run with nested, but as the saying goes, things don't always go as planned. David used single port multiple OUT to different blocks and took input outside of the composed block from multiple blocks. However, I wrote for single IN - OUT, so it could not map the multiple blocks; it was taking one block and connecting to another block. This is a big issue as it requires looking again at the mapping of wires and adding conditions for such situations.
diff --git a/docs/_posts/2024-07-05-code-w11-12.md b/docs/_posts/2024-08-20-code-w11-12.md
similarity index 100%
rename from docs/_posts/2024-07-05-code-w11-12.md
rename to docs/_posts/2024-08-20-code-w11-12.md
diff --git a/docs/_posts/2024-08-25-code-w13.md b/docs/_posts/2024-08-25-code-w13.md
new file mode 100644
index 0000000..97dcd5e
--- /dev/null
+++ b/docs/_posts/2024-08-25-code-w13.md
@@ -0,0 +1,54 @@
+---
+title: "Coding Period Week 13: Aug 21 ~ Aug 26"
+categories:
+ - Blog
+permalink: /coding-week13/
+toc_label: Table of Content
+toc: true
+sidebar:
+ nav: "docs"
+---
+
+This is the final evaluation week, where ongoing and new errors were resolved, a demo video was created, and the summary report for the final evaluation of GSoC was written. New blocks, such as a generic PID and person detector, were also developed and tested by creating demo circuits. Although there are some loose ends left that I plan to address after GSoC, everything in the current version works perfectly. The remaining loose ends are additional features that need to be added.
+
+
+
+## Goals
+- [x] Develop generic PID and person detector blocks
+- [x] Test new blocks by creating demo circuits
+- [x] Refine the code and add comments
+- [ ] Resolve the issue with multiple instances of prebuilt package blocks
+- [x] Create and edit demo video for final evaluation
+- [x] Complete summary report and publish the video on youtube
+
+
+
+
+## Accomplishment and Challenges
+
+* ### Generic PID and person detector block
+ Now it's time to add some blocks. First on the list is the Generic PID. A question that might arise is why we need this if there is already a PID block. Like you, I asked this question to my mentors, and they explained that the current PID block is designed for a particular use case where the PID is applied to angular velocity, while linear velocity remains constant. This PID block cannot be used for every case, which is why a generic PID block is needed that takes the error and provides a resulting value for both linear and angular velocity, not just angular. The generic PID can be used in any application.
+
+ For the person detector block, I took reference from the Object Detector block. According to my mentor, we need a simple block that outputs an image with a selected box, indicating the detected person along with their coordinates, width, and height. Both blocks were tested by creating a demo application.
+
+ Generic PID and person detector block:
+ ![](../assets/images/thirtyseven.png)
+
+ Inside person detector block:
+ ![](../assets/images/thirtyeight.png)
+
+
+* ### Multiple Instances Issue with Prebuilt Package Block
+ This unexpected error occurred in the code for handling multiple instances from the previous week when blocks were added from the prebuilt collection block. Upon verification, it was observed that the code I wrote was correct and should work for every package block since it was running in loadPackage, which is also called in the collection block. Therefore, the issue is not with the code itself, but rather with the debugging process. It was observed that when one collection block is added, the ID changes, but when adding another identical collection block, the ID changes again, altering the previous block ID. This seems to be modifying the entire model, and the reason is still unclear but needs to be investigated further.
+
+* ### Demo video and summary report
+ Almost everything was aligned correctly for the demo video, with some loose ends that are extra features and minor unexpected errors that can be resolved in the future. Apart from that, everything is functioning as expected. It was time to create the demo video showcasing the features that will be released in v3.6. In the video, I demonstrated the state before v3.6, the modifications made in v3.6, and how to use the composed and nested block features. After verification from my mentors, I published the video on YouTube and also wrote the summary report required for the final evaluation of GSoC.
+
+ [Composed and Nested Blocks Feature Demo - v3.6](https://www.youtube.com/watch?v=xvceQL8AgQ4)
+
+
+## Final Note
+With this, my GSoC work is complete, but I believe this is just the beginning of a new chapter with JdeRobot and open source. I will continue contributing as time allows, alongside my other commitments.
+
+If you’ve been following from the beginning, thank you for reading up to week 13—I truly appreciate your time. If you started with this blog or any intermediate blog, you can read all the posts from day 0 to the present. A summary blog is also available, which covers the entire GSoC project progress. If you have any questions or comments, feel free to reach out to me through my social media handles provided in the sidebar. Again, thank you for visiting my blog and reading about my GSoC journey.
+
diff --git a/docs/_posts/2024-07-05-summary.md b/docs/_posts/2024-08-26-summary.md
similarity index 98%
rename from docs/_posts/2024-07-05-summary.md
rename to docs/_posts/2024-08-26-summary.md
index 1bf5ed1..5906092 100644
--- a/docs/_posts/2024-07-05-summary.md
+++ b/docs/_posts/2024-08-26-summary.md
@@ -25,9 +25,10 @@ This blog post will be a quick summary of what I worked on during the GSOC perio
- [Toshan Luktuke](https://github.com/toshan-luktuke)
-**Official Repository:** [VisualCircuit](https://github.com/JdeRobot/VisualCircuit/)
-**Github Issues**: [Summary](https://github.com/JdeRobot/VisualCircuit/issues?q=author%3ABkPankaj+)
-**Pull Requests:** [Summary](https://github.com/JdeRobot/VisualCircuit/pulls?q=author%3ABkPankaj+)
+**Official Repository:** [VisualCircuit](https://github.com/JdeRobot/VisualCircuit/)
+**About:** [ℹ️ Explore About](https://theroboticsclub.github.io/gsoc2024-Pankaj_Borade/About/)
+**Github Issues**: [View Issues](https://github.com/JdeRobot/VisualCircuit/issues?q=author%3ABkPankaj+)
+**Pull Requests:** [See Pull Requests](https://github.com/JdeRobot/VisualCircuit/pulls?q=author%3ABkPankaj+)
## Goals
diff --git a/docs/_site/feed.xml b/docs/_site/feed.xml
index f4ba3e5..33a7db6 100644
--- a/docs/_site/feed.xml
+++ b/docs/_site/feed.xml
@@ -1,119 +1,4 @@
-
Older version FSM single level circuit: -
- -Recreated working FSM circuit with nested code: - -
- -Output of single level: - -
- -Parameter issue: -
- -Single port - Multiple IN and Multiple OUT issue: -
- -The nested issue was opened by David around a year ago when he faced this problem while creating the FSM circuit with VC. My first goal was to recreate the nested FSM circuit. You may wonder why recreate it? The circuit was made with an earlier version, and the internal blocks will not have interdependency if I build with the older .vc3. So, I had to recreate every block and circuit. There was an issue when I ran the parameters; they were missing, so I checked with data.json and found missing parameters.
-The earlier code was developed for one code block dependency, similar to nested blocks. The parameter IDs depended on the “type ID” of the dependency, but if multiple blocks are inside the dependency, this method will have the same type ID, and the parameters cannot map to the correct block. This type_ID needed to be changed in nested code. All blocks in data.json are at a single level, so the types are basic blocks. Initially, I thought to create a random alphanumeric string of 30 characters as the parameter ID. After implementing it, many issues were found, such as if parameters are used in input and output, leading to more confusion in wire mapping. Then, I implemented a new ID not dependent on type_ID, and particular wires will map with blocks, so the issue of mapping extra wires also won’t occur.
-After solving the parameters issue, I proceeded with the single-level FSM circuit. The blocks such as laser_ROS2, motor_ROS2, and screen used by David were not from the block library. Initially, it didn’t work, and finding the issue took more time. After analyzing the internal code of the above blocks, they were customized. After modifying and recreating, the whole logic ran without any issue. I ran turtlebot3 in an empty world inside my local machine and ran the FSM logic with VC.
-After running the single level, I was confident it would run with nested, but as the saying goes, things don’t always go as planned. David used single port multiple OUT to different blocks and took input outside of the composed block from multiple blocks. However, I wrote for single IN - OUT, so it could not map the multiple blocks; it was taking one block and connecting to another block. This is a big issue as it requires looking again at the mapping of wires and adding conditions for such situations.
-Composed circuit of line follower: -
- -Internal perception composed block: -
- -Global Input Output dialog box: -
- -In the line follower demo, Dr. Jose Maria suggested using two generic PID blocks, which led to the issue of identical IDs across multiple instances. While the line follower worked with a single PID, using two PID instances is more appropriate as it minimizes errors in linear and angular velocities. The issue arose because multiple levels were converted into a single level after backend processing, resulting in identical IDs for both internal blocks, causing incorrect wire and block mapping. To resolve this, I added an extra script in the “Add as Block” function before the jsonModel.design is appended. This script iterates to modify the IDs with random IDs, and not only the block but also the design’s wire and layer block IDs need to be changed, which was achieved in this extra script.
-After solving the issue with identical IDs across multiple instances, another issue arose where, upon entering a package, the ID and internal data of the block remained the same as they were at the time of importing. This issue was due to the node layers in the editor, as the model of the editor was appended in the higher-level block stack. The code I wrote to solve the multiple instance issue involved modifying the IDs of the design model. To fix this, I added an extra iteration in the loadPackage function. In the editor, there were two objects—one for links and one for blocks—so both IDs needed to be changed along with the earlier design IDs.
-This issue occurred when David’s FSM circuit was created using the composed block feature. In David’s circuit, multiple blocks were attached to a single port. My approach was to use a queue operation to map all blocks, but there were many cases where the number of inputs and outputs was not the same, requiring the creation of extra links. The issue with equal numbers of input/output blocks was resolved using the queue approach.
-This GSoC project focuses on adding a global block composition feature, resolving nested issues, modifying the current version’s single dependency codebase to a multi-level dependency, implementing two or more demo robotics applications, expanding the block library, automating the testing of VisualCircuit and its documentation using GitHub Actions, and releasing the new version with all issue fixes.
The last 16 weeks have been an incredible and exhilarating journey filled with learning, challenges, and accomplishments. It was a great experience to work on such an exciting project, applying my web development skills to the field of Robotics, a domain I’m deeply passionate about, and learning more about both areas along the way. These past few months were exciting and memorable, with late nights, early mornings, and sometimes not sleeping at all. The joy of completing tasks is hard to describe in words (though my weekly blog attempts to capture some of that emotion).
@@ -316,183 +201,286 @@Person Detector Block testing: -
]]>To create a global test, I needed a tool that could automatically click respective options in the VisualCircuit application. I explored several technologies such as Puppeteer, Playwright, and Selenium. I chose Selenium as it is widely used for automation. I learned how Selenium works and how to use it.
-From my research, I observed that there are two ways to use Selenium with GitHub Actions: one involves the standard installation of Chrome and ChromeDriver, and the other uses the selenium/standalone-chrome Docker image. I chose the second method as it includes the latest Chrome and ChromeDriver, eliminating the need for a separate ChromeDriver. Additionally, it contains all the functionalities of the Chrome browser. Initially, the browser was not displaying correctly on the Selenium Grid, only showing the logo. To view the live action of the process, I opted for noVNC.
-After successfully running selenium/standalone-chrome on my local machine, I automated the process of clicking the menubar buttons. I needed the XPATH to locate and perform the respective actions. I found the XPATH for the File and Open buttons from the Developer Console. Below is a GIF showing the automation process of opening the browser, launching VC, and clicking the respective buttons.
-Now it’s time to add some blocks. First on the list is the Generic PID. A question that might arise is why we need this if there is already a PID block. Like you, I asked this question to my mentors, and they explained that the current PID block is designed for a particular use case where the PID is applied to angular velocity, while linear velocity remains constant. This PID block cannot be used for every case, which is why a generic PID block is needed that takes the error and provides a resulting value for both linear and angular velocity, not just angular. The generic PID can be used in any application.
-Automating clicking File and Open buttons in the Menubar:
+For the person detector block, I took reference from the Object Detector block. According to my mentor, we need a simple block that outputs an image with a selected box, indicating the detected person along with their coordinates, width, and height. Both blocks were tested by creating a demo application.
- +Generic PID and person detector block: +
-Inside person detector block: +
+The first step was to understand the issue created by David Tapiador. I researched the data flow of opening prebuilt VC projects, adding as a block, and the build options. When the project is built, the dependency section includes package and design key-value pairs. The dependencies were not included, which may be the reason for this nested issue.
+This unexpected error occurred in the code for handling multiple instances from the previous week when blocks were added from the prebuilt collection block. Upon verification, it was observed that the code I wrote was correct and should work for every package block since it was running in loadPackage, which is also called in the collection block. Therefore, the issue is not with the code itself, but rather with the debugging process. It was observed that when one collection block is added, the ID changes, but when adding another identical collection block, the ID changes again, altering the previous block ID. This seems to be modifying the entire model, and the reason is still unclear but needs to be investigated further.
For nested blocks, I modified the Dependency interface to include the interdependencies element. I also modified the package-model and converter for dependencies. Successfully, interdependencies appeared inside dependencies, but they were blank. This blank state is a great checkpoint as modifying internal structures introduced many errors. I am happy with the progress of this blank interdependencies issue.
+Almost everything was aligned correctly for the demo video, with some loose ends that are extra features and minor unexpected errors that can be resolved in the future. Apart from that, everything is functioning as expected. It was time to create the demo video showcasing the features that will be released in v3.6. In the video, I demonstrated the state before v3.6, the modifications made in v3.6, and how to use the composed and nested block features. After verification from my mentors, I published the video on YouTube and also wrote the summary report required for the final evaluation of GSoC.
+ + +Integreation of interdependencies inside dependencies:
+With this, my GSoC work is complete, but I believe this is just the beginning of a new chapter with JdeRobot and open source. I will continue contributing as time allows, alongside my other commitments.
--
+If you’ve been following from the beginning, thank you for reading up to week 13—I truly appreciate your time. If you started with this blog or any intermediate blog, you can read all the posts from day 0 to the present. A summary blog is also available, which covers the entire GSoC project progress. If you have any questions or comments, feel free to reach out to me through my social media handles provided in the sidebar. Again, thank you for visiting my blog and reading about my GSoC journey.
]]>Composed circuit of line follower: +
+ +Internal perception composed block: +
+ +Global Input Output dialog box: +
+I went through some frontend files such as menu/index.tsx
, project-info-dialog.tsx
, and editor.ts
. These files are responsible for editing the project information on the frontend side. Initially, I thought of adding Global Input Output functionality within the existing project editing interface. However, as I began implementing it, I realized that it was more difficult than anticipated since it required changing the Project Info interface in every file. Therefore, I decided to build a new dialog box that can be opened from the “Save Block” option in the menu bar.
In the line follower demo, Dr. Jose Maria suggested using two generic PID blocks, which led to the issue of identical IDs across multiple instances. While the line follower worked with a single PID, using two PID instances is more appropriate as it minimizes errors in linear and angular velocities. The issue arose because multiple levels were converted into a single level after backend processing, resulting in identical IDs for both internal blocks, causing incorrect wire and block mapping. To resolve this, I added an extra script in the “Add as Block” function before the jsonModel.design is appended. This script iterates to modify the IDs with random IDs, and not only the block but also the design’s wire and layer block IDs need to be changed, which was achieved in this extra script.
For choosing the Global Input Output, all inputs and outputs can be shown, and from there, the Global Input Output can be assigned. I created a new script for the dialog box and modified editor.ts
and menu/index.tsx
. Currently, all inputs and outputs are displayed. Next week, I will work on assigning the inputs and outputs as Global for the block.
After solving the issue with identical IDs across multiple instances, another issue arose where, upon entering a package, the ID and internal data of the block remained the same as they were at the time of importing. This issue was due to the node layers in the editor, as the model of the editor was appended in the higher-level block stack. The code I wrote to solve the multiple instance issue involved modifying the IDs of the design model. To fix this, I added an extra iteration in the loadPackage function. In the editor, there were two objects—one for links and one for blocks—so both IDs needed to be changed along with the earlier design IDs.
This issue occurred when David’s FSM circuit was created using the composed block feature. In David’s circuit, multiple blocks were attached to a single port. My approach was to use a queue operation to map all blocks, but there were many cases where the number of inputs and outputs was not the same, requiring the creation of extra links. The issue with equal numbers of input/output blocks was resolved using the queue approach.
+Checkbox for global input output - dialog box:
+Older version FSM single level circuit: +
+ +Recreated working FSM circuit with nested code: + +
+ +Output of single level: + +
+ +Parameter issue: +
+ +Single port - Multiple IN and Multiple OUT issue: +
+ +In this approach, I didn’t use node.dependencies
but instead created blocks and wires for internal dependencies. This solution was suggested by ChatGPT, so I tried it. It involved creating internal wires for dependencies and making the linkages. I spent around two days on this, but it didn’t yield the desired results. Additionally, it was suggesting editing many internal components, so I dropped this idea and returned to my nested block solution.
The nested issue was opened by David around a year ago when he faced this problem while creating the FSM circuit with VC. My first goal was to recreate the nested FSM circuit. You may wonder why recreate it? The circuit was made with an earlier version, and the internal blocks will not have interdependency if I build with the older .vc3. So, I had to recreate every block and circuit. There was an issue when I ran the parameters; they were missing, so I checked with data.json and found missing parameters.
In the previous week, I encountered blank dependencies. I noticed that the interface dependencies contained a single dependency, so I modified it to include an array and used recursive calls to add internal dependencies. Additionally, factory.tsx
had not been changed, so I modified that as well. However, the issue of blank dependencies still persists. I need to consult the mentors regarding this issue, as I feel it can be resolved with some more effort.
The earlier code was developed for one code block dependency, similar to nested blocks. The parameter IDs depended on the “type ID” of the dependency, but if multiple blocks are inside the dependency, this method will have the same type ID, and the parameters cannot map to the correct block. This type_ID needed to be changed in nested code. All blocks in data.json are at a single level, so the types are basic blocks. Initially, I thought to create a random alphanumeric string of 30 characters as the parameter ID. After implementing it, many issues were found, such as if parameters are used in input and output, leading to more confusion in wire mapping. Then, I implemented a new ID not dependent on type_ID, and particular wires will map with blocks, so the issue of mapping extra wires also won’t occur.
+After solving the parameters issue, I proceeded with the single-level FSM circuit. The blocks such as laser_ROS2, motor_ROS2, and screen used by David were not from the block library. Initially, it didn’t work, and finding the issue took more time. After analyzing the internal code of the above blocks, they were customized. After modifying and recreating, the whole logic ran without any issue. I ran turtlebot3 in an empty world inside my local machine and ran the FSM logic with VC.
+After running the single level, I was confident it would run with nested, but as the saying goes, things don’t always go as planned. David used single port multiple OUT to different blocks and took input outside of the composed block from multiple blocks. However, I wrote for single IN - OUT, so it could not map the multiple blocks; it was taking one block and connecting to another block. This is a big issue as it requires looking again at the mapping of wires and adding conditions for such situations.
Level1 Sample Circuit: +
+ +Level2 Inside test_second_block Block (nested level 1): +
+ +Level3 Inside test_first_block Block (nested level 2): +
+ +Before modification of nested issue - data.json: +
+ +After modification of nested issue - data.json: +
+ +Python Modules Scripts after processing: +
+ +Output including printing at every level and code block: +
+I first tried putting the circuit file in the Selenium Docker container through a Python script, but it wasn’t a great solution, so I decided to put the circuit file through YAML using Docker commands. After solving this, I needed to open the file from a particular directory in the file manager dialog box. For this, OS-level control was needed, so I used the pyautogui library for opening the file in Visual Circuit.
-There were many errors when building the project as the backend was running on localhost on the local machine and had to be accessed from the Docker container, resulting in fetch errors. These were resolved after modifying setting.py and .env. After that, the browser wasn’t allowing downloads as Chrome considered the HTTP frontend insecure. After some Googling and searching on StackOverflow, I found a solution. Finally, the whole process was completed automatically by Selenium. The complete process is shown in the GIF below. -Selenium based first automated global test:
+When I completed writing the entire logic, I found that multiple codes were not supported, and extra wires were created that couldn’t connect. Additionally, other code blocks of inter-dependency were not included in data.json, leading to improper linkage. I modified synthesize_modules and changed the logic for adding internal blocks, so they were not treated as whole dependencies. This way, the blocks were added at one level.
In the previous week, I was able to fetch the port data from all blocks, but it was using more iterations and not proper internal functions for fetching the data. So I improved the global input/output function and also added the submit and checklist handlers to pass data to other scripts.
-Depending on the port chosen by the user, the particular global input/output block is generated automatically. It checks the port type, and according to that, the input or output block is generated with the same name. Initially, the global input/output block position is the same as the initial position, and the links are null.
+To understand the process, I created a sample test and added blocks and wires in data.json. This helped me see how the internal file structure of the zip file works after building. I drew the whole connection and tried to replicate it by modifying synthesis.py using recursive and iterative techniques until level 1 was achieved.
I researched the internal structure of the model and tried to access the links and respective link IDs of each block. After this, I wrote down all possible cases for creating a circuit by the user. One case is where the global input/output has zero links, so one link has to be created, and the source and target assigned. Another case is that there is already a link connected with the block, so according to the port type, the particular source or target has to be removed and a new one assigned. Apart from that, there are other cases that need to be tested in the future, such as if there are two links at the same port, which one to choose. I want to ask the mentors about these cases.
+I created the process_dependency function, which is called inside synthesize_modules. This function iterates over all blocks of a dependency and creates module Python scripts depending on the block type. Only code block type modules and block values are included in data.json. If there is a dependency inside a dependency, process_dependency is called recursively until no nested dependencies are left. This method ensures that only code blocks are included in the modules directory, while other blocks such as global input/output, dependencies, and constants are filtered out.
Before generating the .vc3 composed block file, the old model has to be saved so the user can continue working on the circuit without worrying about the blocks global input/output. The model and project info are saved in the stack, and whenever the build is completed, the old model is loaded. There were constant errors, such as storing the data in the stack but it was changing with changes, as I was storing this.activModel directly in the stack, causing changes in the stack. For that, I tried several methods using deepCopy, custom functions, and cloneDeep. Both deepCopy and custom functions didn’t work, so I used the cloneDeep library, which worked without any errors. Similar to the “Save as” functionality, I used that part of the code for generating .vc3 file.
+After obtaining the proper blocks in data.json, I focused on the wires. In the current version, level 1 blocks were being added to data.json, so I modified process_dependency to include every wire. There were wires for packages and global input/output, which required proper filtering and the creation of new links between the required blocks. I iterated over all wires selected from process_dependency and segregated them based on the wire’s source and target block ID. After that, in another iteration, I checked each wire with the filtered blocks in data.json to determine if the block was present, adding the key pair of ob:absent. Then, I created process_wire, where all wire mappings were handled. This function contains nested iterations:
Normal circuit to be converted for block: -
- -Global input ouput port selection : -
+Generated block: -
+This way, new links are created, and the absent value helps the code decide whether to loop again or exit process_wire.
-Internal block structure: -
+Nested dependencies in .vc3/ .json file Level 2: +
+ +Nested dependencies in .vc3/ .json file Level 3: +
+ +Modules directory with all nested python files: +
+As discussed above, we should not have more than one link at the input port, and we need to hide input ports with internal wiring from the block composition dialog box. I modified the globalInputOutput function to segregate ports based on links and port types. In last week’s code, only code blocks were supported, so I made changes to support every block. I also observed an issue with the text being fetched from the package, which was taking a 40-character name. I modified it to take the name port from the labels of the blocks.
+Dr. Jose Maria suggested in the meeting to revisit the basics and look for solutions in the internal architecture. Therefore, I recreated the issue from week 3. I wrote two codes: one where a new node is created according to dependencies and new wiring was made. However, this approach was not sustainable due to the potential complexity from multiple dependencies. I dropped that idea. The second approach was recursion-based on frontend side, aimed at getting all dependencies, but it resulted in blank dependencies. After analyzing this solution, I changed the recursion solution from the package level.
For blocks with multiple wiring at the output side, a new link needs to be added with the respective global input/output attached. Unlike the global input block issue, this requires the parent global output block ID and the respective link ID so that the existing link is not modified. These changes were extensive and altered last week’s code, so I refined the overall code. After refinement, the entire global input/output block was tested with all cases and is working as expected.
+Upon deeper analyzing into PackageBlockModel and factory.tsx, I observed that I had created nested dependencies that were not present in the interface of PackageBlockModel. I modified the dependency array for every script and added internal dependencies to the respective interface and methods. The solution was close to being resolve, but I took a different approach in week 3.
+Initially, the circuit was not building, but the Save as function was working. Due to nested dependencies, the synthesis file could not be processed. I added a recursive solution to get the nested dependencies from the frontend, which was very challenging. The files were being created but not at all levels. After debugging, I found that the issue was the missing internal dependencies at each level and the improper assignment of keys. The above images attached show the progress made this week.
Blank script and no internal script in the modules directory issue image: -
]]>Nested dependencies in .vc3/ .json file Level 2: -
- -Nested dependencies in .vc3/ .json file Level 3: -
- -Modules directory with all nested python files: -
-Dr. Jose Maria suggested in the meeting to revisit the basics and look for solutions in the internal architecture. Therefore, I recreated the issue from week 3. I wrote two codes: one where a new node is created according to dependencies and new wiring was made. However, this approach was not sustainable due to the potential complexity from multiple dependencies. I dropped that idea. The second approach was recursion-based on frontend side, aimed at getting all dependencies, but it resulted in blank dependencies. After analyzing this solution, I changed the recursion solution from the package level.
-Upon deeper analyzing into PackageBlockModel and factory.tsx, I observed that I had created nested dependencies that were not present in the interface of PackageBlockModel. I modified the dependency array for every script and added internal dependencies to the respective interface and methods. The solution was close to being resolve, but I took a different approach in week 3.
+As discussed above, we should not have more than one link at the input port, and we need to hide input ports with internal wiring from the block composition dialog box. I modified the globalInputOutput function to segregate ports based on links and port types. In last week’s code, only code blocks were supported, so I made changes to support every block. I also observed an issue with the text being fetched from the package, which was taking a 40-character name. I modified it to take the name port from the labels of the blocks.
Initially, the circuit was not building, but the Save as function was working. Due to nested dependencies, the synthesis file could not be processed. I added a recursive solution to get the nested dependencies from the frontend, which was very challenging. The files were being created but not at all levels. After debugging, I found that the issue was the missing internal dependencies at each level and the improper assignment of keys. The above images attached show the progress made this week.
+For blocks with multiple wiring at the output side, a new link needs to be added with the respective global input/output attached. Unlike the global input block issue, this requires the parent global output block ID and the respective link ID so that the existing link is not modified. These changes were extensive and altered last week’s code, so I refined the overall code. After refinement, the entire global input/output block was tested with all cases and is working as expected.
I first tried putting the circuit file in the Selenium Docker container through a Python script, but it wasn’t a great solution, so I decided to put the circuit file through YAML using Docker commands. After solving this, I needed to open the file from a particular directory in the file manager dialog box. For this, OS-level control was needed, so I used the pyautogui library for opening the file in Visual Circuit.
+There were many errors when building the project as the backend was running on localhost on the local machine and had to be accessed from the Docker container, resulting in fetch errors. These were resolved after modifying setting.py and .env. After that, the browser wasn’t allowing downloads as Chrome considered the HTTP frontend insecure. After some Googling and searching on StackOverflow, I found a solution. Finally, the whole process was completed automatically by Selenium. The complete process is shown in the GIF below. +Selenium based first automated global test:
+Level1 Sample Circuit: -
+ -Level2 Inside test_second_block Block (nested level 1): -
+In the previous week, I was able to fetch the port data from all blocks, but it was using more iterations and not proper internal functions for fetching the data. So I improved the global input/output function and also added the submit and checklist handlers to pass data to other scripts.
+Depending on the port chosen by the user, the particular global input/output block is generated automatically. It checks the port type, and according to that, the input or output block is generated with the same name. Initially, the global input/output block position is the same as the initial position, and the links are null.
+I researched the internal structure of the model and tried to access the links and respective link IDs of each block. After this, I wrote down all possible cases for creating a circuit by the user. One case is where the global input/output has zero links, so one link has to be created, and the source and target assigned. Another case is that there is already a link connected with the block, so according to the port type, the particular source or target has to be removed and a new one assigned. Apart from that, there are other cases that need to be tested in the future, such as if there are two links at the same port, which one to choose. I want to ask the mentors about these cases.
+Before generating the .vc3 composed block file, the old model has to be saved so the user can continue working on the circuit without worrying about the blocks global input/output. The model and project info are saved in the stack, and whenever the build is completed, the old model is loaded. There were constant errors, such as storing the data in the stack but it was changing with changes, as I was storing this.activModel directly in the stack, causing changes in the stack. For that, I tried several methods using deepCopy, custom functions, and cloneDeep. Both deepCopy and custom functions didn’t work, so I used the cloneDeep library, which worked without any errors. Similar to the “Save as” functionality, I used that part of the code for generating .vc3 file.
+Level3 Inside test_first_block Block (nested level 2): -
+Normal circuit to be converted for block: +
-Before modification of nested issue - data.json: -
+Global input ouput port selection : +
-After modification of nested issue - data.json: -
+Generated block: +
-Python Modules Scripts after processing: -
+Internal block structure: +
-Output including printing at every level and code block: -
+I went through some frontend files such as menu/index.tsx
, project-info-dialog.tsx
, and editor.ts
. These files are responsible for editing the project information on the frontend side. Initially, I thought of adding Global Input Output functionality within the existing project editing interface. However, as I began implementing it, I realized that it was more difficult than anticipated since it required changing the Project Info interface in every file. Therefore, I decided to build a new dialog box that can be opened from the “Save Block” option in the menu bar.
For choosing the Global Input Output, all inputs and outputs can be shown, and from there, the Global Input Output can be assigned. I created a new script for the dialog box and modified editor.ts
and menu/index.tsx
. Currently, all inputs and outputs are displayed. Next week, I will work on assigning the inputs and outputs as Global for the block.
When I completed writing the entire logic, I found that multiple codes were not supported, and extra wires were created that couldn’t connect. Additionally, other code blocks of inter-dependency were not included in data.json, leading to improper linkage. I modified synthesize_modules and changed the logic for adding internal blocks, so they were not treated as whole dependencies. This way, the blocks were added at one level.
+Checkbox for global input output - dialog box:
+ +To understand the process, I created a sample test and added blocks and wires in data.json. This helped me see how the internal file structure of the zip file works after building. I drew the whole connection and tried to replicate it by modifying synthesis.py using recursive and iterative techniques until level 1 was achieved.
-I created the process_dependency function, which is called inside synthesize_modules. This function iterates over all blocks of a dependency and creates module Python scripts depending on the block type. Only code block type modules and block values are included in data.json. If there is a dependency inside a dependency, process_dependency is called recursively until no nested dependencies are left. This method ensures that only code blocks are included in the modules directory, while other blocks such as global input/output, dependencies, and constants are filtered out.
+In this approach, I didn’t use node.dependencies
but instead created blocks and wires for internal dependencies. This solution was suggested by ChatGPT, so I tried it. It involved creating internal wires for dependencies and making the linkages. I spent around two days on this, but it didn’t yield the desired results. Additionally, it was suggesting editing many internal components, so I dropped this idea and returned to my nested block solution.
After obtaining the proper blocks in data.json, I focused on the wires. In the current version, level 1 blocks were being added to data.json, so I modified process_dependency to include every wire. There were wires for packages and global input/output, which required proper filtering and the creation of new links between the required blocks. I iterated over all wires selected from process_dependency and segregated them based on the wire’s source and target block ID. After that, in another iteration, I checked each wire with the filtered blocks in data.json to determine if the block was present, adding the key pair of ob:absent. Then, I created process_wire, where all wire mappings were handled. This function contains nested iterations:
+In the previous week, I encountered blank dependencies. I noticed that the interface dependencies contained a single dependency, so I modified it to include an array and used recursive calls to add internal dependencies. Additionally, factory.tsx
had not been changed, so I modified that as well. However, the issue of blank dependencies still persists. I need to consult the mentors regarding this issue, as I feel it can be resolved with some more effort.
This way, new links are created, and the absent value helps the code decide whether to loop again or exit process_wire.
- -Official Repository: VisualCircuit
-Github Issues: Summary
-Pull Requests: Summary
Official Repository: VisualCircuit
+Project Summary: 🔍 Explore Summary
+About: ℹ️ Explore About
+Github Issues: View Issues
+Pull Requests: See Pull Requests
This is the final evaluation week, where ongoing and new errors were resolved, a demo video was created, and the summary report for the final evaluation of G...
+ME7#~ca&_;H|pZk_W1en$c7dLdXpQeVs7`FN60Jpw(3mG22c7)QgE0I zNgdl*HrUyy!s#B*KX}^wbEdLydfxblZZd7lg4->p$x{{!-sWsc}YYd4mCRIN6` Df9KnAKkweQZ?`Ak70cPfddd1_w`SJ_`pAcA@5D0FatQOccl0+T zu7c?4UpP(KQ^?-Knba+YACnw?6S{f1ow$_a{=Igulx-O`oU4Ix>F|SB{Ojv>{nNiA z5_LqCxD=1hNCWHIvSBzxMW3Wt+-;tyq_1TLkw3l9S!}fgelj!%{C?n`0dE!)+?kcH z `-j$WeH7H-d=FNlMDn9VrN=KtRFer(2%Ceqt0is^kYdMNBpB-5 zP%Lnih*a(#y&**Oo%fta0k@U`8&huHK;yd$N^YI*lHf_|)3eVan<7`BoU?ne`g%b4 z*E*(m@cszM(&yU*lBYTZAQbF02l(0KBmVGB%)Y7VqXkNV7tf!6-IUl-3{<)O*>Bh5 zA8~F84UzJKd3B1^Gh<&s#qF9l!ue}M*n!fSYu}scmbSlVZAPkX8uS+8#HE zYf!U15!Qc-)MO4UJ}tELn_-{ZDWM)%ZXYSOXuKOaLE?!*($>2`CYl{S&54gF5+}!C zv8%dW?w?aqS8HKabsByNYutO{u58(Z{4&7rA#e3i1^}f|&5s1{R%2=D>9_t9d0$_V zgt1lUtIt=}B$~Bfk&$3-;*si5gVqjit~BSZIhe+H6>~0V?ksm|H|)y|kax<>jQ8rM zS=*|WZ @ZBY`M7L(>hX}+>}CB-kS>EonNgzA%CW@;qZW882n?XWHj zCq08 =4iI%vKH~m2jY|b|FBhgr)Obo6`V@(rBzV>I$P4md>{K*N<~@m zn0cL$=0VbD4=+Eigih*jKUO{=et!Q^lAL0KGs{d%`eETjNhShYcTf6p?Z@}-T~P@o zbFs3a7=*M7pJ(opRrhfZk7Daf@u!sMmcZuYEB&LrcqC+Mt#6xU3B?ef2b$0Ts`3A} z(1w>r#te5j)V>8$QNfWzl*hx?_K-&f2Nn0Q`Wo(b^CEJd?`DWaMyxw^8J$dFbCFmy zq$=k7raJYwJ|XU2ttywOHIu-Jb^eLfIw@e=s)vyq^pU93- MAo44EhZG%C2^`7n-_;oARAccCLP=vM%lF1Q z<+W&$rG44 0NwlXaUU6IiCW|BEx!I_VZTs%Di8H^ekcy~x@AIj`wf0I zzNwkc7b^h=pYx9$Z8g<5S{k%4#PrCrSF$oi9hc+@Uv9Lm?n+%DuEV?ya@7sP{}K5f z#nnO_mI|!ANii`y5OxH0eX4-fy)UnO|7_~};l=2k5R0cG^uv*5UKc=X6_Ui58;0Yz z$wX3l9epVUfN6YHV)a|W&eQEXS;KC!3RtY1CIgEa8W?Sc2K{@mEuXd)zmsCM-}CnD zSEqxpm!@aB8Fw=?MLoyl3GH76 O5-%)y&>F=Z;18y7jeEBUo3Hy~28qo%-&XDiD=$O#!6ADY4 zgopZVPIwBosi}NCsrh1w^fcj$=t;H*Ej;y^B1%0xac5`JwvMBr^HafF!1Uy6Gbb+a z$!6Vvv3}S;`Uv!~jCk0nokF9V4;`^X37PCR9Ugv%KG$Q;Quk$N5}2~D=PSmeqkHg5 z_kNYW-Z)t}2h^wP>7N@aNlf }1-BRf3?_zU4DMTMpaC%LJ zN$kNPXF~EfS)WiFc{0qJoVnd=iPqfURB1(aSU!4%M&PP5es@~l?;d*|KWTMmZ0ciE zUx`ieAKU!s&q>Fyo<+>xnydJAzW5hscK*YWA *1 zA;G-(Q7h?e(RZ4%IP9=i-I_y2Zs`pzj`I0++D2GB;RbS?zY-8RvK+c4z{B*PzX@MV z_9e!~mXl>nq)$~PQ6h;_3{hm1 bL%4w;pEkgcw^1 zG0K$O9|HKW&YY|w!1MK$0FNZPYI(5m(N_U?0iNT3E2B-`E|*8)$i$X0@x{TO3Fysg z^wj(6r6OU}rM$=te5NOfsFH&2$EAoPUz}Kaa|U^kSIza8Uqc3YZbp{xd%G;(rHub= z#(nXl-8wxU#ZY?sj3-Qb1~i$C4bKH}L+*dM-_ipHbEjRt8Kf(h2Wv8sDxqy=-PZKo zOphh{Yh%XN)W_C&JuKI0J zlOY$q7Xax!oL_^)P4-{tFiY#jz_6G68BAHjm2K9}XW<@J!a5cHkz^80m*b1OKyvQY zZA;{7$gj>JkNNle=&xQh YcgaSo-fA)uEwyU0)%uehdw_y{H>*dwty;p}8TvzJD{r-)J4q-_UwOmJgf# zJS%)01e2~y*YI*dL$TeZA>*uL#&!{5o8`Ng_3vhoyLb^}bKs3xa%!jjrnrJ(8z-Ar zwFq(%8!X|O|Dxn;WlW93I$u`*mdkWM@{D+)8{Y2wU()rL#QB+i9rk(^swYgOXbxgb z^pQDr4Xrx@@O CqP^Rf5IiTfLCKl1v6?X|+>l^vewBMlXs$i8VHFXiqEGI> z=OKK}khnM8nvK7N4g%^5CN}c}>N2m9BAo8aaBV 2(x})VH)3oi(%T{QK6KvpS9O^AZ0zTkyL%FGD saQdt+IY``n+X>va#vlGa;*XZyOMUzq%ko 8nj}F j9;eHfFYdqok>IhX`%iB`NEem+ b75duYwcx#SLt7|0JBK}RVI~Yv To++YqU%kC$!Me6132d8sJS| zVzkuG`ps+jpv5){|3Va6?)Rc!AUmFi%>Ke%RxZK_t)}~+Yc`j-9GuDM&{N^Pu~E`q zeQW#|S850qIa>I&U^I9;VdK9VfJUzg@K>AA@ZD=c%R!i2<9E6cicVhxxRv`?JJ1M* zc%pSUYyBSxqs{C8s&R7A#uHtbckx +&`OSJ=aiG&)hGlK^e}_ z=NjOWZJ&84snui2mk^Ws7pDF#O8oz a^E@Zyn6fxucL8?_ltPBQFAW8X!4qBJ4gRj zv8nIw CTUDo>ha4aK(})nAqU z)As(8UPd?VKi!FU{|)X$+Wq5ecY@dy9$?yI`K<7{N-p%K6g39M )Hdkp>Pe9V2i|l>y%;J)P8FnwtFG8gcukfo=ei|i|6Q->O2?EA@mcyW>ETHUJLK) zA-t`2rozzBFoYKU@(08BPfObP`fE9DqtV`vxsD~#wcmr^Y*|yH&T{vd7X#z-;|%r3 zXqMTqKtI5ELx1hzd`@tuj<9jV#3*45lb4HI!Ir{DKcgr9`JtZGAOG0GIALHac>QdUF{C3!ZM%p=iEI3ajHrYGeI)31hKYl!X<7hJ{n>MS2# z374Zk<=+z@zvfk6K4==>{G?i#G`{KaNB8|IyMOb|1{)9zO&zwK8XqS;e#$#^CrqAs zzkxF* zEUbJ*#}d$)4PgZt6K(a(~GS&Rf44{Ywgl8F6HsTii;u`YxL`+r3p$ z&C#wu9-u#eRRQ%i9aWIU*pT=un}X}V!;Lg3vM2m=Zo==P=w)zfX<%xug!y0XLK?5< zByPxMW$gZgjajHTUEs9XFO$0VjzhM^FfdBEjSj`1QpPVmhFFPSJ68WRzN*|@qr`7N zS)(3=zdt;XyVTOIY-hHjWlwyfh<2=wBq5z=Pne!JlSEpU;Cs-x=EQfvve8c4^-O`n zo^i*(cxuwH&PVaT7T(}Qbb-D0ruCPdI%a28aH$yaufJbzsl@L}SP|_I8Symn&1Icy z@FlscV4DYvgasU%K!3aZcWR*+7 %YKh88Y zIayL#s#31^@s6J;g=Kwxy~C?lI*f^ rqGYQXTTSzfoUaN_H}(viT`N1h zFV0Th?jWkmViL!l`vP_7Bw!RYO)zZcg?E{H9eJG)6xG62x5IruIy#74-3TIOL@cPq zD=Q&ou32vol=DFX;Mqwg3=BCZymc?fE4L$Xx5FXJKP%|;e9jFa);oJfZQ_a)TmyBO z$oToBQbUw)qt&2i!_NPVJ1$x2`*d)Xu%NxeWOyZ0=-J(f*T0mkXS3f7oZhG;_gC_F zj!Dzk4}!{kc&shs* ~E0C^Zcep7#BR9Ym+K>yO>1i|ortmG~? zDyoC8PSdGsXu|3!%SJ=`g)-=v(nP>BzvC#3sy@$s5K?lj1%@0wu~KzK>BYQDP`-eG z_f{>aVPgXiJXvwYQqG+;wxtvgi^~cs^c}t{1iRFN&EG9{1iJFAE&A)C{Puwta0Rug zu`9T@hXf6L47?SRZ1-~dB2s*sb4+IMs-8@<`8mqhug>}Eys!nZlO|~qzqLQOJ2BPQ zS((MtqC!&~pbDjK?DTr@@FM_rQwj;oI>{>jJ^-H9&14ZI=odS6oO8i_jD^-yhf3dR zkbGmaxGq$DmKWc5aRc{+Q36z|HZr5VUfwxYXomQhwk8rVf4(!;a@nxA(G(x3hy#Yd z&z(tU?jw@a2T7O7?HpB3F{9ujAKjTB72$x}O;JZEqy|X*D&7xSDRPk$^{Y#!!e#I2 zewjyln7~6LXMxhicBp1~0)M))P$DU1$gFb`a@;RibN-_S4`+H+C)Hh{o$5{TwItN@ zz|*>m5i8iLN)n%DU%*x0#dp`ctAd^RcBq5!+RX)zp~C6S^8n-U%*LSCi8P)UXF&zM z=MG#xNRVMhZoUGc)N^Q{UE3iDmA`Aa29Z~T^;OVix_=`0Vvg>BU=rrChdcmT$bx4j zaxay}bHLTV4EBa+GvAC0Xe6U+7jU61?zp~~X zDzTsIN%eJqLmO0Jpd7Tz#?`Sczi^yX+%D}}7xelNcCn;1Z6Bn35?0}f*e>pO*5n!X zRUACp1I#=6KXx}8+HA5q8(&P;kg6L`w6@>-5I5@6UK~N2-pYrcT9B`IwJ9g%j%@Ut zB#E$ZZH0_JApNyD@(|+ c{y=NKOBYTr%lf92p*`o-V$H-pUn@Y$$_9+J^ zj=ecJIL7ZjdcWV_&;P&kxQjZxUiY}}>v~?#=XJkMc%XD~s*A|e&@>5cGWsA*wG49U zt(?ZCi)1=RuCb4B6WldSXeB ulqd4 z)dq2M?3fK@F7s9+r;e5Dvdo3+Ll1Yep5o5ZEEVIhr;dg>W=(6u_i}bi5=&QVSk#?! z6HC23c4M0CZB&f3X$Q1Ogtf)fcdP?nj*G}2oiyjv(YHL7hM|g9);REs{+;obyzbUS z#`puwcnbq(;`CTshEW+D{#(Okpg}{UrkO!>A&F}+d*8hp{c~M#=u?Vv;(og4C+g^% zCnp0 nvXlAX6~Kq4+m+hMVBrqxLo_wXo5Gu;c4;l2%Aq zND`dac~T@nIhS6zYulyvA?O9qE^%_jm$+`{*i=b c$`XQ1w+;uKaM-k`` zJJ?{`X01XS?uYKto}2M-ykCV=nsb|1tvYh?{?xHsY0T+XcgpU-#iQ8GGb8T1Om=VX z)Q+##p`>3~k?K3pH>sNk^}#niZRNbhbo1%r;#zjD_6ND6J>ZJzE33rpsH~Xj&HP=l zn%0qc(sFIn;SWUu5PDjDx^nJ832x>bTxh@R#Oh$6;80&dq1~%qZoJ1Ra3;(yxNQdW zp1gyR_l*-1=WCI&DYo_J%N`FodlT)qUhUpOY*Ufg9JjhTiY#D4Zb;S#NASIn&$-wf z@8d(6QPH1OFyrJ?#1Jk=9@zmJ2MlnIwNCmQR~12Y AP;lNqsI~Eei zi{r7^F}LZS*t;-wv~;OOYT0(|b2Xzvw7vb8Jtw+rU0%sr>wK#y&kZe_5moM-d5z{w z1hSDU+JSQ3)8pyqFcw;j=*c2)s#xdPx70Aoh)uuX0Wm*+`ILp#H=?}>*Rk5F;LaAK z_ilCkTC^TZz%V^1O!;)5;s-9OrYy%f_2N)tjF?g!S|q{y8_7?eDEcbJ^Xb=|GVv@i zD`Hl;+|XB;q^&=$yIg}>7MBiuvg!|g_I{ym-p8}YLur{;FhcP@k-Ym6G9iD(g^vO} ztTPXGWEXgdPFe|#*FG8sOIQ@g Dg8Q#HBV%K0JXcdRnLV_`B0GF~VfcB4K|{mFuOMF{aHSk2z4Aw9_p!&O0%dzi zeqN@c3jCkS%5_^??opLHELUc$OU@CkpSG#&O>|-jjS4?Ke{fV7lJf+~A$byn_=P-0 z9F=Pij3?uy3t*hp%oMt8KEt02N~Tdcmfh9F-4BZlh@VfU&K5d!#QV){*WqrIl?K9x zqTXE4%F)B6d*$7 Cw@?A3%xbhnqW5aFa**0|V+cwY5bxHM)Ns^+4(e^3!RS zX*y@h5RhL1pgcA>n0a*Mm;0=+e?S7yyBEDJu48DBjjd()0yp<>7?9k*w;uFuMr@f3 zHPYYKs<62BT-mH?;S3rxt}bPaYMhmz<3~g2+-6xl=94ru1DQFaY`e7EvR2!?%l7Gf zLL+1hmoG;%pfWvR`A z_xeev#7M_9q-7Z Blaf*{?KtpF3evE(s-41wq_AYI(dXb~u4GNLBi@ (Rntu=N8z!{lJ)n6tjEalAa*B;%YXa(7O|S4pmkMOLz!{%`m#t2 sRkvk<_iRi47(`jnYm~h~>GwJ)VGj^AJ z!*77ZbL0@c3*UswAte3;-c^$otg)lY$SG6xYJXNW?bp&;B){>d$*x>7JEdytq%c#V zpMJvqsrEn-Voy(zejyc2GGfRuX abSsRJwpmE>Fur`bX){po zZie627zy79K8HlxjcC-kIDh#V^OdHZCp%wiYpe7|64miIokWaWP(l{`L)&RFv8%mo zRWDdgN%F$50jJPkN6ird5OY2$=K^gfq9gm-`wO@jJlSASU%W9Y&x&dYf8Z$TxgP4_ zCJl2 x6CbF3QqFr%3?c=xgR}S^<@~g zw1H}hbNk4+IQNM}?+T>54%72tB6lZM=GUJp`#GIz+ownxcVz^|Z3He`wiw5K`RsKv z=t!5sY1g3*w{_Z^Z#5p6Q0JEp$o7h?TRy~{eqpAwJjerc0ohf!ckS%=*>DgH8hqM> z>rz(n=zXd&$`yEXfAn-o*s~|+B+VwXoV|2x#5=%T12wd6^)cP!bU8$#$+R?CO`>9N ze08W-LksR!o6)+Vn*PcZ)jlPNU5R8xiEkZ-{5eS67CY#8TN8kow=Z`=%~kBJ@1<1Q z_vpRPI$5UsV3e3^z?tVGA@z4n3rwLZ3uq5#Yykn{giJMwy9;{wZIG>bE2wdPGjt^a zEnQCIBCdnE(_FT<;Ir<2psJSoc|@h{pn={TdurwGzuj_#Vtu*1W7YbFCP+wDgVR2) zq5ZqqLYOJJFOH<~1YV4r%6ESeZaZ93wflz7$_+WKX}Lox=IjQ4FgcFc9gTD;{x)(4 z+}1+w!7X_agLu!CB)I;HhVb$mYg3v;-?*&Cw^AkAUcw2+^)f1MsiIv(+DOA #=n(E?fqG{8%NjWoOMW4*t$@MCCarx|#d zj^`DyDtyeRyge<}-?9;DZ|e7E0QZ+P RXOzXG;2(4)6M( zID&gXqC`5GlT7%QY u! y)R*)iV^w-l8| z`0kl6%7$m?Yrsow1;m!fJX}neZc~-HI#+sW_C!a@F}@KTz(}0_y7|o^@R{_{kEGq< zHdv{)P5)?UOhH0&pvJ?DW) $+g-A75 w zMuG8T&s$ -XS^PJ^O_{K?H^s!y((i3IvyB1gBR|Qip#!FpN5Kw ziv#wO1F3XB;2%vV0U!CyYZbCPX|gyLlujauCv)mdytkU5lp*&Ko)3kk6C6}_TD%&d zzQm7Bc;;cEZ 68w zSghpJP;pwiQiNz55-<5N`_b#H--B)dPwfXNC4&D)DLFCiN+k6bR#j nFI&?@a;fXh5Q|-HF_ziSa_YkJdU-T)Q-nIkarLqk#4t_}|)_3KwKtguGs< z6pX#(Lo9qm-;P(n-`Q{C*O?`L+f|3ih$X(T*;!PlexMj9#!%L{+brfsKWSnJ84RiE z?OjdkLc22Gz6wOw9`2Qm?4bhC0Q)(gZuGbWhbN~%5;ByFTd|>}13uY> _LErqllCT9h4CY`A5Xa9BhXi4~4g0oOyijTIPyRMm}JRpJZh! zGGzmQCC7NbxALfuHd>BRndvrYZl?Nx%svdr@OJqhaij#8;vy65hY nX0L& z5$4?2F*Yvl>{I|xt}Se7kzAU=&nBLjv-tUt{952Xu(zDR7=ATvK|w*~+-DpK%02UL z9OTysqVWBuY_4%Y6t%XRp}S%c1LB*sfT8{g`ae26{DcyZK8YUy7BFiF1 sRwUlL<53K_NpEKUE*DzF)qS>nOpfr+E|HDHMc z4cs5xyk`-!CWya0{w1S$E9?T1ARME^c}JJ?4n?>eVA08AyQ~cZgH8++nR_ci#OA0{ zP|1A;$@w1xC;J}ESHVnU8F1F10o400=Y*@!*vz?3hl3pk2MP>O-CryGGcRzPT2LVI zTB{Je8Q%?fb2j=|pr-;+XwUE&qLMRr#12rLI*B7SPU8PYh40#HE>Lh`F$yLUbQ+8# zq6__RJl5m?E4Fw*1`016=Nij^pn+fcl$Xp9I@@tuAbUu`Y|8&vy-`F7er`9X`HM3! zk=bo?Nt*Tl)&kVu4u1z=8w~9Sr|w_G08QaFDSl${uh*w|M!&_T)zTw#^DSWSnU|_L z9jdAn9PI7Eq|kL;wH^KUlfY#}$#{GMOTF!5^8U&FrL1qP;JZA#%aT!~h1imz7kqy< z&2qY5JOi!P=^=0?2Aq5j_%sgxdi@%IqY4AnWsekKoJ#p45gpGTlUT{Ex{TWb8Hefi zva5*zwXOhl>6%&!d@=cd3-}sNB=@voXF4 !> z{=1_ jF9kS`1oe zpL#y!zmsEea4YOd++|`Hz|>nCx|t%dxl+AAnyz&+cTl0(*B2yy@ZrO6e4y-@j(-5q zN~M!AAkq^Yim|Pwd3JcdyHH2@{gXF;{`{MS2ZJB``^EAKm9!D%h<5>Ian+AL4#qW# z^*cF^YNNZZNIZeO#*^Odot~!FRfeDemvQdew5R~s?&OJ5wp|g40c9jm^jn*M*VM_E z6c_j0-kBH6Y-xcnvdp`seCl0(SL0Aq&}vqvo}6u6Q$rAS8=?t79z==_enC*J>h^08 z!sxp`=M_#&82vL$PgCK{|5!z)^iv_>)uN6_>zmK5>n=_p_oU&H`Ner^G>Lz*$Dwyu z^@Y<)LmE&c$@=j4v(>d5PXheuycT@LR^Q21!(*%{>cn>kBJS?}Y;PM03^FeyzCK5= z_4oxQ6aoo}K#Ksc_RPVd7z9IIj)WsxGO!_)b4Ni!#cS0GeDWn8@Yx#p*KVzi&0=Qz zAm0eaV{Eo#qN)l|7GXnG<+W@Lh%388y)L8uNr5u) zef=<-Zx{^;Ifm2UT^{52qxpn_L|$t}QDsAJLExBAKnQ~`S{o+X+uI+RstccQ*5dze zY@YuZ?Y(< #ja6|(U1h0qZ*d4wir)t zu~%6(K5E`+I$8=hADb^PAJyORR~gXz#KTHoL}Kof*L=l%km0UC;pXT?$nV$qo_u{) z_ys6;pp})CK`&|mSEQaV=(T15+(q(&P_yTMyo>SLuZ0CDmYA*tEQaR`cg(Grf<{B_ zfzhs)F}mAhsFf8O6p1Wzw_V`lw$`INlIcpeZSGRpvT@&|$-XVgfOXgXfsvSZ6RoMP zF38D|t)22lgn}*eg0HZ`s;j81OufROq^smV^G+OVm6B34OPl(#;B@qCJgrSCdy}>; z{^r^5IuCR@$;!vBg(VX26IGOmgLE`6@tB6B_L=KR`7SPW(RP3#C?9!>;TQ7@okj{# z6;0thO#M#EJ c0Gm@Z<33*2YWV{n zRV()`qlZ?SQv27xR7V;hQ_8qeIQ^6PGPs?6Y&?y<$hu$uA(GZK$mngKDfggL?1@_J z$sDIzl$^kFyY!e<5H50~-qt*^gK&@=Dh!dK0L~ROJ~eINn1ILn_zSmb$xAHz-!0FU z)C(MXFEWDJ_@ChoO1JZHxG2CHp(jEx7q$UjHU-rYX)GC?efiLjy9>+xKVwp$zXj5F z4~qpYvG1w9CrKl?{S~gCZWq~mNh^lZZ<7W(RAwziLd$Y#Y}`7rM+IdKr(_eXL%Czz zeIsot#A=h94~|YrX#XS%wMdj|6;I_mvX1zga<>g dw zy5W_>R_^;|qg6B~gf3?Mz0Eqe%h1Wudb9Uv#q)JNu9oZfj!QuPwDk5y`v#1ShBf4}9RP^)Goju7{VRDR>oGSmfcBfe!SqnBHd9(rrz>S v+JO-Nr)Zl>P zoI86l8T#h%P#U18f@ElSA`bDU=YJS&qwby`eYhNlFv!^ynf#(U0I?+ )z?{vvx0IHuTZmIzc}KtzJqM%!%cpHlR4R%gMIGhoipRCG$whLrB9n@Pt3)S z3DX7kytqsa;-Zwq=J^-xU~@k zE3JP;=xshvG{)4q-!lP;%D-yS?up^YJ{kHAhovU`OA}DU<|#kPihn*R&x21)ZN4os z?U&@f6UlKWGGX2WcxV{tT$K`CmlnX}kCKpczRSLz*ns-gD_TvsKuu6Z2nHKnyI%qM zpAP=EsD*j2w@RexO2*V?sGq_oD@r7-tyqg$JC%B1sFBX}K9grbm42tqT_;~ZX$fA| z&64iK(fyuhEhGNVkQPwFjGQ>Ml7h}q!TovM8RG+LU7d_;`>*=eX{luc)n27znx;V6 z4!);1B+IAkOd$}VZdY1sJ}Q7z*?~V#R@I}gPE5`#Oi7^zG@UX}&l)K5056`nPc~jg ziMkC8G2g2CFwH$XiBsmP=1GdS&mPq!mrqxF(j+aEdMQX0)|&`=zqp(bv_Df*Tsjr+ zMOD0Qb)&GVt%_1Pwp4%g)!1|^bg*~+!ng5zw=TUV1*s*#(V)raXfelkLz70-{$bKP zk#Eh^@hk=a*xd7ftNafP&D>nsL}RoYfbieW1Aytn`%5yoW3Iwt s^C S~CN7PDNRaH2*`c6K@)`L&4@>o1qaWnIKh>ytf*tjY5?vQtcj7tob{#(o(;#yu4{ zsn)I@F%QZY_UAHs8I@j0LNBUke-^pWq5}==(W_YM4r3+X^i*Kbr@4IVNqZIGn(k?q ztrmeir?j*b v6Q(w%d~0w4o?0s^9x{qe!Jy{)aL zscAa!PXNEy9SB~9V*u6Why+MjUno`A#wLFPi5#1lDDqq#F9h7}Dxw@@kcB0mYD$qr zl7i6YJ7Wl!Jp^}AIRc<9ml4Y2*&4~5hDbL)Y(}XDJ^$l`o5^GXm_DoOse3=VhaE_k z23V04$VIE8aptFX&v#GYR5kvqX)XckRh{J3yRH7aj$UZiH1C?D^f;Zmwwu$K6U9-* z_0kdbiTq9C^0?ACV&)OM?VdZY)ht8UAn$%#B#lG^jNgR@K=F@b;=ITCqI}Dw49NmT zCVvoBxF~p*!Ah+}ag`1S$R+j+R)mP~81Bq>Lp0gg0L4o@C1%~j6KzlF(|^> _@2v&UDu z6c;14k2z{}eK&2g`@uQ2%KjDlB2N*>t-i7GexCQp87ct4j-z*Z0dx2*!{U4uU$0nF zD#Q*};iO=)-#w@3vuqAgV=oPzO3PA&)bzQ`B$hNsd5KL0ol+9V#&2SlLK0hc%mNoz zO^-%xq)Kw~8Oq}$`;998VvnZjtack*V7YS;|5C5TQu6}XSyzYOav#QXJUrC4?ZLig z-}0#c!-eII(9Q9dAk(Y?dT9lX(zD}=R!NrP$N?$kE3oRSv^|&Ad0*k>N(9Nc=b5V< z9OFGO!X0#EqgH?5L&vkKI98Hg<>{Ysfk+Y^r}Btu_u 4NikH7flwSIg6)z&A=Ep zTd*12HNXY@RZSDox^d%%@v-OsrM8N47lEJZqKD1n6q)##_@!{yrFx4R7F%HGHBdhj znZ%7CSYJ<-ILkir!y7@^by;C%*HMb2DQt``CLM;5Z!;rZ`SaNr2ORyF8{R=m?>77S z4G?QVD06!(ZL%~q89!=r-q9AIUf-SrxkQiSGeAJ}&c8qkRVkcXA`wA54*&xI7=wI~ znTYP%{M|GEP}oUJ9*<7%>X98-x>i1`kQhhjab7jGltyR^%N!=|i)Z+|#L+Q3XDf8r zAO31?*_tcRC*~3X$ *Fm-_1ID}KoD8TC zABkxzQB!d5bB)sApR;^TS|FiaKnuM&Rswe$G|V_`DE!MGl|d~HB@E3-eQq~vhFcx1 zk}hhGH7H<(8RosLGxMkQs=oP$x6FINB;Vhxtd%*Mz~UaDU|wHCcmn2abZjgakQ*RT zT};o)v*Y-eMZ(|@VQ^gQ y3g)IQ+$_m6*r@w@0!3T%Mv-8N{Wl-okM z*zuRD(OcYw>+89G2YF2%T?}`MJw0AbL!JbKvdF>EMPJ} eWvI!G;9l_5_oJ0d6^lic?J-0Gk#geQ2t88cwi25kWlP7jvT z+6pClN(eb!X;~|^OF;@?s&J 8b%;z2{xAnINX$}A)d5v8Ha?C|Tmh8@ zZcw&*S>QR?%kR`c{iGxEYYhl8QRK2MYfiqM`A*1$d)3D;7u>iYkRK6kZh+5tW~MF- z=JQS@d$KAAb@aYSUUQl=Uvdd&es3!y 17A4hx-F90ggy6TV9H93MzYO0VdTY(}2 zP8Lw&7%msWbi79Yx-yOoVj=JVbj* +2nrwn z7W^|`Gv98c(-dX|MD+~Ve6EWVlI55Xl6e=9Oy7h6V}Or2ARw&qPoUfytvaJVt~UN# zErRGf5KXmC4RLk I`bRn6{WKFY)LKa^iVJJ)5I+@$m@Q5uZXEY5(#Qi zd*_83(wsrH+q1$?pq_F*98|DcYD&-F%B@4GxWHTZm$G&pLg~B)3-dFI-rf{bBx6l%!+X z((=9} N}s{ zH}n2(Fg+uvHBk^fUTfW5AAbjn^CQdvMh7fzu?z5a_wiHu70_)fOH1HPix%)Ke91a^ z5=Rw~I3P#^ox`nxR^u3A@vtA DkMEzS7gK z^05X#J6MJK;nsW+(y8&z)Un}uz)nXI3T+`@QsB0#x0=vY_JK;p{wN7Lf_Avs=B7T6 za)9|Nx=47f>YbI`ls d5cW17Y{sAz|=aeC!t{NOlvP;49jMKlx z4d$s}^Qlfq3HT+*JqW(68TAjt0#OBcXDF5mSY1M(f_p=nqd2V!`-N|>0Q$P-NA$LK zM??5m6thkpl6aj5Gf5Du5;djnl$)Jm_Blr>G_7nm24~wp*(Bh+!aFfP3fI3dRB0-G zaH-UH_ED+d?#r=tzf3Q&?KAf09lHxa(WBMoxAR{2pYi0F7pr+WJq1pDkda8K;Y2_!z0{HaU}r-mR&oCQiF1GuaJi*%VoBK6rS> zrPL9#P CZA0Wc`o)#vhf0gzo_-cy}uSHRu xtKr=nQRKjVa}!@jHV_n&8?t$PWFM*L^=O3(IN5DAWxhVeHgWjFiU zo_cw;FxiFXNEd}sjSY)G(r&emW-6SYZxGwMUgywdC7q|g*;)w~DUmbkcWKKOrf(_S zso1b|?4sdTilg379z(a)b=13}cb7GSjLMsLB3cjoUG{z42f_bwoIzI#^LO8K2RyEN z*}p;>Hjp9+PN~_Q9v`NbxKFxv71q}3c~2Xr<1#Klcs>D$U_EXl3YnsAX@@^6WCF(! ze5wIWP~bRaM1pq_|6(qH |a2xy}y3fexWZ}a-T0%)IIMG zw^>PTZ7qR=YKnl;UGsp7L{7u(r}VxrmfAqo$OW)RR7XH*vnC+e0|Q$+V;Rapp$7 !iZtiK-LpSUn626#ewSmEdyI!i3==XU>9=9p)QkHLWR;)ZReoY-*RFkH!!}a4 zS)RK-cypvq#x84p&?^%&?Da@PS#MB^ItrJ?eHuDnXVchTZh6Ubnkkn>(5ks}vX0 zuq3fJ6W5t)9aYR)VXHe7N>GoCr;QJA26Y=ar5AP`a&iKrw8#}VQGzbz`XmCG56^-$ zK7UO7w7UIj(bL?S6e1I+tJn&O+7F?3r&_=93-jpx(|%X7vW-c-3kt??9C7YdG8Qn* z;$pbyehYTGeP_ORs ~j1!D6CK7#XRDn3UWe zO2v=Ceo#rxc|1zAZWx1g2Ze`)*}kxP@+mAV1Uyf{g7UHiJ&BI)`)oFL)LlY?i0m)b zBZ6xDD#gr<*(J;S3i 546H!(BEp;KmE){ zi+o_ZnrFAa?9D?;N*Yb98g`p>=xd@P)2*AKq|pjlY}a&j)$EcU5?y#<2r8hya$c`6 zAP%wIBGG5e=2h-~sDPMI7j=<<)Kg?7lD@T;o9TVH;c9Mf#=BNepb|-Jap^4 Lpqq_8Bc6H_5XvH}T2)wA> zNeBxoXp_@=hgkJ&8=k_BRC3lGRXJR!F7~)xEC<%~*!7|im}F8%qypz1SrwJ*KW1K) zb44;KJyBP`xr4!w5)szJ*+_>db?TR@AX0@FxQt%0uhqvW_FH0W_tE|zw8co2zcXQl z%nK+RM(*b1*mKi%sry5F!w4YF-;b+fKURCL>VebWlRoHZNuyt(PqOIIs6ebKIRyn^ z3~D}$xH3+IO-FA977%*S&hWf5it1n}7Wxjr9b%t!(8sszh9`w=*WBFQKf++K!NC{i z78ai9jzQOPb}202kP@(#p~=ap#Kb$*b#)K!MBb;5#k{Q^ $Y z?g4 6SdVf<+a|SHbaYwCT%{2*;2;2NB*UPU4dvu0=nS>bJab+ z7m(NEJ{PtP{J2a` kw|; zz9F$YDC@JB?wx5z{c<2Je0ca7@R@Y%Xb?fJjR=5Gkb(kydw~IZU>R#Q?YCNLQ0qul z>x2x+RY`ijJe p>xOsE?r^!qj=b pSn3i3=c1wlFJhXLy)!n)9SM1@;(w7CDl6?eN-67 zz8gFX$pR_QGmg }-0!ne Y+VirHy$bLI<}dxP0#DYLi@7WX zpXr z>D;3G} (IY+LG4w! s}_Sje-=*{W6jMjX^j4O+Pa z{7_g3&A)4b tF8$(3)E@ix9J`EA! z 5^24BwFD>?CYo1;}w zbWK;+zuE3y1mlG_kYi|@an?8COXuTaGmh(qznC3CZ-1$QJ0lY7OwT%J_V436Lw(+v z(P$@Rm_kli$8$~cOGQOb;=X+14ZbI%Ma~ux>?08alpkQ%)z9&U!bp8xPRj#K`n5q1 z@VqKx)PC(|{ym~CpM%=_c;rAYQFWh@QS4%u>*RjD6pRE6tq~rBSd}+3qvz~(>vCtH zW6W-4H+jYW(iCWPL2Ke+qn~X2ML}oUL)ap={910wyUHX0VDd#LsB(`Be@%J3y^yBA z{ZHg;U)_76tBbcfGzjoKl=$FRwmK*fjf=WX8qJ$kdHq(J2#w(8u@q9}K4Ug1li|nY zl4DhtC%A{n$7`qZ_;HW(;um3*q&x9h98*L1(1wdnST<1`ibPk}lJc^E8anlsoWR`9 z&JK^uw1jGg1XV*r1K2{KA_$z-yONTUQrXhXZ$HsS#T7aonodcFi+}%;>uL9;ppJKJ zpsTu-Q%;ESx@AQc3G}uIXYVZZe9>&a;osGw=InjKbo;RY_4}eCP4f9PT$Fvv<#wJ* zFvHaAcOIF9{i(9aX>6qKie(7RW@CH!upQ*?p$Ieo8z7bcWA=QL_KH`qKMxt{&=Pn& z46qU7X%@1~;Cs6`15uX-PNgFtC&I8@1AX1eeNu+;_ z-VoNT^1VpQTJzrb)efy{!`wq6bx`vLVqkE5Doo~J?mN8$SJTXuU#S&@{`99}d1l~l zFS*_>Z9fqYyd9d+d?l{rdH4ERx*IG(dV0>R40Uw7$Smj!3O?jiHx&ZZju~;(;my|5 zy>c|5{_qIU%xC6O^U+H2M*ZZZiNwk7$nUR~7c-zocG!J*zyg0gZllQ+Vd_2e?af6Z z!V5n8e{8moF>rKt -4-NG@AH=c_#}wWY&h$y*`HT+baeg} z6_)|ylarUf1X7^bo*rdL`uc1Twh0BC$~EkyyGGBEwPB~WhU9zGCa;-O+~y|2Dk%V} z+PoD>)NgW)Ip_jm_r=n}%QwW$ py&6W_& zN`ZkJk&%(x2k2OIvP}ja8Ygm_-+X-Q90ZuR(K|Ug+4XD4J < zQc_b%0r0=}zOuTAU;HRP^wq0&?5mZNe7Kl8l`w(V4>@#KDv$HN@~6NVv(dl<+TC#@ zRbzkS*zFNSAdOQ3vf```^>{rLZaMp2*s^EdT!o5^EjirR9C}OHl3l$8OKv}Xaxnm{ z%!BPcyZh# ?ABP1n2rRAH;3 zY (}w;x8~;NWOQ|ZRR#>eE_O>wdzwB4Uc=a!2DqQWiHV3; zBE;=H9~7BB6XSy(^*uejm%LF4ihN^YZUS$ntD9A1ADd_ZJb9w^ugbLz{+=Q&Mrz04 zd*2o@_iu;4@Mo8lbBKjN=F)yt#Z;li)SI`>Z^>Ql=q*#g4W$>LPOtUZJ{-XPX!+oN z%_1aqY8yDau0kw0>i?5E<}sZ#1#@rt<8>VT9=*dAh-%}K$}MK@o6ZOHy9?To*9#Xn zEw<|zWS2XFB6sqklU8)}%wc&cvITzYs3~OJSRrIktL84`gS59=&)%Ecgakn#ZQ2?T zPj^2-ww=)Em77HaCifOY(6Or#IET51sBlFq%q=dW7gAk1tzsoZ8XLt-y#82&@?nJ@ z1ArW^(EC6@$tdJC{u>R6ZNjp)Q@;|hIUrj}ZO50uUZ;E1xWw3eFdMlM$lZGI+{44e zqAP~(#4KkBO5H@?c 6J5^wJ#${mj+z40QJg=nzH O*C&Cqk$}CMHbZ7M2Y&N@fR u zU_+`X8B2^4e0yWXYO$>KGbf!(k*wk- E^?zwzGlGm{s;}&Br@3yFR3%o|LVcR|#k0rLDQNL+|;05PneOHd0Xvg(FSPVYqc< zUA~Ts6RMRC^3`@Io1pwn7+ 43OPN;Qrw NLy?=CE8@Gu1Z??6Y*)Nq)8v;Qmy)vQg5k34X~eO&RSz@%ew_I!ZY(G4 z7 X`Utmz|t_&k!^~Sbfu%% mJ&yw+Fe zDKXoW5aDSbE03W1Y=0HE?vYhbWCT{MwVadx@;!`;BgtI)Tqqm32Q~ccGWH#;ScW zF9Y_9%{w~onn&St!g{civ_MAM)6-MEz}4^<^SO3ksQOb-*aR1xk>2h-`Zt>)l 3X2(hpg`~ga4I!fcd%fyqpev^=6Uk6RV#)xbkc)t;Vwd2Pa{{{G}I3~Ry(i>!^ zWUy}V#F*R@cRu=9tRfT-iifs3&jHk(-?cYP5g o7F1dXI}!eqh$MYt zap!Ntmn#?T7lIU6QDOSz%=7!f!NCL!P4)GQ7y;<9kARR+-sCuloay4;vp^jG4nFgv z!s7b{37|&U!HvOC!UXkZelY}vl)(!R>>3c;F$prp9YWQ*ju)o`$hEoKD9H4tUjP01 zCoGLa!=Em2?8KLYlk**0gsttb0A1c80~Vs-)ZI0s?PTX!kfMSy_EuV?u*{wV$U_nQ z_=$c>g3KnY@|P$RXgDW8$Im zrPe aD#)KCCeZtLQLPXavConGP5jsnlWXh;@f`HhDd@D>2t1Bdcpn_cO4@b}CnctM_B zP7?(S>0UBhMEz{ULrqQ1*ZSsx6re8WkJ&KQ;ZA3}a2Zfe@2C+#2$f$x-u2Ksvx{cE z6 Mm(|5Xx8}#zHvXjU4WV$c6;N)+tqAhGRI>QgE1dwZcGq-fukyAP3m1gsr z{Wn)l%*N)G-QPdPa0C$kvePSR)0oSE8qFysFdFG5pu?I-9W6aD0b0z#hId;eI4ocV z6zvc5)5Yw#oSYm`faK3@7O*Y 4c z51dz_{jsi2Xw6}RV2dw{p_ddG0T l42#irHyX3CXH9bwjAB+ kDhsb@4DDhNxHKO_W?WlqME zH201kTol`AIPMBMz5 LGTk)FrSO-XawT`>C=4`=Hd_K#*3E{#R2Odc;HHFVA#F^sBSgHA>VfBf5d0QzD)c zGsEBx2oua J|GE(T6_Dx7g_+$12R%+UGM>|hd z6pdv7!fi?O24Al2(EMlLe!Ab-rS-6J`tE% EPt a}U2Q+Ien8 zcGR=t(S33_8SC?bG|~FC%3i= Ubl|oFhA_kKN8r`2s$D=-OZQ2vHm=yFeK!1iE-T{WN)Tc88qM| zlg{R)2TQYAdFm)Rew~w>r&}&|TYPmA2W!3;iNC3B!9TZiO(f>xhyWNplTt9?jNpr_ z+b p_HUYM-RW&zm_{LR@3>Q59(5m%4s>%wi zwC>Ric=om2{o*g>$WLXlNY}I|c=~bA?&SZmB+L*M1`uba2s~SfIrOU*BqRKOV#fIK zb=fMFU4AdnClI3Gnm1Hcqi>|5nXr4R8_RZviT=nx9FjQ9^hojs+`YbU)>qsr!w!Gl z suS?F9hA9~?3+;pesrWli>P-p_#-66Di53a7n0Lcd2Ram z-}5p|@d^`P46y`BAmGf*P*FQR5=58Zes!V&u~DG^zA>4V)V|pw-aYdq3W#u7 p2AWhsN#Ks1zg4xM=K*LShnZ^s>orG9{J$Lv!%vXZ`DImc(dx11#R$hnj zY6RS)7CB|e8*rL@>5P>UQ-Kv@1^e*LM@~D `)PsH6U$tNPCl_GRH+XlGqW*0@Rr)@}TAUN}gK0aJ?SJi5cq4gB!%km&srK#Ca} zu#-kpyubdaqldxe$*Y|-M{a8!Hcrl;0O7fgs0my9vu69;XCp#)3-lThR(rTx7sp z^^6L@`jL`a-#!Q4Rv*quR9k0f1p#VFH0vn9p8wQ7k~S1vk}W)J;J%I*0ZY(A;$z8$ zOLt9Pa|bS~y!BHBu*tAWp${3;%ozzw6p*yB-5A)4}1Pn3&kWZz iKXnjbk<&xidF2N0X^0Pumf)Yq#8WW4DXaO{5KjNn_eWf)=;wQ z{wj78-_s$*x$gZ7U`Mdw{woU5$6hHa`mu=FD &rSq-kyrTc1x)Mt@WP{Ku@L;CV`bRJcOC1yfk~9+{T$v($ZF zmT?U^p4)^M-q!Qr$COR_?ke!7jLIMXD=1I>w8chfKE4Iu0uT g0xu9$vdD**d$$&=2{&-)y2ce&2}f26$yP}N`bFA7r9NGKhmgmg%k zq%=rKNK1Ejr=)bZ(v5UUOG`IMcXz*i(BJ>wnRnmJo4IF>4vxUt-@Vsfd#%s A_3<5 |RBU(;!cTefLWOE|e-5L*yv*rUCUeWV3et-K?B?9u(m#q`)>N?Lig%ebj1KAq_ZQ z`j|oO=9PFE?M`U7et)22KSFelagZobSJ|@~9T|z*dwr^^r$>%P%o79(;ThG{&jEtX z;daTmK9C%Ed+YWW+>m;fUnl^gAjbBAU#ZL_VI-D5)59^$6s)Frf|c|FwJ!X+sNHfu z4w?OW V`J*(hr0vFKieQs0QfI*!u!<((3o*~*p6Nf;PxWbO85rHgD!6v zgb(4=easg1TNJBnYfE(-Y3;kymDX#qAG6BKpCz+fcGcVO{GOZJrQrSuz@>C>41%EF z3H*PV;Sh0(=lvC=JY25d2cZpI>@Yn;4FGsINbSLG2 7a73^cNhITXc|3bOjBg_H zY2Q7>cL6pFnwFy$if z&|CxjNeDed;@1ls*9U% xP%Ii@q_e7 zzabt3;UeiX8#4a_Z`%Dk8Az1f0YNIBovDH|4pjQ6f*&hu=Xv;h#i=DFJ5r&T`axM# z`++ak2UA19ih+v4XIE9@kZvw04gfdO@&-HoK!y4mWDfX z!h>UQMx3X7P^6aEFa2bR?V>ZGw12$KSh=)Vl~IR%`s8=tP*FYI5c+w0U+`yrLou-p z+o_3(tCWCt9RLYHK|zX4AZ0-%U;}VVjlIju$e#;MuH{xsZL~!xL9Zm+Qpjx?>l~Q> zzw*72Iz!0QJ$nYN4IwWDjeuG%;IM! YI} zpr8N)1zuiRIlzcDDc1c1bB_9r#k=EEm-*`DrtkxrzEEgfSN=+mljOxepdL7_3I8}5 z&xXAo%c;V?S*G0cpN}hR9O}XO3f{q40GGrKh>Q)J{~}rlG(K71zJ-QDBjWNSuxxzh zEdXWNcqAJ4F%C~clc|2fq1Sl@`e*Ues!&{7awIKH>xi4{<6xa`R28+)P&Bx=-;CM# zcs_jmh>&q&=<4k3+_eFMB*+V2YPl{D1B~S?^=~X J%E8PJZj88`Q3 z#e{tU1tbGhsYY{U0~Zg5&TW{ptcDGt-9Esn{rK}?%98g##&Zv%Vti-csP!c!x0;JmSQI251gR2G5nHSh<{eQgd$$3hKX9 znVqbK1zLVWgc6`jdII${rr&2X5*kWv1+hbK&zNXdixsEx;hOIU(Y$w~MZfLW|F{6g zAz#^TsZIDV$uVar?Xz=Z7HBg85q!^ z @8QQ9*4dpf0hDCy0q?(U;L=9)&)#LNCnnvcZv!8 z+Lre>OwZ)CuB`4K?m720 -FvH(sEpz5eo=#;V=k zI;N$9D0hhOG2t>&e54l!1$?SVEdlhYn>!HjV$>hpP(J;tk5@qp_yYhhmmUT5IC*gL z@)PIErpq`FfKanPfe9u~KNA3qv=@U#ZT|6@r%?~FHnXSpiw+DV&ifue2;CTp^+;UL z$U?QQIi;FzP0LPkWttvPOcoZtGE=B|Vh6I#g^ftI`1HJ(M}Z0&BYw9Qg8tHG+sZO< zud=$Ah@ &~tV-O7Yv6RDT zKErx@!vA2~>kgr|f3hD}f_lX5AXS%^jXO}yv$~jfT**ncXahxa1l73Vu`$29n+v_s z9BE^I;;dnb6c1$L`!zvAk4azs_yLjk`~fu+50nmZ^FHd6gJSQp@DF%h_&u)F-YyHG zt$QBP&mB$n$(fD+$*wVF+#B7ytZBJ>%eNm@i)};S5tbfZc9iDXnIn`+f@|uzrgfOC z8nHCE6aU9wYp=7w(+!QC@D|>}v-&w2&*hk-M?_1+T;Rdve5lr9JqjH3pL7qc;O-V% z2EJuu9Eb}ElYdOe<-4Y;_msmVqF|Mj=C`ZBx`D953&h|$xW8HVLW>>0 u35fHzcBvvL5oDo6H+pFy57oly;}f53aA&<+Y*DC zRZi$^tu^^$Jlg`+#)bEs|9*u(r(8FyT>Pn&kINxK?b)Ji_Te_k%B151Y&82^NJ~rR zlj9`rqn(x(xV}XXDDI7W&&$>@B+a^;5T|=#44RfJ*;=u=*%haeG0uco4ljO^tr=dS zc5hys!$npCESEZ2N(5=odnOA`du|U$F~W<7gNL8@us &1R2z)~ujcwT0ew{iqIE|!SW zLZ{4C5GiS49man|&!Ss`Qm@HeZupqZF&R>!)JN8ILDL9OOW3x{&4E25wP{;Z=sXW9 z7i_hf jTU@b0UaE0CY9 zt}N5dTFM6)A_(9gPmtHsY=qqb`mamX%g6*UU{}}Set#H;-6=wV$}nY&ff}=5cfIv+ zI#t^=^L{KQj#27XzYqXZ0Bcu03RGx}%*{o_#JcfjT`4Ze=%}a!EG+07H7x@^LQp?e z473?_E{r$*{2R&46JKl;T?V_OPU_PRE*Tx~X^n8i z_DVKr{}i0hA5HjS_c{m8?N_P?b;+lsiyr7@ie(eN<2&LY9_h!UfhqJcpTw_@+Otar zT!k;f+Nw?LaVL++2B_H!Fyii3t;B~7w&;uf!$pMCmg7T^WDJGfX+4%# z_+7-jZ+c6*FM-E7Zra_7=aN|Z$)B+FdtA@FP?$2gt7A`{=v%nkS!9Og8pl#Ejm7;1 zZuvUA VUX-JyCPrxZ($4Lh+QD--KGeM~hvZgBqL?w4@S` zf_;aftvZ2Ms2E^l5z!4mC>B2U|3d4bSAP>N0T(8~`3C4B$j5ii(yCsLu}TBi+|D>R zi+j@F+4%iC93X?@C7MzxDJwsc1;;u;s|LsoP&6h-`MMw}g|)~QCRs3B)NCf;U$>E1 zn080BT&Hs+;MS`G{s Y2Y?tUzQ`kxlO+#? i2k5f$blSoP+n&{lZMW3|NGSG_QxC|3=z!S z^AJE}bmAcfobQO-jr^}5p-{pBmhxyLqpYfLCCGzciPs*sAp@%DEAifQ8!+dOuZrNm zdqn|2J`kGRfOP1a;1SdDJRp*w59rq*r3Yr#S5Z-Bl69~8!{`|(ID$rIM$j~6#sFDk z$cw6w2OxAqzJU7Jz2a>?3rKoT 5i2nk0IXYdNPSG0H@${52o47 z55$n?bdQf GrF~Ojd{ZTiQ-7gAsZdT`Jwzc_=5hUbzuD3=rVK4HGhL|g1nNO(zK?$m z4J5FvPbWNn$h_YEmh5azNyw00LoFCc#YBM&2CPb4Y%Fg_#oPb2>rWg1g1X*I1h$~g ziwh4}!hltpMb)JIAt-CJdRF=sriJ8uWv4A|R|>N!IJ*+q%<& *4x)NJTsHDw+2ZgATLyc$K3|#m-?!IIii2J8((^9 zH^(~+7sW9AfL6Aum}e&&Lt>;DKhO7OE1R$(8vwkrbo?KUFN@EH5Fy97jddU @;YNN}1qp#SJez*zL* z9+6gIV*p-*8Yp;!0CwY~b>pPYmBlXhHqCq%xZmIQM4;gqxiDuK$e_K8)2IDZivbGN zyGM8G7Ikpr !>E1=s1urrm$&GQR) zT$I`3a)(7mS%GQhckh8dP9Yr~GB)!WKNZ?I|JcWQf((!3@9=y(s?8r6%zuuY=9)xB z T_xvNU&wQThyd_uhF8u{hWJUKT<(bf{p_$x>*HP@#sCy*AX5Y05Vj^ZTm|g~ zSGB36#waVOk*II~oe5MSa1gUftHgC$@MnJ|eF|8_6|_R~F_8TV|CbmnECiUy0IG9p z(gakn^dSV`HH^U(!H td2-;RLH7yfm$LRDDj;P5 z3 Dj0)-~AiV(Nw~z!Soyszs#|h3V zm!7l-WCd1sc0*Tc){c4$ -Ff;93y AeMJ*WFAyPIcCdb#6&dl@!f08fv2u*-_w3yHNI=w6s;3WW zRI(zZe9hV0Wct^O1%&IXnniPWSs@c-4ga%Dowk3AMJgV3BR;mEwvFWThe9^GM; %sR$ FtU@_@^g1KEqogH=Jn)a`+OpAAf1pLk>3}bxo+?ANB_Z8$*5@es?zQo zhA=b>Kku_neX>g*O{kx)5&L4FBu{Z0w)<=|tCFYgj)#dClW(S}!S7sb(!6>{SK#;- zZN3ds#0)YL{+r?&VQ-}o@=m5@LxFt<-T>j4jRVSN=xS%1xyeaZi_Pv|ufG~;j7 S9^`lR<5!JQEVX} zFKZl4c3@m**CU@rhxOu^dIMLQT)a%6b#6%J-RO~nqPeA)9=B0xgn_Fn470HZbPg@G z;8}_2g}p_ha!Z6lQ{gkzK=mahUXF*}eBUOizpJkQZ}Pv_Q?f@Reo&1g6aP?pu~mOy z1c>eWs{2e*qq~l0o6bvC>Cu@$LH!Q^Sq}H~`&6iB&;jYDc0I||sr)eLEgCT7m_x@V@M0du zXg?gVVoAo*Y b=cNQR#i4L_eRX8yb9{*|VKx}dtPwN;;^v_t(?#YviT99!W$ zq0WT#RgD)DOIJ@y-@BF|jQ|@trNP@C+~K%15P@sH$(KF5Y1Y%w*MAKNhYA+Rf$gel z1JgYP2qtOhd-ka~md;pDHjRQ%#b*t&BHt@>d-73+-hY%s`>5H1fS7IQI=3+O-1GV4 zVKn^bFW6{=0<=aUZn9GsH1re`p1CwN?Q QFnjoUI7^}=uiYz`ko?L_P1yC zhDKU+CZ_Gc2&TAd(jkOKz*#e6SSf0Jh+geUA5p!_sUkQmAoinx|83U@qd5-4ZPAY3 zX3{+u1!Yi@ g=61D{05v+bK=140=Zc 2@y7rI>qn5(iq{zWbr zlUSR1Kv_4iDyRzYPIKc@m8@Tj8}){bxEp+lEj8c|ERkm>AlOm%`>WpL+*R$7+b65o z2&9F?ucVOa#&rm1KOpd$)vv@o448Gyp#1V+unAU7nVRe z5FPsok40HVpf!f@eFbdsz|SwKs1_o&QKU!-^*?Z5+jhO{Icf`@4Px8jD6f1rK*@D| zH`P>tVA{;azg9iuW}E3+cSD@j<1h@i(7U#>d&3ra63hVqZ4FfF@+9CPzDt5fJ#Gzl z $dhU)C$_0_Q__nG*(nE*b09?`iCz3zaG1*_VY`HN$y3`{UpM@ zq}yHT$vZJ1Eg}k<1^7m%IQ~?*=afex4zt2O@s3GAW1o-aEo|l)YWh@P`}BKAh?Sc< zZ@48<5?f2_OB|q#N3opbUqA$!E3`*^1ZnFmo;&b;^tRILC*n3&Wopai#` z#7s zA*ISpd~c0(es@*NU81c NoR!Um@g@<4+dBrN+_l#9(r>XC(n)uTJsfp4 zh?I`$U9~;$`fpE#JM59WtHTj8(8mIcvHL zI0|GEFHO)rqIlApvtUQ#a8}0d4eZ9mmXuztN 8WXxFXXVg}9c!ZovVv@ko0@b+@ z)}Hn;yl(F+IbBmr39{iTSwiWbjzQ6m8C2L~9H((vj{w;ut)S_6DN!+ZY+yERFAlTp ztjTO7pG=)Aa?*~ 9JdeYQqKM2=JxWAyN&N=2!6QoyoN J`-iBJ4b`?(ED=8K}bn!kVG8QocjWnCjl!jfxL;W8HGD8F(uawv77X z&(51&2*dXTcHZ-UaiAY%pz YqH0a!C$jC{cdCB*y%z%^ zNvG3XO7#QmYcYowcD*&&jx$(?Cb=bwxPBGFO8S(9b1rvi1_MowXM1O 2{k<9`w zHx&5Kut@kkpseqrVHF1!C_Wu_o-jIF%Y#Cam71Z_`T{?ZWTHBTLUdy);!lByR}SN# z<6ZA&=ky3IWoj4-3b^D X~1hh0H=&PcAnv*7jYJ3;D#mkg~kC zXe2YL2&Tr@9zOg~ZEvK>(H*%JR6Mv|6`}=B)7r$7W!3A&XncIev9FrZ9=yc*I(hDU z5zo#l&@)Lp8bI3C L;q^?-_Va*rP`JcwPrG88ZV M)EUF@G5jc?-_Qj@JeM40=CG#4p_ICxlSyOWI z&pLfbHCzzCKKb@_!8P&vhP?l)I61FC+Qm*MO`_`%@5Y>~!LNSzbxulmM~~<#?45#8 zqJmMg9~`hkO54}AZ-xrHI)y?;{;Up&A_q&fa*xetq7` lz7-IVNuP@Xhw` zdZS;G^!85lYu{sZ+0+h=S-Yxt^ju4(N)-mScI--wEO`7e1fP=mVYm;~or#M=z7jlr zqwY1P&EY;eAIDjsT)6iDHC7BOIa@%py-5RF4=zCwhOnB5-y@~Yc7qx8-!QYVxaJ#% zr`X}k{k%|IS67lpm7&LX6FkFCq1rh=6B<{;!7r|#{wZ%>2b~VRZ)At>D)5WtS6CU7 zw-aoAmc9M$JQv+sAiJCMtan`?EL27hG$g5 zhpQ~Vw~u!&!+3bgplb+3Do5TsTj0E=r0L;QTg6ahNv2Jiifhk6Y?W$shQ+xWk6BZW zj#rctc_*EFZBk^7a;w&_93u)%m)a0l#sqyC;JUn9VEwD#jPSO?{Y$%ziAvFV`o!qU zR*8r_HLQp$7WUq}SxbstZt3h7qPmVx&j&9%h4SANeCH`m@)=`Bl07vGa5YuH;;uO) ztWql)Q^MQ3A+SIwOCq@Y!P<0h*s$KkvJ$vnsqk-}Hy99ukRY=hBxB6cX(41FvSlYQ zT9l&BzA(fF2L}i0&KQJ*p~{8!Pd{J8ePKs;{3S@}*}ioqgb<3R{c{s)#9_@^S4_q> z&@oAHHeF%=p1xxsBBLNLZe_M2pPEIxT;&MKfqc15+f~{?!F1@Pa)* K $t&mi%FsMdG>F0r3yTgcSGcN5l4PWZjFZ`>20n^OtIkd+RwWb{muTRz zb_5n=se#A0pDGDPHY#t<`e741(#u)>HaX}^D+(@=mum*iTHUzxb+U7YS3eBg=3G^W z7J>8wZi@wKkc u1``U%T$_`a#g*Okjx5E^UOYEsu5Sxk{yvFf=Yow9-OOpEgx-ShWwM?%S2hZtd%2t#RYVUB{~$}B#JRGS9avmJI%hoD#UDg zN1Ruc%dZQEdbFj;kF3yFmQd_>N0uS3U3GNY#8!m^e>0OqXWV#RS{TpLyhJSB`!-GH zMMnKM4>Lv7-0$OgNvEYHBSAez)>M;pGN}?Pwn#*4i%V~S!xX{8ffaUH*`7aDt7k=e z!`3YGyfStM2_`t}2ky5W<5-a@TvI7nQD@FjCGBr7z(aIW(x`D>?-~>_=`g7#5z%m* zI6dyJr)1agVU@PC{1~7&TdlZDw_Lm2ZYYV*(1bwX`}P$_iNtq6p`?8-8I3;6J6tWA z{Z2lH*iyagQ&%JV3_RXR+ABSJy#)eu-%w}S?P8_}I#RE#y1LX7p&wy2HS8dxM4J^9 z5<)~mdPzfr9Njb47RftQm` Gp2!#mMq^z7ohDK!ap8B0^)B2jE;6uJ-4c0k3OaSG zF)^0>We$W**rnag6yntVGrNROS1~^Eq%sloU!t9Md{0FAbN+rhrZb`NC0+w*Qc=6V zV*J?B?z*3089~VcS2Z2K8G~! y8>H>lshx8rom`qT+1>&?&Ej)Ol#$pc`fwc%QJ0YMu3$l zs9R*@6rm}kCbs<;P3#Hljvl--=Gv&*;QJcZ7`UT;u!LWY%Dm1i-qm;zR>#3^w`yr9 zxoW>~p}E1lZa9=+I>TZfmqlg7ick9-*}&FxC)$ozeO92-RMDQjN-ZplDq&!qn1lm- zId0Oa&3M`yq69IZ+}Z!P0WGd?bVD;R=t^=w-{ktU*2%`-Lcc$LWeUXjI5;^Y |<=w43sP%*0Z*C!9U~7=kLO2;r!AG{0x)L z1Znp*3k}2*d9U~c)iNf4Wkz#P?+r>^O65wAMnKBTXJpil;a}3*zEM+B?CXJn8;Bc{ zrWFN7;grB|7cgO%_gr65oAd3O!1mUSdJAW#OGs8(aQwg*^E3S5H;`4U`1}UtJL!8OI8jewpL$r!*4Yt ufDL7LYrS+6_%%;aW|Nw?$a zOLFp~!^5)D7fG?Po%{0*)O*@;YEQ`q*#K)JH!m+wVbn`Z_;g-G7zPIB=*alNZsC}? z